diff --git a/README.md b/README.md index ac1e032..273b94c 100644 --- a/README.md +++ b/README.md @@ -15,11 +15,12 @@ Most of the information on how to design in this way are from the following book To run this application you need to first run a ```cmd -mvn clean install +mvn clean ``` in the root directory of this project. This will download all required dependecies and bundle your -project properly. +project properly. It will also auto generate some mapping classes with +the [mapstruct](https://mapstruct.org/) plugin. The database for this application is a mongo db. You either need to have one running on your system, or you can alternatively start the MongoDB in docker with the included docker-compose file. @@ -50,7 +51,42 @@ way. ### Application architecture -![img_3.jpg](documentation/dependency_diagram.jpg) +This application tries to follow the design princples as described in Clean Architecture. To achieve +key characteristics of a good architecture (Single Responsibility, Flexibility, Testability, ... ), +one very defining lession of Robert C. Martins book is that the business logik should be at the core +of the system. + +![circles](documentation/circles.png) + +This diagram shows where dependencies in a system should point to achieve this. How to implement +this however, feels very abstract. + +Alistair Cockburn took this concept and +definied [hexagonal architecture](https://en.wikipedia.org/wiki/Hexagonal_architecture_(software)). +Alternatively this style is also known as the ports and adapters architecture. Perhaps more fitting, +but certainly not as exciting sounding as a hexagon. + +![hexagonal](documentation/Hexagonal.png) + +In the middle lives the **Domain**. This is where all the business logik is contained. Ideally this +code is free of any framework specific annotations. This is especially great for unit testing your +logik. No spring context, that has to boot, or any services that need to be mocked. Just plain +normal Java, which is easy to understand and fast to execute. + +Ecapsulating these Domain models are the **Use Cases**. These represent the features that our +application provides. They receive commands and query / write the data to the adapters. + +Between the Use Cases and the **Adapters** are the **Ports**. Especially the output ports are +important to control the direction of dependencies. In Java these represent interfaces. The output +adapters implement the output ports and therefore have to follow the contract, that the core of the +application defines for them. The input adapters only interact with the input ports and never with +the implementing serivces directly. + +This clear separation of concerns greatly increases flexibiliy. If you wanted to switch from an SQL +to NoSQL DB, you'd just have to rewrite your Persistence Adapter, but the rest of the application +should not be affected by your change. + +![dependency diagram](documentation/dependencies.png) ### Advantages of separated models on each layer in this example @@ -58,7 +94,10 @@ way. the concern in what way to display the data to the client. -- The customer can be persisted different from the domain models structure. The layout in this - example has no benefit, but assume structuring your data in this way would give you a much needed - performance boost. This way the concern on how to handle data persistence is independent from the - business layer and can be handled by the persistence module. +- The AddressType properties can be annotated with web specific annotiations to control + serialization, without cluttering the domain. + + +- The customer can be persisted different from the domain models structure. This way the concern on + how to handle data persistence is independent from the business layer and can be handled by the + persistence module. diff --git a/adapter/addressvalidation/src/main/java/de/strasser/peter/hexagonal/addressvalidation/AddressValidator.java b/adapter/addressvalidation/src/main/java/de/strasser/peter/hexagonal/addressvalidation/AddressValidator.java index 1b82a15..06f4743 100644 --- a/adapter/addressvalidation/src/main/java/de/strasser/peter/hexagonal/addressvalidation/AddressValidator.java +++ b/adapter/addressvalidation/src/main/java/de/strasser/peter/hexagonal/addressvalidation/AddressValidator.java @@ -1,14 +1,14 @@ package de.strasser.peter.hexagonal.addressvalidation; import de.strasser.peter.hexagonal.application.customer.domain.Address; -import de.strasser.peter.hexagonal.application.customer.port.out.AddressValidatorAdapter; +import de.strasser.peter.hexagonal.application.customer.port.out.AddressValidatorPort; import de.strasser.peter.hexagonal.application.customer.port.out.commands.ValidateAddressCommand; import lombok.extern.slf4j.Slf4j; import org.springframework.stereotype.Component; @Slf4j @Component -class AddressValidator implements AddressValidatorAdapter { +class AddressValidator implements AddressValidatorPort { @Override public Address validate(ValidateAddressCommand validateAddressCommand) throws InvalidAddressExc { diff --git a/adapter/persistence/src/main/java/de/strasser/peter/hexagonal/persistence/CustomerDao.java b/adapter/persistence/src/main/java/de/strasser/peter/hexagonal/persistence/CustomerDao.java index e964d0b..fe866bb 100644 --- a/adapter/persistence/src/main/java/de/strasser/peter/hexagonal/persistence/CustomerDao.java +++ b/adapter/persistence/src/main/java/de/strasser/peter/hexagonal/persistence/CustomerDao.java @@ -2,8 +2,8 @@ package de.strasser.peter.hexagonal.persistence; import de.strasser.peter.hexagonal.application.customer.domain.Customer; import de.strasser.peter.hexagonal.application.customer.port.in.QueryAllCustomersCRUD; -import de.strasser.peter.hexagonal.application.customer.port.out.LoadCustomerAdapter; -import de.strasser.peter.hexagonal.application.customer.port.out.SaveCustomerAdapter; +import de.strasser.peter.hexagonal.application.customer.port.out.LoadCustomerPort; +import de.strasser.peter.hexagonal.application.customer.port.out.SaveCustomerPort; import de.strasser.peter.hexagonal.persistence.errors.CustomerDoesNotExistExc; import de.strasser.peter.hexagonal.persistence.mapper.CustomerMapper; import de.strasser.peter.hexagonal.persistence.model.CustomerEntity; @@ -19,7 +19,7 @@ import java.util.List; @Repository @RequiredArgsConstructor public class CustomerDao - implements SaveCustomerAdapter, LoadCustomerAdapter, QueryAllCustomersCRUD { + implements SaveCustomerPort, LoadCustomerPort, QueryAllCustomersCRUD { private final CustomerRepository customerRepository; private final CustomerMapper customerMapper; diff --git a/adapter/web/src/main/java/de/strasser/peter/hexagonal/web/dto/response/AddressTypeResponse.java b/adapter/web/src/main/java/de/strasser/peter/hexagonal/web/dto/response/AddressTypeResponse.java new file mode 100644 index 0000000..f7c954a --- /dev/null +++ b/adapter/web/src/main/java/de/strasser/peter/hexagonal/web/dto/response/AddressTypeResponse.java @@ -0,0 +1,12 @@ +package de.strasser.peter.hexagonal.web.dto.response; + +import com.fasterxml.jackson.annotation.JsonProperty; + +public enum AddressTypeResponse { + @JsonProperty("default") + DEFAULT, + @JsonProperty("shipping") + SHIPPING, + @JsonProperty("billing") + BILLING; +} diff --git a/adapter/web/src/main/java/de/strasser/peter/hexagonal/web/dto/response/CustomerResponse.java b/adapter/web/src/main/java/de/strasser/peter/hexagonal/web/dto/response/CustomerResponse.java index 6a116a4..f437521 100644 --- a/adapter/web/src/main/java/de/strasser/peter/hexagonal/web/dto/response/CustomerResponse.java +++ b/adapter/web/src/main/java/de/strasser/peter/hexagonal/web/dto/response/CustomerResponse.java @@ -16,6 +16,6 @@ public class CustomerResponse { private BigInteger id; private String name; private LocalDate birthday; - private Map addresses; + private Map addresses; private int age; } diff --git a/adapter/web/src/main/java/de/strasser/peter/hexagonal/web/mapper/AddressWebMapper.java b/adapter/web/src/main/java/de/strasser/peter/hexagonal/web/mapper/AddressWebMapper.java deleted file mode 100644 index b0e1baf..0000000 --- a/adapter/web/src/main/java/de/strasser/peter/hexagonal/web/mapper/AddressWebMapper.java +++ /dev/null @@ -1,14 +0,0 @@ -package de.strasser.peter.hexagonal.web.mapper; - -import de.strasser.peter.hexagonal.application.customer.domain.Address; -import de.strasser.peter.hexagonal.web.dto.response.AddressResponse; -import org.mapstruct.Mapper; - -import java.util.Map; - -@Mapper -public interface AddressWebMapper { - AddressResponse toResponse(Address address); - - Map toResponse(Map addresses); -} diff --git a/adapter/web/src/main/java/de/strasser/peter/hexagonal/web/mapper/CustomerWebMapper.java b/adapter/web/src/main/java/de/strasser/peter/hexagonal/web/mapper/CustomerWebMapper.java index a8883f4..1568ad8 100644 --- a/adapter/web/src/main/java/de/strasser/peter/hexagonal/web/mapper/CustomerWebMapper.java +++ b/adapter/web/src/main/java/de/strasser/peter/hexagonal/web/mapper/CustomerWebMapper.java @@ -1,13 +1,10 @@ package de.strasser.peter.hexagonal.web.mapper; -import de.strasser.peter.hexagonal.application.customer.domain.Address; import de.strasser.peter.hexagonal.application.customer.domain.Customer; -import de.strasser.peter.hexagonal.web.dto.response.AddressResponse; import de.strasser.peter.hexagonal.web.dto.response.CustomerResponse; import org.mapstruct.Mapper; import java.util.List; -import java.util.Map; @Mapper public interface CustomerWebMapper { diff --git a/application/src/main/java/de/strasser/peter/hexagonal/application/customer/port/out/AddressValidatorAdapter.java b/application/src/main/java/de/strasser/peter/hexagonal/application/customer/port/out/AddressValidatorPort.java similarity index 87% rename from application/src/main/java/de/strasser/peter/hexagonal/application/customer/port/out/AddressValidatorAdapter.java rename to application/src/main/java/de/strasser/peter/hexagonal/application/customer/port/out/AddressValidatorPort.java index f94f745..b154034 100644 --- a/application/src/main/java/de/strasser/peter/hexagonal/application/customer/port/out/AddressValidatorAdapter.java +++ b/application/src/main/java/de/strasser/peter/hexagonal/application/customer/port/out/AddressValidatorPort.java @@ -3,6 +3,6 @@ package de.strasser.peter.hexagonal.application.customer.port.out; import de.strasser.peter.hexagonal.application.customer.domain.Address; import de.strasser.peter.hexagonal.application.customer.port.out.commands.ValidateAddressCommand; -public interface AddressValidatorAdapter { +public interface AddressValidatorPort { Address validate(ValidateAddressCommand validateAddressCommand); } diff --git a/application/src/main/java/de/strasser/peter/hexagonal/application/customer/port/out/LoadCustomerAdapter.java b/application/src/main/java/de/strasser/peter/hexagonal/application/customer/port/out/LoadCustomerPort.java similarity index 84% rename from application/src/main/java/de/strasser/peter/hexagonal/application/customer/port/out/LoadCustomerAdapter.java rename to application/src/main/java/de/strasser/peter/hexagonal/application/customer/port/out/LoadCustomerPort.java index 4f350c2..5520566 100644 --- a/application/src/main/java/de/strasser/peter/hexagonal/application/customer/port/out/LoadCustomerAdapter.java +++ b/application/src/main/java/de/strasser/peter/hexagonal/application/customer/port/out/LoadCustomerPort.java @@ -4,6 +4,6 @@ import de.strasser.peter.hexagonal.application.customer.domain.Customer; import java.math.BigInteger; -public interface LoadCustomerAdapter { +public interface LoadCustomerPort { Customer findById(BigInteger id); } diff --git a/application/src/main/java/de/strasser/peter/hexagonal/application/customer/port/out/SaveCustomerAdapter.java b/application/src/main/java/de/strasser/peter/hexagonal/application/customer/port/out/SaveCustomerPort.java similarity index 82% rename from application/src/main/java/de/strasser/peter/hexagonal/application/customer/port/out/SaveCustomerAdapter.java rename to application/src/main/java/de/strasser/peter/hexagonal/application/customer/port/out/SaveCustomerPort.java index 49b42a6..5d18922 100644 --- a/application/src/main/java/de/strasser/peter/hexagonal/application/customer/port/out/SaveCustomerAdapter.java +++ b/application/src/main/java/de/strasser/peter/hexagonal/application/customer/port/out/SaveCustomerPort.java @@ -2,6 +2,6 @@ package de.strasser.peter.hexagonal.application.customer.port.out; import de.strasser.peter.hexagonal.application.customer.domain.Customer; -public interface SaveCustomerAdapter { +public interface SaveCustomerPort { void upsert(Customer customer); } diff --git a/application/src/main/java/de/strasser/peter/hexagonal/application/customer/service/AddressService.java b/application/src/main/java/de/strasser/peter/hexagonal/application/customer/service/AddressService.java index 17890d0..7e4fc7f 100644 --- a/application/src/main/java/de/strasser/peter/hexagonal/application/customer/service/AddressService.java +++ b/application/src/main/java/de/strasser/peter/hexagonal/application/customer/service/AddressService.java @@ -5,9 +5,9 @@ import de.strasser.peter.hexagonal.application.customer.domain.Customer; import de.strasser.peter.hexagonal.application.customer.mapper.AddAddressMapper; import de.strasser.peter.hexagonal.application.customer.port.in.AddAddressUseCase; import de.strasser.peter.hexagonal.application.customer.port.in.commands.AddAddressCommand; -import de.strasser.peter.hexagonal.application.customer.port.out.AddressValidatorAdapter; -import de.strasser.peter.hexagonal.application.customer.port.out.LoadCustomerAdapter; -import de.strasser.peter.hexagonal.application.customer.port.out.SaveCustomerAdapter; +import de.strasser.peter.hexagonal.application.customer.port.out.AddressValidatorPort; +import de.strasser.peter.hexagonal.application.customer.port.out.LoadCustomerPort; +import de.strasser.peter.hexagonal.application.customer.port.out.SaveCustomerPort; import lombok.RequiredArgsConstructor; import org.springframework.stereotype.Service; @@ -22,9 +22,9 @@ import java.util.Map; @Service @RequiredArgsConstructor class AddressService implements AddAddressUseCase { - private final SaveCustomerAdapter saveCustomerAdapter; - private final AddressValidatorAdapter addressValidatorAdapter; - private final LoadCustomerAdapter loadCustomerAdapter; + private final SaveCustomerPort saveCustomerAdapter; + private final AddressValidatorPort addressValidatorAdapter; + private final LoadCustomerPort loadCustomerAdapter; private final AddAddressMapper addAddressMapper; @Override diff --git a/application/src/main/java/de/strasser/peter/hexagonal/application/customer/service/RegisterCustomerService.java b/application/src/main/java/de/strasser/peter/hexagonal/application/customer/service/RegisterCustomerService.java index b3f7163..87e22c6 100644 --- a/application/src/main/java/de/strasser/peter/hexagonal/application/customer/service/RegisterCustomerService.java +++ b/application/src/main/java/de/strasser/peter/hexagonal/application/customer/service/RegisterCustomerService.java @@ -3,7 +3,7 @@ package de.strasser.peter.hexagonal.application.customer.service; import de.strasser.peter.hexagonal.application.customer.domain.Customer; import de.strasser.peter.hexagonal.application.customer.port.in.RegisterCustomerUseCase; import de.strasser.peter.hexagonal.application.customer.port.in.commands.RegisterCustomerCommand; -import de.strasser.peter.hexagonal.application.customer.port.out.SaveCustomerAdapter; +import de.strasser.peter.hexagonal.application.customer.port.out.SaveCustomerPort; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.springframework.stereotype.Service; @@ -16,7 +16,7 @@ import javax.validation.Valid; @Validated @RequiredArgsConstructor class RegisterCustomerService implements RegisterCustomerUseCase { - private final SaveCustomerAdapter saveUser; + private final SaveCustomerPort saveUser; @Override public void register(@Valid RegisterCustomerCommand registerCmd) { diff --git a/application/src/test/java/de/strasser/peter/hexagonal/application/customer/service/AddressServiceTest.java b/application/src/test/java/de/strasser/peter/hexagonal/application/customer/service/AddressServiceTest.java index 44d0693..bc76a32 100644 --- a/application/src/test/java/de/strasser/peter/hexagonal/application/customer/service/AddressServiceTest.java +++ b/application/src/test/java/de/strasser/peter/hexagonal/application/customer/service/AddressServiceTest.java @@ -4,9 +4,9 @@ import de.strasser.peter.hexagonal.application.customer.domain.Address; import de.strasser.peter.hexagonal.application.customer.domain.Customer; import de.strasser.peter.hexagonal.application.customer.mapper.AddAddressMapper; import de.strasser.peter.hexagonal.application.customer.port.in.commands.AddAddressCommand; -import de.strasser.peter.hexagonal.application.customer.port.out.AddressValidatorAdapter; -import de.strasser.peter.hexagonal.application.customer.port.out.LoadCustomerAdapter; -import de.strasser.peter.hexagonal.application.customer.port.out.SaveCustomerAdapter; +import de.strasser.peter.hexagonal.application.customer.port.out.AddressValidatorPort; +import de.strasser.peter.hexagonal.application.customer.port.out.LoadCustomerPort; +import de.strasser.peter.hexagonal.application.customer.port.out.SaveCustomerPort; import de.strasser.peter.hexagonal.application.customer.port.out.commands.ValidateAddressCommand; import org.junit.jupiter.api.Test; import org.springframework.beans.factory.annotation.Autowired; @@ -29,9 +29,9 @@ import static org.mockito.BDDMockito.then; class AddressServiceTest { @Autowired private AddressService sut; - @MockBean private SaveCustomerAdapter saveCustomerAdapterMock; - @MockBean private AddressValidatorAdapter addressValidatorAdapterMock; - @MockBean private LoadCustomerAdapter loadCustomerAdapterMock; + @MockBean private SaveCustomerPort saveCustomerAdapterMock; + @MockBean private AddressValidatorPort addressValidatorAdapterMock; + @MockBean private LoadCustomerPort loadCustomerAdapterMock; @SpyBean private AddAddressMapper addAddressMapperMock; @Test diff --git a/application/src/test/java/de/strasser/peter/hexagonal/application/customer/service/RegisterCustomerServiceTest.java b/application/src/test/java/de/strasser/peter/hexagonal/application/customer/service/RegisterCustomerServiceTest.java index 22ed7bf..72817ed 100644 --- a/application/src/test/java/de/strasser/peter/hexagonal/application/customer/service/RegisterCustomerServiceTest.java +++ b/application/src/test/java/de/strasser/peter/hexagonal/application/customer/service/RegisterCustomerServiceTest.java @@ -2,9 +2,9 @@ package de.strasser.peter.hexagonal.application.customer.service; import de.strasser.peter.hexagonal.application.customer.mapper.AddAddressMapper; import de.strasser.peter.hexagonal.application.customer.port.in.commands.RegisterCustomerCommand; -import de.strasser.peter.hexagonal.application.customer.port.out.AddressValidatorAdapter; -import de.strasser.peter.hexagonal.application.customer.port.out.LoadCustomerAdapter; -import de.strasser.peter.hexagonal.application.customer.port.out.SaveCustomerAdapter; +import de.strasser.peter.hexagonal.application.customer.port.out.AddressValidatorPort; +import de.strasser.peter.hexagonal.application.customer.port.out.LoadCustomerPort; +import de.strasser.peter.hexagonal.application.customer.port.out.SaveCustomerPort; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import org.springframework.beans.factory.annotation.Autowired; @@ -25,11 +25,11 @@ class RegisterCustomerServiceTest { private RegisterCustomerService sut; @MockBean - private SaveCustomerAdapter saveCustomerAdapterMock; + private SaveCustomerPort saveCustomerAdapterMock; @MockBean - private AddressValidatorAdapter addressValidatorAdapterMock; + private AddressValidatorPort addressValidatorAdapterMock; @MockBean - private LoadCustomerAdapter loadCustomerAdapterMock; + private LoadCustomerPort loadCustomerAdapterMock; @MockBean private AddAddressMapper addAddressMapperMock; diff --git a/documentation/Hexagonal.png b/documentation/Hexagonal.png new file mode 100644 index 0000000..a66d185 Binary files /dev/null and b/documentation/Hexagonal.png differ diff --git a/documentation/circles.png b/documentation/circles.png new file mode 100644 index 0000000..895e169 Binary files /dev/null and b/documentation/circles.png differ diff --git a/documentation/dependencies.png b/documentation/dependencies.png new file mode 100644 index 0000000..e1b6356 Binary files /dev/null and b/documentation/dependencies.png differ diff --git a/documentation/dependency_diagram.drawio b/documentation/dependency_diagram.drawio index 9ac4e86..a167d52 100644 --- a/documentation/dependency_diagram.drawio +++ b/documentation/dependency_diagram.drawio @@ -1 +1 @@ -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 \ No newline at end of file +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 \ No newline at end of file diff --git a/documentation/dependency_diagram.jpg b/documentation/dependency_diagram.jpg deleted file mode 100644 index f76e2e4..0000000 Binary files a/documentation/dependency_diagram.jpg and /dev/null differ