"Write it so that we can just bolt on whatever we need later"

Teaching the important part of Ports and Adapters

Experientially, I've found that the popular explanations of ports and adapters are not very good at actually explaining Ports and Adapters[0][1][2]. If you send the usual batch of articles to newer devs, chances are high that they'll come back either confused, missing the point, or, most commonly, drawing the wrong lesson entirely (like thinking the important part is the naming). In short, we need to teach it better. This is my approach to explaining the architecture.

From a pedagogy stand point, the problem seems to be that explanations get so bogged down in the details that the main idea never gets to bubble to the surface. Not to mention, for whatever reason, articles on the topic tend to suffer from enterprise buzzword soup which further bogs things down. Read the original ports and adapters article[0] and tell me you don't get semantic satiation of the word "port" by the end. Port. Port. Port. Other popular descriptions floating around the internet aren't much better with their usage of things like "transport layers", "Interactors", and other obfuscations[1]. If you dip into the shamelessly re-branded "clean architecture" version of all this, you'll be greeted with an entire 300+ page book of lingo from your friendly neighborhood Uncle Bob[4]. Throw any of those at someone for the first time, and they'll walk away with the view that Ports and Adapters is some crazy complex over engineered architecture.  

So when explaining it, you've gotta ignore all the details and cut down to the absolute core of what the architecture is about, which is one very basic thing:

Write your code so that you can add new ways of interacting with the world later without having to modify anything you've already written.

That's it. That's the whole explanation. When teaching it, the trick is to not mention "Ports" or "Hexagons", or other shapes, and instead just explain the quality that we want our architecture to provide. Good architecture gives us the freedom to attach new ways of communicating with the outside world without requiring us to modify any existing code in order to do so. That's what we're after.

Then you pair it with a small challenge / heuristic: pick two wildly different ways of interacting with the world, say, an HTTP API and a local CLI, and then ask how they would have to structure their code so that it could be used to power both of these external connections to the world. Magically, all the other buzz word stuff tends to fall into place without ever being explicitly defined or explained, because there's really only one obvious way to do it: by decoupling the core of the program from the external world, giving it some standardized interface (aka: a port)[5] over which new pieces can talk, and then building some adapters for schlepping data in/out of that interface. They'll still of course fumble around a bit with the exact boundaries, but this tends to get the soul of the architecture internalized.

Once the core idea is shoved into their heads, then you can hit them with the "by the way, this approach is usually called {pick your branding flavor here}", and which point they'll have the tools to actually parse through the extraneous details.


  • [0]
  • [1]
  • [2]
  • [4]
  • [5] "interface" used only in the general API contract sense, not in the Java Interface sense. Stop writing so many useless one-off interfaces, people! Interfaces are for abstractions, not concretions!