Monday, March 4, 2024

Unraveling Hexagonal Architecture: A Blueprint for Code Harmony

Hello fellow developers,

Today, let's delve into the captivating realm of Hexagonal Architecture. As software craftsmen, we're constantly seeking design paradigms that not only make our code maintainable but also allow it to evolve gracefully with changing requirements. Enter Hexagonal Architecture, also known as Ports and Adapters.

Understanding the Hexagon

At its core, Hexagonal Architecture revolves around the concept of a hexagon – a shape with six equal sides, each representing a facet of your application. This model focuses on decoupling the core business logic from external concerns, resulting in a more flexible and testable system.

The Hexagon's Heart: The Core

Picture the hexagon's center as the heart of your application – the core business logic. This is where the magic happens, where your unique value proposition resides. It's independent of external details such as databases, frameworks, or UI elements. Here, your business rules reign supreme.

Ports and Adapters: The Boundary

The sides of the hexagon represent the application's boundaries. We have "ports" for interacting with the outside world and "adapters" for implementing those ports. Ports define interfaces through which the core communicates, while adapters provide concrete implementations, bridging the gap between the core and external components.

Adapting to the Real World

Consider an example where your application needs to persist data. Instead of embedding database code directly into the core, you create a port, say PersistencePort, defining methods like save and retrieve. Adapters, then, implement this port – one adapter for a relational database, another for a document store, and so on.

Embracing Dependency Inversion

Hexagonal Architecture thrives on the Dependency Inversion Principle. Rather than depending on concrete implementations, the core defines interfaces (ports) that external components (adapters) implement. This inversion of control empowers the core, reducing its reliance on volatile external details.

Hexagonal Harmony in Action

Let's visualize this with a scenario. Imagine your application is a bakery management system. The core handles crucial bakery operations, like creating recipes and managing inventory. On one side, you have a UI adapter allowing interaction through a sleek web interface. On another side, a persistence adapter ensures your recipes endure, be it in a relational database or a cloud-based storage solution.

Benefits Beyond Symmetry

The advantages of Hexagonal Architecture extend far beyond its elegant symmetry. Your code becomes more modular, promoting easier maintenance and testing. The core remains blissfully unaware of the external forces acting upon it, fostering adaptability to changes without jeopardizing the essence of your application.

Parting Thoughts

In the grand tapestry of software design, Hexagonal Architecture stands as a testament to elegance and adaptability. Embrace the hexagon, where your core business logic resides, surrounded by ports and adapters that dance in harmony, ensuring your application's longevity in an ever-evolving digital landscape.

Until next time, happy coding!

Cheers, JD

Friday, February 18, 2022

Ports and Adapters, Part 2

Ports and Adapters part 2

Approach, not reproach

Many programming tutorials are difficult to follow.  I do not necessarily expect this one to be any different, but I'll try.  I'm going to start with relatively broad concepts, any of which may lead to a new post drilling down into that topic in further detail one day.

Take a client-centric view of the solution

We have nobody to blame but ourselves.  We've all done it.  You hit Google, or StackOverflow, and you grab a chunk of code that interfaces with some library we want to use.  Then we change the shape of our code, introducing abstractions that don't really gel that well with the ones around it, in order to make that adopted code work.
Don't do that.

Design the API you want to use

Think about things from your own application's point of view.  Do you need a database client?  Or do you need a way to get data based on a few 'key' criteria?  What level of abstraction do you really want to be working with as you write your code?

Test first

I prefer a TDD (Test Driven Development) approach to writing code.  When one first encounters the notion, it seems backwards.  It was certainly very different from practices I'd spent years on.  But in the end, following this discipline beats the hell out of attempting to add unit tests to the tangled messes many of us naturally weave otherwise.  I've been called good (or sometimes better than that) at what I do, but when I look around at my code, what I see is still more of a mess than I'd like.
TDD really helps with that.  I think that topic deserves a post of its own.
Use your concept to build some code.  Mock the responses you intend your own API to provide.  Call your own API.  It's all a kind of unit/integration testing hybrid, it's all provably correct.  It also works the way you think as a developer, long before you've actually decided which database or messaging system you'll be using.

Adapt your concept to a real-world library

When you've achieved that level, it's finally time to replace the mocked service provider with a real one... And testing that can appear very difficult.  I'll discuss techniques for that in future posts.

But first, a word about using code that demonstrates use of a library:

There's nothing wrong with learning how to use a library that way.  It should teach you the general usage patterns, pre-requisites, etc.  But that doesn't mean you should copy that demo function into your production application and start to use it!

At a bare minimum paste it into a new source file.  Better yet, use a test-driven approach to create a new file that implements the subset of capabilities you need.

That's really all you have to do to get dependencies out of your own code.  It sounds easy, and sometimes it is.  Actually, a lot of the time it is, once you figure out how to think about it.