使用 Python 实现架构模式

buy the book ribbon 目录

前言

您可能想知道我们是谁,以及我们为什么要写这本书。

在 Harry 的上一本书 Test-Driven Development with Python (O’Reilly) 的结尾,他发现自己提出了一堆关于架构的问题,例如,构建应用程序的最佳方式是什么,使其易于测试?更具体地说,如何确保您的核心业务逻辑被单元测试覆盖,并最大限度地减少所需的集成和端到端测试的数量?他含糊地提到了 "Hexagonal Architecture" 和 "Ports and Adapters" 以及 "Functional Core, Imperative Shell",但如果他诚实的话,他不得不承认这些他并没有真正理解或在实践中做过的事情。

然后他很幸运地遇到了 Bob,Bob 拥有所有这些问题的答案。

Bob 最终成为了一名软件架构师,因为他的团队中没有其他人这样做。结果证明他在这方面很糟糕,但他很幸运地遇到了 Ian Cooper,他教了他编写和思考代码的新方法。

管理复杂性,解决业务问题

我们都在 MADE.com 工作,这是一家在网上销售家具的欧洲电子商务公司;在那里,我们应用本书中的技术来构建分布式系统,以模拟现实世界的业务问题。我们的示例领域是 Bob 为 MADE 构建的第一个系统,本书试图记录下我们在新程序员加入我们的团队时必须教给他们的所有东西。

MADE.com 运营着一个由货运合作伙伴和制造商组成的全球供应链。为了保持低成本,我们尝试优化库存到我们仓库的交付,以便我们不会有未售出的商品堆积在那里。

理想情况下,您想购买的沙发会在您决定购买的当天到达港口,我们将直接运到您家,而无需将其存储起来。当货物需要三个月才能通过集装箱船到达时,掌握正确的时机是一项棘手的平衡行为。在此过程中,东西会损坏或被水损坏,风暴会导致意外延误,物流合作伙伴会错误处理货物,文书工作会丢失,客户会改变主意并修改订单,等等。

我们通过构建智能软件来解决这些问题,这些软件代表了现实世界中发生的各种操作,以便我们可以尽可能多地自动化业务。

为什么选择 Python?

如果您正在阅读本书,我们可能不需要说服您 Python 非常棒,因此真正的问题是“为什么 Python 社区需要这样一本书?”答案与 Python 的流行度和成熟度有关:虽然 Python 可能是世界上增长最快的编程语言,并且正在接近绝对流行度排行榜的榜首,但它才刚刚开始解决 C# 和 Java 世界多年来一直在解决的各种问题。初创企业变成了真正的企业;Web 应用程序和脚本自动化正在变成(小声说)企业 软件

在 Python 世界中,我们经常引用 Python 之禅:“应该有一种——最好只有一种——显而易见的方法来做到这一点。” [1] 不幸的是,随着项目规模的增长,最明显的方式并不总是帮助您管理复杂性和不断变化的需求的方式。

我们在本书中讨论的所有技术和模式都不是新的,但它们对 Python 世界来说大多是新的。本书不能替代该领域的经典著作,例如 Eric Evans 的 Domain-Driven Design 或 Martin Fowler 的 Patterns of Enterprise Application Architecture (均由 Addison-Wesley Professional 出版)——我们经常提到并鼓励您去阅读。

但文献中的所有经典代码示例往往都是用 Java 或 C++/# 编写的,如果您是一个 Python 人,并且已经很长时间没有使用这两种语言了(或者实际上根本没有使用过),那么这些代码清单可能会非常…​令人头疼。最新版的另一本经典文本,Fowler 的 Refactoring (Addison-Wesley Professional) 是用 JavaScript 编写的,是有原因的。

TDD、DDD 和事件驱动架构

为了声名狼藉,我们知道有三种管理复杂性的工具:

  1. Test-driven development (TDD) 帮助我们构建正确的代码,并使我们能够重构或添加新功能,而不用担心回归。但很难充分利用我们的测试:我们如何确保它们尽可能快地运行?我们如何从快速、无依赖的单元测试中获得尽可能多的覆盖率和反馈,并最大限度地减少速度较慢、不稳定的端到端测试的数量?
  2. Domain-driven design (DDD) 要求我们将精力集中在构建业务领域的一个良好模型上,但我们如何确保我们的模型不会受到基础设施问题的阻碍,并且不会变得难以更改?
  3. 通过消息集成的松散耦合(微)服务(有时称为 reactive microservices)是一种在多个应用程序或业务领域中管理复杂性的行之有效的答案。但如何使它们与 Python 世界的既定工具 (Flask、Django、Celery 等) 相适应并不总是显而易见的。

注意 | 如果您没有使用(或对)微服务感兴趣,请不要灰心。我们讨论的绝大多数模式,包括大部分事件驱动架构材料,都绝对适用于单体架构。 ---|--- 本书的目标是介绍几种经典的架构模式,并展示它们如何支持 TDD、DDD 和事件驱动服务。我们希望它能作为以 Pythonic 方式实现它们的参考,并且人们可以将其作为进一步研究该领域的第一步。

谁应该阅读本书

以下是我们对您(亲爱的读者)的一些假设:

我们围绕一个示例应用程序构建我们对架构模式的探索,并逐章构建它。我们在工作中会使用 TDD,因此我们倾向于先展示测试列表,然后再展示实现。如果您不习惯先进行测试,那么一开始可能会觉得有点奇怪,但我们希望您很快就会习惯在看到代码如何在内部构建之前先看到代码“被使用”(即从外部)。

我们使用一些特定的 Python 框架和技术,包括 Flask、SQLAlchemy 和 pytest,以及 Docker 和 Redis。如果您已经熟悉它们,那不会有什么坏处,但我们认为这不是必需的。本书的主要目标之一是构建一个架构,使特定的技术选择成为次要的实现细节。

您将学到的内容的简要概述

本书分为两个部分;以下是我们将涵盖的主题及其所在的章节的概览。

#part1

领域建模和 DDD(第 127 章)

在某种程度上,每个人都学到了一条教训,即复杂的业务问题需要以代码的形式反映出来,以领域模型的形式。但是,为什么总是很难做到这一点,而又不会与基础设施问题、我们的 Web 框架或其他任何东西纠缠在一起呢?在第一章中,我们将概述 domain modeling 和 DDD,并展示如何开始使用没有外部依赖项的快速单元测试模型。稍后,我们将回到 DDD 模式,讨论如何选择正确的聚合,以及此选择与数据完整性问题有何关系。

Repository、Service Layer 和 Unit of Work 模式(第 245 章)

在这三章中,我们介绍了三个密切相关且相互加强的模式,这些模式支持我们保持模型免受不必要依赖项影响的雄心。我们在持久存储周围构建了一个抽象层,并构建了一个服务层来定义系统的入口点并捕获主要用例。我们展示了这一层如何轻松地为我们的系统构建瘦入口点,无论是 Flask API 还是 CLI。

关于测试和抽象的一些思考(第 35 章)

在介绍了第一个抽象(Repository 模式)之后,我们借此机会对如何选择抽象以及它们在选择如何将我们的软件耦合在一起方面的作用进行一般性讨论。在介绍了 Service Layer 模式之后,我们将讨论一下如何实现 test pyramid 并在尽可能高的抽象级别编写单元测试。

#part2

事件驱动架构(第 8-11 章)

我们介绍了另外三个相互加强的模式:Domain Events、Message Bus 和 Handler 模式。Domain events 是捕捉系统中的某些交互是其他交互的触发器这一想法的工具。我们使用 message bus 允许操作触发事件并调用适当的 handlers。我们继续讨论如何将事件用作微服务架构中服务之间集成的模式。最后,我们区分 commandsevents。我们的应用程序从根本上来说是一个消息处理系统。

Command-query responsibility segregation ([chapter_12_cqrs])

我们展示了一个 command-query responsibility segregation 的例子,无论有没有事件。

Dependency injection ([chapter_13_dependency_injection])

我们整理了显式和隐式依赖项,并实现了一个简单的依赖注入框架。

附加内容

我该如何从这里到达那里? ([epilogue_1_how_to_get_there_from_here])

当您从头开始展示一个简单的例子时,实现架构模式总是看起来很容易,但你们中的许多人可能会想知道如何将这些原则应用于现有的软件。我们将在尾声中提供一些提示,并提供一些进一步阅读的链接。

示例代码和一起编码

您正在阅读一本书,但您可能会同意我们的观点,即学习代码的最佳方式是编写代码。我们从与人结对、与他们一起编写代码以及通过实践学习中学到了我们所知道的大部分知识,我们希望在本书中尽可能多地重现这种体验。

因此,我们围绕一个示例项目构建了本书的结构(尽管我们有时会添加其他示例)。我们将随着章节的进展而构建这个项目,就像您与我们结对,并且我们在每一步都解释我们正在做什么以及原因一样。

但要真正掌握这些模式,您需要摆弄代码并了解它是如何工作的。您可以在 GitHub 上找到所有代码;每个章节都有自己的分支。您还可以在 GitHub 上找到 分支列表

以下是您可以与本书一起编码的三种方式:

特别是如果您打算在自己的项目中应用其中的一些模式,那么完成一个简单的示例是安全练习的好方法。

提示 | 至少,在阅读每一章时,请对我们 repo 中的代码执行 git checkout。能够跳进去并在实际工作应用程序的上下文中查看代码将有助于回答您在进行过程中遇到的许多问题,并使一切变得更加真实。您将在每一章的开头找到有关如何执行此操作的说明。 ---|---

许可

代码(和本书的在线版本)已获得 Creative Commons CC BY-NC-ND 许可,这意味着您可以自由复制并与您喜欢的任何人共享它,用于非商业目的,只要您注明出处。如果您想重新使用本书中的任何内容,并且对许可有任何疑问,请通过 permissions@oreilly.com 联系 O'Reilly。

印刷版的许可不同;请参阅版权页。

本书中使用的约定

本书中使用了以下印刷约定:

斜体

表示新术语、URL、电子邮件地址、文件名和文件扩展名。

等宽字体

用于程序列表,以及段落中引用程序元素(例如变量或函数名称、数据库、数据类型、环境变量、语句和关键字)的情况。

等宽字体加粗

显示用户应按字面键入的命令或其他文本。

等宽字体斜体

显示应替换为用户提供的值或由上下文确定的值的文本。

提示 | 此元素表示提示或建议。 ---|--- 注意 | 此元素表示一般注释。 ---|--- 警告 | 此元素表示警告或注意事项。 ---|---

O’Reilly 在线学习

注意 | 40 多年来,O’Reilly Media 一直提供技术和商业培训、知识和见解,以帮助公司取得成功。 ---|--- 我们独特的专家和创新者网络通过书籍、文章、会议和我们的在线学习平台分享他们的知识和专业知识。O’Reilly 的在线学习平台让您可以按需访问实时培训课程、深入的学习路径、交互式编码环境以及来自 O’Reilly 和 200 多家其他出版商的大量文本和视频。有关更多信息,请访问 http://oreilly.com

如何联系 O'Reilly

请将有关本书的意见和问题发送给出版商:

我们有一个关于本书的网页,我们在其中列出了勘误表、示例和任何其他信息。您可以通过 https://oreil.ly/architecture-patterns-python 访问此页面。

发送电子邮件至 bookquestions@oreilly.com 评论或提出有关本书的技术问题。

有关我们的书籍、课程、会议和新闻的更多信息,请访问我们的网站 http://www.oreilly.com

在 Facebook 上找到我们:http://facebook.com/oreilly 在 Twitter 上关注我们:http://twitter.com/oreillymedia 在 YouTube 上观看我们:http://www.youtube.com/oreillymedia

致谢

感谢我们的技术评论员 David Seddon、Ed Jung 和 Hynek Schlawack:我们绝对不配拥有你们。你们都非常敬业、认真和严谨。你们每个人都非常聪明,你们不同的观点既有用又相互补充。衷心感谢你们。

还要非常感谢迄今为止所有读者的评论和建议:Ian Cooper、Abdullah Ariff、Jonathan Meier、Gil Gonçalves、Matthieu Choplin、Ben Judson、James Gregory、Łukasz Lechowicz、Clinton Roy、Vitorino Araújo、Susan Goodbody、Josh Harwood、Daniel Butler、Liu Haibin、Jimmy Davies、Ignacio Vergara Kausel、Gaia Canestrani、Renne Rocha、pedroabi、Ashia Zawaduk、Jostein Leira、Brandon Rhodes、Jazeps Basko、simkimsia、Adrien Brunet、Sergey Nosko、Dmitry Bychkov 等等;如果我们在此列表中遗漏了您,我们深表歉意。

非常感谢我们的编辑 Corbin Collins 的温柔督促,以及他作为读者不懈的倡导者。同样非常感谢制作人员 Katherine Tozer、Sharon Wilkey、Ellen Troutman-Zaig 和 Rebecca Demarest 的奉献精神、专业精神和对细节的关注。本书由于你们的努力而得到了极大的改进。

本书中剩下的任何错误自然都是我们自己的。

<< 上一页 - Appendix E: Validation 下一页 - Introduction >> 1. python -c "import this" 上次更新时间 2023-11-24 02:20:52 UTC