Conceptualized by Alistair Cockburn initially under the name "Ports and Adapters".
In a nutshell:
Application Driver -> Primary Adapter -> Primary Port -> Use Case -> Secondary Port -> Secondary Adapter -> External System/Side Effect
They define the business rules and they should not depend on code related on how the system communicates with the outside world. Throught the use of Ports and Adapters the Use Cases can be reliably tested and change mainly if the business rules change
They expose the ways in which the use cases can be reached (primary) or reach to (secondary) to the outside world. They are technology agnostic.
They deal with with side effects such as: communication outside of the system, random generation, current time, etc.
Based on talks by Jakub Nabrdalik such as https://www.youtube.com/watch?v=2vEoL3Irgiw
There are multiple ways to implement the ideas of this architecture this is by no means the only one. This implementation is modular an can scale to implement a modular monolith (modulith).
-
In the following example I decided to move customerconsole package outside of the customer module because it required it's own module configuration. However there is nothing stopping that package to remain as a folder inside of
com.abc.project.customer -
Depending on the library choice or code implementation, your primary adapters may be required to be public. Jakub's package-private controllers are possible because he uses the Spring framework. Furthermore, primary adapters apen up an API to an external actor so you may want to think about it as a public API regardless of the access modifier used for the class.
https://gist.github.com/corlaez/aa2c1a657438f5c998af9340a3339051
-
Youtube Talk by Jakyb Nabrdalik
-
Github Java Example Implementation by Jakub Nabrdalik (Spring, HTTP API, Repository)
-
Replit Runnable Java Example with Tests by me (0 libraries, CLI, System Time, Random)
-
Excalidraw Library Excalidraw library used to create the diagrams shown here.





