I came to realize that the popular wisdom on good practices is flawed, and most of 101 articles on any pattern or framework are relying on flawed beliefs.
My goal is to expose these flaws by reviewing with you conventional project structures, analyze the origin that contributed to their wide spread use, and explore alternatives.
In this article, the domain refers to a set of concepts in the business you are helping with your software. (Accounting, Finance, HR, Health etc…)
The Domain Space
Every concepts belongs to a space I call the domain space. In this space there is distance between concepts, closer concepts depends more on one another than farther concepts.
As the domain space exists purely in your imagination, you intuitively understand that Accounting, Money and Finance are closer to each other than Finance and Kittens.
But, what is not imagination is your code, which is nothing but a projection of the very same concepts into other spaces:
- File system space : where the distance between two files is the number of directory you need to browse to go from one to the other
- Data space : where the distance between two data is the hamming distance.
- Class space : where the distance between two classes is equal to the length of the shortest path in the dependency graph.
- Project and namespace space : you can also calculate the distance with the dependency graph.
The definition of the best architecture is the following :
The relative distance between concepts in all of these spaces are equal the the relative distance in the domain space.
In plain English: if Kittens and Finance are very far concept, don’t put them in the same directory and don’t reference Finance in Kitten’s class.
The problem is that the domain space does not exist, it is in our imagination, this is why the best architecture is not the best for someone else : you don’t have the same domain space, this is not a code problem, but a communication problem.
The more similar your domain space is from the one in the collective intelligence of the people who will use your software the better.
If two developers share the same domain space, they will always agree on the best architecture. There is no place for taste.
Refactoring happens when your domain space is changing : The one from the collective intelligence of your user change rarely, but yours change quickly at first, then slowly with time. This is learning, a human process identical for everyone. Your knowledge will eventually converge and, hopefully, be close to the one from the collective intelligence.
Refactoring is the process where we project the new domain space in a code that already exists.
With all of these definition I can finally define coupling and coherence, and why high coupling might be good (or bad):
Coupling : The closer two **** are in the **** space, the more tightly coupled they are.
Coherence : The coupling between three **** are relatively equal with their projection in the domain space.
Replace **** with class/project/namespace/file.
If Finance references Kittens, then Finance and Kittens are highly coupled but it is not coherent.
If Finance references Money, then Finance and Money are highly coupled and coherent.
Finance should be lowly coupled to Kittens (better : not coupled at all since I don’t see any path in the dependency graph !), this would be coherent.
Maximize coherence do not minimize coupling.
Things that change together must stay together
First observation : The structure of a project reflect the focus of its creators.
Second observation : I almost never see a structure reflecting the domain
Conclusion : Few developers are focusing on the domain, they focus on design patterns or frameworks instead… The resulting structure is pattern-driven, not domain-driven.
As an example of this non sense take the default ASP.NET MVC project and compare the distance in the File system space :
Stop doing that
The distance AccountController-Login and AccountController-Register are equal, this is coherent.
But why AccountController-Login is equal to AccountController-Error ? This is not coherent.
The same observation holds with AccountModel-Login/Register/Error.
How to fix the coherence problem ?
Move AccountController and AccountModels in the Views/Account folder.
I explained in comments why I think MVC Areas are a pain killer but not medicine.
Why calling a folder “Views” when you can find Models and Controllers inside ?
So you delete the Views folder, and it leaves you with a project’s structure, more aligned with the domain.
Yes, you need to use extensibility points from ASP.NET MVC to support such structure, this is not hard, but require to understand ASP.NET MVC a little more, I address this point later on.
ASP.NET MVC is not the only culprit, I’ve lived enough WPF project with this structure
Stop doing that
For simple projects, just putting everything in the same folder is as much coherent and even better, because it is more easily usable because the ViewModel file is right next to the View file, you don’t have to browse the whole project each time.
Things that change together share the same domain concept so keep them together, not far apart.
A comment made a good point : When two classes are in different layers, they share the same domain concept but do not change together. This is an interesting remark I should have talked about.
In this article, I focus only on a single layer. Two classes in different layers should not change together even though they share are near on the domain space.
The Model in MVC is not in the business layer, but UI Layer. A model in MVC is different from an Entity of the business layer. (As Eric Evan talk about in DDD)
Why pattern-driven structures exist
Some of you may object : Such structures are best practices made by developers that know their craft.
If you can only justify things because it’s how somebody else did, you first need to take a step back think, and come with your own arguments.
Question : Who is the customer of the ASP.NET MVC team ?
Response : You are.
They are doing exactly what you should do when coding for a customer : structuring the project with the domain concepts of your customer.
This has sense here because we are the customer, we, developers, we know what is a Views, ViewModel, or Model, and if we don’t we need to learn these concepts to code properly.
But then, our customer is not a developer, so we need to change the structure to reflect his domain, there is no way that ASP.NET team anticipate this structure. The only thing they can do is to provide extensibility points… which they did great.
Another reason is teach ability : the distinction between Model/View/ViewModel is easier to teach when you save them in separate folders.
Remember, when you learn something from code you build your own domain space from the code, so, the closer the code your are studying from the domain space you want to learn, the better.
Bad reason to use pattern-driven structure in production
Some are tempted to use these pattern-driven structures directly in production.
Designers don’t care about the code, just the view, so it’s better if the views have their own folders.
First your assumption is that the designer of the view and the developer are not the same person, which is only true for company having enough money to pay separate people to do their tasks. Which is only true for big companies.
Even with this assumption, the argument does not hold :
The designer needs to know the URLs he can use in forms, and the fields he can fetch from the model. So he will most likely need to read the model and the controller files.
In this case, the best way is to arrange them next to the view file.
The learning curve is smooth for new developers, most of them know how MVC works.
It is true that getting the structure you want in ASP.NET MVC is harder than just creating the view in the default folders. But new developers do not need to code this part. Using extensibility point of ASP.NET MVC is better handled by experimented developers or architects one time for all. The infrastructure code do not change that much.
The time new developers will take to learn a new, simple structure, is largely compensated by the time they earn each day searching for files in the solution.
Yes, I know about all of great VS features to browse quickly with every keyboard shortcut you want, but if you are concerned about the learning curve for new developers, then the odds are high that they don’t use keyboard shortcut at all…
Experimented developers will grasp thing in less than 10 minutes.
We should respect project templates made by other developers, it is a great way to start and learn a project. But we should not consider their conventions as best practices.
Their goals is to teach you how the framework works, when you know that you need to learn how to adapt it to reflect your goal straightforwardly.
I also try to kill a myth by introducing the concept of Domain Space and defined coupling and coherence from it.
High Coupling can be good, and Low Coupling not always desirable.
Your goal, as architect, is to maximize coherence.
You are accountable to your developers and to the customer or project manager at the same time.
Speak the ubiquitious language of your customer, not the one of framework creators, and teach to talk like your customer thanks to the structure you created.
The straight line between project success and now does not pass through pre-made templates. That’s what make things interesting !