2013/14 I was the lead/architect for a very large team, which is why this question came up. In previous years, with small teams of 10 or less devs, it wasn't as big a deal. But I have architected with 5 different large companies between then and now with the sole purpose of answering this question.
Why the back-story? Because this isn't a programmer question, this is an Architect question. The solution and reference architecture are the job of the Software Architect.
Point 1: Don't give your developers rules on which projects to directly add to which solutions. It isn't their job to permanently add/remove projects, it's the Architect's job.
Point 2: I frown on this, but developers can (temporarily) add references to "Existing Projects" for troubleshooting. (Lengthy sad disclaimer removed...)
Still yet, I have come up with an answer for My Architecture. That is, Solutions focused on Service-Oriented Programming in a Service-Oriented Architecture with Micro Services. If you are doing OO, monolithic projects are sometimes preferrable. That is somewhat by design. And other paradigms may call for other architectures. Though, in my opinion, SOA is the only way to move into the future. :D
This is in no way an exhaustive reference. But, for SOA, this is the idea:
What is a Domain?
A Domain is a set of models which represent a cohesive idea, and the services which move the models.
For example: An Order Domain might have (OrderModel, OrderDetailModel, ReceiptModel)
An Employee Domain, when consuming a third party timesheet management system, might have (EmployeeModel, TaxInfoModel, TimesheetModel).
If you break away from the third party and build your own timesheet subsystem, you might take Timesheet out of the Employee Domain, and create a Timesheet domain with (TimesheetModel, DailyTimeModel, PtoModel).
People frequently think of "The Domain" as the center of the universe. And, for the most part, it is. But it's also a matter of perspective.
In a UI Solution, the Startup project is the UI, and everything revolves around that. You might have a Selenium or CodedUI Project, or an Angular Jasmine setup, or some other portion to do your testing. There shouldn't be any domain logic, but there is a lot of routing logic and integration (consumption) of services you need to test, as well as duplication of model validation for the sole purpose of attempting to have less round-trips to the domain.
In a Mid-Tier Solution, you have no startup project. You start with Unit Testing, and you run that testing to test and debug the application in isolation. Everything revolves around the Models and Services there. All of your domain logic and validation logic are here. There inevitably would also be routing calls to Services and Persistence. You shouldn't require Integration Testing.
In a Data Solution, you have no startup project. There might be minimal Unit Testing, and minimal integration testing. Everything revolves around your data access including Repositories and Entities. I say "Minimal" testing, because most tests I've seen are either testing logic which SHOULD be in the mid-tier domain, or are performing tests which are testing Entity Framework or SQL server... if you have to test those things, you don't trust or understand them enough to be using them.
These are three different types of solutions which require different types of support projects, and might be broken down into different types of separation of cores. But each one has ONE Domain, and satellite projects which support that domain.
To the Architect, or "Higher-up" perspective, ViewModels, Domain, and Persistence all exist. But there are also individual perspectives within each layer. I wrote a bit about layer separation in terms of Boundaries and Models here, which is the "Higher-up" perspective.
To a UI Developer, he has one Domain. For a WebDev, that is the Web Project. For a WPF Dev, that is the WPF Project, etc.
- What a UI Dev calls itself: From his perspective, his models are his "Domain Models." Though, by standard, we call them "ViewModels".
- What a UI Dev calls consumers: Nothing, because nothing "consumes" a UI, other than People.
- What a UI Dev calls other UI's: Nothing. UI's don't consume other UI's. If they do, they are doing it in a method similar to consuming Services, like below:
- What a UI Dev calls services it consumes: API's, SDK's, or "Packages". The models on those services are just called "Models."
- How a UI Dev consumes persistence: He doesn't. A UI should not even know that persistence exists.
To a Mid-Tier Developer, he has one Domain. That is, "The Domain", as we typically call it. These are models, and services which help shape the models.
- What a Mid-Dev calls itself: From his perspective, his models are his "Domain Models." Though, by standard, we all call them "Domain Models."
- What a Mid-Dev calls consumers: Nothing, because he shouldn't care who/what is consuming. That would be Tight Coupling. Though, it might be a UI, or another mid-tier.
- What a Mid-Dev calls other mid-tiers: He either doesn't care, or he uses them as Services (below):
- What a Mid-Dev calls services it consumes: API's, SDK's, or "Packages". The models on those services are just called "Models."
- How a Mid-Dev consumes persistence: A mid-tier should only know about one persistence. That is, a seperate solution which was built solely to handle persistence of his domain. We call that the Data-layer, and its models are "Entities." If persistence happens within or beyond the consumption of some other mid-tier, api, sdk, or package, that is none of our concern.
To a Data Developer, he has one Domain. That is, "Persistence". This is a repository (or set of repositories) which define how entities are CRUD'd.
- What a Data-Dev calls itself: From his perspective, his models are his "Domain Models." Though, by standard, we all call them "Entities"
- What a Data-Dev calls consumers: Nothing, because he shouldn't care who/what is consuming. That would be Tight Coupling. Though, it should typically be a particular mid-tier solution.
- What a Data-Dev calls other data projects: Nothing, it shouldn't know other data projects exist.
- What a Data-Dev calls services it consumes: Nothing, it shouldn't depend on anything other than frameworks that help it CRUD its own data.
- How a Data-Dev consumes persistence: A Data Solution IS Persistence, it should not be consuming other packages which do other persistence.
Perspective - Summary
So "The Domain" is the center of your world. It is your main concern. Other subsystems might consume you, and you might consume other subsystems (SDK's, .Data Solutions, etc).
That said, the "Domain" project you are working in, be it a UI Project, a Middle-Tier Project, or a Persistence project, should be the center of your Solution.
In addition to that ONE project, you might also have support projects. These are typically projects which help your solution understand how to build NuGet packages, do Unit Testing and Integration Testing, define an SDK for your domain, or define an API to access your domain. But all projects revolve solely around the Domain. You don't test support projects. If you feel you need to, that is a code smell. You might also split your "Domain" into the Implementation and Core. The Core might even be split into a Models project and an Interfaces project.
If you follow the same namespacing practices I follow, you can easily tell how your Solutions should be split up. Again, this isn't exhaustive and complete, but it's an example.
Therefore, take this system for example:
UI Solution (Assuming I use a .NET Web, which I currently don't):
- Sua.WebFletch.ViewModels - Models project
- Sua.WebFletch.Web - One Domain Project
- Sua.WebFletch.CodedUI - CodedUI Project to test the Web.
- Sua.WebFletch.Customers.Core - Interfaces
- Sua.WebFletch.Customers.Models - Models
- Sua.WebFletch.Customers - One Domain Project
- Sua.WebFletch.Customers.UnitTests - Tests of Implementation
- Sua.WebFletch.Customers.Data.Core - Interfaces
- Sua.WebFletch.Customers.Data.Entities - Models
- Sua.WebFletch.Customers.Data - One Domain Project