古语有云:「岁有凶穰;故谷有贵贱;令有缓急;故物有轻重。」旨在告诉後人,做任何事情,一定要先搞清楚状况,把事情的优先顺序排好再开始动手,方为上策。时间有限,但要做的事就是那麽多,「重要的事先做」讲起来容易,做起来真的很难。
接下来的几天,我们会聊一个近年来,後端工程师或多或少都听过的主题:「Clean Architecture」。
Clean Architecture 出现後,对笔者的工作影响非常巨大。笔者不算是架构很强的工程师,但正因如此,笔者发现在做後端工作时,只要照着 Clean Architecture 的规划走,就几乎不会出什麽乱子。而且在结构乾净了以後,测试写起来特别好写,重构起来也比较有个依据。对此,笔者如获至宝!
因此笔者在本系列文章中,才特别想要来「野人献曝」一下,不求能教大家太多专门的知识,但期望有多点人能感受到它的好处,而加以研究,使大家工作能更顺利,那我目的就达到了。
Clean Architecture 是 Uncle Bob 在 2017 年出的一本关於「架构」的书。在这之前,出现过很多经典的「系统架构」设计,如 Hexagonal Architecture, Onion Architecture 等。Uncle Bob 认为,这些架构虽各有千秋,但都有一些相似之处:
Uncle Bob 认为,前述这些很棒的架构设计之所以很棒,乃因它们都具备上面的特性。於是综合这些优点,加上自己的见解,Uncle Bob 在 2017 年提出了「Clean Architecture」这个架构。
Clean Architecture 把系统分成四层,这四层不是由上而下排列,而是由外而内排。 排列的依据为:「越细节的越外面,越核心的越里面。」这四层分别为:
核心业务、重要资料所在地。不管你在什麽场景,做什麽操作,在你的问题领域中不论有没有系统帮忙,你都必须得做的事。
这一层包围在 Entity 之外,定义着对於 Entity 逻辑与资料的使用时机与操作顺序,是一个管「自动化」的家伙。
系统的边界,对外取得请求内容,转换成内层认识的样貌、并寻找适当的 Use Case 来执行任务,最後再转换成外界认识的样貌送出去。同时,系统对外发出的请求,也会在这一层转换。
因为位处系统边界,做的事大多都是一些转换的工作,所以命名为 Interface Adapter。
系统中最细节的部分,大部分都是 I/O,举凡网路、档案、资料库、人机介面等,都属於此范围。
那麽什麽叫核心,又什麽叫细节呢?实际操作时,其实就是:「离 I/O 越近的越细节,在外层;离 I/O 越远的越核心,在内层。」
Uncle Bob 说:「Entity 与 Use Case 是你生意能经营的主要推手,必须慎重对待。I/O 虽然有重要,但是是重要的细节,应该要可以简单被抽换。」
这里留个思考题:「Data driven 与 UI driven 的开发方式,与 Clean Architecture 搭配使用的话,会发生什麽事呢?」
Clean Architecture 讨论了很多设计上的注意事项,而简言之可以归纳出三大原则:
来思考一下。依赖原则说不能由内往外依赖,那当 Use Case 需要操作 Entity,但 Entity 资料存放在 DB 里时,应该怎麽办呢?」里,就会需要呼叫呼叫物件导向设计的 DIP:Dependency Inversion Principle 登场救援了。
DIP 说,业务逻辑不该依赖资料实作,而应使两方共同依赖一个抽像介面。
在上面的场景,内层的 Use Case 不该认识外层的 Repository,所以这时 Use Case 应该要定义一个 Repository 抽象介面,而安心的把这个介面的实作放在 Interface Adapters 层,这样就可以又符合 Clean Architecture 与 DIP,又符合业务需求了。
说到跨层原则,有时候遵守起来挺麻烦的。举例来说,照 Clean Architecture 的规划,Adapter 层只可以认识 Use Case 层的物件,它对最内层的 Entity 应该要一无所知。所以,就算你要回传给前端的物件格式与 Entity 几乎一模一样,也不可以直接回传,要嘛在 Use Case 要转一下格式,要嘛要套用 CQRS 模式,跳过 Use Case 层,真接与同一层的 Repository 合作,让它回传一个客制化的物件。
为什麽这麽麻烦?这时又要请出另一个物件导向设计原则的 SRP:Single Responsibility Principle 了。Entity 身为系统的核心逻辑,理应只关心「领域模型」中最重要的运算与资料,不应该管外层表现的需求。会这样设计,为的就是使核心业务不被外层的细节干扰。你如果为了一时方便,让负责与前端网页沟通的 Adapter 去直接存取 Entity,那以後网页要拿什麽值,要改什麽格式,核心的 Entity 就不得不改了。
注意到了吗?「最内层的 Entity 因为最外层的网页需求,而需要修改」耶!这不是反模式,什麽才是反模式?所以,跨层原则虽麻烦,但好好遵守,架构才会乾净!
使用 Clean Architecture 以後,元件的安排有了依据,核心运算逻辑不会依赖於细节的资料库或是网页,整个系统不论整洁度或是灵活性都比以前好很多。重点是,安排工作时,知道什麽要先做,什麽可以晚点决定,不会进退失据。总之至少目前为止,用起来挺不错的!
谜之声:「事有轻重缓急,月有阴晴圆缺 XD」
图片截自 Wikipedia
ithelp2021
<<: [FGL] 程序开发(3) - 输入用的INPUT系指令与DIALOG
通过执行Web Server Footprinting,我们可以收集到有价值的系统资讯 例如帐户资讯...
Day 27 - 这是一个三方合作的温馨(瘟腥)故事 设计师 : 架站的资料记得拿 Favicon,...
前面我们讲到如何应coroutine的flow和liveData合作,但android其实还推出了另...
前言 在Object [上]中我们介绍了物件的宣告、型态、拷贝等等特性,接下来我们继续介绍物件中都有...
最後一天~~~ 压轴当然是要最好玩的东西啦,讲完今天的内容,大家就可以在介面上自由的创作了! ♠♣今...