Added more description to README
This commit is contained in:
93
README.md
93
README.md
@@ -10,6 +10,12 @@ Most of the information on how to design in this way are from the following book
|
||||
|
||||
[Implementing Domain-Driven Design | Vernon Vaughn](https://www.amazon.com/-/de/dp/B00BCLEBN8/ref=sr_1_1?__mk_de_DE=%C3%85M%C3%85%C5%BD%C3%95%C3%91&crid=E6QQJD59WB0U&dchild=1&keywords=implementing+domain-driven+design&qid=1618152014&sprefix=implementing+d%2Caps%2C237&sr=8-1)
|
||||
|
||||
### Prerequisites
|
||||
|
||||
* Java 11
|
||||
* Maven
|
||||
* Docker or mongoDB
|
||||
|
||||
### How to run
|
||||
|
||||
To run this application you need to first run a
|
||||
@@ -18,7 +24,7 @@ To run this application you need to first run a
|
||||
mvn clean
|
||||
```
|
||||
|
||||
in the root directory of this project. This will download all required dependecies and bundle your
|
||||
in the root directory of this project. This will download all required dependencies and bundle your
|
||||
project properly. It will also auto generate some mapping classes with
|
||||
the [mapstruct](https://mapstruct.org/) plugin.
|
||||
|
||||
@@ -29,8 +35,6 @@ or you can alternatively start the MongoDB in docker with the included docker-co
|
||||
docker-compose -f mongodb-docker-compose up
|
||||
```
|
||||
|
||||
Docker / docker-compose need to be installed for this.
|
||||
|
||||
The application can then be started by running the main function in:
|
||||
|
||||
```
|
||||
@@ -42,7 +46,7 @@ hexagonal-example\config\src\main\java\de\strasser\peter\hexagonal\HexagonalAppl
|
||||
This app can register customers, add addresses to these customers and retrieve a list of all
|
||||
customers.
|
||||
|
||||
The supported usecases in the business layer can be inspected in the applicationmodule. Under
|
||||
The supported use cases in the business layer can be inspected in the application module. Under
|
||||
application/src/main/java/de/strasser/peter/hexagonal/application/customer/port all the supported
|
||||
operations are clearly visible, which is a major selling point to structure your application in this
|
||||
way.
|
||||
@@ -52,9 +56,9 @@ way.
|
||||
### Application architecture
|
||||
|
||||
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.
|
||||
key characteristics of a good architecture (S.O.L.I.D., Flexibility, Testability, ... ), one very
|
||||
defining lesson of Robert C. Martins book is that the business logic should be at the core of the
|
||||
system.
|
||||
|
||||

|
||||
|
||||
@@ -69,9 +73,7 @@ but certainly not as exciting sounding as a hexagon.
|
||||

|
||||
|
||||
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.
|
||||
code is free of any framework specific annotations.
|
||||
|
||||
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.
|
||||
@@ -82,10 +84,6 @@ adapters implement the output ports and therefore have to follow the contract, t
|
||||
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 flexibility. 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.
|
||||
|
||||
To achieve true decoupling between the application components the services are not allowed to
|
||||
construct instances of objects themselves. If a use case class would construct the instance of an
|
||||
output adapter in its class it would introduce dependencies into that layer, which we do not want.
|
||||
@@ -105,7 +103,9 @@ configuration component is the component, where the Spring main function lives.
|
||||
|
||||

|
||||
|
||||
### Advantages of separated models on each layer in this example
|
||||
### Advantages of separated models on each layer
|
||||
|
||||
Some Examples:
|
||||
|
||||
- The customer response can easily exclude the (hashed) password without much effort. This separates
|
||||
the concern in what way to display the data to the client.
|
||||
@@ -119,5 +119,66 @@ configuration component is the component, where the Spring main function lives.
|
||||
how to handle data persistence is independent of the business layer and can be handled by the
|
||||
persistence module.
|
||||
|
||||
- The Command models can validate the input to the business logik and make sure nothing
|
||||
|
||||
- The Command models can validate the input to the business logic and make sure nothing
|
||||
unprocessable enters the services.
|
||||
|
||||
What we can learn from these examples is that, even though it might seem very redundant and tedious
|
||||
work at first, every model has
|
||||
a [specific job](https://en.wikipedia.org/wiki/Single-responsibility_principle) and is there for a
|
||||
reason.
|
||||
|
||||
The overhead from writing more code in the beginning is offset by the fact that the code is much
|
||||
more readable and maintainable.
|
||||
|
||||
### Advantages of the domain models in the center of the code
|
||||
|
||||
With the domain models being free of any framework specific annotations this is especially great for
|
||||
unit testing your business logic. No spring context, that has to boot, no proxy classes, or any
|
||||
services that need to be mocked.
|
||||
|
||||
Just plain old Java, which is easy to understand and fast to execute.
|
||||
|
||||
### Advantages of the adapters
|
||||
|
||||
One great benefit is that we comply with
|
||||
the [Single Responsibility Principle](https://en.wikipedia.org/wiki/SOLID). Each adapter does only
|
||||
the thing it is supposed to do. The web adapter for example only handles incoming web requests and
|
||||
nothing else.
|
||||
|
||||
The clear separation of concerns also greatly increases flexibility. 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.
|
||||
|
||||
### Advantages of the ports
|
||||
|
||||
The ports help us comply to
|
||||
the [Interface Segregation Principle](https://en.wikipedia.org/wiki/Interface_segregation_principle)
|
||||
and
|
||||
the [Dependency Inversion Principle](https://en.wikipedia.org/wiki/Dependency_inversion_principle).
|
||||
|
||||
Between the adapters and the use case services the ports serve as a layer of abstraction. By
|
||||
defining a port interface for every use case that we have, we can make sure that no client (or
|
||||
adapter in this case) has to depend on methods that it does not use.
|
||||
|
||||
By defining the port interfaces we can force the adapters to comply to the rules of the application
|
||||
/ business module. This is known as dependency inversion.
|
||||
|
||||

|
||||
|
||||
Without the interface the RegisterCustomerService / application module depends on the CustomerDao.
|
||||
|
||||

|
||||
|
||||
With the interface the CustomerDao depends on the Application module.
|
||||
|
||||
### Disadvantages of this architecture
|
||||
|
||||
This style of implementing a service has alot of overhead. For a simple CRUD application or any
|
||||
application without much business logic this approach, would certainly be overkill and would result
|
||||
in alot of tedious mapping without much benefit.
|
||||
|
||||
### So when should I use this architecture?
|
||||
|
||||
This architecture really shines in an environment with a lot of business logic and is *very* well
|
||||
suited to implement [Domain Driven Design](https://de.wikipedia.org/wiki/Domain-driven_Design).
|
||||
|
||||
BIN
documentation/dependency.png
Normal file
BIN
documentation/dependency.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 8.8 KiB |
BIN
documentation/dependency_inversion.png
Normal file
BIN
documentation/dependency_inversion.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 13 KiB |
1
documentation/drawio/dependency_inversion.drawio
Normal file
1
documentation/drawio/dependency_inversion.drawio
Normal file
@@ -0,0 +1 @@
|
||||
<mxfile host="app.diagrams.net" modified="2021-04-14T17:05:35.072Z" agent="5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/89.0.4389.114 Safari/537.36" etag="wZkBuEXJztbDjSEqoCSY" version="14.5.10" type="device"><diagram id="DweDaofu-D3ANnZX0Zdt" name="Page-1">zVZNj5swEP01OW4VIBByzCbb9tBVq43UpqfKsQewajAyJpD++o6DCZ+rbaVU6imeN57xzHuDnYW3S+sPiuTJs2QgFu6S1Qtvv3BdZ7Nx8ccgF4s43rpBYsWZxTrgwH+BBZcWLTmDYrBRSyk0z4cglVkGVA8wopSshtsiKYan5iSGCXCgREzRb5zppEFDd93hH4HHSXuyE2waT0razbaTIiFMVj3Ie1p4OyWlblZpvQNh2Gt5aeLev+K9FaYg038SQA9fn48VzT+nwY/T5fHysHlxHmwbZyJK2/A2zwWnRHOZ2br1pSUDW8jNMpWsNNgjETzOEBAQYQ2PRU4oz+JPV2uP9XQ7KFYJCoEzKI35xdY6tMwRjbgQOymkuh7kMR9CtjIZtZI/oecJ3ZMXBOixhWM2qF9lxLnxjBMKMgWtLrilDfCsNHY4vXboqk5pz7dY0lPZXVqQ2OmKb7k7AXBhNfgLPZyJHi8Q8wKp25WFxkPUAdSZU5hoo2SZMTC5De1VwjUcUA7jrfDbRCzRKdayd6Z0R1HkUjpHNwtOgX8vutcjugN/Qre7nqF786/Ydidstyzvibwrw4xAGM0yHNAQTtF9GPb99X/GsDdheEIrZGxrLmpzSQhSFJwOmYSa62Nv/d0I8M631r62elyNS2tkWPyxb/SijNmFXa02rikO2ORNGCmADchSUXj7S9ZExaDfmsGpoj3F5m6gFlMg8Ko+D8udU9Ge8EVybOQ2MCt/+EmuwtEgNG3aqP7jMkrkBqNEzihRw8Mk0XWobm3PzRma3RvZbO/+anhPvwE=</diagram></mxfile>
|
||||
Reference in New Issue
Block a user