Software Engineering When You No Longer Write the Code
In the following blog post we will explore the most important ideas, in my opinion, as we transition away from being code writers.
Soft skills
I think the soft skills portion of engineering grows in importance as we no longer write code. Having a strong technical foundation is still important, as we need to understand the output of AI, provide it the right context, correct its direction, or solve problems that AI cannot crack. This also depends on the organisation’s structure and size, but you have to remember that the role of an engineer is to solve problems that ultimately provide value to the customer, whether that is explaining to product why we should invest in a feature or aligning the team on a shared technical direction.
Avoiding arguments
We have all been in meetings that turn into arguments where each party is just concerned with getting their idea across instead of working towards a solution. Most of these discussions are inconsequential and just waste time. It’s best to avoid adding to them and let them dissolve on their own. You may wonder if it is bad practice to let individuals with strong opinions always have their way. However, agreeing is one thing; these decisions usually require follow-up action, and that follow-through is often lacking. Common arguments are about stylistic coding patterns, like class-based versus functional, or whether linting rules are helpful. There are also project management debates, such as whether to spend a lot of time planning or whether there should be pair programming. I think the answer usually depends on the situation, and it’s very difficult to say a certain rule is always correct.
It’s best to focus on outcomes instead of how you achieve them. If projects are delivered on time, at the agreed scope, and at a high quality in the eyes of external engineers and customers, then whatever method you used to achieve that is the right one. This takes experience and effort to achieve.
Aligning the right way
Instead of long winded arguments in Zoom calls, the right way to achieve alignment is to lead with data where possible and provide examples. This often takes the form of technical documents like Requests for Comments (RFCs), DACIs (Driver, Approver, Contributors, Informed) or Lightweight Decision Records (LDRs). A well written technical document is short and concise on the problem and solution, but also goes into technical detail if needed. For example, if you are considering using a certain framework and performance is important, you carry out a load test to see the impact. Or if you are deciding whether to develop a certain feature, you could look at customer usage patterns and measure the impact it could have. I would avoid things where the impact is unclear or I can’t clearly define it. That’s a signal to me it’s not worth our time.
Verification pipeline
This could also be known as the testing pyramid, where you have many unit tests, fewer integration tests and even fewer end-to-end tests. Personally I don’t like that analogy, because it’s hard to set rules in software. I think it’s okay to have more integration tests than unit tests if that is what helps you prevent regressions. What is universally agreed is that you must have a performant, reliable and high coverage suite of tests that covers both the functional and non-functional requirements of your software application. This is critical to shipping reliable software with velocity, and it also enables us to let autonomous tools like AI make changes with confidence.
The hard part is actually implementing this verification pipeline, because it costs a lot of time and effort to build and maintain. That’s why the test pyramid exists: to balance the trade-off between coverage and maintenance. Like most things in life, I believe it’s an iterative process. You have to ask, what is the smallest change I can make today that will deliver the most value? Usually I think it would be a script which executes the critical path of your product. If you are a platform team like a model provider, it would be a script which calls a set of APIs to simulate a user building a harness. If you are a product like Jira, it would be a user signing in and creating a Jira issue. Once you have your critical path covered, you can make changes with confidence, whether it’s letting an intern or an AI loose on your code.
Understand the system not niche parts of it
As we transition from code writers to code readers, the bottleneck is moving to human understanding of what is being built. Humans still need to be the decision makers, as AI does not have empathy and may not ultimately make the right choice for humans. We don’t want to compete with AI at code writing, as it already crushes humans at the task; its ability to contextualise entire languages and complex code bases and make changes to them is unparalleled. This means there is less and less value in going deep on a certain area of the code base. The value add is understanding your domain and the services in your system, then planning and directing AI to make changes in the correct parts. This task is much harder for AI because there are a lot more moving parts, and it requires a deep understanding of the domain you work in. An example is directing AI to migrate a workflow rule entity for a third party app. Just this sentence would not make sense to most people, both outside and inside Atlassian. Currently AI cannot piece together all the information required to form a coherent solution, and the human needs to provide it context on where the code lives, which teams own it, and what this entity is. Even with all the context provided, we find AI struggles with domain specific requirements.
What does the future look like
Currently programmers are orchestrating AI to generate the appropriate code using their expertise in coding and the domain. Professional programmers are still needed to create guardrails to ensure AI produces valid, maintainable, reliable and performant output. However, people with domain expertise can now have a greater impact by implementing features themselves. Programmers will also need to move to a higher level understanding of the system, and I think the leading companies already understand this, hence there are fewer openings for mid to senior level roles. Instead it is mainly principal level roles, showing a push for higher level understanding instead of pure coding. It’s a scary time for career-long programmers like myself, but I think it’s also an exciting time if we continually learn and improve our toolset, like when C came along and let humans be more productive writing a higher-level language instead of assembly. Today, it turns out the high-level language is English, with the emergence of LLMs.