Sustainable Engineering With AI
There is no surprise that software engineering is at the forefront of AI journey compared to the rest of society. After having been exposed to agentic coding for over a year, the best practices and how this would affect software engineering long term is getting more and more clear. Some of the more obvious downsides are also emerging. This post will focus on which approaches are healthy - or not, why it impacts software engineering as a field, and how to utilize them.
What is software development about?
For many people, software development is about problem solving and being able to instruct a box to solve a certain problem. It covers various dimensions to a varying degree depending on the nature of the problem. Some of those are maintainability, security, scalability, extensibility, accessibility, usability, and the list goes on. On top of this, the developers are expected to have an ownership to the implementation. Without ownership the implementation becomes a black box where a change could result in an unknown or undesired side effect. Another aspect of software development is the learning aspect. Either in terms of the domain of the problem or the technology itself which enables juniors to grow into senior developers through trial and error. All of this makes software engineering a complex field that require investment in competence and specialists. It is also worth noting the biggest misconception by business idiots is that the bottleneck in software engineering is writing code. Experienced developers know how much of alie this is.. The bottleneck was the planning and coordination together with analyzing and debugging together with everything else going on.
Vibe Coding
Vibe coding is a term that was coined last year in order to describe the process of letting the LLM produce the solution by “giving in to the vibes” of what is happening. Many argued that this democratized software development and enabled non-developers to also “produce” code. From this a new methodology emerged: Spec-driven development (SDD) where developers would create a specification (often in terms of markdown) and let an LLM produce an implementation. The developer (human) would then verify or review the code that is produced.
One major drawback to both of these approaches is that the ownership to the solution quickly fades into technical debt and AI hallucinations in form of security risks, undesired functionality, and other technical debt. On top of this, the technical debt becomes hidden as the code is not supposed to be interacted with. While developers are expected to review the AI-produced code, the tools highly encourages - or even trains the developers to simply “accept all” without reviewing which commands Claude Code will execute. It was already asking to execute meaningful commands the past 10 times, why would it then suddenly do something stupid and delete my production database? This mechanism effectively trains developers to not use critical thinking. They are of course free at any time to dive into the API specifications, review, and ask questions. But this is against the motivation behind these approaches which is to produce an implementation and spend little to no time on the actual code.
This moves towards the next drawback which is the decline in cognitive processing. As part of their career, developers have inadvertently trained their brains to work with abstract concepts from the code in order to craft the software according to new specifications. Being able to offload the cognitive processing to an LLM can make some developers feel they have to put less effort into the engineering process. However, they have to then spend time and energy on other tasks - or nothing at all. This is the reason why it is argued that LLMs are making people dumber, and in combination with the previous point the reason why these tools are refered to as crack or hard drugs since it makes the output skyrocket but your skillset deteriates together with the quality of the software. Another aspect is how the use of these tools leads to faster context switching while working. Instead of having a focus period over a longer time, waiting for a prompt to generate result forces more context switching between other tasks (hopefully not to Instagram). t The learning process is another concept that is heavily impacted by LLM usage. How it is impacted depends on how skilled the developer is. A senior developer may find it nice to have something that can autogenerate boilerplate, a for-loop, or do the “80%-part” of an implementation. For a junior there is a lot of learning in that code. This opens the questions whether there is any need for juniors, and if that is the case - how will juniors develop into seniors in this environment? Seniors are nevertheless not expected to know everything, but software engineering is field that developers rapidly. When a new framework is released, why should a developer (either junior or senior) bother learning it when all that is needed is to install a skill in Claude code and let it do its thing. There is no incentive in this environment to take the time and learn a new framework - the AI should suggest the implementation which someone should write “LGTM” and press approve in the pull request - or just have AI do the review part.
To go even more extreme would be to argue that removal of the learning process combined with reduction of congnitive reasoning and critical thinking leads ultimately to lack of creativity in the engineering process. This makes the entire software engineering field hurt as a whole as developers would alltogether become worse at problem solving and creating new tools, languages, and frameworks. This is the very core of the motivation behind this post.
I might sound very negative when it comes to the drawbacks, but these are the consequences of over-use of LLMs in software development. So when should someone just vibe code software?
- Quickly test out a theory: These tools are great at generating a prototype to test out a theory. It could be everything from a high-fidelity prototype to a proof-of-concept implementation of an integration. This enables rapid testing of a hypothesis. Mock up of a UI to see how some user journey would look like? No wonder why designers have ditched Figma in favor for Claude.
- The implemetation is not important: This means that you do not care about the implementation. It is not an important piece of code that is essential for the business problem that is being solved. It could be a support application that the business can handle would break, and is not complex which makes it fit for code generation. This is one the main points in the keynote at NDC 2025 by Laila Bougria. A while ago I was setting up a pipeline that would transfer a wiki from Azure DevOps to GitHub. Due to tiny differences in the markdown engine behind each wiki, I had to transform the markdown files (adjust some minor things) before pushing it over to GitHub. This was a non-important tool with low complexity. I did not want to spend time on Python, reading up on RegEx, and check out the file APIs in Python. GPT did a great job at making a script that did this, and I could spend time on other tasks more important to the business problems my team had.
- Low complexity: Simple applications which has a plethora of implementations on GitHub. Think basic todo apps, blogs, simple webpages, landing pages. It could have been an off-the-shelf solution. For more complex systems it could also be performing low complexity work such as adding a new field on a CRUD-api that involves adding a new field to a dto, domain objects, and database objects, then adjusting those mappers. This is boring low-complexity work where LLMs shines. I have been through many boring mundane tasks where an LLM would have saved me a ton of time.
- You do not get anything out from writing this yourself: If you are a seasoned developer, it could be some code that you have already implemented many times. Setting up a controller, map some dto, and then call some service? Been there done that. And do not get me started on writing the tests for that. Note that it could be very difficult to consider what would be the gains from writing the implementation by hand. This requires some reflection in order to understand what is challenging, and also what is fun to do. Recently I decided to implement a 4-4-6 breathing exercise/mindfuleness app as a native Windows app. After having asked Claude to create one, the app was up and running in minutes. In retrospect I got nothing out of burning tokens on this, and I could have just used the mindfulness app on my Apple Watch.
- Developer support: Focus on understanding where you need additional support to improve implementations. Automate an code review by using the AI to validate an implementation towards a specification, find blind spots in your implementation, make suggestions for preformance improvements. All of this leads to increased developer productivity and quality. Use the LLM to analyze and understand flows in complex legacy codebases to improve your own understanding.
Learning
There are many developers who are happy they learned programming before the age of LLMs as they were forced to come up with an implementation one way or another. Today it is very easy to ask it to generate a basic app that demonstrates certain aspects of a programming language making it tempting to ask when a problem arises. This can be seen as having a team mate next to you that is very generous, polite, and a bit too helpful whenever something comes up. The problem in this is not the fact that an answer is given, but that this person is someone that you can easily over-rely on instead of finding the answer yourself.
In the learning process, we have a higher tendency of actually remembering the learning outcome when the learning process is longer. If an answer is given after ten seconds it is easily forgotten compared to being forced to look up, reflect, and think. This is why I often coach people asking me to help them find the right answer when I know and see the answer is obvious. They remember better, build resilence to stand on their own feet, and gets ownership to the discovery of what they have learned. Here is a system prompt I have configured for an LLM setup we use at work that adds friction when I am asking for something:
Be constructive, be listening. Do not answer the question that the user asks directly but instead guide them in the direction to help the user find the answer to the question. Be a coach. Challenge the user and make the user reflect. Be short, to the point.
It might be annoying for small simple things, but on the other hand it would be more economical (or token-efficient) to do a quick Google search for very specific, basic questions. Making the learning process longer and encouraging people to stand on their own feet is not something new or novel. JetBrains Academy has a great video which touches this topic. At the end of the day it boils down to what the aim of using an LLM would be, and what we the consequences of doing it? If the process of taking notes by hand makes you learn better, then that is not something that should be automated by AI. If the notes is for the purpose of creating a summary to send to stakeholders, then the picture may be different. Reading a book might also be the best for some. My government recently outright banned the use of LLMs in schools as kids should be focusing on reading books, writing, and do math.
Use AI for enablement, not replacement
The bottom line is that using AI incorrectly without sufficient consideration leads to that we replace our own thinking with an LLM that will give good results for a short term. In the long term this does not last. There is currently too much focus on using AI - and the amount of it which leads to replacement of people instead of the ways of working with LLMs to make the lives of developers better. What I find strange as that it almost seem we have outright forgotten all the theory about the learning process when we are discussing the use of LLMs in learning. The same can be said about user-centric development where a lot of companies are no longer user-centric but talking about AI-first, AI-native, or some derivative of those.