DEV Community

Cover image for How Not to Lose Yourself in the Age of AI
Ilia
Ilia

Posted on Edited on

How Not to Lose Yourself in the Age of AI

The promise that we'll soon stop writing code by hand is far from new. COBOL was made to look like English so that programs would be readable by more than just programmers. SQL's predecessor was called SEQUEL, literally Structured English Query Language. Then no-code platforms arrived. The amount of manual work really did go down, but programmers didn't disappear. If anything, there were more of them than before.

Now it's the turn of large language models (LLM). For brevity I'll just call them models from here on. And this time we've met the final boss: for the first time, a tool genuinely works in natural human language from end to end. It became possible to write entire programs knowing nothing about programming languages.

That sounds a little frightening. But we quickly reached a reassuring conclusion that only the routine work disappears, and demand grows for the people doing architecture and review. Surely there still need to be people who define the tasks and then check the generated code.

But what are we going to lean on when we check that code? In sheer volume of knowledge, a model already outstrips any individual developer: it can reproduce most known algorithms and patterns, it knows a huge number of libraries, it knows the syntax. No human holds that much in their head. Competing with models on the amount of memorized information is pointless.

And yet they still haven't become a full replacement for a programmer. So our value isn't only in knowledge, there's something else.

What makes us different

The model doesn't have your context.

At least not in the form you have it. Technically, model context windows are already big enough to fit an entire library. In practice the model only sees what made it into the working session. And even when a lot of information fits, that's no guarantee the relevant connection gets noticed: models draw unevenly on different parts of a long context and can miss even explicitly stated instructions.

Rules files and project descriptions help, but you can't pack the whole context into them. You can't fit ten years of experience into a single set of instructions. If understanding could be transferred as one document, we'd have been turning juniors into seniors with a README a long time ago.

So a model can hold nearly all of humanity's knowledge and still be unable to replace experienced specialists.

The model doesn't carry responsibility.

You're the one who gets pulled in on a weekend, who explains to the team lead or the business why production is broken, who fixes the aftermath. And the thing is, responsibility forces you to see where a decision led, and that's where experience comes from.

Someone who once wiped a production database didn't just learn a new fact. They had to live through the consequences, and that kind of experience tends to stick. It's what keeps you from making the same mistake twice. A model, meanwhile, gave its answer and moved on to the next task. As long as the mistake is in the current context it can account for it, but that experience never becomes a durable habit.

So our advantage really isn't the amount of knowledge. It comes out of accumulated experience and our own decisions, out of feedback from reality, out of the ability to notice when something's off, and out of having to answer for our choices. And here, it seems to me, a problem starts to take shape, because all of that is formed and sustained through practice.

How we pick up skills

Understanding used to arrive on its own, just in the course of the work. A task lands from an unfamiliar area, you read the documentation and Stack Overflow, try different approaches, make mistakes, debug. In the end an understanding of the implementation takes shape in your head. You remember the path to the solution, you find your way around the code faster, you can explain the choices you made and answer questions about them.

Working out how a finished solution works and arriving at it yourself are not the same thing. When you look at a completed implementation, it's easy to get the feeling that it's all clear. Then you try to reproduce the same solution on your own and discover that the understanding was an illusion.

A skill forms where you do the work yourself, mistakes included.

These days models increasingly walk that path for us: they break down the task, pick an approach, write the code and the tests, fix the errors. If you only join at the end, it's easy to remain a spectator. The code looks comprehensible, but no understanding of the solution of your own ever appears.

That said, there's no point clinging to everything either. Some skills genuinely can be let go. Why spend effort on things models already do faster? The goal isn't to refuse progress, it's to avoid losing your own understanding along with the routine work.

What's left is deciding which skills to keep and which can safely be released.

What to release and what to keep

I ended up with a single criterion: does this skill help with the things we're still better at than the model?

Release.

Anything you can look up and verify quickly: exact syntax, API details, boilerplate, a ready-made implementation of an algorithm. If the answer takes a minute to find and correctness is easy to check, there's no obligation to keep it in your head.

But it's important not to confuse implementation with understanding here. You can ask a model for the code of an algorithm. Understanding its complexity, its limitations, and whether it fits your particular problem is still worth doing yourself.

Keep and develop.

Everything that accumulates over time: knowledge of the project, the reasons the workarounds are there, the ability to debug, a sense of the boundaries and constraints in your own specific context. Working with incomplete requirements. Working with a team. The cost (in every sense) of one decision over another.

Put simply, what's worth keeping is what you can't get from a single prompt. Which means keeping for yourself the work in which that understanding appears.

What this looks like in practice

Almost any task has at least four stages:

  1. Framing — what we're doing and why.
  2. Contract — what data goes in and out, where the boundaries are, which states are valid.
  3. Acceptance criteria — how we'll know the task is solved.
  4. Implementation — code and configuration.

Framing has to stay our responsibility, because this is where context matters most. We know the business we work for, the history of the product, the verbal agreements and the constraints that never made it into the documentation. Some of that can be passed to a model, but it won't find it out on its own.

Describing the contract is the next important stage. This is where gaps in the framing usually surface and where clarifying the requirements begins. Either we go and clarify the details, or we make a deliberate decision based on experience.

Beyond that, the contract gives a high-level picture of how the feature is put together: what data it needs, what goes in, what comes out, what changes in between. This is where a connection forms not just with the task but with the implementation to come.

Acceptance criteria (tests or acceptance conditions) are better defined before the model writes any code. They're what separates a correct solution from a plausible one.

If the model writes the implementation first and then generates tests from it, it can misread a requirement once and repeat the same mistake in the checks. The tests will be green: they're simply consistent with the code. So the criteria have to come from the framing, not from code that already exists.

In principle a model can be brought into the framing, the contract, and the criteria too. It'll offer options, find edge cases, and argue with the contract you've chosen. But as a second pair of eyes, not as the sole author.

Once framing, contract, and criteria are settled, implementation looks like the most natural candidate for near-total delegation. Everything's decided; all that's left is writing the code. But do that every time and you deprive yourself of practice you need.

Two questions help work out which work to hand over.

Will this task give me new understanding?

If the solution is already clear, the result is easy to check, and all that's left is assembling it from known parts, the work can go to the model almost entirely. But if the approach still has to be found, or the area is new to you, a lot will only become clear while working on it. And the more you delegate in a task like that, the less understanding you come away with.

What are the risks?

The higher the cost of a mistake and the harder the rollback, the less autonomy the model should get. You need to have a picture of what you'd do if something breaks. Here your involvement isn't about learning any more — it's about staying in control of the consequences.

In conclusion

LLMs don’t strip us of our skills, but for the first time we’re at a point where the end result of work can be separated from getting the experience and skills. Previously, getting a task done meant actually understanding it, but now you can get working code without ever going through that process. And the problem is that we ourselves give in to the temptation of staying in the role of the ones who just assign tasks and check results, even though the ability to do that well also came from practice. So I think we need to start asking ourselves what to delegate and what not to, so we don’t lose ourselves.

Top comments (0)