In the previous post, we saw the limitations of AI developer tools. Yes, they are not perfect. However, they are still able to improve our productivity significantly.
This time, we’ll dive into how we can effectively use them to achieve a better development experience, higher-quality output, and faster delivery.
Why Do We Need AI?
First, we need to understand our pain points to identify solutions. According to software.com’s Global Code Time Report, the median daily code time per developer is 52 minutes. Considering that most of us enjoy this activity most, this is a shockingly low number.
The rest of our time goes into the following activities1:
- Meetings: We must share knowledge and synchronize our work with peers. Also, we need to keep in touch with stakeholders. Many companies have other types of meetings with varying usefulness.
- Maintaining documentation: A different form of communication is written text. To ease the job of our peers, we should maintain documentation - whether it’s a user story, software documentation, process documentation, etc.
- Reading: Ideally, someone reads the documentation we write. On top of that, we read many other things. A few examples are existing code, StackOverflow, and language specifications.
- Learning: IT is a rapidly evolving industry. If we want to be up-to-date, we must invest in upskilling ourselves.
- Administration and chores: Reporting, periodic password changes, software updates, and timesheet submission fall in this category.
- Code reviews/pull requests: Code reviews ensure software quality. But, depending on the author and the reviewer, they can take significant time to perform.
- Collaborative work: Software engineering is a team sport. We need to help each other or brainstorm about solutions for more effective work.
- Building software: Build times are still a factor2. Different languages, frameworks, codebase sizes, and building processes heavily affect this, but we can’t ignore it.
- Debugging and maintenance: Finding problems in the code and refactoring are essential parts of the software lifecycle, and they can be very time-consuming tasks.
- Context switching: We suck at multitasking, and our focusing capabilities are also limited. The overwhelming amount of external stimuli and the cognitive load of software development puts the cherry on top. As a result, context switching is a significant time consumer3.
- Socializing: Humans are social creatures. Even software engineers need human interactions. Interacting with our peers outside of work-related topics is crucial to our mental health.
- Resting: Time-to-time, we need a break. We must take a short walk, stretch, look at our emails, or use the company ping-pong table to recharge our batteries.
This list is not exhaustive but covers the most important items.
We can boost our productivity and happiness by making as many of the above activities as efficient as possible.
The two most exciting areas where AI can help us are text processing and code generation.
Text Processing
As we learned in the previous post, we shouldn’t trust AI tools unquestioningly. But that doesn’t mean they can’t be helpful. We should also pay attention to legal considerations when we use them - especially for work. We should keep these considerations in mind when we apply the following tips.
Reading through lengthy texts - especially poorly structured - is challenging. Large language models (LLM) are pretty good at extracting information from them.
For example, we could ask them to summarize the entire text so we can have a bird’s eye view of it. Then, if we need more detailed information about a specific topic, we can ask directed questions. It’s essential to ask for a reference in the original text to double-check the validity of the answer. There are many prompt engineering techniques to achieve this. Prompt engineering guide is an excellent site to understand them.
When it comes to user stories, we can identify them manually and create them from requirements using prompting techniques. Using a standardized user story template is beneficial so that AI will include all the necessary information.
Handling PRs is also easier with AI. When we send it, we can summarize our changes in free text (for example, Graphite does this). Reviewers can also generate a summary if the author didn’t create one. On top of that, they can prompt about different parts of the change to better understand it.
We can even request code examples based on language, library, or framework documentation. Like with StackOverflow answers, we shouldn’t copy-paste the code without understanding it first.
AI as a Programmer
Compared to text processing, it’s even more exciting that LLMs can generate code from our prompts because they already know of many technologies.
Nvidia CEO Jensen Huang predicts that AI will kill coding. John Carmack, the co-creator of Doom and Quake replied to him
with the following:
“Coding” was never the source of value, and people shouldn’t get overly attached to it. Problem solving is the core skill. The discipline and precision demanded by traditional programming will remain valuable transferable attributes, but they won’t be a barrier to entry.
Many times over the years I have thought about a great programmer I knew that loved assembly language to the point of not wanting to move to C. I have to fight some similar feelings of my own around using existing massive codebases and inefficient languages, but I push through.
I had somewhat resigned myself to the fact that I might be missing out on the “final abstraction”, where you realize that managing people is more powerful than any personal tool. I just don’t like it, and I can live with the limitations that puts on me.
I suspect that I will enjoy managing AIs more, even if they wind up being better programmers than I am.
So, could we use AI to replace software engineers? In a previous post4, we learned that requirements and code are different representations of the same thing: software behavior. Since it’s nothing more than transforming one representation to the other, theoretically, they could generate entire applications (including tests) from the requirements.
With current tooling, doing this wouldn’t be wise for the following reasons:
- We have no control over the code quality
- We can’t easily verify that the requirements, code, and tests are describing the same behavior
- Humans still suck at writing precise requirements
- Implementing entire applications is still too complex for current AI tools
The solution is to follow the same process we do today: create the code one user story at a time. The changes will be more localized and easier to reason about. Also, we should have manual control over what is happening during development. What changes is that we’ll use AI to generate some parts of the code.
Test Vs. Code Generation
We already know from the post about software behavior4 that tests and code cross-verify each other. Therefore, we should write one manually and generate the other with AI. This way, we can ensure that the software works as intended. But which one should we write manually?
Tests and code are on a different abstraction level. Tests describe what the software should do, while code defines how.
Many developers focus on writing the code first and then adding the tests because they don’t like testing. It seems obvious to automate test generation because they dislike that part. However, this introduces a few problems:
- It is like writing the requirements based on the code. We verify that the code does what it does - including bugs.
- Jumping from requirements (user stories) to implementation is jumping from the “what” to the “how” question. It’s a significant cognitive load.
- Verifying that the code, the tests, and the requirements are in sync is not obvious.
- It’s hard to incrementally add behavior to code when we think about the final solution or when the current implementation traps our thinking.
- We may need to rewrite entire parts of the code to alter its behavior.
On the other hand, manually writing the tests has many benefits over the previous way:
- Both tests and requirements focus on what the software should do - making it easier to transform one into the other - primarily if we use a high-level syntax like Gherkin.
- If the tests and the requirements are in sync and the generated code passes the tests, we can be sure that the code works as intended.
- The developer’s cognitive load is lower.
- Every test represents a single behavior. Adding a new behavior means adding more tests - without touching existing ones.
- AI will generate code to pass tests. It doesn’t mind rewriting huge portions of the codebase.
In other words, we reinvented test-first development (TFD). Currently, the industry prefers TDD over TFD. Primarily because it’s easier for humans to evolve the code incrementally, one behavior at a time, rather than writing it in one shot. AI tools don’t have this limitation; they can deal with more complexity and larger code blocks. In other words, they might bring the golden age of TFD5.
Conclusion
As of 2024, AI tools won’t replace software engineers. But they can significantly improve our productivity if we know how to use them. We must learn effective prompting and new working methods to utilize their capabilities.
In this exciting era, every developer has the potential to drive change and revolutionize how we work. Are you ready to do that?
-
This comic is an excellent representation ↩︎
-
At least for the few months before they wipe out humanity ↩︎