Patrick Smacchia [MVP C#]

Sponsors

The Lounge

Advertisement

Images in this post missing? We recently lost them in a site migration. We're working to restore these as you read this. Should you need an image in an emergency, please contact us at imagehelp@codebetter.com
Advices on partitioning code through .NET assemblies

The tenet is: reduce the number of your .NET assemblies to the strict minimum. Having a single assembly is the ideal number. This is for example the case for Reflector  or NHibernate that both come as a single assembly.

 

A lot have been said on this topic. I dig in this article why using more namespaces and less assemblies for componentization is a good thing. Jeremy Miller does it so in this blog post. The point is that assemblies are physical while namespaces are logical. As a consequence, having N assemblies multiplies by N the burden of dealing with physical things. This burden consists of referencing N assemblies from a Visual Studio project, slowing down significantly compilation of N Visual Studio projects, managing the deployment for N files, need for the CLR to do N CAS security checks at startup time, etc… Personally I have seen applications with up to 750 assemblies! Quote from Jeremy Miller: I took 56 projects one time and consolidated them down to 10-12 and cut the compile time from 4 minutes to 20 seconds with the same LOC

 

I would like to discuss here the motivations behind creating an assembly. I will then illustrate these reasons through the choices we did for assemblies of the NDepend code base. In an effort to reduce the number of assemblies in your shop, it is a good thing to find a valid reason for the existence of each assembly of your code base. If no solid reasons can be found you’ll find room for merging assemblies.

 

Valid and Invalid reasons to create an assembly

 

Valid reasons to create an assembly:

  • Tier separation: Need to run some different pieces of code in different AppDomain or process. The idea is to avoid overwhelming the precious Window process memory with large pieces of code not needed.
  • Potential for loading large pieces of code on-demand. This is an optimization made by the CLR: assemblies are loaded on-demand. In other words, the CLR loads an assembly only when a type or a resource contained in it is needed for the first time. Here also you don’t want to overwhelm your Window process memory with large pieces of code not needed most of the time.
  • Framework features separation. In case of very large framework, users shouldn’t be forced to embed every features into their deployment package. For example, most of the time an ASP.NET process doesn’t do some Window Forms and vice-versa, hence the need for 2 assemblies System.Web.dll and System.Window.Forms.dll. This is valid only for large framework with assemblies sized in MB. For example the NUnit http://www.NUnit.com framework certainly does not need 25 assemblies for 15.000 Lines of Code! Quote from Jeremy Miller: Nothing is more irritating to me than using 3rd party toolkits that force you to reference a dozen different assemblies just to do one simple thing.
  • AddIn/PlugIn model, need for interface/factory/implementation physical separation.
  • Test/application code separation. If you are not releasing source code but only assemblies, you likely don't want to release tests. Not releasing test assemblies make this easy.
  • When several assemblies have been created for the reasons above, they likely need to share some common code. Such shared code must be placed in a dedicated shared assembly.

We could add assembly as a unit of versioning but IMHO, the need for versioning is a subset of all these reasons enumerated above.

 

Invalid reasons to create an assembly:

  • Assembly as unit of development, or as a unit of test. Modern Source Control Systems make it easy for several developers to work simultaneously on the same assembly (i.e the same Visual Studio project). The unit should be here the source file.
  • Automatic detection of dependency cycles between assemblies by MSBuild and Visual Studio. There are tools such as NDepend that can detect dependency cycles between namespaces or types of an assembly.
  • Usage of internal visibility to hide implementations details. This public/internal visibility level is useful when developing a framework where you want to hide implementation details to the rest of the world. Your team is not the rest of the world, so you don’t need to create some assemblies especially to hide some implementations details.
  • Usage of internal visibility to prevent usage from the rest of the application. If you want to prevent usage and thus control the structure/dependencies of your code base, you should better use some dedicated tools such as NDepend .

If you are interested in reducing the number of your Visual Studio projects/assemblies, I would suggest reading this blog post Hints on how to componentized existing code. It shows how to use some NDepend dependencies features to get some hints about which sets of assemblies should be merged.

 

 

A case study

 

NDepend code base is split across 11 assemblies and here is the dependency diagram of NDepend assemblies (made by NDepend itself):

 

 

 

Something you might notice is the XDepend term. We are currently building the XDepend product (aka NDepend for Java), that will be released in 2009. More information are available on the official website http://www.XDepend.com and I will talk more about this in the future. This XDepend/NDepend duality leads to 2 different deployment packages for the 2 products and this is why there are NDepend.Console.exe, VisualNDepend.exe, NDepend.Platform.DotNet.dll on one hand and XDepend.Console.exe, VisualXDepend.exe, XDepend.Platform.Java.dll on the other hand.

 

The need for 4 exe instead of 2 was needed mostly for terminology. XDepend.Console.exe certainly makes more sense for an XDepend user than NDepend.Console.exe. All these 4 executables are almost empty in terms of code. The console ones initialize the platform (Java or .NET) and start the analysis implemented in NDepend.Analysis.dll while the Visual ones initialize the platform and start the UI, implemented in NDepend.UI.dll.

 

The need to initialize the platform (.NET or Java) is a motivation for isolating the code specific to each platform. Hence the need for the 2 assemblies NDepend.Platform.DotNet.dll and XDepend.Platform.Java.dll. This separation will also make easy potential future platform support (C++, Delphi…).

 

The tool comes with 2 primary usages, analyze code and digging into analysis results through the UI. This is the motivation for having 2 different executable assemblies: NDepend.Console.exe and VisualNDepend.exe on one hand, and 2 different libraries, NDepend.Analysis.dll and NDepend.UI.dll on the other hand. The idea is to avoid having both these assemblies loaded inside the same process.

 

NDepend.Analysis.dll and NDepend.UI.dll both rely on a lot of common code, core domain objects + many helper/util code, hence the need for creating the NDepend.Framework.dll assembly.

 

NDepend.CQL.dll is a lightweight assembly (less than 10KB) that contains the plumbing for declaring CQL rules directly inside the source code. Not only this assembly NDepend.CQL.dll is used by NDepend users who harness this possibility, but also we use it extensively to declare our own constraints in our code. For users who which to declare CQL constraints inside their source code, it is more convenient to link with a single and lightweight assembly, hence the need for NDepend.CQL.dll.

 

Finally, the NDepend.AddIn.dll assembly contains the plumbing needed to register the NDepend VisualStudio and Reflector addin. This assembly references big assemblies such as the Reflector.exe assembly. In order to prevent loading by mistake Reflector.exe in one of the NDepend process, it was a good thing to create a dedicated NDepend.AddIn.dll assembly. Also, addin assemblies are registered in VisualStudio and Reflector through their names and the name NDepend.AddIn is well-suited.

 

 

 


Posted 12-08-2008 10:18 AM by Patrick Smacchia

[Advertisement]

Comments

The Inquisitive Coder - Davy Brion’s Blog » Blog Archive » Assembly Partioning Advice wrote The Inquisitive Coder - Davy Brion’s Blog » Blog Archive » Assembly Partioning Advice
on 12-08-2008 6:35 AM

Pingback from  The Inquisitive Coder - Davy Brion’s Blog  » Blog Archive   » Assembly Partioning Advice

Elegant Code » Assembly Partioning Advice wrote Elegant Code » Assembly Partioning Advice
on 12-08-2008 6:59 AM

Pingback from  Elegant Code » Assembly Partioning Advice

Dew Drop - December 8, 2008 | Alvin Ashcraft's Morning Dew wrote Dew Drop - December 8, 2008 | Alvin Ashcraft's Morning Dew
on 12-08-2008 8:12 AM

Pingback from  Dew Drop - December 8, 2008 | Alvin Ashcraft's Morning Dew

Udi Dahan: The Software Simplist wrote re: Advices on partitioning code through .NET assemblies
on 12-08-2008 10:21 AM

Patrick,

I'd suggest that we separate from the development artifact (VS project) and the deployment artifact (assembly).

The fact that Visual Studio automatically compiles projects to assemblies is good for RAD but less so for larger-scale development.

Personally, I use ILMerge to merge the results of multiple project comilations into a single physical assembly.

This makes it easy to see references between different development artifacts without going into a different tool - something that makes code reviews that much quicker and easier.

That being said, I still think NDepend is an invaluable tool.

Kyle Baley wrote re: Advices on partitioning code through .NET assemblies
on 12-08-2008 1:44 PM

This is good advice. The VS solution should be considered a logical organization of your project to help during development.

This can also be achieved with an automated build process. With NAnt, you can compile all relevant files into a single assembly using the <csc> task rather than compiling the solution with msbuild.

www.igloocoder.com/.../how-do-you-build-your-application-details.aspx

Mark Nijhof wrote re: Advices on partitioning code through .NET assemblies
on 12-08-2008 2:32 PM

Even now that the source control systems are getting better I still have the occasional conflict in the project files when multiple developers are working on it at the same time. Because of this we decided to create some extra projects that share the base namespace (abc.xyz and abc.qwe) while in active development and then later merge the code into one project again. Which is easy with R#.

Another thing is the separation between interfaces and implementations. When using an IoC I like to have my interfaces in a different dll as my implementations at the very least they will be in a different namespace so they can easily be moved at a later stage. I like this because it gives the ability to change the implementation and the configuration (dll) and leave the rest alone.

What are your thoughts on this?

-Mark

DotNetKicks.com wrote Advices on partitioning code through .NET assemblies
on 12-08-2008 2:40 PM

You've been kicked (a good thing) - Trackback from DotNetKicks.com

Patrick Smacchia wrote re: Advices on partitioning code through .NET assemblies
on 12-08-2008 3:01 PM

Mark concerning the interface (plugin pattern) I indeed deem that creating assemblies is a good practice as I said in the post.

Concerning crating temporary projects, it is a dangerouis practices such as any temporary flawed state. there is still the risk to forgot or not have the time to go bak to a clean state later.

Reflective Perspective - Chris Alcock » The Morning Brew #240 wrote Reflective Perspective - Chris Alcock &raquo; The Morning Brew #240
on 12-09-2008 3:41 AM

Pingback from  Reflective Perspective - Chris Alcock  &raquo; The Morning Brew #240

2008 December 09 - Links for today « My (almost) Daily Links wrote 2008 December 09 - Links for today &laquo; My (almost) Daily Links
on 12-09-2008 4:06 AM

Pingback from  2008 December 09 - Links for today &laquo; My (almost) Daily Links

Brian wrote re: Advices on partitioning code through .NET assemblies
on 12-09-2008 2:37 PM

It's funny how 4 years ago when I was screaming about how many people were adding unnecessary complexity to their systems by adding so many assemblies under the ruse of 'loose coupling' and 'greater flexibility' are now coming back to their senses and realizing that there is a bell curve to it.

However, be careful with this one:

Framework features separation. In case of very large framework

Take a look at Microsoft Patterns and Practices 4.1 - it has reached the point that if you aren't already indoctrinated with EL, that the ramp up time and understanding of it is HUGE because there are so many 10's of assemblies that come with this thing.

The premise behind it being - you should be able to just add the assemblies you need to your deployment, and that you won't have to have extra features you don't need - but it's so darn fine grained you have a monstrosity of a bin folder (unless you GAC'd it which means you have 2 pages in your GAC just dedicated to EL assemblies).   EL, if it was collapsed into 1 assembly wouldn't be that big (take make a couple seconds longer to download over dial-up on a one-click deployed application) or take any noticeably longer time to load, plus you wouldn't have to ensure other assemblies are loaded also just to use it.   They created there own monster and I don't even want to use the thing anymore.

Now look at CSLA - one of the easiest, most flexible and scalable architectures I've used in the past 9 years - 2 assemblies.  BTW...it's extremely performant (if you've never used it) I got load tests that just fly when I use it (may because it doesn't require a billion pointer to run).

The lesson here is that flexibility and scalability is a factor of design, not implementation!

My rule of thumb has always been, if I haven't had or have had some have a VALID reason to use the assembly as a separate item in the past 6 months, I never will, and I collapse it into something else and remove the complexity.

Thanks for the validation.  As always...an awesome post.

Patrick Smacchia wrote re: Advices on partitioning code through .NET assemblies
on 12-09-2008 4:57 PM

>They created there own monster and I don't even want to use the thing anymore.

And notice the irony, they are the ones who provide architecture guidance :o)

Brian wrote re: Advices on partitioning code through .NET assemblies
on 12-09-2008 6:06 PM

NO KIDDING!

Ira wrote re: Advices on partitioning code through .NET assemblies
on 12-10-2008 9:39 AM

Do you know what a pain posts like this are?

I am now sat merging several libraries into the one library where the previously split dll's are separated by namespace instead.

Do you know how much fun it is repairing 100's of errors where a ribbon control referenced loads of images in the previous .dll.

God it is boring.

gOODiDEA.NET wrote Interesting Finds: 2008.12.08~2008.12.11
on 12-10-2008 10:06 PM

Web 3 reasons why you should let Google host jQuery for you 链接A引发的思考 YUI Library, YUI Doc, and Github

gOODiDEA wrote Interesting Finds: 2008.12.08~2008.12.11
on 12-10-2008 10:09 PM

Web3reasonswhyyoushouldletGooglehostjQueryforyou链接A引发的思考YUILibrary,YUIDo...

Code Monkey Labs wrote Weekly Web Nuggets #42
on 12-12-2008 5:58 PM

Pick of the week: How to Guarantee That Your Software Will Suck General Getting Started with Domain-Driven Design : Rob Conery begins his journey into DDD with the MVC Storefront. Contributions to the Entity Framework Community : For being the next big

Friday Links #29 | Blue Onion Software * wrote Friday Links #29 | Blue Onion Software *
on 12-12-2008 6:55 PM

Pingback from  Friday Links #29 | Blue Onion Software *

RealDolmen blogs wrote Links
on 12-16-2008 7:50 PM

Links

RealDolmen blogs wrote Links
on 12-16-2008 11:02 PM

Links

La Web de Programación wrote Noticias 28-Noviembre-2008
on 12-28-2008 6:38 AM

Volviendo de las vacaciones navideñas... unas cuantas noticias ;) Biztalk Server 2009 beta disponible

Patrick Smacchia [MVP C#] wrote Lessons learned from the NUnit code base
on 01-11-2009 6:40 AM

I recently analyzed NUnit v2.4.8 with NDepend . The first impression is that developers behind NUnit

Community Blogs wrote Lessons learned from the NUnit code base
on 01-12-2009 12:01 PM

I recently analyzed NUnit v2.4.8 with NDepend . The first impression is that developers behind NUnit

Invalid Argument » Advices on partitioning code through .NET assemblies wrote Invalid Argument &raquo; Advices on partitioning code through .NET assemblies
on 01-18-2009 8:32 AM

Pingback from  Invalid Argument &raquo; Advices on partitioning code through .NET assemblies

Robert Beal wrote re: Advices on partitioning code through .NET assemblies
on 02-22-2009 7:42 PM

Awesome article, just what I was looking for. Am effectively the build master at Huddle now. I've been trying to reduce build time, and have done many things, but now am at the point where I need to reduce some of the 60 projects we have.

It was a good read. I've yet to use NDepend fully, but that's next on my list.

Code Monkey Labs wrote Weekly Web Nuggets #42
on 02-22-2009 10:34 PM

Pick of the week: How to Guarantee That Your Software Will Suck General Getting Started with Domain-Driven Design : Rob Conery begins his journey into DDD with the MVC Storefront. Contributions to the Entity Framework Community : For being the next big

Patrick Smacchia [MVP C#] wrote Analyzing the code base of CruiseControl.NET
on 03-15-2009 12:59 AM

As I already did with several popular.NET projects like NUnit , NHibernate , .NET Framework , Silverlight

Community Blogs wrote Analyzing the code base of CruiseControl.NET
on 03-15-2009 1:47 AM

As I already did with several popular.NET projects like NUnit , NHibernate , .NET Framework , Silverlight

Patrick Smacchia [MVP C#] wrote My 100th blog post: Top 5 development practices you should care for
on 03-25-2009 3:48 AM

This is a modest number but I am happy to have reached it, especially taking account that I spend weekly

Community Blogs wrote My 100th blog post: Top 5 development practices you should care for
on 03-25-2009 3:59 AM

This is a modest number but I am happy to have reached it, especially taking account that I spend weekly

Patrick Smacchia [MVP C#] wrote Analyzing the code base of CruiseControl.NET
on 03-27-2009 9:15 AM

As I already did with several popular.NET projects like NUnit , NHibernate , .NET Framework , Silverlight

Patrick Smacchia [MVP C#] wrote Can we avoid tooling to prevent spaghetti code?
on 05-03-2009 8:49 AM

Normal 0 21 false false false FR X-NONE X-NONE Recently, Jeremy D. Miller wrote on twitter : I still

Howard van Rooijen's Blog wrote Speeding up your Desktop Build [Part 1]
on 05-09-2009 11:44 AM

On my current project I wanted to do a little pit stop after our 1st sprint to ensure that the solution

Preved wrote re: Advices on partitioning code through .NET assemblies
on 05-16-2009 7:35 AM

Add a Comment

(required)  
(optional)
(required)  
Remember Me?