July 19 09:07~10:58
▲Figure 1: ” Get Your Hands Dirty on Clean Architecture ” program example directory structure
foreword
In September 2021, Teddy wrote a book review for the book ” Get Your Hands Dirty on Clean Architecture ” (please refer to < [One less book] Get Your Hands Dirty on Clean Architecture >). A while ago, Boshuo Publishing House informed this book in Chinese The version will be available in August this year, please Teddy help it write a recommendation sequence.
I read the English version more than a year ago, and I can’t remember some details in the book. I spent some time in the past few days and read the Chinese version hard once. The Chinese version of this book is well translated, and friends who are interested in Clean Architecture can refer to it. Yesterday, Teddy mentioned the problem of Figure 22 in the book ” Clean Architecture ” in his blog article “Let’s talk about the implementation of Clean Architecture”. Today, I want to talk about the “not so clean” program example in the book ” Get Your Hands Dirty on Clean Architecture “. question.
***
Program example structure
The program example of ” Get Your Hands Dirty on Clean Architecture ” is here: https://github.com/thombergs/buckpal , villagers can download and read by themselves.
First analyze the program structure, please refer to Figure 1. It can be seen that the code is packaged by feature first and then packaged by layer according to the recommendations in the book. The package account represents a feature. Because the sample program in this book is small in scale, it only demonstrates the transfer function between different accounts, so from the directory structure, it seems that the flavor of package by feature is very thin, but It really has package by feature.
As for the domain, application, and adapter in the account, they are equivalent to the entity layer, use case layer, and interface adapter layer of Clean Architecture. The BuckPalAccplication placed in the outermost layer of the package is what Clean Architecture calls the Main Component.
***
Entity Layer
Then see Entity Layer, which is the domain layer code of this book, please refer to Figure 2. There are four objects in this layer: Account, Activity, ActivityWindow, Mondy. The book does not apply Domain-Driven Design (DDD; domain-driven design), which means that there is no Aggregate in the Entity Layer. But from a DDD perspective, Account seems to be an AggregateRoot.
But this is not the point, the point is that the author uses the lombok framework in the Entity Layer to automatically generate getters/setters/constructors, etc. Strictly speaking, the core Entity Layer should not depend on external tools and frameworks, but lombok is a very popular tool in the Java community, which can save a lot of annoying code, and the code exists in the form of annotations , which is a relatively minor invasion.
For the use of the framework, it is mentioned in the Clean Architecture book that after using the framework, your system is married to the framework. You may be very happy when you are newly married, but if you are unfortunate enough to get divorced in the future, the divorce procedures will be very troublesome, and your property will even be divided into half of the other party. Taking ezKanban as an example, Teddy does not use lombok, but in order to automatically serialize/deserialize objects and convert them to JSON, Jackson annotations are still attached to a few categories that Jackson cannot automatically identify (Jackson is a tool for processing JSON). ).
Therefore, if possible, try not to use external frameworks or tools in Entity Layer. If you really want to use it, you must be mentally prepared to stay together for a lifetime.
▲Figure 2: Account program example
▲Figure 3: ezKanban uses jackson’s annotation on the Entity Layer category
***
Use Case Layer
Use Case Layer is called application layer in the book, please refer to Figure 4. The book ” Get Your Hands Dirty on Clean Architecture ” uses a hexagonal architecture, so there are two subpackages under the application layer:
- port : The interface that stores the application layer’s external dependency inversion, which is divided into in port and out port. The distinction between in/out is from the perspective of the application layer. If the interface is used by the outer layer (such as a web controller) to call the inner layer, it is an in port (viewed from the outside); if it is used by the application layer The interface of the object calling external services, such as the repository used to access the database, is an out port (from the inside out).
- service : The object that implements the port is called service. For example, the object that implements the SendMoneyUseCase interface is called SendMoneyService. You can also call it SendMonyUseCaseImpl, depending on what naming method you like.
▲Figure 4: Use Case Layer (Application Layer) structure
Next, Teddy is going to start picking faults. Please refer to Figure 5. SendMoneyUseCase is the use case mainly used as an example in the book. It has only one sendMoney method, the input parameter is SendMoneyCommand (please refer to Figure 6), and the output is boolean.
▲Figure 5: SendMoneyUseCase code
▲Figure 6: SendMoneyCommand code
Compare Figure 5 and Figure 6 to Figure 7 that Teddy drew yesterday in <Let’s talk about the implementation of Clean Architecture >:
- Input Port: SendMoneyUseCas
- Input Data: SendMoneyCommand
- Output Data: boolean
Have you seen any problems with the villagers here?
▲Figure 7: The result after Teddy corrected Figure 22 in the book ” Clean Architecture “
Please refer to Figure 8. In the book “Clean Architecture”, it is mentioned that the cross-layer data structure is usually a simple data structure. SendMoneyCommand is an object that spans the application layer (use case layer) and the adapter layer, but its attributes have AccoundId. , Money, these two Value Objects located in the Entity Layer. That is to say, the objects of the Entity Layer are passed to the third layer through SendMoneyCommand. Although this does not violate the dependency principle of “Clean Architecture” (dependency is from the outside to the inside), it violates the cross-layer principle. This is formed by SendMoneyUseCase. Input Port (Input Boundary), not a complete bidirectional interface.
In the book “Clean Architecture”, it is mentioned that the interface should ideally be two-way isolation. It is also possible to use a one-way isolation interface at the beginning, and then adjust it to a two-way interface as needed in the future. In the current ezKanban, the objects of the Entity Layer must be converted before they leave the Use Case Layer. They are converted to DTO objects to the UI layer, to Data objects to the database layer, and to RemoteDomainEvent when domain events are passed to other Bounded Contexts. object,
▲Figure 8: Page 172 of the Chinese version of “Clean Architecture”
***
Interface Adapter Layer
Finally, see the SendMoneyController code in the Interface Adapter Layer, as shown in Figure 9. It can be clearly seen that SendMoneyController generates a SendMoneyCommand object on line 26, and then the AccountId and Money objects in the Entity Layer are also referenced by SendMoneyController in the third layer (Interface Adapter Layer). As Teddy mentioned in the previous section, SendMoneyCommand is the data structure on the Input Port interface. It should use the basic data type, and do not use the objects of the Entity Layer, so as not to cause the system structure to be unclean .
▲Figure 9: SendMoneyController code
***
in conclusion
” Get Your Hands Dirty on Clean Architecture ” is a good book, but like all good books, you must hold the attitude of “it is better to have no books” when reading, so that you can read deeply and improve your thinking ability.
In fact, there are other problems in the examples in the book, and Teddy didn’t have time to point them out one by one. For example, the example program includes a GetAccountBalanceService program, please refer to Figure 10. Teddy thought he could see the Query example in CQRS, but this program has an interface (GetAccountBalanceQuery) and an implementation (GetAccountBalanceService), but it doesn’t use its Controller (no one uses GetAccountBalanceService in the example program). Note that its interface returns Money, an object located in the Entity Layer. Has it been converted to DTO and passed to the UI? Who will do this conversion? How to implement the Presenter in the book “Clean Architecture”? These problems are not included in the program example, and the villagers may still not know how to do it after reading it.
▲Figure 10: GetAccountBalanceService code
If you want to know the complete and clean “Clean Architecture” architecture and implementation method, welcome to participate in the [ Domain Driven Design and Simple Architecture Introductory Implementation Class ].
***
Youzo’s inner monologue: You can’t see the problem when the code is very small.
This article is reprinted from https://teddy-chen-tw.blogspot.com/2022/07/clean-architecture_19.html
This site is for inclusion only, and the copyright belongs to the original author.