A straightforward Go app that demonstrates the implementation of CQRS (Command Query Responsibility Segregation) without requiring any library. The aim of this project is to learn how to physically divide classes into two distinct responsibilities, in order to achieve scalability, maintainability, performance and adapt to two mindsets. It is highly adaptable in navigating complex domains, allowing for independent customization of the data structure for read and write operations.
├── cmd
│ └── main.go
├── docs
├── go-cqrs.http
├── go.mod
├── go.sum
├── internal
│ ├── app
│ │ ├── app.go
│ │ ├── dependencies.go
│ │ └── routes.go
│ ├── controllers
│ │ ├── movieReadController.go
│ │ ├── movieWriteController.go
│ │ └── response.go
│ ├── database
│ │ └── inMemoryDatabase.go
│ ├── entities
│ │ ├── entityBase.go
│ │ └── movie.go
│ ├── handlers
│ │ ├── abstractions
│ │ │ ├── ICommandHandler.go
│ │ │ └── IQueryHandler.go
│ │ ├── commands
│ │ │ ├── addMovieCommandHandler.go
│ │ │ ├── deleteMovieCommandHandler.go
│ │ │ └── updateMovieCommandHandler.go
│ │ └── queries
│ │ ├── getMovieByIdQueryHandler.go
│ │ └── getMoviesQueryHandler.go
│ └── repositories
│ ├── abstractions
│ │ ├── IReadRepository.go
│ │ └── IWriteRepository.go
│ ├── movieReadRepository.go
│ └── movieWriteRepository.go
ReadRepository has only one responsibility, all of its methods are used to read data from the database. It is used to transfer data from database to the application as efficient as possible without changing its state.
WriteRepository has only one responsibility, all of its methods are used to write data to the database. It is used to transfer data from application to the database in more generic ways.
Manual Dependency Injection [dependencies.go] file manages the dependencies of the application. Every functions in this file is used to instantiate the dependent objects and inject them into the parent object through constructor injection.
Here is an example of how an update operation functions in a loosely coupled manner. In the UpdateMovieCommandHandler struct, we have two interactions with the database using two different objects. First, we have to retrieve the last state of that movie from the database. Second, we have to replace the old state with the new one and save the latest state (Movie) in the database. This has to be done in a loosely coupled way.