One of the concepts of clean architecture is the concept of layers. A layer will divide your code between different concerns. Each layer has its purpose and acts as a barrier. Thinking about your architecture, and how your application is separated. Is an important step. Teams that not take this step have an increased chance to create lots of Technical Debt. This results in code smell and slows down teams. There are different ways to solve this. Good or right does not exist. There is only bad, good and better. At least aim for good. Not having an architecture. Not having a process to think about it. That will result in the Technical debt you want to avoid.
UPDATED on March 25, 2018 (Planning on creating a new and improved version of this article in the coming weeks or months. This article does not reflect my current stand on this. If you have questions feel free to ask me on twitter or send me an email.)
Symfony Directory and Namespace
The default directory structure that Symfony suggests is not adequate in the long run and makes your code not as clean as it could be. It is also never intended to be the perfect fits all solution.
When having a dozen of controllers, entities and repositories this can start to become confusing. You don’t have the required structure to have an easy overview. You can’t expect anyone to hold rules and create clean code if it is hard to figure out were to place what. If I see this directory structure and ask; Where do I place business logic? There is no predefined answer. This can be everywhere and lead to thick controllers and domain logic all over the place.
Three Layered Architecture
The layered architecture structure I prefer and use at the moment consists out of Domain, Application and Presentation layer. With this we split our code in 3 separate layers, each with its own responsibilities. We move from Domain to Infrastructure to Presentation. The upper layer can always work separate from the layers under it, but not the other way around. Your domain should be able to work separate on its own without any of the other layers. But your presentation layer can’t do anything without Application or Domain.
The first and most important layer is the Domain layer. This is the life of your application. This represents your domain business, your business logic. This layer has no interaction with the outside world. The other layers only exist to provide for this layer.
It consist of the following types of objects:
- Entities / Domain Object
- Value Objects
- Domain Events
- Domain Services
- Repository Interfaces
All these types of objects represents your business logic. Services created in this layer are business logic related. Any services that have code that represents infrastructure or application should not be in here. If you have a general class that only handles converting a XML to CSV, this is not a domain service, but an application service.
In the Domain Directory/Namespace I create a sub directory Model. Then for each aggregate I create another directory. In this directory all things related to that aggregate is contained.
- Domain\Model\Product\Product (Entity)
- Domain\Model\Product\Price (Value Object)
By doing this you clearly separate your different aggregates. This creates structure.
Then the next layer is Application. This is the combination of the Infrastructure and Application layer. It wraps around your domain layer. In most cases I don’t see any use of making separate layers for Infrastructure and Application. There might be use cases for that, and when it makes sense to separate these layers, then do it. Don’t make layers just to have layers. But an Application layer holds objects that are in charge for persisting your data or to do functionality that is not related to pure domain logic, but related to application and infrastructure.
This means this layer consists of the following types of objects:
- Application Events
- Application Services
- Infrastructure Services
This layer consists of the code to get your application working. Your framework is actually part of infrastructure. Any extensions on the framework is infrastructure.
The last layer is presentation. This is all the code used to represent your application. This should only communicate with the Infrastructure layer or with Domain Services. You might say, why isn’t this part of the Infrastructure layer? Isn’t this Infrastructure? Well it could be. But I like to have anything related to presentation separated. I could move out this complete layer and replace it with another and you would only have to use services to write code to represent your application. This means the presentation layer should not consist of any code related to business logic or rules. Keeping controllers thin is crucial here.
This layer consists of the following types of objects:
- JS and CSS assets
When working with Symfony its a good thing to think about your directory structure. If you are not sure or don’t have any experience with this. Start by using the architecture I suggest here. Its a good starting point. And based on requirements you can change the layers (just don’t make to many). If you are working with bigger and more complex applications it might be a good idea to look at DDD or Hexagonal architectures. But for small to medium or applications of less complexity this is a good start. As always, think before you code! And reduce your Technical Debt…
UPDATE: March 25, 2018
I realized that I made some mistakes in this article. I have update this article so it is more correct to my current knowledge. If you still find any errors or misconception, let me know.
I’m planning to create a new Updated article concerning this topic with how I actually work now, or the variations I use. I also want to give a more deeper and clearer explanation. Also concerning to what is a domain, application and infrastructure service. There is a lot of confusing a round those things for who is new to this.