Why shouldn't I have a single monolithic utili

2019-03-29 10:49发布

问题:

We've got a few common libraries (C# but I guess this isn't platform- or language-specific), let's call them A, B, and C. Library A has references to B and C, library B has a reference to a 3rd-party DLL, and library C stands alone. The idea behind three separate projects was that each library had distinct functionality, but library A has over time become a more or less "catch-all" common library that most every client app references. Only a few apps reference B and/or C without A as well.

We're trying to improve our source control conventions, and one thing we're trying to do is properly tag and release these library DLLs, so client project files can point to a static version of the code instead of the always-changing trunk. This is proving a bit convoluted - for example, a client project that references both A and B. A itself references B, so there are technically two references to B coming from the client project.

So the obvious thing seems to be to just combine everything into a single common/utility library with well-organized namespaces. As I said, almost every client app references one of these libraries, so who cares? Doing this won't introduce any undesirable situations with 3rd-party dependencies, and all our target machines are internal and maintain roughly the same environment/software configuration.

This seems too easy of a solution though, so I figured I'd at least get a second opinion. An alternative could be to use the GAC and strongly sign/version everything. Am I missing any catches here?

回答1:

I think you're right consolidating into a single library.

Very often code is componentized into too many deployable units whereas the logical piece of functionality seems to be the criteria for separation. This is wrong IMO. Assemblies should be aligned with the deployment scenarios and release cycles instead. Otherwise you end up with a horribly complex dependency graph where anyways every assembly is managed, built and deployed together.

Interesting question though! Let's see what other people think :)



回答2:

This is a classic "Goldilocks and the 3 Bears" problem.

You don't want a single monolithic library - and you don't want too many libraries. You want exactly the right number of libraries :) Not too many, not too few, just right.

There are reasons for having different libraries:

1) Independence of development - the libraries can be developed independently. 2) Smaller deployable

I think that a general rule of thumb might be if there is a separate team that is dedicated to doing full-time development on a particular section of the library, it should be separate. If multiple teams add a few bits of code here and there every now and then, then there should be no issues with independence of development and deployment and you might as well have a single common library. It sounds like this is the case in your situation, so go with a single library.

Another question to ask is "What problem that we are currently experiencing would splitting up the library solve?" If it doesn't solve any problems, then no need for separate libraries.



回答3:

View Point 1
Having as few libraries as possible simplifies build scripts and deployment (fewer parts to worry about). Having one library with all the internally developed UI components is great for starting new projects. Just add in that one reference and you've got all the internal components ready. Hopefully that reduces the time spent reinventing the components because someone forgot there already was a library with such a component. Same thing with a general utility library - it's nicer to have only one so you've got all the functionality available with one reference.

View Point 2
Separating the various related bits of functionality into separate libraries keeps those libraries focused and makes their intent clear. Since each library is more focused, each individual library will be smaller. Thus your end deployment package can be smaller since you'll include only the libraries you actually need. However, you'll then have to remember how many libraries you have and what each contains. This can be a documentation and knowledge transfer nightmare.

So what's more important to you, deployment size or developer usability? Pick the priority and then match the code organization to it.



回答4:

I agree that having a single library for these utilities is ideal, as long as the namespaces are properly maintained and the code itself is broken up nicely for any future maintenance on the library. The main justification I see for this is exactly what you mentioned, nearly all your internal apps are using it.

However, one thing to think about is the functionality of these pieces. If one piece is the utility namespace for doing clever tricks with controls or labels, and the second piece is the security library that handles your login procedures, you may run into some unintended problems when "cool trick D" gets added to the utility library, but breaks an existing application that is reliant upon the security library, but is forced to upgrade since the entire DLL has now been updated.

You might consider rewriting all three libraries in a way that eliminates the cross dependencies and see if that makes for a better overall situation for your current and future apps.



回答5:

There might be a reason to have separate projects for libraries with completely different purposes, or projects that reference third party libararies. Other than that you can put most in a common base libarary.

We have a common library for a lot of classes, but a separate project for web related classes, a separate project for PDF related classes (as it uses a third party DLL that we don't want in all applications), a separate project for MySQL related classes (as it uses a third party connector).

We also have a separate project for database (MS SQL) related classes, but that could really have gone into the common library as we have so few applications doesn't use a database.



回答6:

I'd say it really just comes down to what works best for you. A big util library could be hard to find things in, but then again it's all in once place everyone knows where to look they may be of more benefit. Also depending how the library is managed, it may be easier for different groups to maintain their own util libraries (if they need to control changes to them), but if it's managed by a single group (or if everyone gets along) then one big one may be easier. So really whatever works for you.



回答7:

Just sharing some recent experience that has caused me to have a slight change in point of view on this...

Reducing 150 projects in a solution to about 30 has cut our build time to about 25% of what it was (1 minute and change vs 5 minutes on our typical dev machine). If you're doing dll references, it doesn't matter that much, but if you're including the projects in the main solution, you may find it matters. To be honest, I was a bit surprised at that difference, but past results don't guarantee future returns.

Everytime .net loads a dll for the first time, you take on JIT-ing and file I/O overhead. For WinForm/WPF apps where the user may launch it several times a day this is a bigger concern than web apps. Even for Winform/WPF apps, it may not be that big of a concern for many apps.

The other thing to look out for is intricate dependencies which cause situations where "if I use A, I have to use B because A exposes types from B. Mean while, I rarely use B by itself" Just combine it and be done with it.

So, my understanding is there are a few concrete reasons to try to consolidate. There's probably a million subjective reasons, but in a large solution file, it seems better to try to be a simple as you can reasonably pull off.

More subjectively, I would also encourage you to look at the project file as a build artifact and not a code artifact. Think about the .cs file as what you really want to reuse and not the .csproj. Sure, most of the time you would reuse the .csproj as well and just build the assembly the same way all the time. But, don't try to force yourself to have dependencies or a bunch more code than you actually need in your project@. The relationship between .csproj and .cs is reasonably loose most of the time.

EDIT: @ - added "in you project"