Grouping classes in an assembly

This useful bit of information crossed my desk today:

When it comes to packaging in separate assemblies, remember that you pay a fairly large performance hit on an assembly load. An assembly should really be considered a unit of security control, independent versioning, or contribution from disparate sources. You might consider placing code in a separate assembly if it is used extremely rarely, but probably not.

Here are some pointers from the “Designing .Net Class Libraries” course:

Factor functionality into assemblies based on:

– Performance – There is overhead in loading each assembly. All other things being equal, the fewer assemblies an application loads, the quicker the load time.

– Versioning – All code in an assembly must version at the same rate.

– Security – All code in an assembly has the same identity and is granted the same level of trust.

Assemblies and Performance

– Prefer single, large assemblies to multiple, smaller assemblies

– Helps reduce working set of application

– Large assemblies are easier for NGEN to optimize (better image layout, etc)

– If you have several assemblies that are always loaded together, combine into a single assembly.

Comments (23)

  1. kevin white says:

    Fine, but is there a way to have multiple Vs projects produce a single assembly?

  2. John Rusk says:

    Are there design-time advantages to breaking things up into multiple assemblies? E.g. IDE only needs to recompile code in the one small assembly that you’ve changed. Although with the good speed of the C# compiler, I’m not sure how much difference this would make in reality…

    Also, as Barry wrote, there are advantages in using multiple assemblies when it comes to enforcing discipline about which layers can access which other layers.

    I guess one option is to use "many" "small" assemblies at design time. Then, if you are using a build process (such as Ant) which is independent of the IDE’s project structure, you can compile the release version of your system into relatively few "large" assemblies.

  3. Darren Oakey says:

    I actually try to break things up into as many PROJECTS as possible, for heaps of reasons… obviously we should actually link them into the same assembly, but we never seem to get around to doing that.

    However, some of the reasons I am trying to go more, not less:

    a) VS gets exponentially slower as you add more classes

    b) it’s the only way of enforcing layering, otherwise people can just call anything from anything

    c) I think and design in subsystems – various teams are responsible for a subsystem – and aren’t given the code to the other subsystems, so one group will be working on all the customer classes (data access, business logic, displays, editors) while another will be working on say the lease details.

    d) With a bunch of groups, sourcesafe is impossible to use – to add a class to a project, you must have that project checked out. Not a problem if you have 100 projects, so 20 different groups can have 20 different projects out – but if you have 1 project… well no one can ever add anything!

    e) I still think in "Components" – I want to finish a component – the address system. I have a class to store address details. Something to save them, something to load them. A summary display, a full display, an editor, and web versions of each of those. AND I NEVER WANT TO TOUCH IT AGAIN (unless a bug is found of course).. I want to sign off and say "addresses are finished". I DON’T want people accessing the code. I DON’T want people "extending" it, or using it in some weird way. I just want more and more lego blocks "finished" – so as new systems are required our development speeds up each time – we just click the existing blocks together. I believe every component developed in the company, even if you know or were on the team involved in the component, should be treated exactly the same as if you bought a third party component – you just click it in and use it, and deal with any limitations of it. Otherwise, across an enterprise, there is no way of guaranteeing and enforcing reuse and stability – people go off in their own directions each time. If I find a bug in the storage of an individual – I want to be able to fix it in every system in the organisation, right now – I don’t want to have to look at 300 different systems to see if they have "customised" their use of the individual class.

    f) it’s just easier, if you are working on a single project that has like 15 classes/objects in it, and everything else is "system"… You don’t have to think, you don’t have to search for things, you don’t make mistakes.

    g) different components can be written in different languages, without having much impact on the system as a whole – certainly not placing the restriction that you use the same component for your new stuff

    h) components that haven’t been touched in months attain a level of "trust" – you "know" they are reliable, you "know" they are complete – makes it a lot easier to track down bugs, because you know where to start first (your stuff :))

    etc etc etc

    So – our coding standards say (not strictly) but a max of 20 classes per "component"- and at the moment "component" = "project" = "asssembly". A component must be split internally into 4 layers/namespaces (UI, Web (ui), business, and data). Typically, a component is built around one primary business concept. eg – individual, address, contactMethod are all components in their own right – and they are all components we haven’t needed to touch for over a year.. If you are making a screen or web page that deals with an individual, you drag on the individual summary, and say Summary.Individual = myObject.Individual – and thats the end of it.

    An example of just how wonderful this is: We used to store addresses in a table suprisingly called Address. We bought a feed of every legal address, so our validation became a search, and we no longer store any address details in the system – we just store an address ID from this external feed. To do this change, we had to open exactly one component – the Address component. And everything across the organisation, both internal apps and the website, that used addresses suddenly worked with the new method – off the data from the CD.

  4. Hugo Rodger-Brown says:

    I agree with the more-is-more approach, esp. given that very few of the projects I’ve worked on suffer from performance-problems related to the overhead of assembly loading?<p>

    I have to take Darren on though – having UI / Web /Business / DA in the same compiled component – surely not? How much abstraction does that provide?</p><p>

    I’d always believed that components should be split horizontally – business / da / ui etc., allowing for interface design and implementation abstraction.</p><p>

    My current favourite design model uses a transparent and abstract DA component to define the required data access method signatures (GetXxx, SaveXxx, DeleteXxx, etc.), with a separate concrete implementation that is loaded dynamically at runtime. This has been used on several projects with great success – you can start a project with simple file-based persistance / serialization, just to get you going, and move up to SQL / web services without changing any core components – simply drop the new data access assembly into the bin and change the relevant config entry.<Br>If you’re trying to get developers specializing in certain areas, does it not make more sense to have a data access guru, rather than a Customer guru?

    Combine that with a data access factory class, and most of the complexity is removed from data persistence. Or am I deluding myself?

    Dynamic class loading incurs an even greater overhead, but the advantages far outweigh the performance issues (IMHO).</p>

  5. Well, if I understood correctly the intent behind the "Domain-Driven Design" book, by Eric Evans, the driving force to create components (in .Net, assemblies) should be the domain problem. The classes aggregated in an assembly should be cohesive in accordance to the domain problem.

    Machine specific issues should be dealt only if we verify there’s a compelling reason to do so.

    Like David West would also say, think in objects… 😉

  6. Darren Oakey says:

    Hugo – I actually agree, sort of.

    We have lots of discussions about this at work, and always use the same terms – do we split horizontally in layers, or vertically in functional/domain areas.

    In point of fact, we do both. _Logically_, we split horizontally. We design in separate layers, and try to actually use common classes to do the work, (for instance our persistance layer works off reflection – the first time a class is loaded, it investigates it and creates the code needed to persist it)..

    We very much THINK in the layers you specified, and keep UI, Business, and Data _very_ separate.

    HOWEVER.. PHYSICALLY, we break them up vertically. Weird huh? We design in one way, store in another..

    The reason is simple: Maintenance. We have a lot of different programmers and teams doing a lot of different things. If I want someone to make a change in something, I want them to have to understand the least possible about the system, to not have to search very much, and to have the least possible impact on the system.

    So – let’s suppose I have to add a field to customer. Storing vertically, I open the customer component, change the customer dal, change the customer class, and look at all the displayers/editors to decide whether they need to be affected. And check it in. And anything that uses customer is affected, but hopefully we haven’t altered existing interfaces, and the effect is minor or negligible.

    Storing vertically, it’s a different story. First, I have to understand what layers are out there. Then I have to go and find the actual projects where the bits of customer are defined – and there are probably lots of them – eg web, ui, data, business etc. I have to make the changes in them, separately, and probably to check them in at different times, unless I want half the system checked out to me. And when I make a change, because there are other things in each layer project, I am in fact affecting them somehow, just because I’m rereleasing the dll they are in…

    Also, if I have a data layer project, have I for convenience combined in a few different classes? Maybe customer, address, and contacts, because I didn’t want 3 different projects just for that information?

    That means that when someone is making another app – for instance a footy tipping app where they are storing the address of who has signed up for the comp – if I give them my "address" components (of which I have to give them four anyway) – they also get my customer components – which they have no interest in, and no business using. Anyway, because I’m having to give them four dlls and a bigger part of the system, chances are, from both sides it all becomes too much work, and they go and write their own address storage/entry display.

    So – we _think/design_ horizontally, because it makes sense, but physically store _vertically_ because it provides a much simpler and more reliable framework for maintenance, system organisation, and re-use.

  7. Barry Gervin says:

    I have some comments on how to combine both Eric’s performance requirements of larger fewer assemblies with the smaller more assemblies at design time to enforce layering rules.

    Yes you can compile multiple projects together into a single assembly.

  8. Franz says:

    Sometimes, I don’t know how to combine all of them together. For example, a UI Control which contains a MS Web Browser. It needs some ActiveX Interop dlls. Also, when you just got some assemblies from the Internet without the source projects. How can we combine them into a LARGE assembly? Does anyone know? 🙂 When the outside world doesn’t use the assembly directly, it is always good to pack them inside the assembly which uses it.

  9. David Knight says:

    Does the "large performance hit on an assembly load" happen just once at when the assembly is first used? Under what circumstances are assemblies unloaded / reloaded? Just how large is the "large performance hit?"

  10. Navin Varma says:

    I know I shouldn’t be writting this to you but I also know you could be one of the medium to voice it Microsoft Product managers…

    Microsoft is so busy expanding its horizon that its completely forgot all its users are suffering miserably all over the world. It is so occupied with crushing its opponents that its missing out on very obvious needs of Windows users.

    Today almost every machine is infected with spyware, I have not heard even a single time

    from any Redmond guys about this nightmare.

    This I guess is the reward to customers by MS

    By ignoring this MS seems to be doing to itself what it did to Netscape … force users away from IE broswer. Quite innovative 🙂

  11. Andre Beier says:

    Is there a way that I can incorporate a compiled assembly into my main project.

    My project uses only one 3rd party DLL and I would like to have only 1 final DLL instead of 2.

  12. As a big fan of components, my applications are often composed of many different assemblies… essentially I break out anything that seems ‘ready to reuse’… but perhaps I should reconsider?