Published on

The Reasoning Is the Hard Part

Authors

I have been thinking about what "software engineering" actually means. Not the job title. The discipline.

We use the word engineering casually. But most days, what we do does not look much like engineering. It looks like opinions.
Someone prefers this pattern, someone read a blog post about that architecture, someone feels strongly about a framework. We argue, we pick one, we move on.

Then I came across David Farley's definition in Modern Software Engineering, and it stuck with me:

Software engineering is the application of an empirical, scientific approach to finding efficient, economic solutions to practical problems in software.

Every word in that sentence is doing work. The definition is Farley's — the reading of it below is my own:

Empirical and scientific means based on facts, evidence, testing and experience — not preference, not fashion, not whoever argues loudest in the pull request.

Efficient and economic means we are not chasing the perfect solution. We are chasing the one that solves the problem at a cost that makes sense. I have written about that before.

Practical problems means the whole thing is pointless if it does not ship and create value for someone.

That is engineering. Everything else is just typing.

Code Contains the Answers, Not the Reasoning

Here is the part that really got me thinking.

Open any codebase and the answers are right there. The problems and the solutions are always clear in code.
This is how we validate the order. This is how we handle the timeout. This is what happens when the payment fails. Code cannot be vague — it does exactly one thing.

What code never contains is the reasoning.

Why a timeout of thirty seconds and not five? Why retry three times? Why is this handled here and not one layer up?
The code answers every "what" perfectly and every "why" not at all.

And the reasoning is the hard part. It always was.

Writing the code is the easy bit — more than ever, now that machines can do a lot of the typing for us. The value of a developer was never in producing the answer. It is in the chain of reasoning that leads to it: understanding the problem, weighing the trade-offs, knowing which evidence to trust, and knowing why this solution and not the ten others that would also compile.

That reasoning lives in your head, in a commit message if you are disciplined, in a conversation that nobody wrote down if you are not. And when it disappears, the next developer inherits an answer with no question attached.

What I Try to Hold Myself To

Somewhere between the definition and the reasoning problem, I ended up scribbling a few lines in my notebook. Not a methodology, not a manifesto — just what I catch myself caring about on an ordinary working day:

  • Make it easy to understand. The next reader gets my answer but not my reasoning, so the least I can do is make the answer obvious.
  • Let code test the code. Testing is how "I think this works" becomes "I have evidence this works". It is the empirical part of the definition, applied daily.
  • As few bugs as possible. Not zero — that is the perfect solution nobody can afford. Effort goes where failure actually hurts.
  • Create value, or do not bother. If it does not solve a practical problem for someone, it does not matter how elegant it is.
  • Clean up, always. Small, constant improvements. Not the big rewrite, not the refactor sprint that never gets scheduled.

Nothing on that list is clever, and it is not supposed to be.
It is supposed to be true on a Tuesday afternoon when the deadline is close and the tempting shortcut is right there.

Final thought

The uncomfortable conclusion for me is this: if the reasoning is the hard part, then the reasoning is the job.

The code is the output. The tests are the evidence. But the thing I am actually paid for is the chain of decisions that only exists in my head unless I deliberately put it somewhere — in the design, in the commit history, in a conversation with the team.

So lately I have been asking myself a simple question before I ship: could someone reconstruct why from what I am leaving behind?

If the answer is no, the code might be done. The engineering is not.

These are reflections that came to mind after reading the opening chapters of David Farley's Modern Software Engineering.