We read every piece of feedback, and take your input very seriously.
To see all available qualifiers, see our documentation.
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
基于 NodeJS and Good Practices 想尝试下分层,在做的时候发现另外一个类似的分层,继续翻译记录。
原文:The Clean Architecture
在过去的几年里,我们看到了一系列关于系统架构的想法。其中包括:
尽管这些架构在细节上都有所不同,但它们非常相似。它们都有相同的目的,即关注点分离。它们都通过将软件划分为不同的层来实现这种分离。每个至少有一层用于业务规则,另一层用于接口。
这些体系结构中的每一个都产生了以下体系:
本文顶部的图示尝试将所有这些架构集成到一个可操作的想法中。
同心环代表软件的不同区域。一般来说,你走得越深入,软件的层次就越高。The outer circles are mechanisms. The inner circles are policies.
使这个架构运行的最重要规则是 依赖规则 。这个规则是 源代码依赖 只能指向 内部 。内环的任何东西都不可能知道外环的任何东西。特别是,在外环中声明某些事物的名称不能被内环中的代码提及。这些包括函数、类、变量或任何其它命名的软件实体。
同样,外环中使用的数据格式不应该被内环使用,特别是如果这些格式是由外环中的框架生成的。我们不希望外环的任何东西对内环产生影响。
实体封装了 规划范围(enterprise wide) 的业务规则。实体可以是具有方法的对象,也可以是一组数据结构和函数。只要实体可以被规划中的许多不同应用程序使用,这就无关紧要了。
如果你没有规划(enterprise),只是编写单个应用程序,那么这些实体就是应用程序的业务对象。它们封装了最一般和最高级的规则。当外部事物发生变化时,它们最不可能发生变化。例如,你不希望这些对象受到页面导航或安全性更改的影响。对任何特定应用程序的操作更改都不应影响实体层。
这层中的软件包含 特定于应用程序 的业务规则。它封装并实现了系统的所有用例。这些用例编排了进出实体的数据流,并指导这些实体使用其 规划范围 的业务规则来实现用例的目的。
我们不希望此层中的更改影响实体。我们也不希望这一层受到外部因素(如数据库、UI 或任何公共框架)变化的影响。这一层与这些问题无关。
但是,我们确实希望对应用程序操作的更改 会 影响用例,从而影响该层中的软件。如果用例的细节发生了变化,那么这层中的一些代码肯定会受到影响。
这层中的软件是一组适配器,用于将最方便适用于用例和实体的数据格式,转换为最方便适用于数据库或 Web 等外部机构的格式。例如,正是这一层将完全包含 GUI 的 MVC 架构。Presenters、Views、Controllers 都属于这里。这个模型就像是从 Controllers 传递到用例的数据结构,然后从用例返回到 Presenters 和 Views 。
类似地,在这层中,数据会转换,从对于实体和用例最方便的形式转换为对于持久化框架(例如数据库)最方便的形式。这个环里的任何代码都不应该知道数据库的任何信息。如果数据库是 SQL 数据库,那么所有 SQL 都应该限制在这一层,特别是这一层中与数据库有关的部分。
这层也是用于将数据从一些外部表单(如外部服务)转换为用例和实体使用的内部表单的适配器。
最外层通常由框架和工具组成,如数据库、Web 框架等。一般来说,除了与向内的下一个环通信的粘合代码外,你不会在这一层编写太多代码。
这一层是所有细节的所在。Web 是一个细节。数据库是一个细节。我们把这些东西放在外面,这样它们尽量小的造成伤害。
不是的,圆环只是示意图。你可能会发现你需要的不仅仅是这四个。没有规则说你必须只有这四个。但是,依赖规则 始终适用。源代码依赖总是向内。当你向内移动时,抽象的层次会增加。最外面的圆环是低层次的具体细节。当你向内移动时,软件变得更加抽象,并且封装了更高级别的策略。最里面的圆是最通用的。
在图示的右下角是一个如何跨越边界的例子。它展示了 Controllers 和 Presenters 与下一层的用例进行通信。注意控制流(flow of control)。它从 Controllers 开始,穿过用例,然后在 Presenters 中执行。还要注意源代码的依赖关系。它们中的每一个都向内指向用例。
我们通常使用 Dependency Inversion Principle 来解决这个明显的矛盾。例如,在像 Java 这样的语言中,我们会安排接口和继承关系,使得源代码依赖关系在边界的正确点上与控制流相反。
例如,考虑用例需要调用 presenter 。但是,这个不能是直接调用,因为这将违反 依赖规则 :外环中的任何名称都不能被内环提及。因此,我们让用例在内环调用一个接口(这里就是图示中的 Use Case Output Port),并让外环的 presenter 实现它。
同样的技术用于跨越架构中的所有边界。我们利用动态多态性来创建与控制流相反的源代码依赖关系,这样无论控制流朝哪个方向,我们都可以遵循 依赖规则 。
通常,跨越边界的数据是简单的数据结构。如果你愿意,可以使用基本结构或简单的数据传输对象。或者数据可以只是函数调用中的参数。或者你可以把放入一个散列表(hashmap),或者把它构造成一个对象。重要的是跨边界传递的数据结构是独立的、简单的。我们不想欺骗和传递 实体 或数据库行。我们不希望数据结构有任何违反 依赖规则 的依赖关系。
例如,许多数据库框架返回一种方便的数据格式来响应查询。我们可以称之为行结构(RowStructure)。我们不想让行结构越过边界向内传递。这将违反 依赖规则 ,因为这将迫使内环知道外环的一些事情。
因此,当我们跨越边界传递数据时,它总是以最方便内环的形式传递。
遵守这些简单的规则并不难,而且会为你今后省去很多麻烦。通过将软件分为多个层,并遵循 依赖规则 ,你将创建一个本质上可测试的系统,其中包含所有的好处。当系统的任何外部部分(如数据库或 web 框架)淘汰时,你能以最小代价替换这些淘汰的元素。
时隔多年,当我再次看《恶之华》的 tv 版本时,有了完全不一样的感受。
记得第一次看的时候,让我感觉到内心很压抑,现在看时,感觉好神奇,能这样直视讨论人内心不一样的一面。
明明只有 13 集,居然换了 4 首片头曲,还有片尾曲很有趣,每当片尾曲的节奏响起时,仿佛强调了主角内心的变化。
不知道什么原因,现在豆瓣直接把部 tv 作品屏蔽了,我第一次看的时候记得很清楚,豆瓣上是有的。
看完 tv 接着去看漫画,发现漫画里面有更多有趣的信息,因为作者也会在漫画结束页进行一些交流。
The text was updated successfully, but these errors were encountered:
No branches or pull requests
目录
引子
基于 NodeJS and Good Practices 想尝试下分层,在做的时候发现另外一个类似的分层,继续翻译记录。
原文:The Clean Architecture
正文
在过去的几年里,我们看到了一系列关于系统架构的想法。其中包括:
尽管这些架构在细节上都有所不同,但它们非常相似。它们都有相同的目的,即关注点分离。它们都通过将软件划分为不同的层来实现这种分离。每个至少有一层用于业务规则,另一层用于接口。
这些体系结构中的每一个都产生了以下体系:
本文顶部的图示尝试将所有这些架构集成到一个可操作的想法中。
依赖规则(The Dependency Rule)
同心环代表软件的不同区域。一般来说,你走得越深入,软件的层次就越高。The outer circles are mechanisms. The inner circles are policies.
使这个架构运行的最重要规则是 依赖规则 。这个规则是 源代码依赖 只能指向 内部 。内环的任何东西都不可能知道外环的任何东西。特别是,在外环中声明某些事物的名称不能被内环中的代码提及。这些包括函数、类、变量或任何其它命名的软件实体。
同样,外环中使用的数据格式不应该被内环使用,特别是如果这些格式是由外环中的框架生成的。我们不希望外环的任何东西对内环产生影响。
实体(Entities)
实体封装了 规划范围(enterprise wide) 的业务规则。实体可以是具有方法的对象,也可以是一组数据结构和函数。只要实体可以被规划中的许多不同应用程序使用,这就无关紧要了。
如果你没有规划(enterprise),只是编写单个应用程序,那么这些实体就是应用程序的业务对象。它们封装了最一般和最高级的规则。当外部事物发生变化时,它们最不可能发生变化。例如,你不希望这些对象受到页面导航或安全性更改的影响。对任何特定应用程序的操作更改都不应影响实体层。
用例(Use Cases)
这层中的软件包含 特定于应用程序 的业务规则。它封装并实现了系统的所有用例。这些用例编排了进出实体的数据流,并指导这些实体使用其 规划范围 的业务规则来实现用例的目的。
我们不希望此层中的更改影响实体。我们也不希望这一层受到外部因素(如数据库、UI 或任何公共框架)变化的影响。这一层与这些问题无关。
但是,我们确实希望对应用程序操作的更改 会 影响用例,从而影响该层中的软件。如果用例的细节发生了变化,那么这层中的一些代码肯定会受到影响。
接口适配器(Interface Adapters)
这层中的软件是一组适配器,用于将最方便适用于用例和实体的数据格式,转换为最方便适用于数据库或 Web 等外部机构的格式。例如,正是这一层将完全包含 GUI 的 MVC 架构。Presenters、Views、Controllers 都属于这里。这个模型就像是从 Controllers 传递到用例的数据结构,然后从用例返回到 Presenters 和 Views 。
类似地,在这层中,数据会转换,从对于实体和用例最方便的形式转换为对于持久化框架(例如数据库)最方便的形式。这个环里的任何代码都不应该知道数据库的任何信息。如果数据库是 SQL 数据库,那么所有 SQL 都应该限制在这一层,特别是这一层中与数据库有关的部分。
这层也是用于将数据从一些外部表单(如外部服务)转换为用例和实体使用的内部表单的适配器。
框架和驱动因素(Frameworks and Drivers)
最外层通常由框架和工具组成,如数据库、Web 框架等。一般来说,除了与向内的下一个环通信的粘合代码外,你不会在这一层编写太多代码。
这一层是所有细节的所在。Web 是一个细节。数据库是一个细节。我们把这些东西放在外面,这样它们尽量小的造成伤害。
只有 4 个环?
不是的,圆环只是示意图。你可能会发现你需要的不仅仅是这四个。没有规则说你必须只有这四个。但是,依赖规则 始终适用。源代码依赖总是向内。当你向内移动时,抽象的层次会增加。最外面的圆环是低层次的具体细节。当你向内移动时,软件变得更加抽象,并且封装了更高级别的策略。最里面的圆是最通用的。
跨越边界
在图示的右下角是一个如何跨越边界的例子。它展示了 Controllers 和 Presenters 与下一层的用例进行通信。注意控制流(flow of control)。它从 Controllers 开始,穿过用例,然后在 Presenters 中执行。还要注意源代码的依赖关系。它们中的每一个都向内指向用例。
我们通常使用 Dependency Inversion Principle 来解决这个明显的矛盾。例如,在像 Java 这样的语言中,我们会安排接口和继承关系,使得源代码依赖关系在边界的正确点上与控制流相反。
例如,考虑用例需要调用 presenter 。但是,这个不能是直接调用,因为这将违反 依赖规则 :外环中的任何名称都不能被内环提及。因此,我们让用例在内环调用一个接口(这里就是图示中的 Use Case Output Port),并让外环的 presenter 实现它。
同样的技术用于跨越架构中的所有边界。我们利用动态多态性来创建与控制流相反的源代码依赖关系,这样无论控制流朝哪个方向,我们都可以遵循 依赖规则 。
什么数据跨越边界
通常,跨越边界的数据是简单的数据结构。如果你愿意,可以使用基本结构或简单的数据传输对象。或者数据可以只是函数调用中的参数。或者你可以把放入一个散列表(hashmap),或者把它构造成一个对象。重要的是跨边界传递的数据结构是独立的、简单的。我们不想欺骗和传递 实体 或数据库行。我们不希望数据结构有任何违反 依赖规则 的依赖关系。
例如,许多数据库框架返回一种方便的数据格式来响应查询。我们可以称之为行结构(RowStructure)。我们不想让行结构越过边界向内传递。这将违反 依赖规则 ,因为这将迫使内环知道外环的一些事情。
因此,当我们跨越边界传递数据时,它总是以最方便内环的形式传递。
结论
遵守这些简单的规则并不难,而且会为你今后省去很多麻烦。通过将软件分为多个层,并遵循 依赖规则 ,你将创建一个本质上可测试的系统,其中包含所有的好处。当系统的任何外部部分(如数据库或 web 框架)淘汰时,你能以最小代价替换这些淘汰的元素。
参考资料
🗑️
时隔多年,当我再次看《恶之华》的 tv 版本时,有了完全不一样的感受。
记得第一次看的时候,让我感觉到内心很压抑,现在看时,感觉好神奇,能这样直视讨论人内心不一样的一面。
明明只有 13 集,居然换了 4 首片头曲,还有片尾曲很有趣,每当片尾曲的节奏响起时,仿佛强调了主角内心的变化。
不知道什么原因,现在豆瓣直接把部 tv 作品屏蔽了,我第一次看的时候记得很清楚,豆瓣上是有的。
看完 tv 接着去看漫画,发现漫画里面有更多有趣的信息,因为作者也会在漫画结束页进行一些交流。
The text was updated successfully, but these errors were encountered: