I’m doing research on software architecture, layering, and looked lots of open source .net projects, like Orchard CMS.
I think Orchard is a good example for some design patterns.
As I know, UI, Services, Repositories and Entities should be in separate assemblies, due to misusing. But in Orchard, (due to being modularity and pluggable) I see service, repository and entity classes and interfaces in same folder and same namespace.
Isn’t it an anti-pattern, or is it correct for patterns?
I’m doing research on software architecture, layering, and looked lots of open source .net
Share
TL;DR: assemblies are not necessarily the right separation device.
No, what’s important is that they are separated, not that they are in separate assemblies. Furthermore, the way you would factor things in most applications has to be different from what you do in an extensible CMS. The right separation in an extensible CMS is into decoupled features that can be added and removed at will, whereas regular tiered applications require decoupling of layers so those can be worked on and refactored with minimal risk and impact. The right comparison is actually between one of those applications and a module or feature in Orchard, not with Orchard as a whole. But of course, good practices should be used within modules, and they usually are.
Now separation into assemblies is a separate concern, that is more technical than architectural. You can see an assembly as a container of self-contained code, created for the purpose of code reuse and dynamic linking, but not especially as a way to separate layers. This is why they coincide in Orchard with the unit of code reuse, the module.
Also consider the practical aspect of this: good architectural practices have one main goal, which is to make applications easier and cheaper to maintain (and not, surprisingly (NOT!) to make consultants rich by enabling them to set-up astronaut architectures that only they can understand). A secondary goal is to codify what makes scalable and well-performing applications (although that is a trickier goal as it can easily lead to premature optimization, the root of most software evil).
For that first goal, conceptual separation is the most important, but the way this separation is made is usually not very important.
The secondary goal unfortunately conflicts with the idea of using assemblies as a separation device: Orchard as it is already has dozens of assemblies before you even start to add optional modules. And assemblies do not come for free. They need to be dynamically compiled, loaded, jitted, come with memory overhead, etc. In other terms, for good performance, you’ll usually want to reduce the number of assemblies.
If you wanted to separate an Orchard site into assemblies for modules as it is today, and then separate each of these modules into layered assemblies, you would have to multiply the number of modules by the number of layers. That would be hundreds of assemblies to load. Not good. As a matter of facts, we are even considering an option for dynamic compilation to build all modules into a single assembly.