Click here to Skip to main content
15,868,016 members
Please Sign up or sign in to vote.
5.00/5 (1 vote)
See more:
I was wondering what is the best and most maintainable way to seperate your dll's?
I am building a WinForms application that makes use of Classes I want to re-use in other applications. So here's the catch:

Let's say I build a library called StringManipulator, put it in a seperate project file and build it as a dll. Pretty obvious what it does. Now I want a user interface that calls my StringManipulator.dll. For this user control I am making a new project, called StringManipulator.WinForms.dll. I do this because at a later time I might need the StringManipulator in a WPF application.

So it's a little like this:
StringManipulator.WinForms.dll needs StringManipulator.dll

So I now have two dll's, not so bad. But as the application progresses I have MANY dll's, all consisting of a general part and a WinForms specific part. Many dll's have only one or two classes and it all becomes quite hard to maintain (should new code go in an existing dll or in yet another new dll?). Plus a single application could actually reference all twenty dll's, which seems like a lot to me...

Things now look more like:
Project1.WinForms.dll needs Project1.dll
Project2.WinForms.dll needs Project2.dll
...
Project10.WinForms.dll needs Project10.dll

That already makes twenty dll's for ten uses!
So to make things easier I put all WinForm controls in a single dll. Wrong! My WinForm dll now references about 10 other dll's. Now when an application needs one WinForm component I need to deploy ALL my dll's even if I needed just one control.

It looks like this:
WinFormsProject.dll needs Project1.dll, Project2.dll ... Project 10.dll

Now surely I am not the only one with this problem. I've read about dll granulation (these articles by Robert Martin no less![^]), but I've also seen posts on the internet where companies had 50 dll's and where building, maintaing and deployment became a nightmare.

Currently I am in a situation where one dll references many which in turn reference other dll's too. Now a colleague wanted to use a single control from the WinForms dll and as a result had to deploy ALL dll's (about twenty) that he doesn't use at all (now actually this just means copying a folder full of dll's to the customer).
Now I am pretty much in favour of having many dll's even if they have only one or two Classes each. Of course we'd still have to deploy lots of dll's, but at least they would all be used. Another alternative would be to just throw it all in one big project file since we now have to deploy everything anyway.

At the current stage of development I could relatively easy break up the WinForms component into many small components. In the future we will be implementing our dll's into more applications and segregating further will become more difficult.

I'd like to hear the opinions and experiences of the people here. What do you suggest and recommend? Any tips if we choose one way or another?

Thanks.
Posted
Updated 4-Feb-12 8:26am
v2
Comments
thatraja 9-Feb-12 0:35am    
My 5! for your question
Sander Rossel 9-Feb-12 2:48am    
Thanks thatraja :)

This is why making a dll for every helper class is a dumb idea. I would break things apart mostly to seperate things that a project may not use, or to limit the size of my main exe, such as, I have a dll with a lot of the UI images we use that are large, so I don't need to ship those in essence if I ever send a patch. Breaking out your business process from the presentation layer is smart. Writing 500 dlls is not so smart.
 
Share this answer
 
Comments
Sander Rossel 5-Feb-12 12:37pm    
I agree that having a seperate dll for every helper is a bad idea. And writing 500 dll's is also not very smart. But the question is if having one dll that does everything that's not UI related is any smarter... Although perhaps it wouldn't hurt in most cases...
Let me get this straight: I could for example grab five dll's and put their code in a single dll even though their functionality is completely different. As long as they don't require any additional components to be deployed that you might not want or need, correct?
Christian Graus 5-Feb-12 15:57pm    
Most people grossly overestimate the odds of reusing their code. If you can move your business logic to a different UI platform, odds are it won't matter to you if it's in 1 or 5 dlls.
Sander Rossel 6-Feb-12 16:50pm    
Actually we're already reusing it. But indeed, I think it won't matter all that much. I guess we should be wary of not placing stuff that requires third party components into projects that, until that point, didn't need those components. If they don't they can pretty much be put safely into that project. I think this has been an eye-opener, be it an obvious one.
Thanks!
First thing you have to think about is dependency layers. You should design then the way each layer serves a platform for the above layers. If should be in sync with your build process; all code in a layer should depend on one of more layers below it, never on anything above.

You should picture and document your layered architecture first, and the DLLs come next.

Breaking the code apart in DLL is not directly related to is, but certainly, no DLL should be a cross-level one. It is not very untypical that the whole layers is implemented in one DLL. However, more then one DLL implements the same layer. In this case, each DLL represents an isolated field of responsibility on the same layer. In this case, one more dependency constraint should be added: the DLLs on the same layer should not depend on each other.

[EDIT]

Following up the discussion related to maintenance, proper development cycle and testing:

I usually quote two famous article by Joel Spolsky which maybe every developer should know:

The Joel Test: 12 Steps to Better Code, http://www.joelonsoftware.com/articles/fog0000000043.html[^].

Top Five (Wrong) Reasons You Don't Have Testers, http://www.joelonsoftware.com/articles/fog0000000067.html[^].

Please read them, draw your conclusions by yourself.

—SA
 
Share this answer
 
v2
Comments
Sander Rossel 5-Feb-12 12:27pm    
Yeah, I agree with you there. We've tried to reach this goal, but unfortunately we failed. Let's picture this, it's a common scenario I can't seem to figure out:

I have library A, which can be extended by the use of an interface.
I have library B, which does its own thing, but COULD be combined with library A (for some extra functionality).
The problem is, when I extend A by referencing it in B (or vice versa) I'll ALWAYS need A and B together to deploy.
When I create library C which references both A and B I can now deploy A and B seperate but I'll need to deploy A, B AND C when I want a combination.

This is a common problem I've been having. I've now come at a point where I have library A that can be combined with B and C so I needed to create D and E that only have a single class each (because B and C have nothing to do with each other, but could still both use A). That's how fast it seems to go right now and limiting dll's is difficult because most do entirely different things.
Luckily we've kept our dependencies pretty neat, except for that one project which needs all the others :)
Sergey Alexandrovich Kryukov 6-Feb-12 18:12pm    
The problem is not 100% clear. When you mention "deploy", does it mean deploy of different subsets for different customers? Also, do you combine different versions of software in one deployment? This is all about it.

If you need more flexibility, you might not also the plug-in architecture. This is the only way to make functional units replaceable. If you need it, I can share with you the references to my other answers where I provided a sketch of plug-in architectures to a pretty fine detail. Are you interested?

Are you going to accept this answer anyway?
--SA
Sander Rossel 7-Feb-12 3:00am    
When I say "deploy" I mean giving the customer the latest version of all dll's that customer uses (which might not be the same dll's another customer is using, but might still have overlap). Since I only deploy the newest versions we don't have different versions of software in one deployment.
I don't think we need a plugin structure for now, but I am always interested in seeing how others solved certain problems. So please share :)

I hope your willingness to help does not depend on my likeliness to accept your answer. When we're done and I feel sufficiently helped I will accept your solution. Seeing your history of successfully helping me and others I don't think that should be a problem... I already rated your answer 5 since you gave me a good answer. I want to wait with accepting until you also answer my follow-up question (which I hope is now clear to you).
Sergey Alexandrovich Kryukov 7-Feb-12 17:53pm    
Accepting is irrelevant. I'm just trying to help.

You still don't answer about the plug-ins. You should feel the dependency structure better than I do.

I think you should use the following simple principles: 1) deploy only the latest version; 2) don't keep branches under development; 3) increment version with every release; 4) automatically set the version of the assemblies for each component for each release; 5) you should have one common Revision Control code base and one common one-click build for all the software, with all components optional or not, universal or specialized (please see above).

For example; if the user say "I wand the same version, but with the bug fix fixed in a new version", never agree. It cannot be the same version by definition. Any fix done after some release should always be a different version, by definition. So, provide only the latest version in this case. (Of course, latest stable version, not the very latest.) Do not deploy any mixed versions.

The only problem is this: you might have different deployment packages for the different users. Example #1: some modules are only available for extra fee. Example #2: some layer depends on hardware; different users have different hardware and are provided only with the software implementing the same interface but for different hardware. In both cases, those optional or replaceable component should be plug-ins. They should be on the very top of dependency layers, never referenced from anywhere, loaded only during run time. So my question is: are we gettting to plug-ins or not?

--SA
Sander Rossel 7-Feb-12 18:11pm    
When you put it like that I think those plug-ins might solve some issues we are having, though not necessarily related to this question.
Your examples cleared some stuff up for me. I work at a small company where we don't have to deal with that kind of stuff very often. But we do deal with different hardware and extra modules lately (sometimes depending on non-backwards compatible third party software). I must confess we have no proper way of dealing with this yet and plug-ins never crossed anyone's mind.
So bring on the plug-ins!

The dependency structure is currently a mess. I wrote my boss a document today suggesting an alternative, partly inspired by CG's answer and party by yours. And of course based on experience and my knowledge of the components. Actually I guess that does mean you answered my question sufficiently. If you could still tell about those plug-ins I'd be very happy though :)
This is a separate topic: but please consider adding some plug-in architecture.
Please see some motivation in my comments in our discussion over my previous answer on this page.

Introductory notes: plug-ins should not create any dependencies. More exactly, no assembly should depend on plug-ins. That said, they go on the very top level of layered model, except perhaps tests and demos. Even though host applications depend on plug-ins, this is not a circular dependency: plug-ins can depend on host application and can even reference the assembly of host application (in .NET, EXE files can be referenced exactly as any other assemblies), but the host application depends on plug-in during run-time only.

I have explain the skeleton of this application in detail here:
C# Reflection InvokeMember on existing instance[^].

Please see my other past solutions:
Create WPF Application that uses Reloadable Plugins...[^],
AppDomain refuses to load an assembly[^],
code generating using CodeDom[^],
Dynamically Load User Controls[^].

I must apologize that in first post above and some other posts I discuss some aspect which is much more advanced than what you might need: working across the boundary between different Application Domains. You only need that if you need not just to load them, but also re-load during run time. The problem is that it is not possible to unload any loaded assembly, but you can only unload it with the whole Application Domain.

On this topic, see also this article: http://www.west-wind.com//presentations/dynamicCode/DynamicCode.htm[^].

If you need "just plug-ins", you can ignore re-loading problem.

—SA
 
Share this answer
 
v2
Comments
Sander Rossel 8-Feb-12 14:41pm    
Thanks once again for a great explanation SA! :)
It's actually fairly easy, unless you involve AppDomains, but I'll certainly have a look into those too. I never needed them thus far, but I better know how they work if I ever should.
Ever considered writing a tip/trick or even article about this? I think it would help many people.
Sergey Alexandrovich Kryukov 8-Feb-12 21:05pm    
You are always welcome.

Agree, this is fairly easy if you do it the way I recommend, and robust enough. This way excludes random mistakes not detected by a compiler, validation and process of rejection of invalid plug-ins turns out to be straightforward.

Yes, this is a good candidate for an article, but there are others...

Best,
--SA
Espen Harlinn 9-Feb-12 10:22am    
5'ed!
Sergey Alexandrovich Kryukov 9-Feb-12 12:10pm    
Thank you, Espen.
--SA

This content, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)



CodeProject, 20 Bay Street, 11th Floor Toronto, Ontario, Canada M5J 2N8 +1 (416) 849-8900