I've been reading a lot a bout hexagonal architecture and I do get most of the concepts (well, I hope I do), I didn't find any example of that architecture use-case wise.
Let's say that my application domain model is to make people drunk. The whole business logic is contained in Person
class which resides in the domain layer.
class Person
{
private $name;
private $age;
function __construct($name, $age)
{
$this->age = $age;
$this->name = $name;
}
public function drink()
{
if ($this->age < 18) {
echo $this->name . ' cant drink';
}
echo $this->name . ' drinks tequila';
}
}
Domain layer also contains a PersonRepository
interface PersonRepository
{
public function findPersonByName($name);
}
implemented by:
class DoctrinePersonRepository implements PersonRepository
{
public function findPersonByName($name)
{
// actual retrieving
}
}
Let's assume I want to make a person drunk by accessing: GET /person/johnDoe/drink
.
Should I create a use case like:
class MakePersonDrinkCase
{
/**
* @var PersonRepository
*/
private $personRepository;
function __construct(PersonRepository $personRepository)
{
$this->personRepository = $personRepository;
}
function makePersonDrunk($name)
{
$person = $this->personRepository->findPersonByName($name);
if ($name) {
throw new \Exception('Person not found');
}
$person->drink();
}
}
and call it from the controller? Should this mentioned case reside in domain layer or application layer? What is a port and adapter in this case? What if I want to have to ways of getting this person drunk - one from GET request, and other from some php console person:drink John
CLI command? How should I structure my app?
It is one of the main benefits of Hexagonal Architecture. Decoupling the business rules from external concerns such as Database, Framework, UI, and other dependencies allows you to test those business rules independently.
Hexagonal Architecture promotes the separation of concerns by encapsulating logic in different layers of the application. This enables a higher level of isolation, testability and control over your business specific code. Each layer of the application has a strict set of responsibilities and requirements.
In the book, DDD examples use a traditional layered architecture, but the book also states that DDD can be used along with any other software architecture. If you want to use hexagonal architecture it's fine too. Hexagonal architecture splits application in 3 concentric layers : adapters, ports, business.
Hexagonal architecture is a model or pattern for designing software applications. The idea behind it is to put inputs and outputs at the edges of your design. In doing so, you isolate the central logic (the core) of your application from outside concerns.
TL;DR: I think that from a DDD point of view, you're basically right, but in order to be an Hexagonal design, you should be able to register or expose your use-cases in your primary ports: web, console or "usage" as @chris-f-carroll suggests.
I currently work in a big Java8 codebase project and we have structured our application following the principles of Clean Architecture/Vertical Slicing and CQRS. We have an Hexagon with 6 ports: web, console, database, scheduling, queues and email.
In order to initialize our app, we create all the required adapters and we use them to create our app instance. Then our app's modules explicitly register their use-cases on the primary port adapters. Finally we start our primary port adapters and the app is running.
Alistair Cockburn tells that "A port identifies a purposeful conversation". In our case, as our design implies CQRS, our purposeful conversation between our application and the HTTP protocol is about exposing Queries and Commands (our use-cases).
That's the reason for having expose(uri, query) or expose(uri, command) methods in our web port instead of get(uri, handler), post(uri, handler), put(uri, handler), delete(uri, handler), etc.
How these queries and commands are exposed (i.e. as HTTP GET or POST) is an implementation detail of the web port adapter that my hexagon needs not to know.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With