Project Structure - By Artifact or Business Logic?

We're currently at a crossroads about how to structure projects. On one hand we started down the path of putting classes and files into folders that made sense according to programming speak. That it, Interfaces; Enums; Exceptions; ValueObjects; Repositories; etc. Here's a sample of a project with that layout:

image

After some discussion, we thought it would make more sense to structure classes according to the business constructs they represent. In the above example, we have a Project.cs in the DomainObject folder; an IProject.cs interface in the interface folder; and a PayPeriod.cs value object (used to construct a Project object) in the ValueObjects folder. Additional objects would be added so maybe we would have a Repository folder which would contain a ProjectRepository.

Using a business aligned structure, it might make more sense to structure it according to a unit of work or use case. So everything you need for say a Project class (the class, the interface, the repository, the factory, etc.) would be in the same folder.

Here's the same project as above, restructured to put classes and files into folders (which also means namespaces as each folder is a namespace in the .NET world) that make sense to the domain.

image

It may seem moot. Where do I put files in a solution structure? But I figured I would ask out there. So the question is, how do you structure your business layer and it's associated classes? Option 1 or Option 2 (or maybe your own structure). What are the pros and cons to each, or in the end, does it matter at all?

13 Comments

  • I go with options 2. I find that as the project grows you have a larger set of folders, but each folder does not grow. I would rather deal with fifty folders of 10 items in each folder than 10 folders with fifty items in each. Generally when you are making a change in a business layer, you more likely to impact multiple files related to functional area than you are to affect multiple interfaces, or multiple constants at once.

  • I've always followed Option 2. One reason it that the groups in Option 1 can continue to grow until they reach an unmaintainable size.

    It's also more likely I'll need to modify a group of related classes/interfaces together than modify all the interfaces.

  • Ugh.. I should hit refresh before posting redundant comments. At least it proves I'm not alone. The similarity is entirely by accident.

  • Why use the file system as the view over how your code structure looks like? Isn't it more efficient to use the class explorer in vs.net ? (and thus it doesn't matter where files are stored?

    If you have 200 entities, would option 1 OR 2 still be valuable? I have my doubts though I'd go for option 1 in that case as it is less problematic to find a file.

  • Timely topic! We're mulling this over where I work too.

    I think option 2 helps convey the domain concepts better. Evans has good advice on this in his Domain Driven Design book:
    "Use packaging to separate the domain layer from other code. Otherwise, leave as much freedom as possible to package the domain objects in ways that support their model and design choices." p.115

    He takes it even further in chapter 10 with the notion of Conceptual Contours:
    "Decompose design elements (operations, interfaces, classes and aggregates) into cohesive units, taking into consideration your intuition of the important divisions in the domain. Observe the axes of change and stability through successive refactorings and look for underlying conceptual contours that explain these shearing patterns. Align the model with consistent aspects of the domain that make it a viable area of knowledge in the first place." p261

    By looking at the project structure in option 2, it is easier to see what the major stories, object interactions, and conceptual boundaries are in the system.

    I would even take it as far as saying that Constants, Interfaces, Specifications, Value Objects, Enums and Repositories are terms that could hurt more than help in this layer (the IDE will handle the branding for you in most cases). I'd rather a developer name a class the OvertimeQualificationRule rather than the OvertimeQualificationSpecification because it will use vocabulary that a customer, business analyst, project manager, and general user won't have to translate or sit there with glazed over eyes while you discuss it in front of them. It might be a good idea to have a comment that the class is using the Specification pattern, and probably it's base class would tell you that anyway.

    In practical terms, a developer will do less folder hopping and walking when working on a story in the domain layer for the second option.

  • I'd strongly prefer option #2. It'd be a much bigger deal without "CTRL-N" though.

  • I most definately think that option 2 is the better option. This is the one I am using myself. Especially because it naturally integrates with using namespaces for logical divisions in your code as well.

    Option 1 is the dark side.

  • I would go with Option 2 too.
    As the other posters have said, it is easier if the organisation is done by the module or component as its easier for different developers to work on different parts of the system.

  • @David: That's funny since I'm the maintainer of Tree Surgeon.

  • @Udi: Sounds great. I like splitting things up along aggregate roots and the interface idea sounds good. I've been wanting to do that, but sometimes forget (like on one project I'm on) so now it's hard to do.

  • Option 2 definately! Organizing the hierarchy by types is equivalent to hungarian style naming, very 20th century ;) In the same way we've moved from using data types to describe our variables to using meaningful names.

    Organization by the domain model / functionality is more intuitive and will facilitate locating artifacts more efficiently.

  • Wierd, I was about to post in the DDD forum then found this.

    We have quite a big code base and have gone for something like option 2 so at the root of the domain you have this sort of structure:

    Aggregates

    ...

    Common
    BaseClasses
    ...
    Enumerations
    ...
    Interfaces
    ...
    Value Objects
    ...
    Mapping Files
    ...

    The Common folder is there because whats in that folder is used by multiple aggregates, and thats where it gets messy. Looking for an enum, will it be in the Common folder or with a particular aggregate thats the only one that uses it?

    Any thoughts on this structure?

  • I'd tend towards lucky#2 with one addition: separation of interfaces from the implementations. So a seperate project with the same folder structure containing only ur interfaces.
    #2 also aligns itself more with the service oriented concept where each service is self contained.
    Also, option 1 doesn't lend itself nicely to large distributed groups maintaining discrete chunks of functionality independently.
    So forget 'tend' - viva numero due.

Comments have been disabled for this content.