The Burden of Responsibility

27th August 2025

Outside of work, two things I enjoy are cryptic crosswords and sudoku puzzles. They're clearly defined problems with simple rules and a single correct answer. My work as a software engineer is similar in many ways. There may not be a single correct answer, because there are lots of ways of writing the code, but we get a clearly defined problem in the form of a bug or a feature request. The rules are to complete the task, while working within the constraints of the existing codebase, as well as trying to keep things fast and secure.

Using AI to write code is like using AI to solve a crossword. A completed crossword brings no joy, the joy is in solving the problem. Sometimes I get stuck and frustrated, but that's outweighed by the pleasure when I solve another clue and move a step closer to a solution. If we use AI to solve the problem, our only job is to check the answers.

I'm not paid to write code, I'm paid to solve business problems. Part of that is writing code, but it's plenty of other things too; translating product requirements into code, ensuring that new features don't break existing ones and keeping the application and all the infrastructure as secure as possible. At the moment, AI can only solve part of the puzzle. You can't give it a product requirement and expect a complete, polished, fast, secure solution, but plenty of people think that will change in the coming months and years. If that's true, then software engineering is no longer a career that offers the problem-solving challenge it did before. We are no longer coders, we're reviewers.

Screenshot of a tweet from @AuthorJMac  that says: "You know what the biggest problem with pushing all-things-AI is? Wrong direction. I want AI to do my laundry and dishes so that I can do art and writing, not for AI to do my art and writing so that I can do my laundry and dishes." Like this, but with "code reviews" instead of "laundry and dishes".

When the idea for a blog post comes to me, it seems to be fully-formed. It isn't until I try to bring it into the world that its gaps and flaws become apparent. When I sit down to build a new feature, it's the same. As I read the description I start to construct a solution in my head. It isn't until I start to actually write the code that I see the gaps. I remember that scheduled task I'm going to need to account for, and the webhooks I'm going to need to handle differently. We build confidence in a solution by considering each step of the process as we're writing it. If we're no longer writing the code, we're no longer going through that process. Writing the solution is the path to the solution.

When we review pull requests from other engineers, we call on our knowledge of the application. We try to judge whether the changes we see will complete the task at hand, while conforming to our design patterns and style guide, as well as being performant and secure. We give this our best shot, but when we haven't spent the time in the weeds of the problem, we're only ever seeing part of the picture. This is why the ultimate responsibility for what is being released always remains with the writer. They are the person with the most complete context of the task at hand and the reasoning behind the implementation.

When we work together with a junior engineer, we shoulder some of this responsibility, because they're still learning the codebase. We help them uncover the unintended consequences and side-effects that are hidden in the shadows of their unfamiliarity. Over time, as the junior builds their knowledge of our project and familiarity with our style, we can reduce the level of scrutiny we apply to their work. For senior engineers that know the application deeply, for whom we have a high level of trust, we may just be checking for small things.

But an AI can't ever take responsibility for its work. Now we're relegated completely to the role of reviewer, but have to take on all the responsibility for what gets released. Without spending the time wrestling with the problem, I haven't built context and can't accurately judge whether this implementation is the right path to take, but if something goes wrong or something gets missed, the AI isn't going to lose its job.

Just as the process of writing the blog post makes it real, so working through a coding problem helps us to understand whether it's the right solution for the task at hand. Using AI we're losing that familiarity, but we still have to shoulder the burden of responsibility. The longer we go on reviewing code rather than writing it, the farther we get from understanding the codebase and how it solves the business problems.

What I cannot create, I do not understand.

- Richard Feynman

One suggestion is to use the AI to perform the boring parts of the job, like writing tests, but they are also part of the process. If I write tests before the implementation, then I'm looking to write the cleanest, most obvious API, that then informs the outer layers of the implementation. If I write the tests after the implementation, they help me to think through all the different scenarios I need to account for, and whether there are any edge cases I may have missed, as well as whether the implementation covers all the requirements and acceptance criteria of the feature.

AI robs us of the joy of solving the problem and leaves us holding the bag of responsibility.

Where Next?

There are plenty of other parts of the work that AI can be useful for. If we're working with a language, framework or API with poor documentation, or that we're not familiar with, it can help us learn. But we still need to be the ones writing the code.

I hear and I forget. I see and I remember. I do and I understand.

As the adage goes; "you can have it fast, cheap or good, but you can only pick two". When we use AI to write the code, we're optimising for speed. We don't have to slow down to write the code by hand, it's gifted to us on a platter, but every optimisation has trade-offs. What might the process look like if we were optimising for something else, like security or readability? Rather than getting the work done in a fraction of the time, it might take the same amount of time as it does without AI, but the end result is better optimised, more secure, or more readable.

An alternative flow, that allows us to perform the enjoyable parts of the process but still enables us to leverage AI, would be to flip the scenario and make the LLM the reviewer. We might still load the codebase and the acceptance criteria of the feature as context, but rather than having the model write the code and us acting as a reviewer we could write the code, immersing ourselves in the problem space, and use the AI as an occasional reviewer. It might suggest alternative implementations that better match other areas of the existing codebase. It might suggest alternative variable names that are more succinct or more descriptive of what they're doing or what they hold. We leverage the models understanding of code, without losing familiarity with our codebase.

Sadly, as Dan Sinker has written, we are living in The Who Cares Era. Care and craftsmanship are secondary to speed and economy. Humans seem hard-wired to optimise for convenience over just about anything else, so I don't hold out much hope. Fingers crossed I'm proved wrong.