For example, if I’m using some MVC-like architecture, which folder structure should I use:
domain1/
controller
model
view
domain2/
controller
model
view
Or:
controllers/
domain1
domain2
models/
domain1
domain2
views/
domain1
domain2
I deliberately left out file extensions to keep this question language-agnostic.
Personally, I’d prefer to separate by business domain (gut feeling), but I see that most/many frameworks separate by technical domain. Why whould I choose one over the other?
1
I think this depends on specific project.
For example, if the different business domains are totally independent of each other, then I’d organize by business domain.
But if there is shared code between the business domains, or rather, the business domains are different variants of the same code base, then it seems more logical to organize by technical domain.
And if you use any sort of Object Oriented language, then you can probably subclass your generic controllers, models, etc in your business-specific files to make them thinner.
There is also a (golden) mid-way between the two – strip out shared code into it’s own domain and use that in other domains. This gives you your gut feeling-powered layout, but allows shared code between business domains.
Domain1 # This domain changes bits of standard MVC code
controllers
models
views
Domain2 # this domain only modifies views, all else is standard
views
Shared # Here is the better part of code base
controllers
models
views
PS. I think that most frameworks organize by technical domain just because they tend to expect that you mix different business domains into single project only if you have shared code and otherwise would create separate projects.
EDIT:
For example, suppose there is a web app that handles a company’s warehouse. In generic form this might apply to many companies, but each of them might have some specifics that aren’t met and forbids them to buy in. E.g one of them has deployed tablets to the forklifts and needs special View for them while yet another wants to organize items into three levels instead of the default of two.
You could of course fork the project for each of these companies.
But if the framework/language allows, you could use subclassing or plugins etc to customize bits and pieces of the generic project to every customer’s needs and organize them in the Business Domain layouts.
E.g if generic project exports to JSON only the Item itself, Domain1 can subclass the controller and make it export also recent delivery problems.
And if you later find that Domain1 has a component that is also valid for Domain2, you can extract generic version of it to Shared.
As you said, many frameworks organize by technical domain and that is what I have used for now, just because my FW of choice makes this easier. But with a little (or a lot) of elbow-grease, I think I could rewrite the include paths to support Business Domain layout too.
2
I think it’s enlightening to ask, “what am I more likely to add on a regular basis, more domains or more technical divisions?” Then whatever the answer is, put that at the top level.
In most cases your technical architecture will solidify faster than your domain. That means you should organize by domain first, then by architectural component. The reason is that when something in a domain changes, you may have to add or change multiple technical components in that domain, but hopefully that’s localized and doesn’t spill over much into other domains.
If you changed your GUI framework, then that means your changes will spill across the whole application, but then again, you rarely change your GUI framework, but you’re always changing your domain logic.
Keep things together if they’re likely to change at the same time.
3
There is another alternative and that is moving the seperate parts in plugins. CakePHP does that for example. It will allow you to generate complete MVC parts which are re-usable which you can sort by any logic you want.
Your main application will just use them and link to them.
Basically your question is also about cohesion and coupling. You want the separate parts to work as independently as possible. That way you get testable and re-usable code.
Taking that into consideration: If you split up by domain how would you re-use parts of your application? For example take a webshop: a request comes in for /orders/view/1 so you need to show order nr. 1. Goes to /orders/controllers/order_controller If you seperated domain by products and orders you would already need parts of the other “domain”.
There you can start interfacing things but likely things are in most business just too cohesive. If you take the technical approach. For example you could have a plugin handling orders. You put in Product objects to it from your central application. That way you can test the plugin easily, just create some Product object with a name and price and send it in.
The plugin will do exactly what it needs to do. It will depend on it’s input and not on other “parts/domains/areas”.
1
Microsoft ASP.Net MVC 3 has the concept of “Areas”. When you introduce “Areas” into your MVC project, they break it up like:
area1/
models
views
controllers
area2/
models
views
controllers
I found this to be quite natural. An area is a “large chunk” of a project, and working in a self-contained unit just made a lot of sense.
We used namespaces to match, FWIW.
3
From my personal experience with a web shop consisting of 300 000 lines of code, I would always go for organizing by business domain. This way, you can not only get a quick overview of all relevant classes when you work on one functional area, in Java you can also make use of the package visibility.
Some details for those who are interested:
When the project was started 5 years ago, the developers created the following package structure:
com
example
web
struts
action
form
shared
functionality1
functionality2
Each shop function such as shopping cart, product search etc. consists of several actions, each with its own form class (structure mandated by the MVC framework). What we ended up with are over 200 classes in the action package, each one completely separated from their associated form class. What’s worse is that actions don’t implement too much logic, but call function-specific services which reside in yet another package.
I suggested and convinced the team that we should switch to organizing packages by business domain. The reasoning is simple: if you really want to see a list of all actions, you can simply open the type hierarchy view of any decent IDE. However, what the IDE cannot do is infer the business domain a class belongs to. Furthermore, that approach allows you to make only those classes public which are needed by several functionalities, keeping the rest on package visibility.
I agree that many frameworks separate by technical domain and so I often start this way when using a new framework. However, I consistently settle on using business domain as the primary level of folder organization.
Personally, I think it’s much easier to keep my Foo Controller and Foo Repository or whatever together than going back and forth between the Controller’s folder and the Repository’s folder as often I need to work on both when adding features around Foo. In larger projects this is even more important as the distance between technical folders can be great and become a noticeable waste of time while developing.