DEV Community

Cover image for Dynamic isn't enough. Operations is the other half.
Hideki Mori
Hideki Mori

Posted on

Dynamic isn't enough. Operations is the other half.

If you've been writing software for a few years, you eventually start designing for change.

A content delivery system: a new format will appear, a new player will appear, so let's not hard-code formats. An e-commerce site: a new payment method will be requested, so let's not hard-code billing logic. A document pipeline: a new processing engine will appear, so let's not hard-code engines.

This is good instinct. You read books like Analysis Patterns, you internalize the idea that the model should be flexible, you push concrete decisions out of code and into data. New format? Insert a row. New payment? Insert a row. New engine? Insert a row.

It's a beautiful pattern. It really does extend the lifespan of a system.

But after enough years of running systems built this way, here's the part that doesn't show up in the books:

Dynamic isn't enough. Operations is the other half — and that other half is usually paid by someone else.


The "wait, maybe..." moment

Reality always overshoots the model. Always.

You build a content system that handles formats dynamically, and then someone asks for a format whose delivery rules don't fit the existing shape. You build a payment system that takes new methods through configuration, and then someone wants a billing model where the "amount" isn't even computed at the same time as the "charge." You build an engine registry, and then a new engine doesn't conform to the lifecycle every other engine has assumed.

Each time, the moment looks the same. You stare at the request, and your first thought is: that's outside the model. And your second thought, a few minutes later, is:

Wait, maybe... if I interpret this field a little differently, and if I add one column here, and if I let this branch handle a special case... it fits. Sort of. It doesn't break anything.

So you do that.

The system keeps running. No downtime. No coordinated migration. No painful conversation with the integration partners. From your seat as the designer, the dynamic structure absorbed the change. The pattern worked.

That's the part designers love. That's the part that gets written about.


Who pays for the other half

Here's what's harder to see from the designer's seat: every "wait, maybe..." moment leaves a small residue somewhere in operations.

The operator now has to remember that for this particular case, the workflow is slightly different. The reporting tool needs a footnote. The on-call playbook gets one more conditional. The next person to onboard needs another paragraph of context. The integrating system has to send a value in a slightly unexpected place.

None of these are catastrophic. None of them break the system. Each one, on its own, is a small inconvenience.

But the small inconveniences accumulate. And the people accumulating them are usually not the people who designed the dynamic structure in the first place.

The designer experiences each "wait, maybe..." as a successful absorption. The operator experiences it as one more thing to remember. Same event, two ledgers. Only the designer's ledger gets reviewed.

This is where engineering satisfaction can become quietly self-serving. The system didn't break. The pattern held. Therefore the design is good — except good for whom, exactly?


The road I didn't take

There is, of course, an alternative. You can stop the system, ship version 2, ask everyone to migrate, and start clean.

A scheduled 24-hour outage. A v2 documentation packet sent to every integrating partner. A coordination meeting. A cutover.

I have, for twenty-four years, mostly chosen not to do this. I have preferred quiet absorption — interpretation, gentle reshaping, "wait, maybe..." — over coordinated rebuild.

Whether that was right, I genuinely don't know. There were probably operators along the way who would have been happier with one painful migration than with years of small accommodations. There were probably integrating systems whose engineers would have preferred a clean v2 over a v1 that kept quietly bending.

I chose to keep the shape. That choice has a cost. The cost is paid in operator-hours, in playbook footnotes, in the small extra cognitive load of working with a system that has absorbed more than its original model anticipated.

I'm not saying I was wrong. I'm saying: I'm still not sure.


Generic underneath, specific on top

There's one thing I do believe, with more confidence than the rest:

When the model gets very generic, the UI usually has to get very specific to compensate.

A maximally flexible data model — the kind that absorbs new formats, new payment methods, new engines — is, almost by definition, awkward to interact with directly. Direct interaction with a generic model means the human has to supply all the missing context. That's exhausting.

The good outcome is: the model stays generic underneath, and the UI is built specific to each use case on top. Each surface is custom. Each surface is rigid in exactly the way that makes it usable.

This is a hard decision to make, because every specific UI you build feels temporary. You're going to throw it away when the use case shifts. You build it knowing it has a shorter half-life than the model below it. That asymmetry is uncomfortable.

But I think the discomfort is the right discomfort. A long-lived generic core, with shorter-lived specific surfaces on top, is — based on what I've watched survive over twenty-four years — closer to how systems actually age well.


Three observations

None of these are conclusions:

  1. Dynamic structure extends a system's life. It does not, on its own, make operating that system pleasant.

  2. Every "wait, maybe..." absorption is a real engineering achievement and a small tax on someone downstream. Both of these are true.

  3. If you make the model very generic, give the operators a UI that isn't generic.

Dynamic isn't enough. Operations is the other half — and that other half is usually paid by someone else.

After twenty-four years of this, that's the only thing I feel sure of.


Earlier in this series:

Top comments (0)