Skip to content

Commit

Permalink
Fix formatting
Browse files Browse the repository at this point in the history
  • Loading branch information
keyvanakbary committed Feb 20, 2018
1 parent e3ca8c4 commit 6868f82
Show file tree
Hide file tree
Showing 4 changed files with 23 additions and 31 deletions.
28 changes: 11 additions & 17 deletions chapters/03-command-query-responsibility-segregation.asc
Original file line number Diff line number Diff line change
Expand Up @@ -90,15 +90,13 @@ DTOs are optimally built to match the screens of the client to prevent multiple

In either case the DTO model is very different than the domain model that was built in order to represent and process transactions.

Common smells of the problems can be found in many domains.
Common smells of the problems can be found in many domains:

Large numbers of read methods on repositories often also including paging or sorting information.

Getters exposing the internal state of domain objects in order to build DTOs.

Use of prefetch paths on the read use cases as they require more data to be loaded by the ORM.

Loading of multiple aggregate roots to build a DTO causes non-optimal querying to the data model. Alternatively aggregate boundaries can be confused because of the DTO building operations.
* Large numbers of read methods on repositories often also including paging or sorting information.
* Getters exposing the internal state of domain objects in order to build DTOs.
* Use of prefetch paths on the read use cases as they require more data to be loaded by the ORM.
* Loading of multiple aggregate roots to build a DTO causes non-optimal querying to the data model.
* Alternatively aggregate boundaries can be confused because of the DTO building operations.

The largest smell though is that the optimization of queries is extremely difficult. Because queries are operating on an object model then being translated to a data model, likely by an ORM it can become difficult to optimize these queries. A developer needs to have intimate knowledge of the ORM and the database. The developer is dealing with a problem of Impedance Mismatch (for more discussion see “Events as a Storage Mechanism”).

Expand Down Expand Up @@ -126,15 +124,11 @@ image::images/the-command-side.png[]

In the “Stereotypical Architecture” the domain was handling both Commands and Queries, this caused many issues within the domain itself. Some of those issues were:

Large numbers of read methods on repositories often also including paging or sorting information.

Getters exposing the internal state of domain objects in order to build DTOs.

Use of prefetch paths on the read use cases as they require more data to be loaded by the ORM.

Loading of multiple aggregates to build a DTO causes non-optimal querying to the data model.

Alternatively aggregate boundaries can be confused because of the DTO building operations.
* Large numbers of read methods on repositories often also including paging or sorting information.
* Getters exposing the internal state of domain objects in order to build DTOs.
* Use of prefetch paths on the read use cases as they require more data to be loaded by the ORM.
* Loading of multiple aggregates to build a DTO causes non-optimal querying to the data model.
* Alternatively aggregate boundaries can be confused because of the DTO building operations.

Once the read layer has been separated the domain will only focus on the processing of Commands.

Expand Down
20 changes: 10 additions & 10 deletions chapters/04-events-as-a-storage-mechanism.asc
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ The goal of this section is to introduce the concept of event sourcing, to show

*An event is something that has happened in the past.*

All events should be represented as verbs in the pas t tense such as CustomerRelocated, CargoShipped, or InventoryLossageRecorded. For those who speak French, it should be in Passé Composé, they are things that have *completed* in the past. There are interesting examples in the English language where it is tempting to use nouns as opposed to verbs in the past tense, an example of this would be “Earthquake” or “Capsize”, as a congressman recently worried about Guam, but avoid the temptation to use names like this and stick with the usage of verbs in the past tense when creating Domain Events.
All events should be represented as verbs in the past tense such as CustomerRelocated, CargoShipped, or InventoryLossageRecorded. For those who speak French, it should be in Passé Composé, they are things that have *completed* in the past. There are interesting examples in the English language where it is tempting to use nouns as opposed to verbs in the past tense, an example of this would be “Earthquake” or “Capsize”, as a congressman recently worried about Guam, but avoid the temptation to use names like this and stick with the usage of verbs in the past tense when creating Domain Events.

It is absolutely imperative that events always be verbs in the past tense as they are part of the Ubiquitous Language. Consider the differences in the Ubiquitous Language when we discuss the side effects from relocating a customer, the event makes the concept explicit where as previously the changes that would occur within an aggregate or between multiple aggregates were left as an implicit concept that needed to be explored and defined. As an example, in most systems the fact that a side effect occurred is simply found by a tool such as Hibernate or Entity Framework, if there is a change to the side effects of a use case, it is an implicit concept. The introduction of the event makes the concept explicit and part of the Ubiquitous Language; relocating a customer does not just change some stuff, relocating a customer produces a CustomerRelocatedEvent which is explicitly defined within the language.

Expand Down Expand Up @@ -49,7 +49,7 @@ This also differs from Martin Fowler’s example of what a Domain Event is.
Further along

"By funneling inputs of a system into streams of Domain Events you can keep a record of all the inputs to a system. This helps you to organize your processing logic, and also allows you to keep an audit log of the system"
-- Margin Fowler
-- Martin Fowler

The astute reader may pick up that what Martin is actually describing here is a Command as was discussed previously when discussing Task Based UIs. The language of “Make Purchase” is wrong. A purchase was made. It makes far more sense to introduce a PurchaseMade event. Martin did actually make a purchase at the location, they did actually charge his credit card, and he likely ate and enjoyed his food. All of these things are in the past tense, they have already happened and cannot be undone.

Expand Down Expand Up @@ -93,7 +93,7 @@ In order to calculate this number the current delta is applied to the last known
|1/8/2000 |Deposit from 1373 |+1000.00 |6992.00
|===

Because all of the transactions or deltas associated with the account exist, they can be stepped through verifying the reult. The “Current Balance” at any point can be derived either by looking at the “Current Balance” or by adding up all of the “Changes” since the beginning of time for the account. The second property is obviously valuable in a domain such as accounting as accountants are dealing with money and the ability to check that calculations were performed correctly is extremely valuable, it was even more valuable before computers when it was common place to have an exhausted accountant make a mistake in a calculation at 3 am when they should be sleeping instead of working with the books.
Because all of the transactions or deltas associated with the account exist, they can be stepped through verifying the result. The “Current Balance” at any point can be derived either by looking at the “Current Balance” or by adding up all of the “Changes” since the beginning of time for the account. The second property is obviously valuable in a domain such as accounting as accountants are dealing with money and the ability to check that calculations were performed correctly is extremely valuable, it was even more valuable before computers when it was common place to have an exhausted accountant make a mistake in a calculation at 3 am when they should be sleeping instead of working with the books.

There are however some other interesting properties to this mechanism of representing state, as an example, it is possible to go back and look at what a state was at a given point in time. Consider for that the account was allowed to reach a balance of below zero and there is a rule that says it is not supposed to. It is possible and relatively easy, to view the account as it was just prior to processing that transaction that put it into the invalid state and see what state it was in, making it far easier to reproduce what often times end up as heisenbugs in other circumstances.

Expand Down Expand Up @@ -171,7 +171,7 @@ Many would quickly point out that although it requires more queries in a relatio

==== Rolling Snapshots

A Rolling Snapshot is a denormalization of the current state of an aggregate at a given point in time. It represents the state when all events to that point in time have been replayed. Rolling Snapshots are used as a heuristic to prevent the need to load all events for the entire history of an aggregate. Figure 5 shows a typical Event Stream. One way of process thing the event stream is to replay the events from the beginning of time until the end of the event stream is reached.
A Rolling Snapshot is a denormalization of the current state of an aggregate at a given point in time. It represents the state when all events to that point in time have been replayed. Rolling Snapshots are used as a heuristic to prevent the need to load all events for the entire history of an aggregate. Figure 5 shows a typical Event Stream. One way of processing the event stream is to replay the events from the beginning of time until the end of the event stream is reached.

.An Event Stream
[caption="Figure 5. "]
Expand Down Expand Up @@ -213,14 +213,14 @@ The cost is that a developer really needs to be intimately with both the relatio

Some of these subtle differences can be found in Wikipedia under the “Object-Relational Impedance Mismatch” page but to include some of the major differences.

[, Object-Relational Impedance Mismatch]
____
Declarative vs. imperative interfaces — Relational thinking tends to use data as interfaces, not behavior as interfaces. It thus has a declarative tilt in design philosophy in contrast to OO's behavioral tilt. (Some relational proponents propose using triggers, stored procedures, etc. to provide complex behavior, but this is not a common viewpoint.) – Object-Relational Impedance Mismatch
"Declarative vs. imperative interfaces — Relational thinking tends to use data as interfaces, not behavior as interfaces. It thus has a declarative tilt in design philosophy in contrast to OO's behavioral tilt. (Some relational proponents propose using triggers, stored procedures, etc. to provide complex behavior, but this is not a common viewpoint.)"
-- Object-Relational Impedance Mismatch

Structure vs. behaviour — OO primarily focuses on ensuring that the structure of the program is reasonable (maintainable, understandable, extensible, reusable, safe), whereas relational systems focus on what kind of behaviour the resulting run-time system has (efficiency, adaptability, fault-tolerance, liveness, logical integrity, etc.). Object-oriented methods generally assume that the primary user of the object-oriented code and its interfaces are the application developers. In relational systems, the end-users' view of the behaviour of the system is sometimes considered to be more important. However, relational queries and "views" are common techniques to re-represent information in application-or task-specific configurations. Further, relational does not prohibit local or application-specific structures or tables from being created, although many common development tools do not directly provide such a feature, assuming objects will be used instead. This makes it difficult to know whether the stated non-developer perspective of relational is inherent to relational, or merely a product of current practice and tool implementation assumptions. – Object-Relational Impedance Mismatch)
"Structure vs. behaviour — OO primarily focuses on ensuring that the structure of the program is reasonable (maintainable, understandable, extensible, reusable, safe), whereas relational systems focus on what kind of behaviour the resulting run-time system has (efficiency, adaptability, fault-tolerance, liveness, logical integrity, etc.). Object-oriented methods generally assume that the primary user of the object-oriented code and its interfaces are the application developers. In relational systems, the end-users' view of the behaviour of the system is sometimes considered to be more important. However, relational queries and "views" are common techniques to re-represent information in application-or task-specific configurations. Further, relational does not prohibit local or application-specific structures or tables from being created, although many common development tools do not directly provide such a feature, assuming objects will be used instead. This makes it difficult to know whether the stated non-developer perspective of relational is inherent to relational, or merely a product of current practice and tool implementation assumptions."
-- Object-Relational Impedance Mismatch

Set vs. graph relationships - The relationship between different items (objects or records) tend to be handled differently between the paradigms. Relational relationships are usually based on idioms taken from set theory, while object relationships lean toward idioms adopted from graph theory (including trees). While each can represent the same information as the other, the approaches they provide to access and manage information differ.
____
"Set vs. graph relationships - The relationship between different items (objects or records) tend to be handled differently between the paradigms. Relational relationships are usually based on idioms taken from set theory, while object relationships lean toward idioms adopted from graph theory (including trees). While each can represent the same information as the other, the approaches they provide to access and manage information differ."
-- Object-Relational Impedance Mismatch

There are many other subtle differences such as data types, identity, and how transactions work. The object-relational impedance mismatch can be quite a pain to deal with and it requires a very large amount of knowledge to deal with effectively.

Expand Down
2 changes: 1 addition & 1 deletion chapters/05-building-an-event-storage.asc
Original file line number Diff line number Diff line change
Expand Up @@ -120,7 +120,7 @@ There can be a single process running or many depending on needs due to throughp
[caption="Figure 4. "]
image::images/snapshotter.png[]

The [SnapShotter] sits behind the Event Storage and periodically queries for any Aggregates that need to have a snapshot taken because they have gone past the allowed number of events. This query can be done quite easily in the simple Event Storage discussed by joining the Aggregates table to the Snapshots table on the Aggregate identifier. The difference is calculated by subtracting the last snapshot version from the current version with a where clause that only returned the aggregates with a difference greater than some number. This query will return all of the Aggregates that a snapshot to be created.
The [SnapShotter] sits behind the Event Storage and periodically queries for any Aggregates that need to have a snapshot taken because they have gone past the allowed number of events. This query can be done quite easily in the simple Event Storage discussed by joining the Aggregates table to the Snapshots table on the Aggregate identifier. The difference is calculated by subtracting the last snapshot version from the current version with a where clause that only returned the aggregates with a difference greater than some number. This query will return all of the Aggregates that require a snapshot to be created.

The snapshotter would then iterate through this list of Aggregates to create the snapshots (if using multiple snapshotters the competing consumer pattern works well here).

Expand Down
4 changes: 1 addition & 3 deletions chapters/06-cqrs-and-event-sourcing.asc
Original file line number Diff line number Diff line change
Expand Up @@ -97,9 +97,7 @@ Outsourced projects often fail because large amounts of communication are requir

The Read Model as an example is an ideal area of the system to outsource. The contracts for the Read Model as well of specifications for how it work are quite concrete and easily described. Little business knowledge is needed and the technical proficiency requirements on most systems will be in the mid-range.

The Domain Model on the other hand is something that will not work at all if outsourced. The developers of the Domain Model need to have large amounts of communications with the domain

experts. The developers will also benefit greatly by having initial domain knowledge. These developers are best kept locally within the team and should be highly valued.
The Domain Model on the other hand is something that will not work at all if outsourced. The developers of the Domain Model need to have large amounts of communications with the domain experts. The developers will also benefit greatly by having initial domain knowledge. These developers are best kept locally within the team and should be highly valued.

A company can save large amounts of capital by outsourcing this area of the system at a low risk, this capital can then be reinvested in other, more important areas of the system. The directed use of capital is very important in reaching a higher quality, lower cost system.

Expand Down

0 comments on commit 6868f82

Please sign in to comment.