none
Reference project or class library (dll)? RRS feed

  • Question

  • Hi,

     

    We have some projects that are "common" in all development. These include also the Microsoft practices Enterprise Library to give a feeling of what we are talking about. These projects all have strong names and are (until now) just maintained by 1-2 developers.

     

    As a developer - would you prefer to reference such projects as DLL's - or as projects (e.g. from source safe)??

     

    As an architect - would you prefer that the developers reference such projects as DLL's - or as projects (e.g. from source safe)??

     

    --

    Werner

     

    Thursday, November 22, 2007 10:48 AM

Answers

  • The way I see it, each application has a dependency on a set of assemblies. These assemblies are placed under a Lib folder at the root of the application source tree. Other applications could, of course, reference different versions of these same libraries, and that is fine.

    Any differences of version requirements amongst these assemblies must be resolved whether you store them under source control or not. For example, if your Logging.dll requires a different version of Utility.dll than your Application.dll, you will need to resolve this regardless. Sometimes a binding redirect is the right answer, sometimes migrating to a different version is better, etc.

    Of course, at some point you need to stop placing these dependencies in your Lib folder. I tend to stop at the framework itself. For example, if I'm using Infragistics libraries I will include these in my Lib folder (and not rely on them being in the GAC on the build machine) but I won't place BCL assemblies such as System.Windows.Forms.dll in my Lib folder.

    HTH,
    Kent
    Friday, November 23, 2007 10:17 AM
  • This is not something I've had to work around. As I hinted earlier, you might be better off fixing the mismatch in versions depending on the situation. However, if you need to store both versions you can just create a directory structure in your Lib folder:

    Code Block

    + Lib

    |-+ Utility

      |-+ ForProjectA

      |-+ ForProjectB


    You can then reference the assembly in the appropriate folder and version it independently. Or you could just introduce a Lib folder at the project folder level.

    HTH,
    Kent
    Friday, November 23, 2007 2:43 PM
  • Sorry for the confusion. I mis-typed when I said "Solution with Project References", it should have been "Solution with Project Dependencies".  References (regardless of type) are always stored in the .??proj file. Dependencies are stored in the .sln file!!!!!. I use ONLY DLL references!

     

    As to not keeping the solutions under source control. I am referring to Ad-hoc solutions that are created by developers so they have multiple projects open at the same time in a single Visual Studio session.

     

    Consider a development effort which has 60 seperate projects for the "Real Code" (plus 100+ projects for Tests, Development Utilities, Prototypes, etc). With just the real code, there are:

    • 3540 - 2 project solutions possible
    • 205320 - 3 project solutions possible.
    • 11703240 - 4 project soltions possible.
    • etc....

    Surely that vast majority of these possible solution configureations would never be used (nor overly useful), and there is NO point in putting them under Source Control. They are created on-the-fly do address specific work efforts.

     

    As an example assume I am working on a Custon UI control [in Project24.csproj]  An eventual effect of an action on this control is that something happens deep within the system in the Caching [Project51.csproj]. So I create a solution to look at this and just include the two projects + the project that contains the executable.. Now I debug the executable. Finding necessary changes, (Assuming no externally visible changes) I can quickly edit the file and trigger a build which executes in mere seconds. (A "do-nothing"/"all-projects-up-to-date" MS-Build of tthe environment takes a little over three minutes).

     

    This reduces my "cycle time" (time from "see the bug" back to "debugging the program") drastically. When you multiple this by the number of times "F5" is pressed over the development cycle of a product, this can easily result in days or weeks of net savings per developer. If you consider $100/hr (loaded cost), 10 developers, and a savings of just 20 hours [IMHO this is a VERY VERY low number] per developer. this nets out to $20K in savings!

     

     

     

     

    Friday, December 7, 2007 2:29 PM

All replies

  • If they are owned by another team or are under a different project umbrealla, I'd treat them as 3rd party libraries and reference the assemblies. Keep these assemblies under source control so you maintain history and have to explicitly roll forward to new versions. Imagine if you automatically picked up changes being made by another team who haven't tested their changes against your product.

    HTH,
    Kent
    Thursday, November 22, 2007 1:31 PM
  •  Kent Boogaart wrote:
    If they are owned by another team or are under a different project umbrealla, I'd treat them as 3rd party libraries and reference the assemblies. Keep these assemblies under source control so you maintain history and have to explicitly roll forward to new versions. Imagine if you automatically picked up changes being made by another team who haven't tested their changes against your product.

     

    Thanks for your answer, and yes its a fair logic. However there must exist some restrictions on what assemblies are under source control I would say. Take for instance this very small scenario (no special logic - just for example):

     

    Logging.dll references Utility.dll

    Data.dll references Logging.dll, Utility.dll

    Application.dll references Data.dll, Logging.dll, Utility.dll

     

    All referenced DLL's are kept under source control - so Logging.dll stores Utility.dll and Data.dll stores both Logging.dll and Utility.dll etc etc etc. Wouldnt this be some dll hell thinking of solutions with just 30+ assemblies? And with above the Utility.dll could even be of different versíon I would say.... Perhaps you thought of something else? It would be valid to assume that all class libraries have strong names, which would take care of many problems but Im curious to hear if the above is what you do IRL? Or how do you deal with such scenarios?

     

    --

    Werner

     

     

     

     

     

     

    Thursday, November 22, 2007 8:10 PM
  • The way I see it, each application has a dependency on a set of assemblies. These assemblies are placed under a Lib folder at the root of the application source tree. Other applications could, of course, reference different versions of these same libraries, and that is fine.

    Any differences of version requirements amongst these assemblies must be resolved whether you store them under source control or not. For example, if your Logging.dll requires a different version of Utility.dll than your Application.dll, you will need to resolve this regardless. Sometimes a binding redirect is the right answer, sometimes migrating to a different version is better, etc.

    Of course, at some point you need to stop placing these dependencies in your Lib folder. I tend to stop at the framework itself. For example, if I'm using Infragistics libraries I will include these in my Lib folder (and not rely on them being in the GAC on the build machine) but I won't place BCL assemblies such as System.Windows.Forms.dll in my Lib folder.

    HTH,
    Kent
    Friday, November 23, 2007 10:17 AM
  • Hi Kent,

     

    So to recap from my example:

    You would, in your Application.dll project, have a Lib folder with:

    1. Logging.dll
    2. Data.dll
    3. Utility.dll

    And where Utility.dll might in fact be a different fileversion than the Utility.dll used to build Logging.dll?

     

    Edit: I need to ask one more thing. You must be avoiding mixing this strategy with project references. In that mixture Application.dll could have a project reference to Application2.dll that in itself references a copy of Utility.dll. If that dll is a different version than Utility.dll referenced in Application.dll (and it might very well be just that) we have trouble. I cant see how that can be solved gracefully. Have you come across this?

    --

    Werner

    Friday, November 23, 2007 10:23 AM
  • This is not something I've had to work around. As I hinted earlier, you might be better off fixing the mismatch in versions depending on the situation. However, if you need to store both versions you can just create a directory structure in your Lib folder:

    Code Block

    + Lib

    |-+ Utility

      |-+ ForProjectA

      |-+ ForProjectB


    You can then reference the assembly in the appropriate folder and version it independently. Or you could just introduce a Lib folder at the project folder level.

    HTH,
    Kent
    Friday, November 23, 2007 2:43 PM
  • Hi,

     

    I'll take our discussion with me to the next developer meeting.

    Thanks for your time Kent.

     

    --

    Werner

    Friday, November 23, 2007 7:02 PM
  • Just a usefull link a recieved - maybe others find it interesting too.

    http://www.cmcrossroads.com/bradapp/acme/

     

    --

    Werner

    Monday, November 26, 2007 7:40 AM
  • Our firm takes a rather different view than most. (I am the originator of this policy...)

     

    1) We ALWAYS use DLL references. Project references are maintained by the SOLUTION. They eliminate the ability to have multiple minimal solutions for different develoipment aspects.

     

    2) We ALWAYS copy (as the post build event) the DLL's from the "bin" directory structure to a Dedicated Target Location. This location is also under source control, but only the Build system can update it.

     

    This allows us to have any developer at any time, get a single project from Source Control (TFS for us) along with the pre-built target location DLL's and work on that specific project.

     

     

     

    Thursday, November 29, 2007 7:36 PM
  •  TheCPUWizard-2007 wrote:

    1) We ALWAYS use DLL references. Project references are maintained by the SOLUTION. They eliminate the ability to have multiple minimal solutions for different develoipment aspects.

     

    So this means that if you have 2 applications on your developer PC, say "Project1" and "Solution2", that both references "Include.dll" they would point to the same physical file on disc?

     

    --
    Werner

    Monday, December 3, 2007 12:23 PM
  • If "Include.dll" is the result of one of our own "Shared Projects", then yes all other projects would refer to the same DLL. Typically in:

     

    "C:\DynConProjects\Published_Assemblies\..."

     

     

    Tuesday, December 4, 2007 4:18 PM
  •  TheCPUWizard-2007 wrote:

    If "Include.dll" is the result of one of our own "Shared Projects", then yes all other projects would refer to the same DLL.

     

    I see, but how does that differ from using project references? What is the gain using shared DLL's instead of project references? If all projects are referencing the same DLL's - then they would adopt changes in excatly the same way if some project reference is "checked in" in source control. There must be some business gain that I am missing?

     

     

     

    Wednesday, December 5, 2007 7:24 AM
  • Big differences and big business gains.

     

    1) You do not need all of the source code with DLL references. Many of our projects/assemblies are only accessable in source form (even readonly) be a select group of developers

     

    2) You can easily create many mini-solutions. Consider my current project, over 300 Assemblies. Trying to create ONE solution is way to big for VS to handle. Mantainng solutions with arbitrary combinations of projects and using project references is virtually impossible. With DLL references, if I am working on a task that involves Project3, Project 42, Project57 and Project270; I Simple create a solution (NOT source controlled) with those 4 projects and program away!

     

     

    Wednesday, December 5, 2007 9:28 PM
  • How do you decide whether to put Debug or Release assemblies in the output location? What if they're Debug and I want Release, or vice versa?

     

    And who checks in the assemblies once they're built? It seems to me you'd want the automated build to do so after building - is that the case?

     

    Kent

    Wednesday, December 5, 2007 10:49 PM
  •  

    The automated build creates both Debug and Release versions, and puts them into distinct (but common) directories. The individual developers will copy from one of these two directories (almost always release) into the "reference" directory. If the developer builds a given assembly (what ever configuration) it gets copied to the local "reference" directory as part of the (local) build process..
    Thursday, December 6, 2007 7:43 PM
  •  TheCPUWizard-2007 wrote:

    With DLL references, if I am working on a task that involves Project3, Project 42, Project57 and Project270; I Simple create a solution (NOT source controlled) with those 4 projects and program away!

     

    Could you explain this more? I dont quite get the idea. Your example defines:

    1. With DLL references
    2. Solution with project references

    How do those two combine? wouldnt you always use DLL's? So that you have NO project references?

     

    And the the "NOT source controlled" sentence. Why are you creating solution that isnt in source control? Please explain this - Not only dont I understand why on earth you would choose NOT to have source code in source control - but I dont get the context of your DLL / Source code discussion.

     

    Thanks,

     

    Friday, December 7, 2007 9:25 AM
  • Sorry for the confusion. I mis-typed when I said "Solution with Project References", it should have been "Solution with Project Dependencies".  References (regardless of type) are always stored in the .??proj file. Dependencies are stored in the .sln file!!!!!. I use ONLY DLL references!

     

    As to not keeping the solutions under source control. I am referring to Ad-hoc solutions that are created by developers so they have multiple projects open at the same time in a single Visual Studio session.

     

    Consider a development effort which has 60 seperate projects for the "Real Code" (plus 100+ projects for Tests, Development Utilities, Prototypes, etc). With just the real code, there are:

    • 3540 - 2 project solutions possible
    • 205320 - 3 project solutions possible.
    • 11703240 - 4 project soltions possible.
    • etc....

    Surely that vast majority of these possible solution configureations would never be used (nor overly useful), and there is NO point in putting them under Source Control. They are created on-the-fly do address specific work efforts.

     

    As an example assume I am working on a Custon UI control [in Project24.csproj]  An eventual effect of an action on this control is that something happens deep within the system in the Caching [Project51.csproj]. So I create a solution to look at this and just include the two projects + the project that contains the executable.. Now I debug the executable. Finding necessary changes, (Assuming no externally visible changes) I can quickly edit the file and trigger a build which executes in mere seconds. (A "do-nothing"/"all-projects-up-to-date" MS-Build of tthe environment takes a little over three minutes).

     

    This reduces my "cycle time" (time from "see the bug" back to "debugging the program") drastically. When you multiple this by the number of times "F5" is pressed over the development cycle of a product, this can easily result in days or weeks of net savings per developer. If you consider $100/hr (loaded cost), 10 developers, and a savings of just 20 hours [IMHO this is a VERY VERY low number] per developer. this nets out to $20K in savings!

     

     

     

     

    Friday, December 7, 2007 2:29 PM
  • TheCPUWizard-2007,

     

    Thanks for sharing. We have developers in different countries and I see that it might be usefull to adopt your ideas. I try to work some more with these ideas and get some workflows / ideas written down.  

     

    Thanks,

     

    Monday, December 10, 2007 1:03 PM
  • Werner,

     

    Distributed teams is one place where this really works well for me. Each team gets only the source code for their specific area of developement (e.g. UI, DAL), along with a pre-built set of DLL's for all the other components. Since some of our teams are off-shore third-party developers, this minimizes some of the intellectual property exposure.

     

    When a team publishes an new "version", we evaluate it here at corporate to make sure it integrates properly. If it does not, it gets sent back to the team who developed it. If it does, it gets included as the current version in each new push to the other teams.

     

    The only "tweak" this process has needed over the years has been the occasional equirement to send "non-owned" projects to specific teams to facilitate debugging of certain inter-project situations. This is not a "problem" and we do not accept back changes to "non-owned" projects (although we do forward information to the owning team). If we find this situation happening too often, we re-evaluate our project boundaries and documented interfaces.

     

    If you (or other readers) want do discuss this directly, I can be contacted as david dot corbin on my com domain of dynconcepts. (humans should be able to figure that out, but not bots...)

    Monday, December 10, 2007 1:42 PM
  •  TheCPUWizard-2007 wrote:

    The automated build creates both Debug and Release versions, and puts them into distinct (but common) directories. The individual developers will copy from one of these two directories (almost always release) into the "reference" directory. If the developer builds a given assembly (what ever configuration) it gets copied to the local "reference" directory as part of the (local) build process..

     

    Thanks for the contact information. When I have passed the "dumb question stage" I might take advantage of your offer.

     

    However some questions arise after giving this some more thoughts. Please comment where I dont get/follow your logic Smile. Suppose you have 3 assemblies in public location like this:

     

    \public\release\1.dll

    \public\release\2.dll

    \public\release\3.dll

     

    Now I create new solution that is called PingService. This service needs all 3 assemblies from above. So I copy those to my local reference directory.

     

    Question 1: This local reference directory - is that local to Solution "PingService" or to my developer PC?

     

    Now I want to publish my PingService.dll. I copy release and build assemblies to global location. This means that I have this structure now:

     

    \public\release\PingService.dll

    \public\release\1.dll

    \public\release\2.dll

    \public\release\3.dll

     

    Correct? But what if "\public\release\2.dll" changed while I was developing my PingService? Then I would have inconsistency in my global assemblies?!

     

    Hopefully you get my questions (or others that might comment).

     

    EDIT:

    Is this where a dedicated "build server" would come in handy? Or how do you all cope with situations like above?

     

    --

    Werner

     

     

    Tuesday, December 11, 2007 9:26 AM
  •  

    Not "dumb" questions, simply "poor" explainations...

     

    A BuildServer (or a close simulation) is exactly what makes this work.

     

    Continuing (and revising your secnario). the directories

     

    \public\release\

    \public\debug\

     

    Both exist on the client (developer) machine, but are not directly written to by the developer. These directories are only updated by a push from the build server or (in the case where the server can not push) by an explicit "get from build server"

     

    The developer would then copy from these two trees the assemblies they want to acccess. Typically developers simply copy the entire release tree, and only grab from the debug tree if they need to debug some assembly that they dont control. These files end up in

     

    \mySharedAssemblies\

     

    All developers must agree (usually via mandate) that this directory exists in the same location on all machines, as all projects will be developed to use DLL references to assemblies in this location.

     

    One developer then starts working on "PingService". Once it is "working", we assume that this developer may create another project which references it. Since all references are to "\mySharedAssemblies\", this is where the developer copies it (often as part of a post build). The new project, can then easily reference it.

     

    At some point this assembly will get registered with the Build Server as a public assembly. Once this happens it will appear in the "\public\release" and "\public\debug" directories OF ALL DEVELOPERS (by virtual magic if you have been following....

     

     

    Thursday, December 13, 2007 3:44 PM
  •  TheCPUWizard-2007 wrote:

    Not "dumb" questions, simply "poor" explainations...

     

    Thanks Smile

     

     TheCPUWizard-2007 wrote:

    A BuildServer (or a close simulation) is exactly what makes this work.

    [snip]

    At some point this assembly will get registered with the Build Server as a public assembly. Once this happens it will appear in the "\public\release" and "\public\debug" directories OF ALL DEVELOPERS (by virtual magic if you have been following....

     

    But suppose a dependency for "PingService", say "1.dll" was updated by another Developer and registered on the build server tree. When "PingService" arrives at the build server it was build with another version than the one lying beside it on the build server! That cant be all good?

     

    Actually building things on the build server would remedy this - however I get the feeling that you just use the server as storage? If you actually are building things on the build server - how are your builds organized? Do you have like this:

     

    \12345\public\debug

    \12345\public\release

     

    Where the number would be some build number? And then the assemblies on a developer PC would always be from on (and only one) specific build from the build tree?

     

    Thanks, its really helping me to shape some politics... 

     

    --

    Friday, December 14, 2007 12:54 PM
  •  Werner Clausen wrote:

    Actually building things on the build server would remedy this - however I get the feeling that you just use the server as storage? If you actually are building things on the build server - how are your builds organized? Do you have like this:

     

    \12345\public\debug

    \12345\public\release

     

    Where the number would be some build number? And then the assemblies on a developer PC would always be from on (and only one) specific build from the build tree?

     

    Thanks, its really helping me to shape some politics... 

     

    --

     

    No, the BuildServer is being used quite heavily for all of the builds. Fortunately (most) of our development efforts (maintenance phase is slightly different) are such that we always work against the "current" build.

     

    So the person who is building the "PingService" should make sure that the code builds against the current version of all dependancies (by doing a local build immediately before "publishing").

     

    There ARE "race conditions" but the number of development TEAMS here is fairly small, so it is managable FOR US.

     

    Getting to your specific situation. Lets consider what happens with a developer working on "Library" project. A set of changes is published to the Build Server. This triggers a continous integration build. Since "PingService" would be registered as a dependancy on "Library" it will also get build and unit tested.

     

    If the changes to "Library" break this proces,s the developer of "Library" will be immediately (oik a few minutes later) be notified that the changes were breaking changes. These changes would be either rolled back, or coordination would take place between the teams.

     

    We strive hard not to implement breaking changes (public interface changes, or gross functional changes) without a pre-implementation coordination effort. In some cases we will add the new functionallity in parallel (so it is non-breaking), and then remove the old functionallity when all of the dependancies have been updated to make use of the new functionallity.

     

    Again, this is a methodology that works for us. A small-midsize group of developers (many who have known each other for years and years) along with a set of remote (typically third party) teams. I am quite aware that this methodology would NOT directly scale up is there were hundreds of developers working in dozens of teams, on inter-related development efforts (think Microsoft developing Vista or Office). On the other hand, my experience has been that policies and procedures which are required for the very large teams also do not scale DOWN to maximum efficiency.

     

     

    Friday, December 14, 2007 2:49 PM
  •  TheCPUWizard-2007 wrote:

    Again, this is a methodology that works for us. A small-midsize group of developers (many who have known each other for years and years) along with a set of remote (typically third party) teams. I am quite aware that this methodology would NOT directly scale up is there were hundreds of developers working in dozens of teams, on inter-related development efforts (think Microsoft developing Vista or Office). On the other hand, my experience has been that policies and procedures which are required for the very large teams also do not scale DOWN to maximum efficiency.

     

    I agree. We're also just a small group of developers (in this country), and implementing the best practices of the "Microsoft Team Development" just doesnt scale to our needs. Picking up bits and pieces seems to be a better (and cheaper) idea. Now along with some real word examples, like yours, it would be possible for me to construct something that would work for us...

     

    Again thanks Smile

     

    --

     

    Friday, December 14, 2007 5:08 PM
  • Werner, please contact me directly. Thanx!

     

    Saturday, December 15, 2007 5:31 PM
  • TheCPUWizard-2007,

     

    In order to have file-references build on the build server I need to have manually created dependencies in the Solution file correct? Do you have some examples of how to do this? Or perhaps a link to the syntax?

     

    Thanks,

     

     

    Monday, December 17, 2007 11:01 AM
  • Solution level dependencies are the correct way. The manual way (and the only way I know of "out of the box") is to right click on each project in the solution and set a dependency for each DLL Reference.

     

    My firm is currently working on a tool to automate this processs, but it will not be available for the public until 1st quarter 2008.

    Monday, December 17, 2007 2:40 PM
  •  TheCPUWizard-2007 wrote:

    Solution level dependencies are the correct way. The manual way (and the only way I know of "out of the box") is to right click on each project in the solution and set a dependency for each DLL Reference.

     

    My firm is currently working on a tool to automate this processs, but it will not be available for the public until 1st quarter 2008.

     

    However choosing a project dependency in VS would require the project to be included? But the whole deal was to use DLL references - not project source code? So an off-site developer would still have to include the source code? Or how would his project ensure that dependencies are build first?

     

    What am I missing?

     

    --

    Werner

    Tuesday, December 18, 2007 7:52 AM
  • This gets back to why solutions (except for a "master") are NOT kept in TFS (or other source control).

     

    Saw I am working on a system that has 99 projects "Project01.csproj" through "Project99.csproj"

     

    a) The task I am working on involves ONLY source code in Project23, therefore I create a solution with only Project23. The project file contains all the DLL references. No other source code is needed.

     

    b) The task I am working on involves source code in Project86 and Project99. therefore I create a solution with only Project86, and Project99. The project file contains all the DLL references. No other source code is needed.

     

    c) The task I am working on involves source code in Project42, but I want to be able to step into Project69. So I request the source code (if I dont have it), and  create a solution with only Project42, and Project69. The project file contains all the DLL references. No other source code is needed.

     

    Overtime, the number of solutions will grow as the permutations of issues are worked on. There is NO need to save them, they contain no (long term) useful information.

     

    HOWEVER, in order for builds to work cleanly when working with these scenarions (except for "a"), it is necessary to establish the proper build order. This is done via Project Dependencies (wihch are stored only in the Solution file).

     

    Clearer?????/

    Wednesday, December 19, 2007 5:55 PM
  •  TheCPUWizard-2007 wrote:

    a) The task I am working on involves ONLY source code in Project23, therefore I create a solution with only Project23. The project file contains all the DLL references. No other source code is needed.


    HOWEVER, in order for builds to work cleanly when working with these scenarions (except for "a"), it is necessary to establish the proper build order. This is done via Project Dependencies (wihch are stored only in the Solution file).

     

    Clearer?????/

     

    Well no I'm afraid...I have the feeling that I'm asking about Bananas and you are talking about Apples here because there are some fundamental issues that isn't clear at all. I can understand if you through in the towel..In case you dont, I dont get your first example "a":

     

    Lets define the task as "Solution1" as a new solution that holds the source code of "Project 23". Now suppose "Project23" includes a DLL reference "Project1.dll". How do you ensure that "Project1" gets build before "Project23"? Using project dependencies in the solution or what? So you would have to include "Project1" source code? 

     

    --

     

    Wednesday, January 2, 2008 12:30 PM