Skip to content

Commit

Permalink
copies reprocessed figs, cleans up edits
Browse files Browse the repository at this point in the history
  • Loading branch information
katherinetozer committed Feb 26, 2020
1 parent bb05a08 commit 92f560f
Show file tree
Hide file tree
Showing 27 changed files with 81 additions and 78 deletions.
4 changes: 2 additions & 2 deletions appendix_django.asciidoc
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ package next to our main allocation code:
[TIP]
====
The code for this appendix is in the
https://github.com/cosmicpython/code/tree/appendix_django[appendix_django] branch on GitHub:
appendix_django branch https://oreil.ly/A-I76[on GitHub]:
----
git clone https://github.com/cosmicpython/code.git
Expand Down Expand Up @@ -452,4 +452,4 @@ NOTE: We'd like to give a shout-out to David Seddon and Ashia Zawaduk for
have enough personal experience of, but they may have failed.

For more ((("Django", startref="ix_Django")))thoughts and actual lived experience dealing with existing
applications, refer to the pass:[<a href="epilogue_1_how_to_get_there_from_here">epilogue</a>].
applications, refer to the <<epilogue_1_how_to_get_there_from_here, epilogue>>.
2 changes: 1 addition & 1 deletion appendix_project_structure.asciidoc
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ be of interest to outline the moving parts.((("projects", "template project stru
[TIP]
====
The code for this appendix is in the
https://github.com/cosmicpython/code/tree/appendix_project_structure[appendix_project_structure] branch on GitHub:
appendix_project_structure branch https://oreil.ly/1rDRC[on GitHub]:
----
git clone https://github.com/cosmicpython/code.git
Expand Down
22 changes: 11 additions & 11 deletions appendix_validation.asciidoc
Original file line number Diff line number Diff line change
Expand Up @@ -472,17 +472,6 @@ this is very brave," it may mean that the reviewer admires your courage—unless
they're British, in which case, they're trying to tell you that what you're doing
is insanely risky, and only a fool would attempt it. Context is everything.

In software terms, the pragmatics of an operation are usually managed by the
domain model. When we receive a message like "allocate three million units of
`SCARCE-CLOCK` to order 76543," the message is _syntactically_ valid and
_semantically_ valid, but we're unable to comply because we don't have the stock
available.

TIP: Once you've validated the syntax and semantics of your commands
at the edges of your system, the domain is the place for the rest
of your validation. Validation of pragmatics is often a core part
of your business rules.((("validation", startref="ix_valid")))

[role="nobreakinside less_space"]
.Validation Recap
*****************************************************************
Expand Down Expand Up @@ -517,3 +506,14 @@ Locate each of the three types of validation in the right place::
*****************************************************************


TIP: Once you've validated the syntax and semantics of your commands
at the edges of your system, the domain is the place for the rest
of your validation. Validation of pragmatics is often a core part
of your business rules.((("validation", startref="ix_valid")))


In software terms, the pragmatics of an operation are usually managed by the
domain model. When we receive a message like "allocate three million units of
`SCARCE-CLOCK` to order 76543," the message is _syntactically_ valid and
_semantically_ valid, but we're unable to comply because we don't have the stock
available.
1 change: 1 addition & 0 deletions chapter_01_domain_model.asciidoc
Original file line number Diff line number Diff line change
Expand Up @@ -178,6 +178,7 @@ so that the examples are easier to talk about.
pass:[<a data-type="xref" href="#allocation_notes" data-xrefstyle="select:nopage">#allocation_notes</a>] shows some notes we might have taken while having a
conversation with our domain experts about allocation.

[role="nobreakinside less_space, small"]
[[allocation_notes]]
.Some Notes on Allocation
****
Expand Down
34 changes: 17 additions & 17 deletions chapter_07_aggregate.asciidoc
Original file line number Diff line number Diff line change
Expand Up @@ -22,14 +22,14 @@ Why? Let's find out.

[TIP]
====
The code for this chapter is on GitHub at
https://oreil.ly/vlnGg[appendix_csvs]:
The code for this chapter is in the appendix_csvs branch
https://oreil.ly/vlnGg[on GitHub]:
----
git clone https://github.com/cosmicpython/code.git
cd code
git checkout appendix_csvs
# or to code along, check out the previous chapter:
# or to code along, checkout the previous chapter:
git checkout chapter_06_uow
----
====
Expand Down Expand Up @@ -115,7 +115,7 @@ raise an error if there's no stock available.
This gets much harder when we introduce the idea of _concurrency_.((("concurrency"))) Suddenly we
might be allocating stock for multiple order lines simultaneously. We might
even be allocating order lines at the same time as processing changes to the
batches themselves.
batches pass:[<span class="keep-together">themselves</span>].

We usually solve this problem by applying _locks_ to our database tables. This
prevents two operations from happening simultaneously on the same row or same
Expand Down Expand Up @@ -358,16 +358,6 @@ class Product:
// IDEA (hynek): random nitpick: exceptions denoting errors should be
// named *Error. Are you doing this to save space in the listing?


NOTE: This `Product` might not look like what you'd expect a `Product`
model to look like. No price, no description, no dimensions.
Our allocation service doesn't care about any of those things.
This is the((("bounded contexts", "product concept and"))) power of bounded contexts; the concept
of a product in one app can be very different from another.
See the following sidebar for more
discussion.


//IDEA: talk about magic methods on aggregates maybe? ie, a non-aggregate entity
// might have a __hash__ so that we can put it into a set, but because you
// are never supposed to have a collection of aggregates, they could return
Expand Down Expand Up @@ -413,6 +403,16 @@ elsewhere. The Fowler link at the start of this sidebar is a good starting point
*******************************************************************************


NOTE: This `Product` might not look like what you'd expect a `Product`
model to look like. No price, no description, no dimensions.
Our allocation service doesn't care about any of those things.
This is the((("bounded contexts", "product concept and"))) power of bounded contexts; the concept
of a product in one app can be very different from another.
See the following sidebar for more
discussion.



=== One Aggregate = One Repository

Once you define certain entities to be aggregates, we need to apply the rule
Expand Down Expand Up @@ -581,7 +581,7 @@ rules such that only one of them is allowed to `commit` the new `Product`
with `version=4`, and the other update is rejected.((("transactions", "concurrent, attempting update on Product")))

[[version_numbers_sequence_diagram]]
.Sequence diagram: two transactions attempting a concurrent update on `Product`
.Sequence diagram: two transactions attempting a concurrent update on pass:[<code><span class="keep-together">Product</span></code>]
image::images/apwp_0704.png[]
[role="image-source"]
----
Expand Down Expand Up @@ -618,7 +618,7 @@ What we've implemented here is called _optimistic_ concurrency control because
our default assumption is that everything will be fine when two users want to
make changes to the database. We think it's unlikely that they will conflict
with each other, so we let them go ahead and just make sure we have a way to
notice if there is a problem.
notice if there is a pass:[<span class="keep-together">problem</span>].
_Pessimistic_ concurrency control((("pessimistic concurrency"))) works under the assumption that two users
are going to cause conflicts, and we want to prevent conflicts in all cases, so
Expand Down Expand Up @@ -863,7 +863,7 @@ read1, write1, read2, write2(succeed)
----

Some people refer to ((("read-modify-write failure mode")))this as the "read-modify-write" failure mode.((("PostgresSQL", "Anti-Patterns: Read-Modify-Write Cycles")))
Read https://oreil.ly/uXeZI["PostgreSQL Anti-Patterns: Read-Modify-Write Cycles"] for a good overview.
Read https://oreil.ly/uXeZI["PostgreSQL Anti-Patterns: Read-Modify-Write Cycles"] for a good pass:[<span class="keep-together">overview</span>].

//TODO maybe better diagrams here?

Expand Down
10 changes: 5 additions & 5 deletions chapter_08_events_and_message_bus.asciidoc
Original file line number Diff line number Diff line change
Expand Up @@ -39,13 +39,13 @@ image::images/apwp_0801.png[]
[TIP]
====
The code for this chapter is in the
https://oreil.ly/M-JuL[chapter_08_events_and_message_bus] branch on GitHub:
chapter_08_events_and_message_bus branch https://oreil.ly/M-JuL[on GitHub]:
----
git clone https://github.com/cosmicpython/code.git
cd code
git checkout chapter_08_events_and_message_bus
# or to code along, check out the previous chapter:
# or to code along, checkout the previous chapter:
git checkout chapter_07_aggregate
----
====
Expand Down Expand Up @@ -377,7 +377,7 @@ multiple processes--which may be different containers within the same
service, or totally different microservices.
If you follow us in this approach, your API for distributing tasks
is your event pass:[<span class="keep-together">classes--</span>]or a JSON representation of them. This allows
is your event pass:[<span class="keep-together">classes</span>]or a JSON representation of them. This allows
you a lot of flexibility in who you distribute tasks to; they need not
necessarily be Python services. Celery's API for distributing tasks is
essentially "function name plus arguments," which is more restrictive,
Expand Down Expand Up @@ -763,9 +763,9 @@ should I do if I need to change multiple aggregates as part of a request?" Now
we have the tools we need to answer that question.((("aggregates", "changing multiple aggregates in a request")))

If we have two things that can be transactionally isolated (e.g., an order and a
product), then we can make them _eventually consistent_ by using events. When an
pass:[<span class="keep-together">product</span>]), then we can make them _eventually consistent_ by using events. When an
order is canceled, we should find the products that were allocated to it
and remove the allocations.
and remove the pass:[<span class="keep-together">allocations</span>].

[role="nobreakinside less_space"]
.Domain Events and the Message Bus Recap
Expand Down
6 changes: 3 additions & 3 deletions chapter_09_all_messagebus.asciidoc
Original file line number Diff line number Diff line change
Expand Up @@ -22,13 +22,13 @@ image::images/apwp_0902.png[]
[TIP]
====
The code for this chapter is in the
https://oreil.ly/oKNkn[chapter_09_all_messagebus] branch on GitHub:
chapter_09_all_messagebus branch https://oreil.ly/oKNkn[on GitHub]:
----
git clone https://github.com/cosmicpython/code.git
cd code
git checkout chapter_09_all_messagebus
# or to code along, check out the previous chapter:
# or to code along, checkout the previous chapter:
git checkout chapter_08_events_and_message_bus
----
====
Expand Down Expand Up @@ -692,7 +692,7 @@ NOTE: We're adding a query to our repository to make this use case easier to
implement.((("aggregates", "query on repository returning single aggregate"))) So long as our query is returning a single aggregate, we're not
bending any rules. If you find yourself writing complex queries on your
repositories, you might want to consider a different design. Methods like `get_most_popular_products` or `find_products_by_order_id` in particular would
definitely trigger our spidey sense. <<chapter_11_external_events>> and the pass:[<a href="epilogue_1_how_to_get_there_from_here">epilogue</a>] have some tips on managing complex queries.
definitely trigger our spidey sense. <<chapter_11_external_events>> and the <<epilogue_1_how_to_get_there_from_here, epilogue>> have some tips on managing complex queries.

==== A New Method on the Domain Model

Expand Down
6 changes: 3 additions & 3 deletions chapter_10_commands.asciidoc
Original file line number Diff line number Diff line change
Expand Up @@ -16,13 +16,13 @@ message bus but with slightly different rules.
[TIP]
====
The code for this chapter is in the
https://oreil.ly/U_VGa[chapter_10_commands] branch on GitHub:
chapter_10_commands branch https://oreil.ly/U_VGa[on GitHub]:
----
git clone https://github.com/cosmicpython/code.git
cd code
git checkout chapter_10_commands
# or to code along, check out the previous chapter:
# or to code along, checkout the previous chapter:
git checkout chapter_09_all_messagebus
----
====
Expand Down Expand Up @@ -494,7 +494,7 @@ things half-finished.
WARNING: At some point, regardless of tenacity, we'll have to give up trying to
process the message. Building reliable systems with distributed messages is
hard, and we have to skim over some tricky bits. There are pointers to more
reference materials in the pass:[<a href="epilogue_1_how_to_get_there_from_here">epilogue</a>].
reference materials in the <<epilogue_1_how_to_get_there_from_here, epilogue>>.


=== Wrap-Up
Expand Down
4 changes: 2 additions & 2 deletions chapter_11_external_events.asciidoc
Original file line number Diff line number Diff line change
Expand Up @@ -26,13 +26,13 @@ image::images/apwp_1101.png[]
[TIP]
====
The code for this chapter is in the
https://oreil.ly/UiwRS[chapter_11_external_events] branch on GitHub:
chapter_11_external_events branch https://oreil.ly/UiwRS[on GitHub]:
----
git clone https://github.com/cosmicpython/code.git
cd code
git checkout chapter_11_external_events
# or to code along, check out the previous chapter:
# or to code along, checkout the previous chapter:
git checkout chapter_10_commands
----
====
Expand Down
4 changes: 2 additions & 2 deletions chapter_12_cqrs.asciidoc
Original file line number Diff line number Diff line change
Expand Up @@ -12,13 +12,13 @@ but hopefully we can make the argument that it's not _totally_ unreasonable.
[TIP]
====
The code for this chapter is in the
https://oreil.ly/YbWGT[chapter_12_cqrs] branch on GitHub.
chapter_12_cqrs branch https://oreil.ly/YbWGT[on GitHub].
----
git clone https://github.com/cosmicpython/code.git
cd code
git checkout chapter_12_cqrs
# or to code along, check out the previous chapter:
# or to code along, checkout the previous chapter:
git checkout chapter_11_external_events
----
====
Expand Down
4 changes: 2 additions & 2 deletions chapter_13_dependency_injection.asciidoc
Original file line number Diff line number Diff line change
Expand Up @@ -48,13 +48,13 @@ dependencies and testing them.
[TIP]
====
The code for this chapter is in the
https://oreil.ly/-B7e6[chapter_13_dependency_injection] branch on GitHub:
chapter_13_dependency_injection branch https://oreil.ly/-B7e6[on GitHub]:
----
git clone https://github.com/cosmicpython/code.git
cd code
git checkout chapter_13_dependency_injection
# or to code along, check out the previous chapter:
# or to code along, checkout the previous chapter:
git checkout chapter_12_cqrs
----
====
Expand Down
2 changes: 1 addition & 1 deletion colo.html
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ <h1>Colophon</h1>

<p>The animal on the cover of <em>Architecture Patterns with Python</em> is a Burmese python (<em>Python bivitattus</em>). As you might expect, the Burmese python is native to Southeast Asia. Today it lives in jungles and marshes in South Asia, Myanmar, China, and Indonesia; it’s also invasive in Florida’s Everglades.</p>

<p>Burmese pythons are one of the world’s largest species of snakes. These nocturnal, carnivorous constrictors can grow to 23 feet and 200 pounds. Females are larger than males. They can lay up to 100 eggs in one clutch. In the wild, Burmese pythons live an average of 20 to 25 years.</p>
<p>Burmese pythons are one of the world’s largest species of snakes. These nocturnal, carnivorous constrictors can grow to 23 feet and 200 pounds. Females are larger than males. They can lay up to a hundred eggs in one clutch. In the wild, Burmese pythons live an average of 20 to 25 years.</p>

<p>The markings on a Burmese python begin with an arrow-shaped spot of light brown on top of the head and continue along the body in rectangles that stand out against its otherwise tan scales. Before they reach their full size, which takes two to three years, Burmese pythons live in trees hunting small mammals and birds. They also swim for long stretches of time—going up to 30 minutes without air.</p>

Expand Down
Loading

0 comments on commit 92f560f

Please sign in to comment.