Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to model the StackOverflow website with DDD

I take the example of StackOverflow because obviously you know that website, and my real usecase is really close.

So let's imagine a simplified SO domain description:

  • There are users
  • Users can create new questions
  • Users can create answers to these questions
  • Users can edit their own questions and answers
  • Users can edit other users questions if they have more than 1000 reputation (took that threshold randomly)

The last bold rule is the one that matters to me.

What I understand about an AggregateRoot is that it should contain the state that serves to take decision to accept or reject commands, and it should not query a DB to do so. It guarantees the consistency of the app. It should only listen to the events it emits to update its state.

Now what I think is that the SO domain has an aggregate root called Question. That question would then handle commands like:

  • CreateAnswer
  • EditQuestion

The thing is, when the EditQuestion is fired, how the Question AggregateRoot would be able to decide wether to accept or refuse that command? Because if you remember, the command should be rejected if you try to edit the question of another user if you have < 1000 reputation.

It does not seem to make sens to me that the Question AR maintain a list of all users reputations, to be able to know how to act on that command.

The problem is that when trying to model my domain I have this modeling problem coming over and over again, and I always end up with a single big fat AggregateRoot

Can someone tell me what I am missing and help me solve this problem? thanks

This question seems to say that we should not put the authorization system inside the domain model. I agree this may be practical for things like role-based authentication. However, to me the "users can't edit unless they have enough reputation" is really an SO business rule, so how could it be outside of the domain?

IMPORTANT: when answering, please consider YOU are the business expert. You know StackOverflow as an user and can guess what are the SO constraints by yourself. Even if you are wrong about them, it's not a big deal: just make a proposal for your wrong business constraints I'm fine with that!!!

It's not the first time I ask this kind of question and it always ends up with no answer but just endless discussions. What I want to know is how you would model StackOverflow if you had to build this site, with a focus on the business rules about the minimum reputation to edit.

like image 232
Sebastien Lorber Avatar asked Nov 22 '15 18:11

Sebastien Lorber


1 Answers

Well, things are quite simple IMO (in this SO scenario only). This is how I would do it (obviously, other devs probably have different approaches):

You tagged the question well with the "cqrs". In the EditQuestion handler, I'd use a Domain Service (a Query from a CQRS point of view) which will check if a certain use has the required points and then return a true/false. Something like this (more or less pseudo code)

public class CanUserEditQuestionService
{
    //constructor with deps\\

    public bool Handle(CanUserEditQuestion input)
    {
       //query the read model, maybe a query object to get us the rep of the user
      var rep=getReputation.Get(input.UserId);

      //we can have a dependency here which tell us the number of points required for a specific permission

     return(rep>=1000);
    }
}

If the query returns true, then the handler will perform changes on the Question entity i.e question.ChangeText() or smth (I think SO takes an event sourcing approach).

What you have here is a simple use case of a concept "Question" , its command behaviour "Edit" and the business rule that dictates who can do what. The thing is, the 1000 rep rule is never part of the Question concept definition, therefore it doesn't belong to that aggregate i.e how the question is edited. However it's part of the use case itself and part of the application service.

I'm sure that you'll ask me : "What if the read model used by the domain query is behind the command model?". In this case it matters very little, the delay it's probably measured in seconds at most. Also the main thing here is: the business rule is not part of the Question aggregate so it doesn't care about being immediate consistent.

Another thing is that user rep is always a different concept than of a Question so dealing with rep should be never a part of a Question aggregate. But it is part of the application service.

If you view an application as a group of use cases doing things with concepts (which themselves encapsulate data and business constraints), it's quite easy to identify which is the application service, aggregate, domain service etc.

like image 83
MikeSW Avatar answered Sep 28 '22 02:09

MikeSW