When someone asks me to look at their infrastructure, the problem is rarely capacity, architecture, or vendor choice. It is that nobody can say with confidence what is actually running, why it was set up that way, or what happens if it is changed.
That is not an engineering failure. It is a memory failure, and it has a specific cause: the environment was built by hand, and the reasoning behind it lived in someone’s head. Then that person changed roles, or the decision simply aged out of anyone’s working memory. What remains is a system that works, that nobody wants to touch.
The symptoms are consistent
- Changes happen in the console, not in a repository, because that is faster and it is what everyone already knows how to do.
- There is a server that cannot be rebooted, and the reason is folklore rather than documentation.
- Staging does not match production in ways nobody has fully enumerated.
- Onboarding a new engineer takes months, most of which is spent discovering things that were never written down.
Each of these is usually treated as a separate annoyance. They are the same problem wearing different clothes.
Why “just document it” fails
The obvious fix is to write documentation, and it does not work — not because people are lazy, but because prose documentation and the running system drift apart immediately. The document describes the environment as it was on the day someone had time to write it. Nothing keeps the two in sync, so within a few months the documentation is actively misleading, which is worse than absent.
Infrastructure as code works where documentation fails for one structural reason: it is the system. There is no drift, because the description and the thing described are the same artifact. Get that right and you get the documentation as a side effect — plus review, history, and the ability to rebuild.
Starting without a rewrite
The mistake here is going for a full greenfield rebuild, which is expensive, risky, and usually abandoned halfway. A less dramatic sequence works better:
- Inventory first. Find out what actually exists before deciding what to change. This is unglamorous and consistently produces surprises.
- Import, do not recreate. Most IaC tools can adopt existing resources. Bring the current state under management before changing any of it.
- Freeze the console. Once a resource is managed in code, changing it by hand has to stop, or you are maintaining two sources of truth and trusting neither.
- Rebuild one thing, for real. Stand up a complete environment from code and prove it works. Until you have done that once, you do not know whether your code describes your system — you only hope it does.
- Then improve the design. Now that changes are reviewable and reversible, the architectural work is safe to do.
The payoff is not elegance. It is that the environment stops depending on anyone’s memory, including yours. That is what makes it possible to hand the system to someone else — which is, in the end, the only real test of whether infrastructure is in good shape.
Working on something like this?
If this is close to a problem you have, the first call is free and I will give you a straight read on it.