I’m worried about AI.
I’m not worried about it taking my job. I believe AI is a genuine productivity tool. By which I mean it can make developers produce more.
The question is whether those developers are producing something good or not.
The difference between an experienced developer and a junior is that an experienced developer knows:
- There’s more than one good solution to every problem.
- The answer to “what’s the solution” is “it depends.”
- What “it depends” on, or at least has a handle on how to find out what it depends on.
The way we train juniors, whether it’s at university or in a boot camp or whether they train themselves from the materials we make available to them (Long Live the Internet), we imply from the very beginning that there’s a correct answer. “This is the solution for printing the Fibonacci sequence using recursion.” Junior developers are trained to think that if the code solves the problem, the job is finished.
However, what we do in software development usually hasn’t been done before. If it has, it’s usually codified into a language, framework, or library.
What does this have to do with AI? Currently, generative AI gives you The Answer. As AI improves, it will probably even give you an answer that works. This is great! We no longer need to spend loads of time training developers; we can train them to be “prompt engineers” (which makes me think of developers who arrive on time), and they will ask the AI for the code, and it will deliver.
But it’s more complicated than that. Assuming the first answer the AI gives us compiles and works, it may not match our code style; it may not use the libraries and frameworks the team has available to them; it may not take into account the peculiarities of the business domain of our specific application; it may not meet our performance requirements. An experienced developer would spot all of this and either ask the AI to massage the answer into the correct shape or do it themselves. A junior developer may be tempted to shoehorn this code into the application in whichever way works.
I want to be very clear here. I do not blame junior developers for this. This is part of learning. We’ve been doing this for decades. When I graduated with my computer science degree, I was using AltaVista (yes, I am that old) to find solutions to my problems and poking the code until it did what I wanted, often in spite of whatever tools, frameworks, or design patterns we were using. Later, juniors were using code from Stack Overflow as inspiration, blissfully unaware of which lines they pasted into the code base were doing nothing and which were actually relevant. These days, those pasted lines of code will be code created by generative AI.
Our responsibility as an industry has always been to steer newly minted developers in the right direction. It’s always been important for experienced engineers to point out the disadvantages of an approach and to show juniors better or newer ways of doing things. I still clearly remember a developer, only two years my senior, explaining to me why I should be using ArrayList
and not Vector
. Growing as an engineer is not about learning to write more code; it’s about learning which questions to ask, what are the compromises and “it depends” issues, and which solutions might be correct ones for a given problem.
So, let’s get back to why I’m worried about AI. I’m worried that experienced developers will add it to their arsenal of tools to get the job done, just like IDE code completion, Stack Overflow, and Google. They will learn how (and when) to use it to give them ideas, point them in a direction, and do the heavy lifting of creating boilerplate or chunks of common code. They will learn how to coach the AI to give them “better” code (for some definition of better) over time. All this time, they’re training the AI: they’re not training junior developers. In fact, experienced engineers are being encouraged to train generative AI in a way they were never encouraged to invest time in training juniors.
And juniors—well, juniors will assume the AI-generated code works. The experienced engineers will be so busy training the AI that they won’t be helping the juniors level up. Juniors won’t have the tools to improve, and senior developers might spend so much time fixing bugs in poorly implemented code from the juniors that the organization might decide that juniors are not only not needed but actually an undesirable productivity drain.
What’s the problem? Surely whether we’re training juniors or training the AI, the end result is the same? Code that works for our problem. Sure, and as AI gets better, perhaps we will rely on it even more. And let’s say, for the sake of argument, that AI does improve enough to replace junior developers. Will it become good enough to replace experienced developers? Maybe, but we’re definitely not there yet. If it’s not good enough to replace experienced developers and architects, and if we don’t invest in today’s juniors, we won’t have any seniors tomorrow. We will need experienced developers for the foreseeable future, even if it’s “just” to train the AI or help create the next generation of AI tools.
Beyond the pipeline problem, I want to address something that I think is very often overlooked in our industry. Developers are not code-production machines. Our job is not to type code. I don’t just mean experienced developers; I include juniors in this too. When I worked in a team that paired regularly, when I was a developer with a solid 10+ years’ experience, the people who challenged me the most were the juniors. Yes, I learned a great deal from smart, experienced people like Dave Farley and Martin Thompson. What I learned from them was often new stuff I didn’t already know, or they confirmed beliefs and ideas I already had. But the juniors, they were the ones that really helped me to understand what I cared about and why I did the things I did. Juniors really challenge you as a developer. Juniors ask great questions: Why did you do it that way? Why did you reject this idea? What are you thinking about when you’re trying to decide which of these approaches to take? Why is it hard to make this test pass?
These questions help us to grow as mid- and senior-level developers. Why did we do it that way? Is it because once upon a time someone showed us to do it that way, and we’ve just blindly followed that approach? Or did we discover, after extensive Googling and searching on Stack Overflow, after a lot of trial and error and eventual refinement, that this is the best way to do it? The answer to that will tell us a lot about how much we understand this thing and whether we understand the trade-offs we’re making when we take that route. It should also make us think about whether we need to do more research on this approach or tool—Has it been updated since we learned this approach? Is there a newer/better/faster/cleaner way to do the same thing?
Of course we could just sit there pondering these questions in silence and then carry on doing whatever we were doing (or decide to do things differently). But verbalizing the inner conversation, the doubts or certainties we have about the answers, will not only give the junior some insight into our thought processes but help them create their own process for making decisions. It’s perfectly acceptable to say, “I’m not sure, really. I’ve just always done it that way. Should we do a bit of research on whether there’s a better way?” Or “Well, back in my last job, we had a limit on the number of open connections, so I always close them when I can. That doesn’t apply as much here, but it seems like a good habit anyway. Can you think of a reason not to do this?” It’s good to ask the juniors questions to get them thinking, and it’s great to have a two-way conversation about trade-offs and implementation decisions. Goodness knows we’ve all been stuck thinking in circles about a problem, only to solve it just by asking a question. (We often don’t even need the answer!)
Seniors know the answer to everything is “it depends.” Growing as a developer means discovering more and more things “it depends” on, being able to spot those things in the code, the infrastructure, or the organization, and asking questions to uncover known unknowns. Answering a junior’s questions, or guiding them to their own answer, helps them on their own journey to finding out what “it depends” on and where to strike the balance in the trade-offs. It also helps us to better understand our own processes and update them where necessary.
An AI doesn’t ask questions. It gives answers. With confidence. It does not challenge you. It bows to your wisdom when you express an opinion and yet also does what the hell it wants to.
We need the tension between seniors and juniors. That’s what helps us all grow. As juniors, we can ask questions, learning for ourselves and helping the seniors challenge their assumptions. As seniors, we have a lot more experience with the subtleties of why we would choose a specific solution and what preferences we, or our team, might have on our solution. But while we can mould an AI to give us the sort of answer we ourselves might have written, the AI is not going to ask us, “But why do you want to do it that way?” or “What are the issues you’re worried about with this solution?” These questions are the ones we need to grow as individuals, to create better code that doesn’t only work but meets the requirements of the business, the user, and the team maintaining the code. Creating good software is a team sport.
(I did a video on this topic too: https://youtu.be/AK9pFlLJwbQ?feature=shared.)