Single or multiple assemblies for big apps and code reuse?

G

Guest

Hi everyone,

I have a question about .NET code sharing and reuse, and also about
application design best practices / guidelines.

Currently, we have many different .NET projects in source depot. Although
they are different, in some of them we share C# code by referencing source
files that are external (not part of the projects) on each project.

For instance, some of our projects have the typical “sources†file with:

SOURCES = \
..\..\some_other_different_unrelated_project_A\fileA1.cs \
..\..\some_other_different_unrelated_project_B\fileB1.cs \
..\..\some_other_different_unrelated_project_B\fileB2.cs \
Program.cs
Class.cs

And so on.

Some people in my team think that DLLs and assemblies are evil and should be
completely avoided. Therefore, they advocate treating all projects in the
depot as one huge, monolithic project (even they are not, as they are
different projects), sharing code by referencing source files all over the
depot.

Basically, each application has one and only one assembly containing all the
application source code plus all source code that belong to other projects
too but is reused by referencing the other project(s) C# source files.

Other team members (BTW facing huge opposition) insist in packing the
shareable code into one or more assemblies, although for some people,
assemblies and DLLs are absolutely forbidden.

Can someone please tell me the pros and cons of each approach? Is it right
to be completely against packing certain substantial modules or pieces of
functionality into separated assembly/assemblies, as opposed to having one
and only one single, huge monolithic assembly containing the whole
application + other project source files?

Those in favor of having shareable code packed into separate assemblies,
instead of putting everything (all the source code of the application plus
the sources of our libraries, plus the sources of all subsystems, etc.) into
one, big monolithic assembly, point to these other URIs:

http://msdn.microsoft.com/practices/compcat/default.aspx?pull=/library/en-us/dnbda/html/distapp.asp

http://msdn.microsoft.com/practices...pull=/library/en-us/dnbda/html/apparchch2.asp

http://weblogs.asp.net/savanness/archive/2003/07/22/10417.aspx

http://msdn.microsoft.com/library/d...n-us/cpguide/html/cpconassembliesoverview.asp

So, I wonder, are there any guidelines and/or best
practices/patterns/anti-patterns in regards to C# source code sharing and
reusing among different projects? Any authoritative answers? Is it
reassonable to build big, different applications from one huge source tree,
having only one and just one assembly per application and nothing more? Or it
makes more sense to split the app into multiple assemblies, but keeping the
number of assemblies to a minimum?

Thanks and regards,

Claudio
 
E

Eric Cadwell

What do you use to build your projects? I've used nant in the past - it had
no concept of a project, it was all file based compilation.

I prefer to package common code in separate assemblies. We had two large
applications sharing 3 common libraries. The hard part about shared code is
coordinating the changes (which you're already doing).

-Eric
 
D

David Browne

Claudio Pacciarini said:
Hi everyone,

I have a question about .NET code sharing and reuse, and also about
application design best practices / guidelines.

Currently, we have many different .NET projects in source depot. Although
they are different, in some of them we share C# code by referencing source
files that are external (not part of the projects) on each project.

For instance, some of our projects have the typical "sources" file with:

SOURCES = \
..\..\some_other_different_unrelated_project_A\fileA1.cs \
..\..\some_other_different_unrelated_project_B\fileB1.cs \
..\..\some_other_different_unrelated_project_B\fileB2.cs \
Program.cs
Class.cs

And so on.

Some people in my team think that DLLs and assemblies are evil and should
be
completely avoided. Therefore, they advocate treating all projects in the
depot as one huge, monolithic project (even they are not, as they are
different projects), sharing code by referencing source files all over the
depot.

There are many strange people in the world with strange ideas.
Basically, each application has one and only one assembly containing all
the
application source code plus all source code that belong to other projects
too but is reused by referencing the other project(s) C# source files.

Other team members (BTW facing huge opposition) insist in packing the
shareable code into one or more assemblies, although for some people,
assemblies and DLLs are absolutely forbidden.

Can someone please tell me the pros and cons of each approach? Is it right
to be completely against packing certain substantial modules or pieces of
functionality into separated assembly/assemblies, as opposed to having one
and only one single, huge monolithic assembly containing the whole
application + other project source files?

Those in favor of having shareable code packed into separate assemblies,
instead of putting everything (all the source code of the application plus
the sources of our libraries, plus the sources of all subsystems, etc.)
into
one, big monolithic assembly, point to these other URIs:

http://msdn.microsoft.com/practices/compcat/default.aspx?pull=/library/en-us/dnbda/html/distapp.asp

http://msdn.microsoft.com/practices...pull=/library/en-us/dnbda/html/apparchch2.asp

http://weblogs.asp.net/savanness/archive/2003/07/22/10417.aspx

http://msdn.microsoft.com/library/d...n-us/cpguide/html/cpconassembliesoverview.asp

So, I wonder, are there any guidelines and/or best
practices/patterns/anti-patterns in regards to C# source code sharing and
reusing among different projects? Any authoritative answers? Is it
reassonable to build big, different applications from one huge source
tree,
having only one and just one assembly per application and nothing more? Or
it
makes more sense to split the app into multiple assemblies, but keeping
the
number of assemblies to a minimum?

Sharing source files between applicaions is usually a terrible idea. You
are better of creating multiple copies shared source files and letting each
application maintain its own copy. At least then it's possible (through cut
and paste and compare) to manage changes in the shared libraries.
Otherwise, managing change in the shared source and its impact on
applications is pretty hard.

When one application requires a change to a shared source file, what happens
to the other applications? The next time they get compiled they will pick
up the change to shared file. But what if they are just doing a minor bug
fix, and the change in the shared source file requires testing, or
introduces another bug, or is incompatible with their existing source code?
When you compiled version 1.2.0.2 of some application, what version of the
shared source file was that using? There is no permanent record of exactly
what version you used. There is no "1.2.0.2" version of the file, since
it's shared among many applications., and you may never be able to figure
out exactlly what source code went into the build.

That being said, some source control systems can track and manage shared
source files and provide resonable answers to these questions. But
assemblies work so well, I wonder why you'd bother sharing source.

David
 
G

Guest

Hi Eric and David,

Thanks for your kind response. My goal is to help my team improve the way we
design and develop some of our applications, and your emails will hopefully
help me achieve that goal. Thanks so much.

Claudio
 
G

Guest

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?

mark
 
G

Guest

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
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Top