Despite what people are saying, limiting yourself to three projects in a solution is as retarded as allowing things to get out of hand as far as 20... it's my belief that the fewer projects you can practically have in your solution, the better. But arbitrarily limiting yourself to any specific number is dumb. Use your common sense. Here are the questions I ask myself and the rules of thumb I follow for determining how many projects I need in my solution.
- Am I writing an application that needs to be distributed across multiple servers?
- Am I writing an application where different departments need different front-ends for the same data/business rules?
- Am I writing a one off application that connects to its own database that will be used by one person or that everyone will see and use in the same way regardless of what it's being used for?
If you answered yes to the first 2 questions, then you probably need to separate your code into multiple projects or solutions. Ask yourself:
- Does this code really need a separate project or solution than my application?
- Is the code I want to put in the new project specific to this application or will it be useful in multiple applications? If it's not specific to this application, but it won't be useful in other applications, don't bother splitting it out.
- Is the code I want to put in the new project dependent upon anything specific to this project? If the answer is yes, go on to the next question, if not, skip ahead to the last one.
- Can any application specific dependencies be injected, thus removing the application dependency and therefore making it reusable in other projects? If the answer is no, then it shouldn't be its own project.
- What is the realistic likelihood of the new project being reused? Truthfully. If it's unlikely to be reused, then it's a waste of time splitting it out.
Rules of thumb for defining the number of projects in my application solution:
- Any code that is not specific to this application should be its own project(s), where practical in its own solution.
- All projects should be as dependency free as is practical. This probably won't be none, it's usually far more effort than it's worth to make a project completely dependency free.
- Any projects that are coupled so tightly that you cannot use either one without the other should be a single project. If there needs to be logical separation of concerns within that project, it should be in folders not projects.
- Any project that can be used independently of other projects in the solution should be separated and linked with a binary reference at the earliest possible opportunity.
When I start developing a new application, I potentially start with the following projects in my solution:
- Caching Layer [Potentially not needed] - This helps eliminate expensive hits on the database. It may not be needed depending on the application/circumstances/business needs. Most of my apps have this built into the data access layer, but a couple have required a centralized cache that can be hit with multiple instances of the DAL, thus required a separate deployment and thus a separate solution. Before the caching layer reached maturity enough that it could be used separately from my application though, it existed as a project within my solution.
- Data Access Layer [Potentially already exists] - It would be ideal if this had no dependencies on any other project in your solution, but the fact is, it needs to return business objects, which are defined in your Business Object Layer, so your DAL and BOL are coupled, like it or not - although the BOL isn't dependent up on the Data Access Layer - it's a one way dependency.
- Business Object Layer [Potentially already exists] - This doesn't need any dependencies on any other project in your solution. In an ideal world, your objects are just data storage devices for in-memory data. KISS. If your objects are dumb, it separates concerns and doesn't leave any awkward edges. I'm quite likely to use my business object layer in other projects because they're generic and don't do anything. I should be able to new up a business object and load it with data without needing to even reference my DAL. These are unchanging logical containers for data regarding company specific operations. In my current company that means: Stops, Manifests, Locations, Customers, Shipment. There's no logic, it's just data. These things don't change over time. A shipment is picked up from one location, delivered to another location and a customer gets billed for the shipment - that's trucking, it won't change until they invent teleportation. This allows my application to do what needs to be done. Like the Data Access Layer, this may have already been written and tested for other projects, if so, you'd just have a binary reference rather than a project/project reference in your solution.
- Business Logic Layer [Optional] - Business rules that are non-project specific, i.e. if rules apply across all software in your organization - which they probably don't, so you probably don't need a project for this. These will relate to unchangeable business processes/practices. Given that very few business processes/practices are immutable, and given that if you change them, you'll likely need to modify your application, you probably don't need this layer separated from your application project. In cases where the rules apply to things that don't change very often - like the laws of physics, they could feasibly be stored in a business logic layer allowing multiple applications to make use of them. Usually though, business logic is application specific and as such, doesn't require its own assembly.
- Application Layer (or Presentation Layer) - This contains application specific code: logic, helpers, utilities and configuration.
- Projects for non-project specific utilities that don't belong in existing libraries - These are utilities being written for first time use and proofing with this project. These can't have any dependencies on any other projects in your solution (except amongst themselves) as once they reach maturity, you will be breaking them out into their own libraries and changing project references to binary references to remove clutter from this solution. If utilities belong in pre-existing libraries, they should be added to those libraries and tested before inclusion as a binary reference in this solution. Any chance to avoid adding a project to your current solution, will avoid headaches navigating around your code later. You should remove these projects and replace them with binary references at the earliest possible opportunity.
If you're really lucky and you've got a previously developed DAL and BOL and don't need any helpers that don't already exist in other libraries, you'll only need a single project in your solution. If you're not so lucky you'll be developing the DAL and BOL yourself. You'll probably also need at handful of non-project specific helpers that are logically unrelated to each other. These projects will sit in this solution until they've reached maturity enough that they can be broken out to their own solutions leaving a few binary references in their wake.
By the time you're finished, if you did it right you should just be left with your application layer and a bunch of binary references - a single project.
Of course, if you're writing a one off application and you're not going to have multiple applications floated over top of each of the different pieces, then there's precious little point in having any more than one project. You may as well just use folders in a single project from the outset.