ALGSoftware & Photography
← All articles

Software Engineering in the Generative AI Age

For the last few years, software went from being expensive and slow to build to becoming almost like a commodity, thanks to generative AI. We now see apps that would take months to build achieving completion within weeks. Laymen, often labeled "vibe coders", now can prompt their way into an actually somewhat working application. That must mean we won't need software engineers anymore, right?

I don't think so. In fact, we might need smart engineers even more now. Sure, the role has changed, and I somewhat grieve it. Writing the entire code from start to finish, debugging it, and seeing the great result that weeks of work achieved was very fun to me and it's a kind of joy that is hard to find. But AI is still only the last revolution we've seen in this field -- one that is impressive, sure, but not the first one -- and we must adapt to it, accept it and move on. It won't ever be like the old days, and in some ways for the better. Let's compare to previous revolutions we've had.

At the very beginning of computing, researchers wrote the machine code on plain paper. No text editor, no programming language, no immediate visual feedback. A group of assistants would manually translate every single line of the assembly to binary code. This long stream of ones and zeroes was manually input into the machine. A long and painful process, which had many bottlenecks.

Then in 1952, Grace Hopper invented the first compiler, coining the term forever. It was a major milestone for computer science. Soon after, in 1957, came FORTRAN, the first commercially available compiler. Now many instructions and common abstractions (functions, memory management, flow control and math) could be condensed into a single instruction in the higher level programming language. But the main process was still similar to the older one: the code was written on paper sheets, and transcribed manually to machines called keypunches, which punched the code into punch cards. Only after then it was compiled.

A FORTRAN punch card encoding the statement Z(1) = Y + W(1).

A FORTRAN punched card. Photo: Arnold Reinhold, CC BY-SA 2.5.

The move from this workflow to actually editing the code in a digital system was slow, taking decades. It only became routine for all programmers after the development of Unix in 1969 at Bell Labs. They used command-line text editors such as ed directly on video terminals (VDUs) or teleprinters.

Then editors featuring a terminal user interface (TUI), like the ancient vi, came. The obvious next step was graphical user interface (GUI) editors and integrated development environments (IDEs). We could talk all day about them, but perhaps the biggest feature that sped up development was code completion. One of the most popular systems came out in the 2000s: the Abstract Syntax Tree (AST) analysis featured in IntelliJ IDEA.

Then only in 2016, Microsoft launched Language Server Protocol (LSP): an open protocol that streamlined most of the proprietary features of previous code completion systems. It also allowed many other mass code editing features and static analysis in a single tool, integrating directly compilers with IDEs. It was one of the features that popularized Visual Studio Code among developers.

In parallel to these code editing evolutions, programming languages also evolved. Older languages, like FORTRAN and C, got many improvements, while higher-level languages, like Python and Java, started popping up. Their biggest disadvantage was (and still is) that often they lack performance compared to lower-level languages, but this got a lot better over the years.

We see how many times the software engineering industry has changed significantly. In the current revolution, programming languages are the low level. We tell the machine what we want in human language, and it "compiles" into the programming language, the middle ground between human and machine languages -- though sure, it's not a deterministic process. The Large Language Model (LLM) proved fantastic for predicting code based on the input. But not once did knowledge cease to be necessary when building production applications, and I don't think it's different now.

Now back to my main point: LLMs have several limitations that fundamentally make a human operator required. The most obvious one: the requirements themselves are up to the human. Sure, the product owner could interface directly with the machine, without the programmer "translating" their wishes. But the engineer was always responsible for translating those requirements and I don't think now it's different. We still have to take technical, architectural decisions considering scalability, legal compliance, privacy, security and many more. From my experience, even the best models, like Anthropic's Fable, are very bad at these kinds of decisions. When I experimented with "vibe coding" a complex app not long ago, I frequently ran into errors it simply couldn't fix. The code was an utter mess and it completely lacked security and scalability in the design.

Unreviewed AI-generated code is dangerous. And please don't tell me AI can review itself, because it can't. It lacks the context window, within and without the application's code to fully understand liabilities. I think the biggest concern for programmers in the generative AI age is not whether there won't be jobs for them anymore, but how many jobs there will be, considering the increased output of a single developer. Engineers that understand this will be rewarded, while the remaining are being punished. Now more than ever we must learn the architectural principles of a robust application and infrastructure.