-
Notifications
You must be signed in to change notification settings - Fork 2
Hexagonal Architecture
This page is about the hexagonal architecture.
The above picture has been taken from Growing Object-Oriented Software Guided by Tests by Steve Freeman and Nat Pryce (Creative Commons License).
The central idea here is to move the dependencies to external systems to the boundaries of your domain model. By defining ports (realized as interfaces) and adapters (implementations of these interfaces that connect to the external system), we
- Prevent externalities leaking into our system, such as relational data models, JSON and/or XML message structures, and so forth.
- Make it easy to plug in fakes and stubs into our ports, which in turn keeps our tests independent of the external systems and guarantees that they remain fast!
Since some of the coding katas in this repository specifically address this topic, this page discusses the required concepts that are common to all these katas. These concepts all fall under the umbrella of what's generally known as the Hexagonal Architecture (a.k.a. Ports and Adapters). Uncle Bob elaborated on this concept and coined it the clean architecture.
A question that is often raised is: How do I practice TDD when I have to deal with the dependencies of my system to the outside world? Examples of such dependencies are databases, file systems, networks, etc. So isn't it inevitable then that I eventually have to include tests involving these external systems in my tests and as a consequence my tests (gradually) become slow?
Many people are inclined to introduce mocks into their tests at this point, but apparently these people haven't heard of the don't mock what you don't own principle. A good but somewhat long read about this topic is also Martin Fowler's well-known mocks aren't stubs.
So what do we do then when mocks are not meant to be used for this purpose? The answer is to apply dependency inversion and to use so-called ports and adapters.
-
Dependency Inversion is the last of the five well-known SOLID principles. In a nutshell, it boils down to dictating to the outside world what the data should look like, as opposed to letting the outside world determine your (object) model. The idea is to think in terms of the domain model first and to make the primary and secondary actors comply with the ubiquitous language established by our domain model. This implies e.g. that no field names or data models from external systems should be able to "leak" into our domain model!
-
Ports and adapters: as is explained in this article, "The main principle of the Ports & Adapters architecture is to have inputs and outputs on the edges of technology-agnostic code".
A good read is the Ports and adapters as they should be post by Felipe Flores. By realizing the ports & adapters by using the adapter pattern (which is polymorphic by definition), we keep our system under development testable all of the time.
This work is licensed under a CC-BY-SA-4.0 license. Attribution: github.com/zhendrikse/tdd.