22

Are there any guidelines for deciding when a class should be in its own assembly/DLL? I often see two schools of thought:

1) Every "grouping" of classes belongs in its own DLL e.g. Repositories, Services, DTOs, Infrastructure, etc.

2) Everything should be in a single DLL but separated out via namespaces/folders e.g. have a "Core" DLL with additional namespaces e.g. Core.Repositories, Core.Services, Core.DTO, etc.

At work we just lump everything in a single Assembly called "Business". There are some folders but there's no real separation - business objects (with logic, some of which shouldn't even be classes) are lumped in a "BusinessObjects" folder without care. Things used in more than one class are in a "Core" folder. Utilities are in a "Utilities" folder, the data access infrastructure is a "Data" folder - you get the idea.

For a new module I'm working on I want/need to have a separate data access layer (think a rudimentary Repository implementation) but I don't want to just throw it under the "BusinessObjects" folder with the other 160 (!) classes there. At the same time I'm concerned about creating a new Class Library since everyone is used to stuffing a class in the single Library; a folder/namespace could work however.

12

I find it's better to have more projects (i.e. assemblies) with classes divided by category in each project than one project with all of these classes in separate namespaces. You should aim for your projects to be reusable and to represent different layers in an application. You can then feasibly reuse these projects in future applications without having to include a whole bunch of unnecessary classes.

For instance, based on what you have mentioned, I would definitely have the following projects:

  • Core
  • Data
  • Domain (or BusinessObjects)
  • Services
  • Utilities (or Helpers)
  • 2
    Regretfully I cannot down vote the answer. This is exactly what is advised in our firm. As result having 6 or so projects e.g. for medium size web site you cannot maintain feature based hierarchy of directories etc. As result you end up with the six projects with each is a big messy impossible to navigate pile of files. Usually people who advice this have never tried the feature based structure of projects on relatively large projects (sorry for direct judgment but dealing with results of such overweening is a real pain). The jammycakes answer advises correct approach. – alehro Feb 15 '17 at 9:48
  • Dividing classes by category is what leads to mess in large projects. Divide them by feature/aspect. Then namespaces will be just mirroring this division. And the whole structure will mirror lexicon from specification. Dividing classes by category is like adding type abbreviations to variable names - usually is bad smell. – alehro Feb 15 '17 at 10:03
  • It's easy to abuse both proposed solutions (i.e. too many projects or too few). Finding a good balance where reusability and low coupling is kept in mind should lead to something more testable and maintainable. – Bernard Feb 15 '17 at 22:13
16

"Uncle Bob" Martin of Clean Code, SOLID Principles fame has outlined three principles here:

  • The Release Reuse Equivalency Principle: The granule of reuse is the granule of release.
  • The Common Closure Principle: Classes that change together are packaged together.
  • The Common Reuse Principle: Classes that are used together are packaged together.

The general rule of thumb is that you should keep the number of projects in your solution as low as possible. Only split them up if you need to do so in order to implement one or more specific user stories, or if having a single assembly is causing measurable performance issues (typically once they get up to several megabytes in size).

  • 2
    +1 these principles are good guidelines. Separating classes into different assemblies introduces additional design considerations (for example which versions of each assembly are allowed to work together) increasing the overall codebase thus increasing the cost of maintenance. – Ben Oct 4 '14 at 7:53
  • 1
    However, in addition to these principles I would add that it is often a good idea to package code that is likely to be replaced or swapped in a separate assembly. This code will benefit from the additional considerations needed for coupling separate assemblies and having it separate will make it easier to test and compare the different versions. – Ben Oct 4 '14 at 7:53
  • 4
    Yes, but make sure that there is a genuine requirement for it to be replaced or swapped. For example, frameworks and third party libraries -- NuGet packages and the like -- usually need to support multiple IOC containers and multiple logging frameworks. For userland code, on the other hand, such abstractions are usually purely speculative, unnecessary and obstructive, and never work out in the end on the rare occasions when they are actually needed. – jammycakes Oct 4 '14 at 9:47
  • "Only split them up if you need to do so in order to implement one or more specific user stories, or if having a single assembly is causing measurable performance issues (typically once they get up to several megabytes in size)." - totally random and not grounded in reality advice – hyankov Nov 17 '17 at 12:11
  • 1
    I'm sorry, but exactly what is "totally random and not grounded in reality" about it? I posted this answer after years of working on solutions that were split into far more projects than necessary for no reason whatsoever other than That Is How You Are Supposed To Do It. The result? Glacial compilation times and a morass of dependency hell (especially in the pre-NuGet days). Splitting things up into separate assemblies has a cost, and if there isn't any benefit to offset that cost, then it's just a case of stealing from the business. – jammycakes Nov 17 '17 at 13:38
4

Some other guiding princicples I work with:

  • Do you think you will re-use this code in other projectS? For one group of related web applications, we had one user account-related module that all the applications made use of, since they all used the same model for user accounts and logins. I've done similar things with geometry and math libraries and reused them in multiple applications, just by including the DLL.

  • Do you want to be able to modify / deploy this code without redeploying / recompiling the whole project? Sometimes it's been useful to just rebuild the module, deploy and restart the web application.

It sounds like in your case a basic and generic Repository could be useful again in the future, it might be worth it to separate it into a new DLL if you can.

  • I think your second point is truly reasonable. Dividing into modules should aid development / testing and compiling times. – W.M. Mar 26 '17 at 17:12

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.