Very few software projects start out with the goal of being a fragile house of cards.

The problem is that software has a natural tendency towards exactly that outcome.

A system gets built. Almost all projects have a set of constraints so few systems are “perfect.” Even a perfect system, given the passage of time, looses its shine.

A system that isn’t perfect can have things added to make it better. Those things paper over some of the faults of the first system. But each add-on tends to bring its own baggage. Those faults get patched as well.

This process keeps going forever — or until you get a chance to rebuild it. (Of course you rarely get that choice because it’s easier to kick the maintenance can down the road)

So you keep adding hacks and patches forever.

Each layer adds complexity. Code that’s written and working rarely gets changed, first because it’s working, then because you’re afraid of it because it’s so old. Code on top of code. Interface and facade down the strata.

Each bit of complexity is a place where things can break.

Given enough time you have the house of cards that somehow is standing, though you’re not ever quite sure why.

Eventually the frog gets boiled, and the cost of the next feature is greater than the cost of a rebuild.