Pergunta

I am trying to design an application that will be a REST API following MVC. For now ,I have 2 main features: Projects and Tickets associated to Projects.

I would like to apply SOLID principles, and I want to have a rough idea on how to design it, before I start coding.

My idea so far has been like this to create the Controller -> Service -> Repository

This means for Project:

ProjectController -> ProjectService -> ProjectRepository

This may lead to methods such as:

getProject()
getProjects()
createProject()
updateProject()
deleteProject()
getProjectConfiguration()

Likewise, for Ticket I would have:

TicketController -> TicketService -> TicketRepository

This may lead to methods such as:

getTicket()
getTickets()
createTicket()
updateTicket()
deleteTicket()

Each of them are likely to be extended in the future. Maybe just updating a certain part of the Project or Ticket, so a new endpoint would be added and therefore new methods.

How can I adapt this design to Single Responsibility Principle ?

This principle states each class should do one thing and be changed for one thing. But I don't know the level of abstraction of such thing.

Should I create a class for whatever involves the creation in Project, another for whatever involves updating in a Project and the same for deleting and retrieving, and the same for Ticket? Something like: ProjectCreationXXX, ProjectUpdateXXX, ProjectRetrievalXXX, etc etc etc

Or can my initial approach be considered to implement doing only one thing, since it is making a part for Project and another for Ticket ?

Foi útil?

Solução

No, the Single Responsibility Principle does not say that a class should do only one thing: it says it should have one reason to change. It’s not my claim but Uncle Bob’s, and he knows about the topic since he invented SRP.

In the MVC, at a high and abstract level, the layers have a single responsibility:

  • the Model has one reason to change: the domain model including its business logic
  • the View has one reason to change: the user interface appearance
  • the Controller has one reason to change: the interpretation of the accepted input.

But the devil is in the details:

  • if you change the model, you might have to adapt the views, since the views depend on the model that they can query.
  • if you change the model, you might have to change the controller to add new commands to be applied to the domain
  • if you create or remove views, you may have to update the controller, since it creates specific instances of the view.

So for being SRP compliant, you need to isolate the concerns in the classes that decompose each layer. You did this very well so far, for example:

  • by specializing the controller by domain service: the change in the service will be the reason to change for the controller.
  • by encapsulating persistence of the aggregate in a repository.

Now, going further on the decomposition of consistent comprehensive project/ticket classes and decompose them into single actions is not required for SRP, because the a Project/Ticket in the Model is an aggregate, which is a consistent whole for whatever operation has to be performed on the aggregate, so there is already only one reason for change.

Nevertheless, you could chose to pursue your decomposition but for other reasons than SRP, for example if you want to use the command pattern in your service. Don’t make the right decision for the wrong reasons: if you do not need this pattern, there us no need to over-complicate the design.

Licenciado em: CC-BY-SA com atribuição
scroll top