A graphical overview of the architecture is shown in the figure below. Lets do a quick walkthrough of the figure. A user opens an application and the first screen is loaded. The data is fetched from the Query side. In this example it goes through a WCF service and uses, lets say NHibernate, to read data from the database and into a DTO that returns the data to the GUI. The DTO is tailored to fit the screen the user is viewing. The query database is often de-normalizedto improve reading. The user may brows through different screens, and the process is the same. A DTO tailored for the users screen is returned from the database. Eventually, the user wants to change the data in one of the screens. What then happens is that a command message is created based on the data that have changed in the view and sent down the left side of the figure; the command side.
The command message is sent into the domain model to get validated against the business rules. A error message is sent back to the client if some of the business rules fails (how this is done can differ). If the message goes through the domain model without errors, it’s persisted to the write database and synchronized with the read database(s). The read databases then will pick up the new messages from the queue or bus, and update itself. The synchronization arrow in the figure it is used to initialize the read databases based on the write database.
The command side should never return other data than the error message. If you follow this rule, the command side will only be behavioral. This makes logging of what happens in the domain model very easy, and it’s quite easy to track what the user wanted to do, not only what the result of his actions were. The approach I’m describing in this post is a bit different than Greg Young describes. His solution promotes no database on the command side; a database is only needed for reporting. This is a great approach, but it makes things a bit more complex and it requires a green field project(?). The approach I’m describing can be used with a brown field application without much change to the existing architecture. In most cases you only have to add a query-side to the “old” architecture.
Why add query side DTOs?
In a traditional domain model, you will create the objects for solving domain logic, not for viewing. They have behavior rather than shape. To make domain objects more viewable, many developers use mapping between the domain model and a DTOs tailored for being displayed. This results in a lot of mapping between objects for the developer and domain models who exposes getters and setters (To learn why this is bad, do a Google search on; getters and setters are evil).
If you are using a ORM like NHibernate, you have to add getters to the domain model (and make the properties and methods virtual if you want to use lazy loading), and I think this is ok. The model is still protected against unwanted changes that can make it invalid. Every change have to happen through its command methods.
Summary
What you get from this architecture is; scalability on the read side of the application (where you normally get most load), the possibility to log all happenings in the domain model (by tracking the commands and events in the domain model), and a domain model that only have to worry about writing data, not be a transporter of data from the database to the GUI. I guarantee that this alone will make things a lot easier for you. And one final thing; creating objects (DTOs) based on the view helps us avoid a lot of mapping and a lot of requests against the database to fill the view with data. I will go through the parts of the architecture in more details in future posts.
[source] : From Fossmo
No comments:
Post a Comment