AI Loves to Write It From Scratch

24 June, 2026

Example situation

Let’s say we are doing some validation. An LLM could gleefully start spitting out something like this…

if (typeof data.email !== 'string') {
  errors.email = 'Email is required';
} else if (!/^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(data.email)) {
  errors.email = 'Invalid email';
}

…instead of reaching for a validation library like Zod, even if it was already sitting there in the project.

This is just an example, and the models have been getting much better at looking around the codebase for existing patterns before inventing their own. Even so, I still see this happen all the time, especially during larger refactors. The model has access to perfectly good abstractions, but decides to recreate them anyway.

At first this feels a bit strange. Why reinvent validation, sorting, date handling, or whatever else the project already has an established solution for?
The answer makes a lot of sense once you think about it from the model’s perspective: writing something from scratch is often the cheapest option.

Using a library isn’t free. Before the model can write any business logic, it has to identify the right package, understand whether it’s already installed, remember or verify the API, figure out which functions to use, and resolve any uncertainty along the way. Doing all that consumes context and tokens. Writing the implementation directly skips almost all of that.

The comparator (yes, that’s the actual name), the regex, the handful of closures—those are already encoded in the model’s weights, so there is very little uncertainty involved. It can produce working code immediately, without spending context budget figuring out an abstraction. From the model’s point of view, this is a perfectly rational path to take. The model nees to pay the cost of using a library right now, on this one request. Your team pays that cost once, then reaps the benefits for the foreseeable future.

Before anyone gets mad: yes, if I explicitly tell the model to use Zod (or whatever library), it’ll happily do so. I simply often forget to do so, because using the existing library feels like the obvious choice.

Is this a bad thing?

None of this is inherently bad. I generally dislike dependencies that could have been reasonably avoided (super hot take), and regularly find myself hand-rolling even moderately large functionalities if it means I don’t have to add another dependency. The real issue isn’t whether the model built something instead of importing it, it’s that the decision was made using the model’s incentives rather than your project’s.

This is where QA comes in. Thirty lines of straightforward validation logic is probably fine. One hundred lines reimplementing timezone arithmetic that a date library would have handled in three is probably not.

You need to recognize that the build-vs-import decision is increasingly being made for you. Sometimes that’s fine. Sometimes it introduces maintenance overhead because it was the path of least resistance for the model, not the path that is best for the continued wellbeing of your codebase.