Home

Temporary Gods

In my mind, at least, the core value of SOLID is that when you are adding functionality, you are always adding, not changing code. This is good because reading and (really) understanding code to make an edit is hard: you need to build up a model in your head of what the code is doing, then determine what change you need to make to that model to do the thing you want.

You need the model either way, but a model where:

Unfortunately for SOLID, mental models have gone the way of the computer. By ‘computer’ I mean the people who used to perform calculations by hand before we made calculators. Calculators automated arithmetic, and now LLMs have automated mental models.

This changes the assumptions that lead to SOLID, right? If the cost of building a mental model is the same (one prompt) regardless, why bother?

Well, it’s not quite the same. I don’t think we have empirical research on the effects of codebase organization on coding agent performance, but clear, well-architected codebases do seem to be more productive for agents. We also stand to lose the other benefits of SOLID: testability, blast radius containment, etc.

Surely it opens up some new options for development patterns, though.

Here’s one I’ve found to be useful recently, that I haven’t seen around elsewhere: unless new functionality has a clear and obvious pattern to extend, it goes into a god component. Every god component wants to be a bunch of little single responsibility components. Once your spec stabilizes, your integration tests are passing, and you have an idea of how this functionality fits into the overall system, you refactor it out into a new component, document, etc. It’s basically a specific case of Kent Beck’s make it work, make it fast, make it right.

Here, the god object is a staging area (I will call it this from now on) for functionality allowing lightning-fast iteration. Understanding the existing staging area and performing the refactor are almost free operations given a coding agent. It’s easier to find the right abstraction for a feature after it is implemented (hindsight is 20/20, after all). Given all of that, it seems clearly more efficient to defer finding the right abstraction until the integration tests are passing and you have a solid idea of how the functionality will be used.

The drawbacks of this approach are pretty clear:

This isn’t a tool for enterprise programming. Or if it is, it should be kept squarely within the bounds of a single PR, and not allow god objects to be merged into the trunk.

It is, however, a nice little pattern for rapid iteration.

- omegastick