在上一篇文章中我们有:
因此,一些决定已经完成。我们拥有一些工具并已经决定了存储库的外观。
这是我喜欢 polylith 的原因之一:无论您编码什么或您的组织有多大,所有存储库看起来都一样 – 如果您需要多个存储库。
无论您使用 fastapi、flask 还是 django,构建单个或多个库,还是使用 celery 运行后台任务,您的存储库结构都是一致的。
主要优势之一是简化新开发人员的入职流程。假设他们掌握了 polylith,他们将很快熟悉项目结构:可重用组件位于 components 文件夹中,入口点位于 bases 文件夹中,演示脚本位于development 文件夹中,等等。
实体
来自 bob 叔叔的“清洁架构”实体是我们架构的基石,它们是我们架构的最内层。所以我们需要从它们开始,在 polylith 中实体应该作为组件存在。
有多少个组件?
我相信组件的数量取决于解决方案的大小和复杂性。但是,我建议从实体的单个多块组件开始。这种方法有助于保持清晰且重点突出的架构,特别是对于较小的项目。
为什么实体只有一个组件?
避免第三方依赖。
为了最大限度地减少外部依赖并增强架构灵活性,请努力使用python的标准库来表示实体。这包括利用字典、列表、枚举、函数、类和最近的数据类等数据结构。
为什么要避免使用 pydantic 或 django models 等第三方库?
- 与外部框架的耦合:依赖这些库可能会引入与特定框架不必要的耦合。
- 复杂性增加:外部库可能会增加复杂性和潜在的维护问题。
- 灵活性降低:通过限制外部依赖,您可以更轻松地适应需求或技术的变化。
通过遵守这些原则,您可以创建一个健壮且可维护的架构,能够适应未来的变化。
待办事项实体
我们的示例很简单,核心实体是 gordon 的“待办事项”。我们可以向我们的存储库添加一个新组件,但选择正确的名称至关重要。
虽然使用“core”或“main”等通用名称可能很诱人,但选择在域上下文中有意义的名称至关重要。理想情况下,这些名称应与客户或产品所有者使用的术语一致。通过使用特定于域的名称,我们增强了代码的可读性和可维护性,使开发人员和利益相关者更容易理解项目的结构。
存储库工作区名称定义为 todo。因此,我们所有的导入都将遵循以下格式:
from todo.xyz import ... import todo.xyz
为了简单起见,在本示例中,我们将使用实体作为组件名称。但是,在现实场景中,请考虑反映您的域的命名约定。例如,如果您的应用程序围绕文档恢复,则名为恢复的组件将是合适的。同样,为了清晰起见,游戏应用程序可能会使用锦标赛实体。
使用 python polylith 创建组件很简单:
poetry poly create component --name=entities poetry poly sync poetry install # it may be necessary
这将在组件文件夹中添加一个 python 包,这是源树中的新条目:
./components └── todo └── entities ├── __init__.py └── core.py ./test/components └── todo └── entities ├── __init__.py └── test_core.py
python-polylith 工具将为我们生成测试示例,这是一个很好的功能。可以通过在 [tool.polylith.test] 部分中将enabled = true 值设置为 false 来更改workspace.toml 文件中的此行为。
在新的实体组件中,添加了两个文件:__init__.py 和 core.py。您可以重命名 core.py 模块以更好地满足您的需求。常见的做法是通过 __init__.py 公开包的公共 api,同时在 core.py 等其他模块中维护内部组织。
根据要求,目前我们只有一个实体,即 todo 项:
@dataclass class TodoItem: owner: str title: str description: str is_done: bool = False due_date: Optional[date] = None
测试这样一个简单的实体似乎没有必要,但我更喜欢至少测试所有字段的存在。虽然这在贡献者较少的小型项目中似乎并不重要,但它可以防止在拥有许多开发人员的大型项目中出现重大问题。从实体中删除单个字段可能会无意中破坏应用程序的各个部分。
在这部分的拉取请求中,您将看到我为该实体添加了一些基本测试。
已经定义了一些测试,我借此机会添加了 github 工作流程来自动运行每个拉取请求的测试。
结论
- 应用程序基本实体
- ci 设置
接下来:我们来谈谈坚持