I think that you are on the right track but it might be easier to understand possible different nomenclature to get a better understanding about the role that each of the layers will play in the architecture.
The Martin Fowler article that you linked where he coined the term, Anemic Data Model was his criticism at the time for transactional based architecture and the trend to push Behavior out of data objects entirely. Being a staunch believer in OOP programming and design it is a valid criticism, as he worries about the sophistication of software devolving back to the days of structs and procedural programming. Personally I feel he is rather alarmist and this will not be a problem if strict architectural adherence to layerd and tiered software design is followed in a stateless and transactional way.
Domain layer consists of data objects that have the knowledge and ability to persist themselves to database or file
Infrastructure layer This could also be known as your Data Access Layer. Stateless DAO classes will have the ability to fetch data objects.
I propose you have a seperate Business Logic Layer. Any and all application logic, special domain logic, interactions with multiple DAO or external web services, integrating third party services to satisfy business rules and all in a stateless transactional way, are all examples of what code belongs here. Sure some of this will simply be a wrapper to a single DAO call, but the seperation of concerns and low coupling is the benefit.
Presentation Layers There can be multiple presentation layers but they will typically be the arbiters of stateful communication with your users. A good example of this would be the Controller in MVC architecture. It can maintain stateful interaction, and where business logic operations are required, it should be as simple as calling the necessary transactions to retrieve the data needed or perform the necessary operation. There are different types of presentation as well, a thick client or web server will can call the business logic layer directly, or perhaps the business logic can be wrapped by web services that return the data in a useful form.
Service Layers The service layer should be devoid of any application or business logic and should focus primarily on a few concerns. It should wrap Business Layer calls, translate your Domain in a common language that your clients can understand, and handle the communication medium between server and requesting client.
Knowing this and understanding the benefits of why this type of transactional architecture might be useful to you however depend entirely on the type of software that you are building. Also questions about the appropriate number of services are meaningless in this case without a complete understanding of your business and technical requirements. It is a valid approach if you wish to build large highly maintainable, scalable solutions with low coupling. If you are building a smaller application with few business concerns or objectives then perhaps it is overkill.
If the controller talks directly to the presenter you lose the ability to independently swap out controllers and presenters. They are now entangled. They know about each other.
If the controller sticks to talking through an abstraction to something that implements, lets say, a Use Case Input Port, then it neither knows nor cares which presenter displays error messages.
![enter image description here](https://i.stack.imgur.com/RJTrw.png)
You do not have to use an "extra use case". Each use case can be capable of formulating their response regardless of whether that response indicates a result or an error.
Also, understand that the controller doesn't have to decide which use case it talks to. That is determined when this object graph is constructed. You don't see construction diagrammed here but none of this stuff builds itself if it wants to maintain independence. This decision could have been made in main()
. It's a handy place to put construction code.
Regarding davidh38's comment:
Why no extra usecase? Is the controller not doing something like if input == "show data" then ... else usecase.call_invalid_input. Can you elaborate on that please
Remember that the Controllers job is to be an Interface Adapter. You don't put business rules here. The CLI Controller's job is to beat CLI input into something so uniform that nothing can tell that it came from the CLI rather than the web, the GUI, or whatever. Violations of business rule expectation are dealt with by things that understand those rules.
That doesn't mean that controllers never deal with errors. But there are many options for dealing with errors that do not require a special use case for them. Returning error codes and exceptions send the flow of control right back where it came from. In this case the blue ring. There may be times when that's appropriate. For example, something has happened that has destabilized the whole system in an unrecoverable way and now it's time to roll over and die before the system starts sending the president threatening emails.
The more interesting case is when there exists a value that can be passed to the use case that defies the expectations placed on it's type. I'm not talking about null, since it's evil. I'm talking about things with some semantic like empty string that make it obvious that displaying nothing without blowing up is OK. -1, "N/A", and special symbols for unrecognized Unicode characters all come to mind.
And yes, you can have a use case for errors. All I said was that you don't have to use one. Most likely you're going to need a mix. Though hopefully you wont have to mix exceptions and error codes. Yuck.
Forgive me while I respond to Lavi's comment with what seems to have become a rant.
If we want the controller to be reusable so that we can use the very same controller for the web as for the command line,
Yes.
the controller should not be in charge of instantiating the output port. Right?
Yes.
It should rather be informed alongside with the controller's inputs in every call.
If that were the case, the outer layer (the blue one in this case) should be responsible for the injection of the output port. Am I right?
Clean Architecture doesn't tell you how to construct any of of this. You're looking at an object graph. Nothing Mr. Martin has published tells us how it got built. I've talked about this before.
However, I'm a fan of reference passing. You'll probably find more recent info about that if you call it Pure Dependency Injection but rest assured, it's the same thing.
That's important to understand because it colors the way I approach this problem. You don't have to do it my way. But if you do here's what you think about:
How long do these things live? When is the earliest we can decide what they're going to be? How far up the call stack can we push their construction? Can we push construction all the way up to the program entry point? The highest place you can push this to, regardless of framework restrictions, was called the Composition Root by Mark Seemann. In normal programs we call it main()
.
Everything I see in this graph seems like something that could live for the entire life of the program. I see nothing here that must be ephemeral (a fancy way to describe things that blink in and out of existence). In other words, this object graph looks static. Guess what? main()
is static.
That means we can build the whole thing before a single line of behavior code is executed. This pattern of build it before you run it isn't just a dependency injection pattern. This is something server code authors do because server code has to be stable. Server code must stay up for months at a time. So it's really nice if you can separate code that has a fixed memory foot print from code that dynamically allocates memory as the program runs. Because a memory leak is not your friend. It's nice if the places you have to hunt for it are few. And yes, you can leak memory in Java and C#. Just hold a reference to an ephemeral object longer than you need it.
So if an object is going to live as long as the program I'd prefer to build it in main()
not the blue ring. That doesn't mean main()
is a pile of procedural code. Use every language feature and creational pattern you like. Just make the behavior code wait until later.
main()
simply isn't in this diagram. When this object graph exists main()
is on it's last line. Which is usually something like: runner.start();
.
But like I said, Mr. Martin is utterly silent on construction here. So all that stuff is up to you.
Best Answer
I am using Clean Architecture for a rich desktop application since about a year now and it works well for GUI-heavy, event-based applications. It's not a good fit for a "real-time" game like a jump'n'run, but a chess game will work just fine.
Instead of dissecting your question, I will go through a recap of the layers and will end with following the process of moving a figurine.
The Entities Layer
"Enterprise wide business rules". In your case, that means encapsulating the rules of the game. Having the age old game of chess here instead of an actual business gives you an advantage - once you wrote this layer, the only way it will ever need a change is if you found a bug here.
The Use Cases Layer
Think of use cases as application user actions. In this layer, you define these user actions, the input they take, the output they give back and the interfaces they use in order to achieve their goal. Such a use case will not really do any work itself. It's more like a step-by-step description of what happens.
The Interface Adapters Layer
The code you write that does the "grunt work" goes in here.
The Framework & Drivers Layer/Details Layer
This layer is purely an adapter from some external thing to your code (= the inner 3 layers). It consists almost completely of wrappers. This part needs to be so thin/simple that it doesn't need to know about the other 3 layers. It doesn't know about your models, it only works with strings, ints, events, etc.
The exception to this might be your setup code that connects everything, which is also in this layer for practical reasons rather than semantical.
(You called this the "Presentation layer", but that's a bit misleading. On one hand because a DB, some hardware device, internet access etc are also all external things that get their wrappers in this layer. On the other hand because all the "view logic" - like turning a model into strings for the GUI - happens in the previous layer.)
Moving a chess piece
Details layer
BoardView
in the details layerBoardView
calls aBoardViewPresenter
with the simple info('A', 1, 'B', 3)
Interface Adapters layer
BoardViewPresenter
translates that into proper models from your Entities layer.ChessPiece
on A1 and theBoardPosition
B3.MoveChessPieceRequest
from the use case layer.MoveChessPieceUseCase
(obviously also from the use case layer).Use Case layer
MoveChessPieceUseCase
validates the request according to the rules from the Entities layer.MoveChessPieceResult
with a booleanSucceeded
set to false.Interface Adapter Layer
BoardViewPresenter
now has theMoveChessPieceResult
and reacts to the positive result.ChessPieceView
and tells itMove('B', 3)
.Details layer
ChessPieceView
changes its actual position on the screen.