Can You Still Be a Software Engineer If You Don’t Write Code?
For those of you who are not software engineers, let me introduce you to a new diminutive called “Vibe Coding”. It refers to the process of using AI tools that produce code without you writing it yourself. If asked, the AI will not only write the code, but also write the documentation, various types of tests (unit, integration, and CI tests), and even a list of helpful references on how to install the code and its dependent libraries. In my working life as a software engineer, I had just started using AI tools for code generation, but only to generate miscellaneous snippets that were too difficult to write myself or to act as a starting point for a greater effort. I never used AI tools to create new projects from scratch. In part because the tools were not sophisticated enough, but also because I typically worked on large code bases that preexisted AI-generated code. For this reason, my view of Vibe Coding was quite limited.
Over the last few weeks, I have been working, or should I say I have been collaborating with my coding “agent” (the harness used to call the AI model) on the development of a project that would serve to acquaint me with the workflow of sim-to-real development for Reinforcement Learning with a 6-DOF robotic arm. I will tell you more about this project (latest version available here) in a future post. For now, I will focus on what I learned about using the agent effectively, and I will let the project documentation (generated by the AI) explain how the project works. This post is less about robotics and more about answering the central question posed in the title: can you still be a software engineer if you don’t write code, but instead use only what the AI has created for your project?
First, let me define what differentiates engineering from most other professions, particularly when collaborating with researchers. The engineer is usually the one responsible for turning what researchers have conceived (or hypothesized) into a working prototype. This is analogous to the work of the “experimentalist” who seeks real-world results relative to the content of the work produced by “theoreticians”. This often requires the engineer to solve the problems that were impossible to imagine within a conceptual framework of a research paper.
With this in mind, can an engineer still be an engineer if the prototype is implemented, tested, and documented by an outside agent? I mean, what’s left for the engineer to do? Indeed, why don’t researchers just let the agent read their paper and let it produce the code to validate their concept? In some cases, this might actually work, but only for projects of limited scope. This will become clear as you continue to read this post.
Vibe Coding: Step 0
In my career, I spent a lot of time writing specifications for code that would be written later by myself and members of my team. It would be reviewed by users and other engineers, as a means of soliciting feedback and, hopefully, to forestall an approach that might be doomed to failure. This approach to describing what you do before you do it was included in a design process called the “Waterfall Method,” which emphasized how knowledge spread from top to bottom and trickled down to other stakeholders.
Another method emerged years later that encapsulated what we already knew: that you couldn’t create a specification for something that you didn’t really understand. And that such understanding could only come from small experiments that revealed essential facts important to the overall design. This technique of iterating on smaller projects, documenting the result, and building up the specification from actual results is called the “Spiral Method”.
Why am I telling you this? Because the agent must also have specifications! And it must have them before you get started, and they must be continuously updated as the project evolves. This is important for the same reasons it would be important to an engineering team of human engineers; we can’t work on anything unless we can agree what it is we are working on. In the case of an agent, it is even more important. Agents don’t remember from one prompt to the next what they are working on, and they will take liberties with your code if you don’t constrain what is allowed.
Imagine that someone new was just added to your engineering team, and this person knew nothing about the project. You would have them read the spec, and you would answer questions as needed. They would accumulate knowledge both from the Q&A and from the written document. The agent is similar to the new engineer, in that it must read the document to learn about the project, but it lacks the benefit of the Q&A, and this is where the fundamental difference lies. The agent will quickly read the spec when needed and reread it as needed to refresh its limited context (i.e., working memory). It will make all kinds of assumptions about what must be done to achieve success; sometimes it will be correct, and sometimes it will result in an agent that suppresses warnings and errors to get the test to pass. When I saw the latter for the first time, I was delighted! Human engineers will occasionally do the same thing if it can unblock a project stuck on one issue. In this case, however, I wanted an honest test result.
So, what is old is new again! The Spiral Method of project specification is back and is more important than ever. The agent must be given an abundance of information on all aspects of the project, including feature requirements for each phase of the project, design objectives, testing requirements, branching policies, etc. Thankfully, you can use the same or different agent to help you start these documents. There is no better way to create detailed Vibe Coding specifications than through the use of another agent. And I must say the recursive nature of this process seems most fitting.
Agentic Superpowers
I have spent many weeks, even years, learning to use third-party libraries. One of my favorites is called the Robotic Operating System (ROS). It has successfully served as the framework for developing robot-specific code within a robot-independent framework. Over the years, the ROS framework has evolved and adapted to the need for real-time performance and full-featured simulation, while retaining its core requirement to keep the logic that commands the robot independent of the robot hardware.
This practice of abstracting vendor-dependent features with vendor-independent interfaces is more generally described as an API (Application Programming Interface), or SDK (Software Development Kit). I often spend many weeks and months developing proficiency in using these APIs. Still, I do so willingly, knowing that after I have made the investment, I will be able to leverage the associated capabilities that would have otherwise required years of effort. Still, after the time spent learning to use the API, I have less time for developing new code to implement an innovative solution. By design, the API encapsulates something I don’t want to do myself, so the less time I spend getting the API’s to work, the more time I can spend creating an innovative solution.
I have frequently used ROS over the years, each time regretting that I was not more proficient. The AI agent has no such regrets, and I must admit it has given me a superpower that is emblematic of the power of Vibe Coding. I indicate in particular files, akin to a section in a traditional specification, what packages in the ROS framework I want to use, and the associated feature. If additional information on the robot or on how to use the API, including sample code, is available, I provide a link to these references in another file, and I can assume that the agent will read these references. Any background information I find online I can reference as a URL, and I can ask the agent to update the documentation to include this information to help human reviewers better understand how the project was implemented. Within minutes, I can see newly generated code with tested and functional API calls implementing my specified feature. This has the effect of getting sample code that suits my exact requirements and is the best kind of documentation for learning how to use the API.
So, if I no longer need to learn how to use APIs for the common code, because the code required to use the APIs is not written by me, what will happen to the many years I spent acquiring the skills to write readable, well-crafted code in many different languages? What do I say to the younger engineers I mentor, who are trying to decide if taking a class in developing software in one or more languages is worth their time?
Should We Still Learn To Code?
Before I answer this question, let me tell you something about what it is like when the agent is running. After you type the prompt, which unleashes the agent to work on your behalf, you will see the output that grants you visibility into the agent’s thinking. You will see what looks like an inner dialogue with itself, not unlike a detailed engineering log if everything the human engineer considered, created, and later tested was documented. As the project grows with more source code and successfully implemented functionality defined in your specification files, you will notice that the agent begins to refer to certain functionality with particular terms or phrases, some of which will connect directly to the code itself as a variable name or self-contained feature. When this happens, it may become difficult to understand the agent’s output, as though the agent is now speaking in a project-specific language that must be learned to keep up with what it has created. Being able to read the agent’s output, particularly in the latter stages of project development, is essential. Let me explain why.
If you are a working engineer, you will undoubtedly remember what it is like to release a project that is almost finished. The last 2 percent of a project always takes the most time to complete, since these are the most difficult problems to solve that only became apparent later when you thought everything should work. That same dynamic will exist when testing the project containing code written mostly by the agent. You will find a bug, explain it in some detail to the agent, perhaps even providing log files that demonstrate the issue at runtime, and develop a prompt that asks for an analysis and possible solutions. If you don’t understand the code the agent has created, you will likely not understand the details of its analysis. You could ask the agent for a recommendation, and keep your fingers crossed that it actually resolves the issue. Remember that this is a bug from the elusive 2% category, so the fix you get may only patch the issue and may not resolve a more fundamental problem that has not been identified. The patch may cause the agent to keep trying if only one aspect of the issue is resolved, and it will do so while consuming your token budget. Hopefully it would eventually realize that the solution is not forthcoming and seek a different solution, or it may redefine the requirements if this problem is related to an unspecified feature. What it is unlikely to do is stop and reflect on the current approach and consider starting over with a different approach. Without your guidance, the agent will work to maintain its existing investment in the project source structure and design. It functions like a good engineer seeking to iterate using the Spiral Method, rather than conceding defeat. It doesn’t mean that the agent is unable to seek alternatives and abandon its current approach; it just won’t do so without the benefit of your collaboration.[1]
If specified in the project rules files, it may be possible to give the agent an unstructured problem and let it wander the solution space for the best possible answer, while discarding failed solutions. This is something I haven’t tried, though I imagine this would rarely serve my purposes, since I have many constraints. ↩︎
And this is where your ability to read and write code in a particular programming language will come in handy. You can probably get along just being able to read the code, but learning to write in a particular language as well will make it that much harder to forget. The agent will make references to something in the code, describing it in terms of a variable name or runtime parameter, or in my case, a configuration YAML file. If you can’t read the code, you won’t be an effective collaborator, and you won’t be able to evaluate whether the current approach will converge to a final, fully functional solution. Hitting your head against the agentic wall, telling it over and over that the bug is not yet fixed, can be agonizing. You may be tempted to enhance the integration test suite and just have it iterate on its own, but the probability that it will find a solution that you understand is remote, and you will become increasingly disconnected from the project. When this happens, you are no longer functioning as an engineer in your use of the agent, but as a testing technician assigned to execute a complex test sequence. The latter is an important role in an engineering team, but probably not the role you want for yourself.
Using the Agent for Project Planning and Restructuring
On one particular issue in my project, I had reached a wall, and I knew that the current approach the agent was taking would not achieve success. I also knew that no matter how good my coding skills were, it would take many hours/days to fully assimilate the code base it had created. Admittedly, I may never be able to fully understand it. Not because it is unreadable or poorly written, but because I don’t have the requisite understanding of how to use the API or the mathematical underpinnings of the current approach. This is when I used a more advanced (i.e., more expensive) agent. It read the specifications (the specs pay dividends yet again), read the code, read the logs, all of it, and within a few minutes it became an expert. I could then ask for an analysis of the problem, ask it to explain certain debug output, or even specific sections of code to further my understanding. I could also ask it for ideas, or propose my own. This is where the true power of our new agentic tools becomes most evident. Our thinking and our effectiveness as engineers are significantly magnified by this type of interaction. You may not see it just using an agent to generate code snippets until you begin working on a codebase that is primarily developed by the agent.
At the end of the conversation, I then asked the agent for an update to the project specifications, knowing that this is what would guide the other less capable (i.e., cheaper) coding agent responsible for more routine code generation.
In a more general context, learning to use multiple agents effectively, as in the above example, requires yet another level of engineering, and is undoubtedly the focus of many AI-focused organizations.
Educating Future Engineers
Education in the fundamentals has never been about learning what you need to do something, but about how to change your mind about what you want to do. In other words, changing how you think, and yes, coding may become one of those fundamentals that teach us to think like a computer, to communicate in the problem space of the computer. We may not write as much code, but we will need it more than ever since we are now talking to both agentic and human engineers. In the same way we don't do arithmetic by hand anymore, we still need to understand it since it is at the foundation of the technological universe, as is the code agents will produce in ever greater quantity.
What Will Become of the Software Engineer?
We are in a new era of AI-originated projects where code changes will only be performed by an AI agent in collaboration with an engineer. Difficult decisions will be required about when to change course with new designs, abandon old requirements, incorporate new technologies, scale existing technology to more users, and establish acceptance criteria defining success. All need engineering and engineers. To be sure, the skill sets will need to shift from simply how to use a programming language to the thinking and problem-solving required when the code is AI-generated, i.e., asking the right questions. In my mind, this was always the difference between a "Coder" and an Engineer. Now, truly, anyone can be a Coder, but software engineering has not changed. It still requires creativity and obsessive dedication to finding solutions to hard problems.
Comments ()