0

I discovered the hexagonal architecture and I'm willing to apply it on a rather large Spring Boot application.

A stackoverflow user started a question with a list of sub-packages looking to me really convenient to use, or at least to think about, in this Classes and packages encapsulation in an hexagonal architecture question.

The questioner was planning to use a list of packages starting that way:

[....].domain.model
[....].domain.ports
[....].domain.services

[....].adapters.inbound
[....].adapters.inbound.rest
[....].adapters.inbound.bus

[....].adapters.outbound
[....].adapters.outbound.db
[....].adapters.outbound.db.entities
[....].adapters.outbound.db.repositories
[....].adapters.outbound.db.mappers

[....].adapters.outbound.bus
[....].adapters.outbound.bus.dtos
[....].adapters.outbound.bus.mappers

What are the most complete lists of sub-packages recommended to use (or to think about) when creating an hexagonal architecture?

I know: it depends of the kind of application I'm doing, that's true. But in general, if you had to do a template, in this given example of twelve first packages, what would you add, change?

Marc Le Bihan
  • 2,308
  • 2
  • 23
  • 41

1 Answers1

0

I would probably rename the domain to core and inside of the core, I would 2 more packages domains, and applications.

core
 |___ domain
 |___ application

inside the domain, I would add more packages such as entities, value objects, and domain events. However, this preference is leaning more toward following a DDD approach that uses hexagonal architecture. I would also move ports under application.

Hence you would have something similar to:

core
 |___ domain
 |      |_ entities
 |      |_ events 
 |      |_ valueObjects
 |
 |___ application
         |_ services
         |_ ports

But, it is worth mentioning that Uncle Bob, emphasizes the importance of aligning your application architecture with your domain. He argues that the architecture of a software system should reflect the business domain it serves, rather than the particular technical details of the application.

Hence, as long your core/domain is independent of any other detail (UI, database, external system) you should be fine.

regarding the other packages you have already mentioned, I would probably leave them the same.

Edited:

Regarding the domain.entities or (domain.model) that represents your domain, you would still have db.entities that are used for persistence. For example, if you are developing a spring boot application and let's say you are using JPA to help in persistence, and your in the context of an OrderService. Typically you you would have in your domain (an entity [in DDD] or model [the name you used in your case]) called Order that is purely a Java object:

public class Order {
  private String id;
  ....
 
  //constructors, other functions ... 
}

However, on the adapters.outbound.db.entities you will have the persistence object of this order domain that would have annotations such as @Entity for example. if you are wondering why you can use this annotation here because you are at the level of the infra where you can are allowed to use ORMs or other technical details technology. Hence you would end up with:

@Entity
public class OrderEntity {

  @Id
  private String id;
  ....
 
 
}

Notice how in the example above am now using hibernate/JPA syntax, in the future if you decide to change to a different ORM you could simply change the OrderEntity instead of your core model Order since the latter should only change for business requirements and not for technical details. So in my previous answer domain.entities does not reflect the persistence model but the Domain model which reflects your business objects. To move from your Order to OrderEntity you would basically do mapping between these two classes by making sure the core does not depend on the infra. Meaning that at no point in time, you shall see OrderEntity in your imports when you are in the core. But vice versa is possible (finding Order in the infra layer) because your external/infra/.. should depend on core.

Regarding domain.ValueObject, in brief value object is an immutable object that represents a concept or an entity that is identified by its attributes rather than its identity these can be used to typically model concepts such as date, time, money... Let's take an example:

Your order would probably have a price, instead of having a double value that represents the price of this order you would probably create a Money value object.

public class Order {
  private String id;
  private Money price;
  ....
 
  //constructors, other functions ... 
}

public class Money {
 private final BigDecimal amount;

  // conversion functions
  // rouding
}

So probably now you are wondering the reason behind this encapsulation. Well, one example behind this encapsulation:

  1. The Money Value Object can encapsulate all the rules and calculations related to money in the domain, such as currency conversion, rounding, and formatting. This couldn't be achieved by having a simple double price field without leaking information to the Order model or by creating for example an OrderPriceCalculator service.

Whereas for the persistence model OrderEntity once you are mapping from Order to OrderEntity the OrderEntity could now have the price as a double property since you are just persisting the Order model, and now logic or conversion should be occurring at this level.

In summary, these added concepts are well-known in the DDD space as previously mentioned. I would encourage to read about the topic as it would help in designing your application.

Roland
  • 198
  • 1
  • 13
  • I agree with `application.services` and `application.ports` in core, but I think `domain.entities` relates to adapters part. Does `domain.valueObjects` mean business objects (POJOs?). If true, it's ok. If they are dto, I would send them to adapters package also. – Marc Le Bihan Apr 27 '23 at 02:56
  • @MarcLeBihan I have edited my answer above to better answer your questions – Roland Apr 27 '23 at 05:15