Day 30: 遗漏的章节

「目前为止,所有建议无疑将帮助你设计出更好的软件,这些软件是由具有明确边界、职责、依赖关系受控的元件所组成。本章的重点是要强调,如果不考虑实作策略的错综复杂,那麽你最佳的设计意图可能会付之一炬」

「想想要如何将你的设计对应到程序码结构、如何组织程序码以及在 Runtime & Compile 时期应用哪些解耦模式、在适用的情况下保留选项

「记得要务实些,要考虑到团队的规模、技术水平以及解决方案的复杂性和时间及预算的限制,并且要注意其他区域(例如资料模型)中的耦合。魔鬼就藏在实作细节中

取自: Clean Architecture (p.250 & p.264)

CH34: 遗漏的章节

让我们暂时先把「整洁的架构」放在一边,来看看几种设计和组织程序码的方法:

法一: 依套件逐层打包 (Package By Layer)

  • 水平横向分层架构 (Horizontal Layered Architecture)
    最简单的一种设计方法,依据技术角度将程序码水平分层。这些层被用来分类相似型态的东西,层应该只依赖於相邻的层
    https://ithelp.ithome.com.tw/upload/images/20211016/20138643zH3GxQUlZ7.png

  • 书中图例:
    https://ithelp.ithome.com.tw/upload/images/20211016/2013864327Wc0zUrbW.png

  • 说明

    • OrdersController: 用来处理来自 Web 的 Request
    • OrdersService: 与订单有关的「业务逻辑」
    • OrdersRepository: 定义如何存取持久性(Persistent)订单资讯的介面
    • JDBCOrdersRepository: 存取 DB 的实作细节 (使用 JDBC)
  • 分析

    • 采用这种分层架构作为开始是个好方式
    • 一旦软件规模复杂度增长,很快就会发现使用三个大桶来装程序码是不够的。你需要更进一步考虑模组化
    • 且,分层架构不会「尖叫」出任何有关业务领域的东西,多个不同业务领域的程序码都以分层架构摆放、并排时,他们可能看起来很相似

法二: 依功能特性打包 (Package By Feature)

  • 垂直切片划分 (Vertical Slicing)

    • 基於相关的特性 (Features)、领域概念 (Domain Concept) 或聚合根 (Aggregate Roots) 而做的划分。所有型态 (Types) 都放置在单一个 Package 当中,该 Package 的命名会反映出分组概念
      https://ithelp.ithome.com.tw/upload/images/20211016/201386438PDZlXQL1h.png
  • 书中图例:
    https://ithelp.ithome.com.tw/upload/images/20211016/20138643T6eKl6Nb2Q.png

  • 分析

    • 上一节的所有介面和类别都被放置在单一个 Package 中,程序码的最高层级组织现在「尖叫」出一些关於 Orders 的业务领域内容
    • 另一个好处是,当使用案例 (Use Case) 变更,找出所有需要修改的程序码会变得更容易

      「在我看来,两者都不是最理想的选择」

      取自: Clean Architecture (p.252)


法三: 端口和转接器 (Ports & Adapters)

  • 以业务/领域为中心的程序码
    这样的程序码库是由「内部 (Domain)」和「外部 (Infrastructure)」所组成,外部一定要依赖於内部,不会有其他的依赖方式。这种组织原始码的方式也是一种可行的方法
    https://ithelp.ithome.com.tw/upload/images/20211016/20138643x3cPCWtvdN.png

  • 书中图例:
    https://ithelp.ithome.com.tw/upload/images/20211016/20138643amVo6Zv2jg.png

  • 分析

    • 注意:图中的 OrderRepository 已被重新命名为简单的 "Orders" ,这概念来自於 DDD 当中的建议。「内部」所有内容的命名都应尽量使用 「普及的领域语言 (Ubiquitous Language)」 来表达

法四: 依元件打包 (Package By Component)

  • 基於元件的架构 (Component Based Architecture)
    这是一种混合式方法,目标是将『与单个粗粒度 (Coarse-grained) 有关的所有责任』Bunddle 到单一的 Package 中。这是以服务 (Service) 为中心的软件系统观点
    https://ithelp.ithome.com.tw/upload/images/20211018/20138643gpJuIOlO40.png

  • 书中图例:
    https://ithelp.ithome.com.tw/upload/images/20211018/20138643gnpaYCK7Mb.png

  • 分析

    • 一个关键好处是,如果你正在编写需要对 Orders 进行处理的程序码,那麽就只会在一个地方撰写 - OrdersComponent
    • 在元件内部,关注点的分离依然保持不变
    • 业务逻辑与资料持久性是分离的
    • 例: 一个单独的 OrderService 封装「与处理订单有关的所有内容」
  • [补充]: C4 Software Architecture Model

    • 又称 "Context, Containers, Components, and Code",属於 Package By Component 的衍生。有兴趣的读者可再自行 Google

组织与封装

  • 如果将所有型态都宣告为 Public,那麽任何的架构风格都只是一种分组机制而已 (就像文件夹那样)
    当所有型态都宣告为 Public 时,四种架构方法在语法上都是相同的!
    https://ithelp.ithome.com.tw/upload/images/20211018/20138643Vigh1o8loq.png
  • 请勿滥用 "Public" 修饰子!
  • 鼓励使用 编译器 (Compiler) 来强迫团队遵守架构规则,而非自律
    否则当菜鸟工程师加入团队、或者专案时程紧急时,就会发生如下情形...
    https://ithelp.ithome.com.tw/upload/images/20211018/20138643IQe4pZsHhK.png

真的被遗漏的章节...

  • 本次挑战赛之【架构篇】Clean Architecture 共包含 34 个章节及附录。以下几章为笔者考量自身能力 (Firmware 非笔者所长 Orz...)、本书精随,以及时间安排後决定不详细介绍的章节

CH23: Presenter 与 Humble Object

  • [Design Pattern]: "Humble Object"
    将行为分成两个模组,其中一个 Humble 模组包含所有难以测试的东西,另一个模组则相反
  • 以 GUI 测试为例,可划分成 PresenterView 模组
    View: 是难以测试的 Humble Object。不处理资料,仅负责转移到 GUI 中
    Presenter: 是可测试的物件。负责资料和字串的格式化处理,并将其放在一个称之为 View Model 的资料结构中,供 View 模组使用

CH28: 测试边界

  • 脆弱性测试问题 (Fragile Tests Problem)
    测试也是系统的一部分,与系统强烈耦合的测试将导致大量的测试被中断 (Test Case 前後关联太强)
  • 不要依赖於易变的东西
    例:GUI 是易变的,则透过 GUI 运行系统的测试套件必是脆弱的
  • 测试 API
    可以建立一个特定的超能力 API 用以验证所有的业务规则 (可避开安全约束、绕过 DB...等)
    目的是将测试结构和应用程序的结构解耦开来
  • 安全性问题
    某一些测试 API 的超能力是危险的,请将其保存在一个分离的、可独立部署的元件中加以控管

CH29: 整洁的嵌入式架构

https://ithelp.ithome.com.tw/upload/images/20211017/20138643Wyd7B2s5Vg.png

  • 硬体和韧体会随时间推移而过时(Obsolete),随即也需要对软件做相应改动
  • 未妥善管理的硬体和韧体依赖仍是软件的头号杀手
  • 原则:依赖於抽象
    • Operating System Abstraction Layer (OSAL)
    • Hardware Abstraction Layer (HAL)

CH33: 案例研究 - 影片贩售

  • 使用案例 (Use Cases) 分析
  • 元件架构
  • 依赖管理

Reference

  1. Horizontal and Vertical Layers in Software Development
  2. concept persistence layer in category .net
  3. Chapter 1. Layered Architecture
  4. Package by Feature
  5. Hexagonal Architecture with Java and Spring
  6. Ports & Adapters Architecture
  7. Hexagonal Architecture with Java and Spring
  8. 战略设计:重点回顾以及比喻
  9. Coarse-grained vs fine-grained
  10. Component Based Architecture
  11. 用于软件架构的 C4 模型
  12. 软件架构之C4模型
  13. The C4 model for visualising software architecture
  14. gotoberlin2018-modular-monoliths
    意外查到的演讲投影片,内容几乎就是 Chapter 34 的详细补充,有兴趣可自行深入研究

<<:  [第三十只羊] 迷雾森林终章 决斗,抽牌

>>:  Day#30 行百里者半九十

第一天 参赛宣言

经历了前两次的失败,决定还是第一天不要直接写文章! 换个心情,先写了参赛宣言。好好的展开一个挑战的开...

DAY29:实作专案之总结

这次的专题实作,从环境问题到实际设计,都遇到一些不同问题: 像是我们日历元件如果在不同装置下去跑,有...

Day08:【TypeScript 学起来】物件型别 Object Types : object

https://bit.ly/2XuVqBJ (这篇必看,不分享对不起自己) //原来南无观世音菩...

笔记-Multimedia Data Representations

Digitization of Sound(声音数字化) Facts about Sound(关於声...

D10 - 「数位×IN×OUT」

电子助教:「这个标题...我闻到了停刊的味道... (́⊙◞౪◟⊙‵)」 这个章节开始我们要建立「数...