Hi Mark,
Thanks for asking; yes, I've got plenty of answers; in general the consensus
is:
1) Do not share/reuse .NET code referencing source files directly, share
assemblies.
2) Favor a reduced number of larger assemblies instead of a large number of
small assemblies, within reasonable limits.
3) Keep in mind that the upcoming CLR versioning may remove the static
library concept.
4) Assemblies (or DLLs, for that matter), should generally be organized
around the subsystems of an application. If you have a UI section and an
underlying processing engine, that's a reasonable place for an assembly
break.
5) The number of assemblies that you load initially can be a big factor in
startup time, so you'll want to keep that down (this doesn't trump other
guidelines, just something to keep in mind).
6) Optional code - code that isn't always used, or is only used in a certain
scenario - is a good candidate for a separate assembly.
7) Don't guess on the performance impact. Track how long it takes to start
your app, and how much of an issue it is.
8) The namespaces in the managed world may give you a hint on how to factor
into assemblies.
9) For examples, study existing, well known .NET applications, such as
NUnit, the Enterprise Library, FXCop and many others.
One of the persons that kindly answered my questions also provided his views
about Pros and Cons of static and dynamic linking:
Static linking - Pros:
- The application is completely self-contained. Basically, everything you
depend on is in a known state, in a known place and there's no room for
surprises.
- No OS overhead for loading multiple modules. Plus you don't need to worry
about getting DllMain right in the case of native apps or managed IJW
assemblies. Also, no rebasing concerns.
- Easy deployment. Just get the EXE and run it (well, N/A for managed client
apps anyway...).
Cons:
- Servicing. For N applications, the cost of fixing a bug in a common
component is multipled by N, because you have to hunt down each binary that
contains the bug. N can be small or huge, but it's always greater than 1.
- Performance. If one runs several instances of the apps at the same time,
there is no code sharing.
- Code rot. You end up knowing internals about someone else's component,
take dependencies on them and make everyone's life miserable when interfaces
aren't cleanly defined and separated anymore. This is especially valid for
source level sharing (i.e. if you link statically against a C++ lib, you
don't have access to the internals, but if you just take a piece of C++ or C#
code and add it to your project, things are way different). You essentially
render C#'s "internal" useless. If anyone thinks that's a small annoyance,
think about the Windows layering disaster.
Dynamic linking - Pros:
- Servicing and performance. You have a "single point of truth" where the
code lies and can be patched, and it can be shared among different apps (as
in, working set sharing). For managed apps you will need to Ngen the shared
assembly, though.
- Clean boundaries between components. Prevents code rot, simplifies
security reviews and makes everyone a bit happier.
Cons:
- DLL hell for native apps. You have to be really careful not to break the
contracts of public interfaces between versions. Solved since Windows XP via
side-by-side execution of native components. The same technology is used for
managed assemblies as well. It can lead to "versioning hell" if you're not
careful, but it tends to work out nicely with a small amount of up-front
planning.
- The overhead of loading multiple modules in a single process and of
getting the base addresses right. Afaik, Windows tends to behave decently for
up to ~100 modules loaded into a process. The ideal figure would be around
20, but given the layering hell we're in now, the average figure tends to go
towards 40-50.
Bottom line:
Dynamic linking in the large is great (i.e. you have a small number of large
assemblies, with large pieces of code in the DLLs being used by several
apps). Dynamic linking in the small (e.g. a 1000 line utility library in its
own assembly) tends to be a bad idea.
Conversely, static linking in the small tends to be fine (for really small
amounts of utility code, in a small number of dependent apps). Generally,
when larger amounts of code start to be linked into several apps, it's a good
idea to switch to dynamic linking.
Finally, these are the MSDN newsgroups where I also posted my questions; you
may find interesting the answers I received there as well.
Thanks and regards,
Claudio Pacciarini
[quoted text, click to view] "Mark Edwards" wrote:
>
> Hi Claudio,
>
> Did you get any other replies to your question?
>
> On the surface it seems like a slam dunk answer. However, since being in a
> production environment initially starting with a C++/MFC client server app,
> and watching the pain managers go through not to change it, the benefit of
> smaller projects has been well illustrated.
>
> Html web pages, database triggers and stored procedures run circles around
> the C++ development process, delivering much faster (and buggier??). The C++
> development process is more rigid, stricter, and taking more time. On the
> flip side these developers don't typically have issues with getting the
> correct version, or wondering if they have the correct version of files. In
> the various environments html pages, triggers and stored procedures have
> constant issues with having the correct versions. SQL Server 2005 seems to
> have better interface with Source Safe, and that might make things better.
>
> The Asp.net enviornment has potential to go either way. Monolithic or the
> compete opposite with single self containted??? pages, or assemblies.
>
> What is the answer?
>