15

First off, let’s agree that namespace should match folder structure and that each language artefact should be in its own file.

(see Should the folders in a solution match the namespace? ).

The next question is how the folders should actually be organised on disk.
Suppose I have ClassC in the A.B.C namespace and ClassD in the A.B.C.D namespace.
Let’s also assume that each namespace is built into its own assembly (project) and that namespaces have dependencies from right to left as per accepted best practice (A.B.C.D can depend on A.B.C which can depend on A.B which can depend on A). I appreciate that each namespace doesn’t have to be in a separate assembly but in the general case we will have some namespaces in separate assemblies and my example illustrates that.

I can see (at least) two ways to create the folder tree – which I’ll call “nested folders” and “flat folders”:

1 - Nested folders:

A
--A.csproj
--B
----A.B.csproj
----C
------A.B.C.csproj
------classC.cs
------D
--------A.B.C.D.csproj
--------classD.cs

OR

2 – Flat folders:

A
--A.csproj
A.B
--A.B.csproj
A.B.C
--A.B.C.csproj
--classC.cs
A.B.C.D
--A.B.C.D.csproj
--classD.cs

You will see I’ve made a few assumptions already:

  • Each project file has a fully qualified name (FQN) based on the namespace.
  • Each class file uses a non-FQN

Nested folders seems more natural (we all like hierarchies), but may be a bit harder to navigate in large solutions:

When you look at your solution in VS, it shows a flat list of projects rather than a nested view. This looks more like “flat folders” so there may be merit in organising the folders on disk to match the view in VS.

If you look in each folder on disk you will see the folder artefacts for that project plus the sub folder for the namespace: taking C as an example:

C
--bin
--D
--obj
--Properties
--A.B.C.csproj
--classC.cs

Depending on D’s real name it may not be obvious that D is a namespace folder rather than an organisational folder in the C namespace.

I know we’ve had folders and namespaces from day one in .NET (8 or 9 years ago) and Java before that, but, personally speaking, we don’t appear to have come to a consensus on best practice project organisation for large solutions. I’d be really interested to find out what you all think.

Thanks
Michael

Community
  • 1
  • 1
Micdev42
  • 151
  • 1
  • 1
  • 4

8 Answers8

8

I use the flat approach. I find a nested hierarchy too hard to maintain. I group my projects into several solutions, with maximum reusability and cross-referencing in mind, and always found this satisfactory. Example (projects are indented):

CompanyName
  CompanyName.Core
    Class1
    Struct2
    Enum3
  CompanyName.Data
  CompanyName.Web

CompanyName.Projects
  CompanyName.Projects.Core

CompanyName.Projects.ProjectX
  CompanyName.Projects.ProjectX.Core
  CompanyName.Projects.ProjectX.Website
  CompanyName.Projects.ProjectX.ToolY

etc. etc.

Edit: removed nonsense remark

user39603
  • 2,235
  • 1
  • 16
  • 13
5

I'm not a big fan of nested projects, since it buries projects deep inside a structure and if you need to reuse that project in another application then what do you do, copy/paste the code? I like to follow somewhat of a flat structure but organized by namespace.

This is how I do it:

- DataHelpers\
---Factory\
---DataAccess\
---...
- Components\
--- EmailProcessor\
--- ErrorLogger\
- Desktop\
--- WindowsApp1\
- Services\
--- WindowsService1\
--- WindowsService2\
- WebApps\
--- WebApp1\
--- WebApp2\

Now, inside each major application I have, for example:

- WindowsService1\
--- WindowsService1\ (this contains all *.cs, bin, obj, etc and .csproj file)
--- Solution\ (this contains the .sln file where you link to other projects like ErrorLogger, etc)

I hope that makes sense!

Ricardo Villamil
  • 5,031
  • 2
  • 30
  • 26
  • In the nested model, the entire project exists under the "dotted" name folder (e.g. A.B.C. in the example), so you can just reference that directly. – Robert C. Barth Dec 30 '08 at 20:09
4

"First off, let’s agree that namespace should match folder structure and that each language artifact [sic] should be in its own file."

Funny, that's how packages work in Java. I always thought that breaking the link between namespaces and directory structure was considered one of the improvements that C# introduced. Is that not true? (Forgive my ignorance, I'm a Java person.)

duffymo
  • 305,152
  • 44
  • 369
  • 561
  • 2
    You're correct, there is no direct link between the folders, file names, namespaces and type names. It's a convention however, so that it's easier to find files, but you're free to mix and match as you want. – Lasse V. Karlsen Dec 30 '08 at 18:17
3

I have always done the nested hierarchy. It makes it painfully obvious where to add new projects to an existing solution and keeps your namespaces nicely organized on disk. It also makes the deliniation of namespace versus project more obvious.

Robert C. Barth
  • 22,687
  • 6
  • 45
  • 52
2

If you use the nested projects you run the risk of hitting the windows MaxPath issue. This is a huge deal breaker for ever using nested structures. Just imagine meeting this little Gem half way though a dev project, having to name VS projects with 3 letter acronyms just so as not to hit MaxPath. An MS bug ending up as the inspiration for the names of your assemblies. What a joke that would be. Working with a flat structures is much better all round.

   -SouceControlFolderName
     -Project1
       -Src
         -Main
           -Company.Project1.AppName
             *Company.Project1.AppName.sln
             *Company.Project1.AppName.Tests.sln
             -Company.Project1.AppName.Common
             -Company.Project1.AppName.Common.Tests
             -Company.Project1.AppName.Entities
             -Company.Project1.AppName.Entities.Tests
             -Company.Project1.AppName.Security
             -Company.Project1.AppName.Security.Tests
             -etc.

You could create a separate directory for the test projects or as above and have them all together which is easier to manage when adding to source control i.e. Subversion (TFS is better in many ways save for the fact it needs Explorer integration not just VS integration and a proper off-line story)

Microsoft Developer
  • 1,919
  • 1
  • 20
  • 27
  • 7
    The same risk exists when using a flat folder structure. _src\Abc.Def.Project1_ is the same length as _src\Abc\Def\Project1_ – user247702 May 05 '11 at 08:59
0

I prefer a flat structure with projects in the root.

  • MyCorp.Core
  • MyApp.Domain
  • MyApp.Data
  • MyApp.UI
  • MyApp.Test

Inside of these I have various folders and namespaces. I only create different assemblies for deployable units. Small apps won't even have this amount of separation. IMO this keeps things simple. If I ever decide that code I have needs to be used elsewhere, it's easy enough to break it into an assembly if needed, as long as I've followed good namespacing practices.

Fred
  • 1,344
  • 1
  • 11
  • 16
0

I think you need to define a cut-off point where the flat approach no longer works. For example, if you have a typical 3-tier architecture in a smallish project, having 3 projects on the outer level is no problem. However, if you have a few dozen, then some sort of grouping helps segment functionality and makes the whole solution more understandable.

Dmitri Nesteruk
  • 23,067
  • 22
  • 97
  • 166
  • Yeah, but isn't it more practical to just start a new (sub)solution then, instead of having dozens of projects in one? Anyway, in the end it's all about personal preference.. – user39603 Dec 31 '08 at 10:35
0

12 Years on, is there any definitive or best practice answer on this question?

I would like to use the Nested folders structure, however given that you:

"agree that namespace should match folder structure and that each language artefact should be in its own file."

How would project A.B.C.csproj folder structure look if it extended code from other namespaces, for example:

  • grand-parent: A.csproj
  • parent: A.B.csproj
  • child A.B.C.D.csproj
  • external namespaces System.Linq or Microsoft.Extensions.Logging

Perhaps something like:

/A                                  // namespace: A
  /B                                // namespace: A.B
    /C                              // namespace: A.B.C
      A.B.C.csproj 
      ClassC.cs                  
      /_                            // External Namespace root folder (underscore with no text)
        /System                     // namespace: System 
          /Linq                     // namespace: System.Linq
            IQueryableExtensions.cs 
        /Microsoft                  // namespace: Microsoft
          /Extensions               // namespace: Microsoft.Extensions
            /Logging                // namespace: Microsoft.Extensions.Logging
              ILoggerExtensions.cs                                  
      /__A                          // namespace: A (Grand Parent folder (2 underscores for 2 levels up)
        ClassAExtensions.cs
        /B                          // namespace: A.B (Nested Parent folder)
          ClassBExtensionsNested.cs
                                    //Parent Namespace folder (1 underscore for 1 level up)
      /_B                           // namespace: A.B
        ClassBExtensions.cs
      /D                            // namespace: A.B.C.D (Child folder)
        ClassDExtensions.cs

Above is trying to demonstrate:

  • A folder with a lone Underscore (_) with no text following would substitute as an empty namespace & new root for all external namespaces.
  • Folders with Underscore(s) (__A) & (_B) followed by text substitutes as a level up in the tree/hierarchy of the current project. 1 level per underscore
tb-mtg
  • 529
  • 8
  • 10