Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
76 commits
Select commit Hold shift + click to select a range
582042d
update Readme.md
fushall Jan 29, 2025
e9421e8
update preface.asciidoc
fushall Jan 29, 2025
d66f78c
update Readme.md
fushall Jan 29, 2025
b76cf9a
update Readme.md introduction.asciidoc
fushall Jan 29, 2025
462034d
update Readme.md chapter_01_domain_model.asciidoc
fushall Jan 29, 2025
697ef94
update Readme.md chapter_02_repository.asciidoc
fushall Jan 30, 2025
752e72e
update Readme.md chapter_03_abstractions.asciidoc
fushall Jan 30, 2025
b803e7e
update Readme.md chapter_04_service_layer.asciidoc
fushall Jan 30, 2025
5740917
update Readme.md chapter_05_high_gear_low_gear.asciidoc
fushall Jan 30, 2025
01b5487
update Readme.md chapter_06_uow.asciidoc
fushall Jan 30, 2025
707ce46
update Readme.md chapter_07_aggregate.asciidoc
fushall Jan 31, 2025
fd8e598
update Readme.md part1.asciidoc
fushall Jan 31, 2025
392e51d
update Readme.md part2.asciidoc
fushall Jan 31, 2025
f01ff55
update Readme.md chapter_08_events_and_message_bus.asciidoc
fushall Jan 31, 2025
b3ded71
update Readme.md chapter_09_all_messagebus.asciidoc
fushall Jan 31, 2025
40390b2
update Readme.md chapter_10_commands.asciidoc
fushall Jan 31, 2025
52154b9
update Readme.md chapter_11_external_events.asciidoc
fushall Jan 31, 2025
70864f4
update Readme.md chapter_12_cqrs.asciidoc
fushall Jan 31, 2025
f2603c7
update Readme.md chapter_13_dependency_injection.asciidoc
fushall Jan 31, 2025
16a1fdd
update Readme.md epilogue_1_how_to_get_there_from_here.asciidoc
fushall Jan 31, 2025
94d8246
update Readme.md appendix_csvs.asciidoc
fushall Jan 31, 2025
fbd7cdc
update Readme.md appendix_project_structure.asciidoc
fushall Jan 31, 2025
4f9c872
update Readme.md appendix_django.asciidoc
fushall Jan 31, 2025
fee2df2
update Readme.md appendix_ds1_table.asciidoc
fushall Jan 31, 2025
f08ab69
update Readme.md appendix_validation.asciidoc
fushall Jan 31, 2025
e117cbb
update Readme.md appendix_validation.asciidoc
fushall Feb 1, 2025
3f305ec
update Readme.md
fushall Feb 1, 2025
37d5126
update preface.asciidoc
fushall Feb 1, 2025
4ea7ec7
update chapter_01_domain_model.asciidoc
fushall Feb 1, 2025
45b0ff8
update chapter_02_repository.asciidoc
fushall Feb 1, 2025
7e239fb
update introduction.asciidoc
fushall Feb 1, 2025
1e4f45a
update part1.asciidoc
fushall Feb 1, 2025
97b8b3a
update chapter_03_abstractions.asciidoc
fushall Feb 1, 2025
1ee5634
update chapter_04_service_layer.asciidoc
fushall Feb 1, 2025
219d930
update chapter_05_high_gear_low_gear.asciidoc
fushall Feb 1, 2025
7231705
update chapter_06_uow.asciidoc
fushall Feb 1, 2025
974ce2e
update chapter_07_aggregate.asciidoc
fushall Feb 1, 2025
78f5e17
update chapter_08_events_and_message_bus.asciidoc
fushall Feb 1, 2025
c84648e
update chapter_09_all_messagebus.asciidoc
fushall Feb 1, 2025
cb882ac
update chapter_10_commands.asciidoc
fushall Feb 1, 2025
b037e42
update chapter_11_external_events.asciidoc
fushall Feb 1, 2025
d2f3e19
update chapter_12_cqrs.asciidoc
fushall Feb 1, 2025
e1ce2ac
update chapter_13_dependency_injection.asciidoc
fushall Feb 1, 2025
a753f66
update epilogue_1_how_to_get_there_from_here.asciidoc
fushall Feb 1, 2025
bf49a85
update appendix_csvs.asciidoc
fushall Feb 1, 2025
8caa637
update appendix_django.asciidoc
fushall Feb 1, 2025
cec27e8
update appendix_project_structure.asciidoc
fushall Feb 1, 2025
6c5b7a2
update appendix_validation.asciidoc
fushall Feb 1, 2025
99ef2a1
update chapter_12_cqrs.asciidoc
fushall Feb 1, 2025
9db63a7
update preface.asciidoc
fushall Feb 2, 2025
b36d5fc
update introduction.asciidoc
fushall Feb 2, 2025
24b3acc
update part1.asciidoc
fushall Feb 2, 2025
8cca05a
update appendix_csvs.asciidoc chapter_02_repository.asciidoc chapter_…
fushall Feb 2, 2025
ac17a73
update chapter_01_domain_model.asciidoc
fushall Feb 2, 2025
71bd2f9
update chapter_01_domain_model.asciidoc chapter_02_repository.asciido…
fushall Feb 2, 2025
014fb98
update chapter_02_repository.asciidoc
fushall Feb 2, 2025
900c535
update chapter_03_abstractions.asciidoc
fushall Feb 2, 2025
46e6725
update chapter_04_service_layer.asciidoc
fushall Feb 2, 2025
ab71d98
update chapter_05_high_gear_low_gear.asciidoc
fushall Feb 2, 2025
1885a5d
update chapter_03_abstractions.asciidoc chapter_05_high_gear_low_gear…
fushall Feb 2, 2025
c331211
update appendix_csvs.asciidoc appendix_django.asciidoc appendix_proje…
fushall Feb 2, 2025
4061a30
update chapter_06_uow.asciidoc
fushall Feb 2, 2025
eff72ed
update chapter_07_aggregate.asciidoc
fushall Feb 2, 2025
27391a9
update chapter_08_events_and_message_bus.asciidoc chapter_09_all_mess…
fushall Feb 2, 2025
99fcb6c
update chapter_09_all_messagebus.asciidoc
fushall Feb 2, 2025
0fda86c
update chapter_10_commands.asciidoc
fushall Feb 2, 2025
397610e
update chapter_11_external_events.asciidoc
fushall Feb 2, 2025
4c894ea
update chapter_12_cqrs.asciidoc
fushall Feb 2, 2025
afa9761
update chapter_13_dependency_injection.asciidoc
fushall Feb 2, 2025
8b64928
update part2.asciidoc
fushall Feb 2, 2025
bea3fd5
update epilogue_1_how_to_get_there_from_here.asciidoc
fushall Feb 2, 2025
0ed1605
update appendix_project_structure.asciidoc
fushall Feb 3, 2025
ddb7312
update appendix_validation.asciidoc
fushall Feb 3, 2025
fc33fd6
Merge branch 'master' into zh
fushall Feb 11, 2025
f83d76d
update chapter_03_abstractions.asciidoc
fushall Feb 11, 2025
6326789
update chapter_01_domain_model.asciidoc
fushall Feb 14, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -13,3 +13,4 @@ acknowledgements.html
epilogue_1_how_to_get_there_from_here.html
epilogue_2_footguns.html
images/*.html
.idea/
54 changes: 29 additions & 25 deletions Readme.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,35 +6,39 @@


## Table of Contents
目录

O'Reilly have generously said that we will be able to publish this book under a [CC license](license.txt),
In the meantime, pull requests, typofixes, and more substantial feedback + suggestions are enthusiastically solicited.

| Chapter | |
| ------- | ----- |
| [Preface](preface.asciidoc) | |
| [Introduction: Why do our designs go wrong?](introduction.asciidoc)| ||
| [**Part 1 Intro**](part1.asciidoc) | |
| [Chapter 1: Domain Model](chapter_01_domain_model.asciidoc) | [![Build Status](https://travis-ci.org/cosmicpython/code.svg?branch=chapter_01_domain_model)](https://travis-ci.org/cosmicpython/code) |
| [Chapter 2: Repository](chapter_02_repository.asciidoc) | [![Build Status](https://travis-ci.org/cosmicpython/code.svg?branch=chapter_02_repository)](https://travis-ci.org/cosmicpython/code) |
| [Chapter 3: Interlude: Abstractions](chapter_03_abstractions.asciidoc) | |
| [Chapter 4: Service Layer (and Flask API)](chapter_04_service_layer.asciidoc) | [![Build Status](https://travis-ci.org/cosmicpython/code.svg?branch=chapter_04_service_layer)](https://travis-ci.org/cosmicpython/code) |
| [Chapter 5: TDD in High Gear and Low Gear](chapter_05_high_gear_low_gear.asciidoc) | [![Build Status](https://travis-ci.org/cosmicpython/code.svg?branch=chapter_05_high_gear_low_gear)](https://travis-ci.org/cosmicpython/code) |
| [Chapter 6: Unit of Work](chapter_06_uow.asciidoc) | [![Build Status](https://travis-ci.org/cosmicpython/code.svg?branch=chapter_06_uow)](https://travis-ci.org/cosmicpython/code) |
| [Chapter 7: Aggregates](chapter_07_aggregate.asciidoc) | [![Build Status](https://travis-ci.org/cosmicpython/code.svg?branch=chapter_07_aggregate)](https://travis-ci.org/cosmicpython/code) |
| [**Part 2 Intro**](part2.asciidoc) | |
| [Chapter 8: Domain Events and a Simple Message Bus](chapter_08_events_and_message_bus.asciidoc) | [![Build Status](https://travis-ci.org/cosmicpython/code.svg?branch=chapter_08_events_and_message_bus)](https://travis-ci.org/cosmicpython/code) |
| [Chapter 9: Going to Town on the MessageBus](chapter_09_all_messagebus.asciidoc) | [![Build Status](https://travis-ci.org/cosmicpython/code.svg?branch=chapter_09_all_messagebus)](https://travis-ci.org/cosmicpython/code) |
| [Chapter 10: Commands](chapter_10_commands.asciidoc) | [![Build Status](https://travis-ci.org/cosmicpython/code.svg?branch=chapter_10_commands)](https://travis-ci.org/cosmicpython/code) |
| [Chapter 11: External Events for Integration](chapter_11_external_events.asciidoc) | [![Build Status](https://travis-ci.org/cosmicpython/code.svg?branch=chapter_11_external_events)](https://travis-ci.org/cosmicpython/code) |
| [Chapter 12: CQRS](chapter_12_cqrs.asciidoc) | [![Build Status](https://travis-ci.org/cosmicpython/code.svg?branch=chapter_12_cqrs)](https://travis-ci.org/cosmicpython/code) |
| [Chapter 13: Dependency Injection](chapter_13_dependency_injection.asciidoc) | [![Build Status](https://travis-ci.org/cosmicpython/code.svg?branch=chapter_13_dependency_injection)](https://travis-ci.org/cosmicpython/code) |
| [Epilogue: How do I get there from here?](epilogue_1_how_to_get_there_from_here.asciidoc) | |
| [Appendix A: Recap table](appendix_ds1_table.asciidoc) | |
| [Appendix B: Project Structure](appendix_project_structure.asciidoc) | [![Build Status](https://travis-ci.org/cosmicpython/code.svg?branch=appendix_project_structure)](https://travis-ci.org/cosmicpython/code) |
| [Appendix C: A major infrastructure change, made easy](appendix_csvs.asciidoc) | [![Build Status](https://travis-ci.org/cosmicpython/code.svg?branch=appendix_csvs)](https://travis-ci.org/cosmicpython/code) |
| [Appendix D: Django](appendix_django.asciidoc) | [![Build Status](https://travis-ci.org/cosmicpython/code.svg?branch=appendix_django)](https://travis-ci.org/cosmicpython/code) |
| [Appendix F: Validation](appendix_validation.asciidoc) | |
O'Reilly 大方地表示,我们将能够以 [CC 许可证](license.txt) 发布本书。
与此同时,我们热情欢迎有关拉取请求、错别字修正以及更深入的反馈与建议。

| Chapter<br/>章节 | |
|--------------------------------------------------------------------------------------------------------------------------| ----- |
| [Preface<br/>前言(已翻译)](preface.asciidoc) | |
| [Introduction: Why do our designs go wrong?<br/>引言:为什么我们的设计会出问题?(已翻译)](introduction.asciidoc) | ||
| [**Part 1 Intro<br/>第一部分简介(已翻译)**](part1.asciidoc) | |
| [Chapter 1: Domain Model<br/>第一章:领域模型(已翻译)](chapter_01_domain_model.asciidoc) | [![Build Status](https://travis-ci.org/cosmicpython/code.svg?branch=chapter_01_domain_model)](https://travis-ci.org/cosmicpython/code) |
| [Chapter 2: Repository<br/>第二章:仓储(已翻译)](chapter_02_repository.asciidoc) | [![Build Status](https://travis-ci.org/cosmicpython/code.svg?branch=chapter_02_repository)](https://travis-ci.org/cosmicpython/code) |
| [Chapter 3: Interlude: Abstractions<br/>第三章:插曲:抽象(已翻译)](chapter_03_abstractions.asciidoc) | |
| [Chapter 4: Service Layer (and Flask API)<br/>第四章:服务层(和 Flask API)(已翻译)](chapter_04_service_layer.asciidoc) | [![Build Status](https://travis-ci.org/cosmicpython/code.svg?branch=chapter_04_service_layer)](https://travis-ci.org/cosmicpython/code) |
| [Chapter 5: TDD in High Gear and Low Gear<br/>第五章:高速档与低速档中的测试驱动开发(TDD)(已翻译)](chapter_05_high_gear_low_gear.asciidoc) | [![Build Status](https://travis-ci.org/cosmicpython/code.svg?branch=chapter_05_high_gear_low_gear)](https://travis-ci.org/cosmicpython/code) |
| [Chapter 6: Unit of Work<br/>第六章:工作单元(已翻译)](chapter_06_uow.asciidoc) | [![Build Status](https://travis-ci.org/cosmicpython/code.svg?branch=chapter_06_uow)](https://travis-ci.org/cosmicpython/code) |
| [Chapter 7: Aggregates<br/>第七章:聚合(已翻译)](chapter_07_aggregate.asciidoc) | [![Build Status](https://travis-ci.org/cosmicpython/code.svg?branch=chapter_07_aggregate)](https://travis-ci.org/cosmicpython/code) |
| [**Part 2 Intro<br/>第二部分简介(已翻译)**](part2.asciidoc) | |
| [Chapter 8: Domain Events and a Simple Message Bus<br/>第八章:领域事件与简单消息总线(已翻译)](chapter_08_events_and_message_bus.asciidoc) | [![Build Status](https://travis-ci.org/cosmicpython/code.svg?branch=chapter_08_events_and_message_bus)](https://travis-ci.org/cosmicpython/code) |
| [Chapter 9: Going to Town on the MessageBus<br/>第九章:深入探讨消息总线(已翻译)](chapter_09_all_messagebus.asciidoc) | [![Build Status](https://travis-ci.org/cosmicpython/code.svg?branch=chapter_09_all_messagebus)](https://travis-ci.org/cosmicpython/code) |
| [Chapter 10: Commands<br/>第十章:命令(已翻译)](chapter_10_commands.asciidoc) | [![Build Status](https://travis-ci.org/cosmicpython/code.svg?branch=chapter_10_commands)](https://travis-ci.org/cosmicpython/code) |
| [Chapter 11: External Events for Integration<br/>第十一章:集成外部事件(已翻译)](chapter_11_external_events.asciidoc) | [![Build Status](https://travis-ci.org/cosmicpython/code.svg?branch=chapter_11_external_events)](https://travis-ci.org/cosmicpython/code) |
| [Chapter 12: CQRS<br/>第十二章:命令查询责任分离(已翻译)](chapter_12_cqrs.asciidoc) | [![Build Status](https://travis-ci.org/cosmicpython/code.svg?branch=chapter_12_cqrs)](https://travis-ci.org/cosmicpython/code) |
| [Chapter 13: Dependency Injection<br/>第十三章:依赖注入(已翻译)](chapter_13_dependency_injection.asciidoc) | [![Build Status](https://travis-ci.org/cosmicpython/code.svg?branch=chapter_13_dependency_injection)](https://travis-ci.org/cosmicpython/code) |
| [Epilogue: How do I get there from here?<br/>尾声:我该如何开始?(已翻译)](epilogue_1_how_to_get_there_from_here.asciidoc) | |
| [Appendix A: Recap table<br/>附录A:总结表格(已翻译)](appendix_ds1_table.asciidoc) | |
| [Appendix B: Project Structure<br/>附录B:项目结构(已翻译)](appendix_project_structure.asciidoc) | [![Build Status](https://travis-ci.org/cosmicpython/code.svg?branch=appendix_project_structure)](https://travis-ci.org/cosmicpython/code) |
| [Appendix C: A major infrastructure change, made easy<br/>附录C:轻松替换重要的基础设施(已翻译)](appendix_csvs.asciidoc) | [![Build Status](https://travis-ci.org/cosmicpython/code.svg?branch=appendix_csvs)](https://travis-ci.org/cosmicpython/code) |
| [Appendix D: Django<br/>附录D:Django(已翻译)](appendix_django.asciidoc) | [![Build Status](https://travis-ci.org/cosmicpython/code.svg?branch=appendix_django)](https://travis-ci.org/cosmicpython/code) |
| [Appendix F: Validation<br/>附录F:校验(已翻译)](appendix_validation.asciidoc) | |



Expand Down
52 changes: 46 additions & 6 deletions appendix_csvs.asciidoc
Original file line number Diff line number Diff line change
@@ -1,28 +1,40 @@
[[appendix_csvs]]
[appendix]
== Swapping Out the Infrastructure: [.keep-together]#Do Everything with CSVs#
更换基础设施:用CSV完成一切

((("CSVs, doing everything with", id="ix_CSV")))
This appendix is intended as a little illustration of the benefits of the
Repository, Unit of Work, and Service Layer patterns. It's intended to
follow from <<chapter_06_uow>>.

本附录旨在稍作说明 _仓储_、工作单元和服务层模式的优势。它是为了衔接<<chapter_06_uow>>的内容。

Just as we finish building out our Flask API and getting it ready for release,
the business comes to us apologetically, saying they're not ready to use our API
and asking if we could build a thing that reads just batches and orders from a couple of
CSVs and outputs a third CSV with allocations.

就在我们完成 _Flask_ API 的构建并准备发布时,业务团队带着歉意找到我们,说他们还没准备好使用我们的 API,
并询问我们是否能构建一个能够从几个 CSV 中读取批次和订单数据,并输出第三个包含分配结果的 CSV 的工具。

Ordinarily this is the kind of thing that might have a team cursing and spitting
and making notes for their memoirs. But not us! Oh no, we've ensured that
our infrastructure concerns are nicely decoupled from our domain model and
service layer. Switching to CSVs will be a simple matter of writing a couple
of new `Repository` and `UnitOfWork` classes, and then we'll be able to reuse
_all_ of our logic from the domain layer and the service layer.

通常情况下,这种需求可能会让团队咒骂连连、怒气冲天,并将其记入他们的回忆录。但我们不一样!哦不,
我们已经确保我们的基础设施逻辑与领域模型和服务层完美解耦。切换到 CSV 只需要编写几个新的 `仓储` 和 `工作单元` 类就可以了,
之后我们就能够重用领域层和服务层的 _所有_ 逻辑。

Here's an E2E test to show you how the CSVs flow in and out:

下面是一个端到端(E2E)测试,向你展示 CSV 数据是如何流入和流出的:

[[first_csv_test]]
.A first CSV test (tests/e2e/test_csv.py)
.A first CSV test (tests/e2e/test_csv.py)(第一个 CSV 测试)
====
[source,python]
----
Expand Down Expand Up @@ -58,9 +70,11 @@ def test_cli_app_reads_csvs_with_batches_and_orders_and_outputs_allocations(make
Diving in and implementing without thinking about repositories and all
that jazz, you might start with something like this:

如果不考虑 _仓储_ 等各种模式,直接开始实现,你可能会从类似这样的代码入手:


[[first_cut_csvs]]
.A first cut of our CSV reader/writer (src/bin/allocate-from-csv)
.A first cut of our CSV reader/writer (src/bin/allocate-from-csv)(CSV 读写器的初步实现)
====
[source,python]
[role="non-head"]
Expand Down Expand Up @@ -120,12 +134,16 @@ if __name__ == "__main__":
It's not looking too bad! And we're reusing our domain model objects
and our domain service.

看起来还不错!而且我们复用了领域模型对象和领域服务。

But it's not going to work. Existing allocations need to also be part
of our permanent CSV storage. We can write a second test to force us to improve
things:

但这行不通。现有的分配也需要成为我们永久 CSV 存储的一部分。我们可以编写第二个测试来促使我们改进:

[[second_csv_test]]
.And another one, with existing allocations (tests/e2e/test_csv.py)
.And another one, with existing allocations (tests/e2e/test_csv.py)(另一个现有分配的测试)
====
[source,python]
----
Expand Down Expand Up @@ -164,11 +182,18 @@ def test_cli_app_also_reads_existing_allocations_and_can_append_to_them(make_csv
And we could keep hacking about and adding extra lines to that `load_batches` function,
and some sort of way of tracking and saving new allocations—but we already have a model for doing that! It's called our Repository and Unit of Work patterns.

我们可以继续不断折腾,在 `load_batches` 函数中添加额外的代码,以及某种方式来跟踪和保存新的分配——但我们已经
有一个现成的模型来处理这些问题了!这就是我们的 _仓储_ 和工作单元模式。

All we need to do ("all we need to do") is reimplement those same abstractions, but
with CSVs underlying them instead of a database. And as you'll see, it really is relatively straightforward.

我们所需要做的(“我们所需要做的”)只是重新实现这些相同的抽象,但用 CSV 作为其底层存储,而不是数据库。
正如你将看到的,这实际上相对来说相当简单。


=== Implementing a Repository and Unit of Work for CSVs
为 CSV 实现一个 _仓储_ 和工作单元


((("repositories", "CSV-based repository")))
Expand All @@ -178,8 +203,12 @@ different CSVs_ (one for batches and one for allocations), and it gives us just
the familiar `.list()` API, which provides the illusion of an in-memory
collection of domain objects:

以下是一个基于 CSV 的 _仓储_ 的实现示例。它抽象了从磁盘读取 CSV 的所有逻辑,
包括必须读取 _两个不同的 CSV_ (一个用于批次,一个用于分配)的事实,并为我们提供了熟悉的 `.list()` API,
这营造出一个内存中领域对象集合的假象:

[[csv_repository]]
.A repository that uses CSV as its storage mechanism (src/allocation/service_layer/csv_uow.py)
.A repository that uses CSV as its storage mechanism (src/allocation/service_layer/csv_uow.py)(一个使用 CSV 作为存储机制的仓储)
====
[source,python]
----
Expand Down Expand Up @@ -229,10 +258,12 @@ class CsvRepository(repository.AbstractRepository):
((("Unit of Work pattern", "UoW for CSVs")))
And here's what a UoW for CSVs would look like:

以下是基于 CSV 的工作单元 (UoW) 的实现示例:



[[csvs_uow]]
.A UoW for CSVs: commit = csv.writer (src/allocation/service_layer/csv_uow.py)
.A UoW for CSVs: commit = csv.writer (src/allocation/service_layer/csv_uow.py)(基于 CSV 的工作单元:commit = csv.writer)
====
[source,python]
----
Expand Down Expand Up @@ -261,9 +292,12 @@ and allocations to CSV is pared down to what it should be—a bit
of code for reading order lines, and a bit of code that invokes our
_existing_ service layer:

一旦我们实现了这些,我们的 CLI 应用程序,用于读取和写入批次和分配到 CSV,就可以被简化为它应有的样子——一些用于读取订单项的代码,
以及一些调用我们 _现有_ 服务层的代码:

[role="nobreakinside less_space"]
[[final_cli]]
.Allocation with CSVs in nine lines (src/bin/allocate-from-csv)
.Allocation with CSVs in nine lines (src/bin/allocate-from-csv)(九行代码实现用 CSV 进行分配)
====
[source,python]
----
Expand All @@ -283,6 +317,12 @@ def main(folder):
((("CSVs, doing everything with", startref="ix_CSV")))
Ta-da! _Now are y'all impressed or what_?

瞧! _现在你们是不是感到惊叹了?_

Much love,

满怀敬意,

Bob and Harry

Bob 和 Harry
Loading