If eventual consistency will not do then you'll need a way to store 100% consistent data on the transactional/write/domain side of things.
That being said, it is sometimes possible to implement a business rule slightly differently but still get the same result. For instance, you could add a list of ChatAggregateComment
value objects to your ChatAggregate
that store, say, the UserId
, CommentId
, and DateCommented
. This list would grow only as big as the number of people involved in the chat. However, if even that is going to be too large then you could denormalize the data and store this same list as immediately consistent on your write side and then query table through some domain-side query interface.
As far as creating a new ChatCommentAggregate
is concerned you could use your ChatAggregate
as the factory for a ChatCommentAggregate
. Your rule could be applied within the ChatAggregate.CreateComment
method.
Am I going about this the right way? Or am I maybe over-complicating it or missing something?
I think you have a start of a design; you are teasing out the concepts and their basic relationships and the constraints on the relationships, which is a great start.
For me, what I like to do is before I do any real detail on classes and operations (e.g. what methods, where business logic goes), I like to lightly enumerate the concepts and relationships in the business terms that create the ubiquitous language for a domain model. The concepts that have business identities (e.g. plane ticket with record locator, user having unique user name or id, etc...) will probably end up being aggregate roots. Ideally, these concepts and relationships are already known in the business and one doesn't have to try reinvent them as part of design. (And of course, iteration, improvements, refactoring, etc... will occur.)
Next, for me personally, having a good start at the concepts and relationships, I like to do application design from the ends toward the middle. I think of it a bit like designing a bridge. I like to have a design for the embankments first, then the middle (the span). In this analogy one embankment end is the persistence implementation, where I'm thinking about modeling concepts and also their relationships and some of their constraints with SQL using tables. The other end is the externally exposed interface, where I'm thinking about a REST API using OData principles.
I then design the classes, methods, and operations as a bridge that spans between the two, now-known embankments. Also note that we have many choices when it comes to class design (e.g. to use ORM or not, which classes get which methods and where business & application logic go), as the classes in the middle are closer to internal implementation and farther from externally exposed API.
I think you will want a formal notion of different kinds of Users (in addition to Developer), such as Business Stake Holder -- they might be the ones to initiate Projects.
The term event is overused in our business, so I try to use it only in a narrow way (my opinion is that an "event" is something that happened, once, either just now or in the past, and events can fire, be subscribed to, etc...). So, you might choose a more specific name within your business domain for what you are calling event. On the other hand, I'd probably move in the direction of more general recursively composed projects, so projects can compose/decompose into any number of other projects. You already have several specific layers of composition: Event, Project, Application, why not get more general? Yet still, recursive composition may not suffice, you may also need to track dependencies between projects (e.g between peer sub projects, or independent project that are not composed). I might try to formalize the notion of schedule along with notions of dependency.
For my aggregates, what do I do here? Do I write a "service" class like "TeamProjectService" with methods such as "CreateTeamProject"? Or what?
I have two comments here.
First, I would tend to think about the items you list in bold as aggregate roots as they probably have solid identities externally referable from outside the aggregate. Aggregate roots can be related to other aggregate roots (and for NxM relations I would model persistence for each of those with their own first-class table). The way you are using the term aggregate above makes me think about the relationships between aggregate roots more than the entities within the aggregate.
Second, I would probably do relationship creation via an operation attached to one or both of the aggregate roots being related. For example, a team entity might be able to create a project, or the project collection could create a project though requiring a team as a parameter.
These days, I like to use OAuth2 (e.g. Windows Live, Facebook, Google+, Twitter, Stackoverflow) for authentication (I do OAuth2 directly but perhaps Azure ACS can help abstract this across the variety of OAuth2 providers).
Best Answer
Just because you have a many to many relationship at a data or database level, doesn't mean it has to be represented in code. You should model for the relationships you care about or are useful to you. The relationship of roles to users is more of an implementation detail and not something worth modelling at all at a code level, let the database handle the consistency. Knowing all the users in a role seems like more of a user search capability than anything useful in working with a role.
In either case you really don't want to model both directions of a many to many case in code at the same time, because you will run into circular reference and consistency issues. Databases are designed to handle that consistency gracefully, let them do the hard work and only model the relationship in one direction at a time in code. Chances are your users are really only interested in one direction of such relationships at a time anyway.