We here at Elegant Code have our own little list group that we participate in. It is a nice place to ask questions to some fairly advanced individuals. Today, David Starr posed the question project structures. He said this could be a religious debate, but I don’t believe anyone took this up as a matter for dogma. The cool part was we actually got a good chunk of the Elegant Code group to comment on this. That is when you know you have a good topic.
But there are a lot of opinions here and a lot of good discussion. Anyway, you can follow the thread. Note: I did a little bit of editing because Tony Rasa doesn’t like capital letters.
David Starr
Here comes a religious discussion.
You are building a new enterprise app. Let’s use my RecipeBox example. It is an MVC app.
What do you think about this project structure? $ = A Visual Studio Project
$RecipeBox.Core
\Services
\Assemblers
\Contracts (or Interfaces) for entities and repositories
$RecipeBox.Domain
\Entities
\Repositories
\Validators
$RecipeBox.Data
\DTOs
\Repositories
$RecipeBox.Web
The MVC app
Thoughts?
Tony Rasa
I prefer having fewer projects and splitting things out after figuring out what the need is – so, having a .Core and .Web (along with .Tests), but then Core contains namespaces similar to what you’ve described. But that’s just me.
There are projects where we’ve split things out by project to enforce design rules, (maybe .Web should never directly reference .Data for example) in cases where we don’t trust the developers, or there is a ‘control issue’ with the project team… I prefer personal responsibility and reviews myself, but I suppose you’ll never get anywhere trusting to the good nature of people..
Jason Grundy
I agree with Tony – Web, Core and Test. Within these, especially as the project grows, I am starting to use namespaces as DDD modules to subdivide the app into functional areas. Nothing worse than having 250 entities in a single namsespace!
Scott Nichols
I actually like having multiple assemblies (like you laid out) for an "enterprise app". Granted "enterprise app" can mean a lot of things to a lot of people but I’ll go with the following assumptions.
– Used by a business/company/group, more likely in an intranet setting.
– The app components will be living in physical and logical tiers owned/managed by users.
– There is a possibility that other types of clients (windows, services, reporting SSRS, etc) may need to access/integrate with the apps data.
– etc, etc..
With some of these assumptions in mind I have found (my opinion) that having multiple assemblies will give you a greater degree of separation of concern, reusability between tiers and clients, and better maintainability if any of
these assemblies get reused by something other than the MVC app. The Application Architecture Guide http://www.codeplex.com/AppArch outlines these practices as well. In fact, when I look at your example I do not think you have gone far enough. For instance…
@ = A Solution
# = A VS Solution Folder (and namespace)
$ = A Visual Studio Project
@RecipeBox
#RecipeBox.Core
$\Services
$\Assemblers
$\Contracts (or Interfaces) for entities and repositories
Why would I do this?
If your Contracts and Services are in their own assemblies you can reuse them independently of each other which would be very important if you ever wanted to create a WCF service for this app (one example). Maybe down the
road you wanted to have two different implementations of the service class but they both still implement the same interface. In any case, it would work just fine by leaving all these classes in a single RecipeBox.Core DLL
as you listed them. Your DLL would just be a bit bigger than it needed to be if you just wanted to share your interfaces for example. Personal preference, I’ve always liked my interfaces (contracts) in their own
assembly.
The downside to all of this is that the more assemblies you add the more management is involved of your entire solution (keeping track of everything). That was the main reason Rocky Lhotka decided to roll all the CSLA assemblies into a single DLL, much easier to distribute. That move made sense to me though, because to use the CSLA framework you had to reference just about every assembly anyway. That is not necessarily the case with a distributed enterprise scenario, you pick and choose more discriminately based on what you are trying to accomplish.
I have also found one other major factor that helps determine how you distribute/group your assemblies. The structure of your IT organization. Really large distributed teams tend to break things down much more
granularly, more assemblies. Smaller more centralized teams tend to like less assembles. This is just an observation I’ve noticed over the years.
My two cents
David Starr
Yeah, I am, thinking in similar terms to exactly what you are saying. The other thing I like about separation via projects is a real enforcement of programming through interfaces. This is forced because to not do so would create circular project references.
Thanks, guys.
Chris Brandsma
I agree with Tony and Jason here. But I don’t think any of us believe this is a major fighting point.
With the extra projects you get forced separation. Which is nice for junior devs (or devs you want to put handcuffs on). But a bad dev will figure out a way to screw up almost anything.
With fewer projects and namespaces you have a virtual separation. But the solution loads quicker.
I like solutions that load faster.
Jason Grundy
Some more observations:
Jeremy Miller would say that an assembly is a unit of deployment.
With multiple projects your compile time will be significantly higher.
When you have multiple pieces that need to integrate for a specific purpose then I don’t think that a single VS solution is necessarily the best solution anyway.
Darrel Carver
One last point on having more projects and assemblies. You can separate the work among your project team. That usually means people are working on more thing independently (interfaces can help enforce that). It also means less conflicts when you check in the work to source code control.
David Starr
That’s what I am doing here.
Physical separation for different teams with a "meet in the middle via contract" agreement.
Jarod Ferguson
some thoughts….
Just curious, but what are the units of deployment, how many app domains? ( are the services WCF? asking because of the word *contract* in there)
This is all relevant to team size, but is sounds like you are heading in the direction of a larger org with many teams?
Its it ideal for team to be separated by modules, vertical slices. Meeting in the middle with a wcf contract may make your teams horizontal.
Why are there repositories at the Data layer & Domain layer?
What is the Data layer? I would make this DLL your contract/interface dll with all your service interfaces AND Dtos, this way the client only has to reference this one Dll to get the service interface & DTO.
As with Jason, I would move to a more vertical ‘business minded’ aka, DDD, namespacing structure as soon as the application architecture would let you (after .Domain in this example). It can get mind numbing to work in all those layers, when what you are trying to do is all related.
E.g
$RecipeBox.Domain
\Entities\Customer.cs
\Repositories\CustomerRepository.cs
\Validators\CustomerValidator.cs
$RecipeBox.Domain
\Customers
Customer.cs
CustomerRepository.cs
CustomerValidator.cs
Scott Nichols
While we are on the topic, the physical folder structure is very important to get nailed down as well, otherwise your source control implementation/maintenance can get a bit ugly too. David, I imagine you being the TFS guy would be all over this. My group put together this basic outline on how to structure the source control folders (hopefully my attachment comes through), any thoughts?
It is basically a variation of what Microsoft published at http://msdn.microsoft.com/en-us/library/bb668992.aspx. It mentions TFS but could obviously be applied to any system.
Tony Rasa
The "so we can switch to Technology X later, if we want" argument always sets off my YAGNI alarm. If you know that you’re going to need the enterprise-wide solution, supporting multiple front ends etc, then yeah, you gotta go with the added complexity. Scott’s one of the guys who has those extra requirements, too often i hear it applied to the
"selling junk online / customer management" website. I think its easier to scale to that as a need is identified (ideally towards the beginning but sometimes you don’t get that luxury), otherwise you’re adding complexity without the payoff…hey, haven’t we had this discussion before 🙂
Agree on the source layout issue as well, pick a structure that works for you and run with it.. don’t let the jr devs mess up the source tree! better yet, train the jr devs so they know better…
Chris Brandsma
Side note: this is a case where I’m not as worried about the junior devs. Mid-levels or or mis-promoted seniors will cause more damage.
Scott Nichols
I am a huge advocate of KIS (keep it simple) and would not disagree with anyone who is trying to keep the number of assemblies to as few as absolutely needed. I imagine given this crowd that with David’s MVC app if developed by any of us it would be layered and broken-down into a very nice API following the SOLID principles. However, given a few other pieces of key information (not provided by David) the same code would be broken-down and packaged differently.
David was pretty vague on the requirements (purposely so I bet). I’ll pick on Chris for a bit (he is man enough to handle it :-) His typical clients (correct me if I am wrong) are not the big enterprise guys that are going to have large distributed teams or infrastructure requirements that require lots of end-points that various systems will need to touch or integrate with. He is going into a company to build application X as fast and under budget as possible in his own little sand box so to speak. If I were in Chris’s shoes I would build this fictitious MVC app as single tired as possible. Ok being me, I would still probably have at least three assembles. Anything to deal or relate to data into a DAL assembly, all service type code especially if messaging based like WCF into a Services assembly, and all the remaining MVC code into a single app assembly. Although, if it were all in one assembly I would not lose any sleep over it , Chris writes nice code, I am sure it could be repackaged later if needed quite easily.
My typical world is a bit different. I may get the same request to build an MVC app but there would be added requirements. This app would probably need to get data from a few systems and then provide it’s data to several other systems (highly integrated/distributed). Multi clients in some form would be in the mix and an architecture that could easily scale the various tiers as the enterprise demands grow. With that, you tend to break things down a bit more so you can reuse your code as I describe in my earlier e-mail. You still need to keep your head about you though, and not go crazy on your physical abstractions (assembly madness) . You do it where it makes sense to meet a business requirement. Start simple (KIS) and repackage (multiple assemblies) as needed to reuse various code bases to fulfill your architecture needs.
i’m ok with capitol letters, its the capital ones that i have a problem with 🙂
I like Multiple projects personally, and I don’t really agree with the Idea that it’s putting Handcuffs on the developer, it’s more of creating a structure that allows expandability.
This is very helpful when your developing applications with multiple UIs, for example I have web applications that are public facing on one set of web servers, have a web service interface on another set of servers, and an internal admin on another set of servers. Next I have multiple applications that use the same data but in different ways, so by breaking the DAL into it’s own project I get away from having a huge BIZ that’s everything to everyone. Honestly, are multiple assemblies really that hard to deal with? Plus by breaking it into multiple Assemblies means you can reuse your assemblies as libs in more then one applications, and not just coping and pasting the code.
My preference is to have 4 projects (UI, BIZ, DAL, OBJECTS(entities, interfaces, etc.)) and then test projects for each one. This way it forces good design, and gives me the flexibility to expand the application easily, I’ve been bitten too may times by the this functionality will only be used by this application, 2 projects later, needing to include the same functionality.
I also like seperate projects. I personally don’t let the speed of a solution loading dictate the structure of my solution. As Richard mentioned, it also lends itself to code reuse and more felxibility for expanding. This is especially useful when using the PRISM framework, where you reuse 80% of your code in different types of projects, web, silverlight, wpf, or win forms.
Another take on this topic (based upon commercial software product developments that cross application boundries).
In hierarchical order:
$App.Utility (reference nothing)
\Math (Utility functions)
\IO (Utility functions)
\Graphic (Utility functions)
\Xml (Utility functions)
$App.Commons (reference only $App.Utility)
\Entity (domain)
\Contract (domain)
Constants.cs (enums, etc.)
$App.Web (reference only $App.Commons Controls Utility Presenters)
\Api (usually REST/ASMX based API gateway talking ONLY to Presenters)
\Language (XML based localization files that cross app boundaries [no .RESX])
$App.Web.Widgets (reference nothing)
\Controls (Server Controls)
$App.Presenters (reference anything, except $App.Data Web)
\Presenter (domain aware, calls $App.Business)
\Helpers (domain aware, UI technology aware)
ResourceHelper.cs
$App.Business (reference anything, except $App.Presenters Web)
\xxx-Manager (domain aware, calls $App.Data)
\yyy-Manager (domain aware, calls $App.Data)
\zzz-Manager (domain aware, calls $App.Data)
$App.Data (reference only $App.Commmons)
\Repository (persistence)
\SQL (create DATABASE objects)
Notes:
1. $App.Utility & $App.Commons can be used, referenced anywhere, and will typically cross application boundaries (e.g. travel through API, get used by “add-on” products).
2. $App.Presenters is the linch-pin: all API calls and web UI go through this (single version of the truth?).
3. $App.Commons never carries any “excess baggage” to ensure that Entity classes (Value Objects) are not decorated with technology/framework specific Attributes.
4. Localization is a first-class citizen across the entire application stack, AND needs to be accessible by “add-on” or third-party applications.