Don't push that merge button yet
Let others pride themselves about how much code they have written, I'd rather boast about the code I've read.
Let others pride themselves about how much code they have written, I'd rather boast about the code I've read.
Many years ago that's how I ended my talk about Legacy Code, making reference to the great Argentinian writer Jorge Luis Borges who said it in regards to books:
Let others pride themselves about how many pages they have written, I'd rather boast about the ones I've read.
I have always stood by the importance of reading code but little did I know back then of how much more important this skill would become.
I believe today, in the middle of the AI revolution, whether we like it or not, our craft is changing, and reading, is the most powerful skill, engineers have to keep shaping this industry.
Stop. Read. Think.
I'm not here to argue whether you should or should not use AI, that's your choice. I do have my opinions and like everything, for me, is a grey area which I like to approach with a mix of curiosity and caution.
To me, writing code was always a creative process, very similar to writing prose. You read some to get inspiration, then you write your own code/ideas. Today many argue AI is taking away the joy of this process, and I agree but I'm here today to offer some perspective on how to resist.
Let's try to re-discover and re-define the fun of the creative process in our craft. I'm old and cynical enough to be open and try AI, but also I'm old and cynical enough to do it in my own way, on my own terms.
Technology in general is taking away our attention span quickly, I have fallen for this and I still do, every day, that's why I strongly believe that, in our craft, a way to resist is to Stop, read and think. You might be thinking duh! Of course! But It's easier said than done.
It is very tempting to see all that code and just ship ship, get the rush of dopamine of seeing all the tests and checks passing and that big green button begging to be clicked so we can move tickets to the done column faster than ever.
My software engineering process today
I cannot believe that just a few months ago my process looked so different. It is evolving so quickly and it is mind-blowing but, more importantly, tiring. But in all honesty, when has our industry not felt overwhelming? Like we say in Mexico: it’s the bread of every day. So, let's keep moving.
But before we jump straight to it, I want to set some expectations, this is not a post to show you a super transformative, automagic multi agent orchestration process that will solve your life. If that's what you are looking for, I think there's plenty of awesome people experimenting with more hands off processes. What you will find here is a more personal process that helps me hold the technical context in my head during the agent's process so it doesn't feel as overwhelming when I have to review it.
For me, it is very different to leave 20 agents with different roles working on big pieces of code and then review that huge result than immersing myself in the process from the beginning with 1 or a few agents and then be there and review every step of the way, at least that works best for me.
I'm a very methodical person (or so I like to think). I like to bring structure whenever I need it, so here is how my process looks today. Is it good? I have no idea. But as usual, I'm sharing in hopes it resonates and helps at least one person.
And if you are still hesitant to continue reading, let me leave you with a quote that might sound familiar because I also stole it and changed it from a famous scene in My Best Friend's Wedding, which ironically, I think it fits perfectly, a scene about loss, and the strength to keep moving on.
Maybe there won't be writing. Maybe there won't be typing of. But by God! there will be reading!
1. Turning on the grill
Just for grounding I would like to mention that I use Claude as my code agent but I'm sure this can work with any agent/model that you chose.
The process starts with writing a medium length prompt with the problem and if I have it, an idea of how to solve it by using the grill-me skill, which if you haven't heard by now is a helpful tool to critically think about the problem at hand.
I use this skill to write an ADR or design document that then I read and I edit by hand because AI can be a bit verbose even if you tell it not to. So I go a lot back and forth editing both the format and the content and talking to the agent as well to refine until I feel the document is clear, concise and readable
Two things are important for me in this process:
- Visualize the solution. I ask the agent to diagram the solution (always), this might require iterations of it's own but for me is a key piece to understand the solution and tweak it.
- Validate claims. While I'm working through the solution I need to validate the agent claims, might require reading some documentation or in another session with a specific task/question.
2. The Plan
This is the step I review the least. Either within the same session or a new one. I use the design document from step 1 to produce a plan and create tickets.
I have iterated in this part, at first I would let the agent write the ticket and not really reviewing much the description. Now, I prefer to ask the agent to have three sections:
- The problem
- The expected outcome from this ticket
- The implementation notes (which come from the implementation plan)
I usually heavily edit the first two to keep them clear and concise in case my team mates need to read them.
3. Into the Diffs
This is the part that has fundamentally changed, and where I like to slow down and iterate a ton.
- I take a fresh session, and do a grill-me session with the first ticket to do the first pass of the implementation
- Then I open a draft PR and read the diff on Github, carefully, slowly. This is never the version I give for review or merge, is just for me to understand what the agent did on the first pass. On this stage I find myself editing things by hand or talking with the agent to clarify or change things, so there's a mix of old school, by hand, commits and co-authored commits. Always reading the diff every time I push anything. This also allows me to get used to the code and catch new things on every push.
- We also have agents in the CI pipeline that review code. I also read those comments and feed them to my working agent to review apply changes if make sense. Then I review the changes and make more changes if needed.
- Once I'm ok with the changes and I address the feedback from my CI agent reviewer I do one last step. I created the following agents:
architecture-reviewer,scalability-reviewer,security-reviewer,repo-convensions-reviewerandreadability-reviewer. I use them on demand, they are not part of any pipeline or automated process, I just invoke them in a new session depending on what I think the code needs, it not always makes sense to pass the code by all of these agents. These agents give me a summary of what they found, and then I decide what to apply, in independent commits, by pushing and reviewing the diff again. In this step I do also sometimes modify things by hand if needed. - Depending on the CI agent reviewers, I might need to make a few last changes or evaluate if needed but usual reading the diff EVERY TIME.
- I do sometimes use the agent to help me write the description but the majority of times I force myself to write the description or at the very least, heavily edit it until it is concise and clear (I know I repeat this a lot but it happens so often that is one of the things I'm more annoyed with, verbose descriptions).
- Then finally open the PR for review.
This is not prescriptive or always exactly like this, step by step process but I try to be disciplined because for me is important to remember: this is not your typical code review. On the days before AI, when reviewing a PR I would be ok with just being familiar with the code.
Today, I do this process until I'm more than familiar with the code, if I feel I'm just familiar with it, that's not enough, I have to remember, I co-authored the code and in many companies that means you are accountable for that code so I have to keep that in mind.
As it has been said before:
Every line of code is liability
4. Validation
There's nothing fancy here. As I mentioned before, I don't have magic tricks so there's nothing like good old fashioned manual validation. Run or deploy your code open your app and check your code is doing what is supposed to do.
For me, no matter how many review agents you have manual validation is not going anywhere. You have to put yourself on the shoes of your users and use your software! That's why we are here.
Finally, I added this part here because I have to admit, this part is still hard for me to do but we have to READ THE TESTS!
Tests are code, they are part of your artifact (same as documentation) so this goes back to the old days: we cannot treat tests and documentation as second citizens, so they also deserve some of the iteration process that I mentioned above.
Conclusion
As you can see, the process is long, might be slightly faster than before but that doesn't mean is easier, especially if you really want to understand what you are shipping. I would argue that today, is the contrary, this job is way more intense and cognitively exhaustive. I like to compare it with the job of a Book Editor, these people have to read thousands of books, learn to identify the good pieces, polish and yes add a bit of their own in the books they read.
Reading is not easy, nor quick and, if we think we really can go faster with agents, I think we are lying and setting ourselves for failure because if we do really want to go faster, there will be consequences, same as before. The ways we work might have changed but the accountability and the expectation of users to have good software hasn't.