I've been all over the board on this throughout my career. Currently, we are looking at a substantial reduction in the number of types in our codebase. This would imply fewer & larger classes. Which is totally fine, as long as you know how to manage that complexity.
Our approach for managing this complexity is to simply say that each class in the domain model aligns to the bounded context of a particular business unit, process, or activity. So, instead of modeling a bunch of different types within some namespace, the type itself represents the entire extent of that business concern, including any business facts as instance properties. Complex types are modeled as nested classes within each context. Nothing is shared between contexts except for trivial domain-wide concerns in the outer scope. This allows for very easy serialization of business state in and out of a database (among many other things). Consider the power that a method override might have in this realm if you wanted to construct a hierarchy of such contexts.
An example of one of these concrete types might be SelfCheckoutContext (if you were working in a retail business domain). This type could be derived from a wider CheckoutContext which could be simultaneously shared other concrete contexts like HumanCheckoutContext.
In our approach, there is also a lot of stuff that exists outside of each context (Views, Services, Repositories, etc). We basically treat these items as a platform layer for the contexts to operate on top of.
Yes absolutely. We took what we felt was the bare essential idea of DDD (bounded contexts) and ran with it. The fewer patterns the better. Allows you to work with fewer constraints, assuming you are responsible with the added power.
Bounded contexts are IMO the most powerful abstraction out there for accurately constructing a very complex business system. They directly get at the root of the problem, which is aligning the implementation with the same grain as the business. They also permit complete isolation of various business units which might have unique perspectives into what would otherwise be shared (and increasingly-convoluted) models. In our latest implementations, models are never shared between contexts. There might be a few models defined in the outer domain scope for things we believe apply universally to the application. Any cross-context communication is achieved via simple mappers.
Our approach for managing this complexity is to simply say that each class in the domain model aligns to the bounded context of a particular business unit, process, or activity. So, instead of modeling a bunch of different types within some namespace, the type itself represents the entire extent of that business concern, including any business facts as instance properties. Complex types are modeled as nested classes within each context. Nothing is shared between contexts except for trivial domain-wide concerns in the outer scope. This allows for very easy serialization of business state in and out of a database (among many other things). Consider the power that a method override might have in this realm if you wanted to construct a hierarchy of such contexts.
An example of one of these concrete types might be SelfCheckoutContext (if you were working in a retail business domain). This type could be derived from a wider CheckoutContext which could be simultaneously shared other concrete contexts like HumanCheckoutContext.
In our approach, there is also a lot of stuff that exists outside of each context (Views, Services, Repositories, etc). We basically treat these items as a platform layer for the contexts to operate on top of.