A hexagon with ports on its edges and dependencies pointing inward

There is a special kind of fear that lives in software teams. It is the fear of the big migration. Changing the database, changing a critical vendor, changing the payment provider. Teams plan these projects like surgery, with months of meetings and a special name and sometimes a t-shirt . I want to tell you about the time one of these changes was almost boring, and why.

And I know what you are thinking. A real database change almost never happens in projects. It is true, most systems are born and die with the same database. Stay with me anyway, because the same idea pays even when nothing changes. I will get there.

The setup

I worked on a system that stored a lot of operational data in a database that was chosen early, when the product was small. The product grew, the data grew, and the database started to be the wrong tool. The queries we needed were slow, the licensing cost was climbing every year, and the vendor knew we were stuck, so the renewal conversations were not friendly. When a vendor knows you cannot leave, the price goes only one direction.

In many systems I have seen, this story ends in pain. The database calls are spread everywhere. SQL strings inside controllers. Business rules that depend on a specific feature of a specific vendor. The migration estimate comes back as eight months and everyone quietly decides to pay the renewal instead. The vendor wins again.

But this system was built differently, and the credit goes to an idea from Alistair Cockburn called hexagonal architecture, also known as ports and adapters. He describes it in Hexagonal Architecture on his site, and the original idea is from the early 2000s. Old idea, still paying rent.

Ports and adapters in plain words

The idea is simple to say. Your business logic, the part that knows your rules and your domain, lives in the middle. It does not know about databases, web frameworks, message queues, or vendors. It only knows about ports, which are just interfaces it defines. “I need something that can save an order and find an order by id.” That is a port.

Around the middle, you write adapters. An adapter is the piece that connects a real technology to a port. A Postgres adapter, a REST adapter, a vendor X adapter. The adapters know all the dirty details. The middle stays clean.

People draw it as a hexagon, but the shape means nothing. The only thing that matters is the direction of the dependencies. The outside depends on the inside. The inside depends on nothing.

The migration that did not hurt

Back to my story. Because the system was built this way, all the database knowledge lived in one place, the persistence adapter. The domain logic asked for “orders” and “customers” through interfaces and had no idea what was answering.

So the migration plan was honest and small. Write a new adapter for the new database. Run both adapters side by side for a while, writing to both and comparing reads, to build confidence with real production traffic. Then flip the configuration and retire the old adapter.

I will not lie and say it took an afternoon. Data migration always has annoying details, indexes to tune, a few queries that behaved differently. It took a few weeks of careful work. But the business logic, the thousands of lines that encoded years of decisions and edge cases, did not change. Not one line. Our tests for the domain did not even notice the migration happened, because they never touched the database in the first place. They tested the middle, and the middle did not move.

Compare that with the eight month surgery projects. The difference was not smarter developers. The difference was a boundary, drawn years earlier, by someone who read Cockburn and took him seriously.

Vendor freedom is negotiating power

Here is the part I really want you to take from this post, because it is the part architects forget to say out loud to the business.

The day we proved we could change the database in weeks, our relationship with every vendor changed. The next renewal conversation was different, because the threat of leaving was real and they could feel it. We had a credible alternative, and a credible alternative is the only thing that moves prices in a negotiation. I have sat on the business side of the table, back in my agency years in Brazil, and I can tell you that “we are locked in” is the most expensive sentence a company can say.

So when someone asks why we should spend extra effort keeping the domain isolated from the infrastructure, the answer is not “clean architecture” or any aesthetic argument. The answer is money. An isolated domain turns vendor changes from a crisis into a project. It turns “we have no choice” into “we are comparing options”. That is negotiating power, and negotiating power shows up directly on the invoice every year, in numbers a CFO can read.

Not only for big migrations

Here is the promise I made in the beginning. The same boundary pays every single day, even if you never migrate anything. Imagine production runs on Oracle or SQL Server. With one simple extra adapter following the same pattern, a developer can run the whole system locally with SQLite or even an in memory implementation. No heavy installation, no license, no shared development database that everybody fights over. A new developer clones the project and runs it in minutes.

Tests get the same gift. The domain tests run against the in memory adapter and finish in seconds, not minutes. Fast tests run more often, and tests that run more often catch problems while they are still cheap. So even if your database never changes in ten years, the boundary was paying you back the whole time.

A warning so you do not cry anyway

One honest warning. Hexagonal architecture is not free and it is not for everything. Every port is an interface someone has to maintain. For a small tool or a short lived project, the ceremony can cost more than it saves. The pattern pays when the system will live for years and the expensive parts, like databases and vendors, might change. Most core business systems fit that description. Most weekend scripts do not.

Also, the boundary only works if the team protects it. One developer in a hurry, importing the database client directly into the domain “just this once”, starts the leak. After ten leaks the boundary is fiction and you are back to the eight month surgery. Protecting the boundary in code review is cheap. Rebuilding it later is not.

Pax et bonum.