译者:李光毅
https://zhuanlan.zhihu.com/p/152220505
作者:Bartosz Pietrucha
https://angular-academy.com/angular-architecture-best-practices/
译者序
这是作为译者我想说的话,并非原文中的内容。
我猜此时此刻你心里的疑问一定是:为什么是 Angular,不是 React,不是 Vue,不是 Flux,不是 Redux ? 因为你已经对它们太熟悉了。我个人作为开发者而言最希望是能够汲取到“圈外”的“营养”,这样才能给我的成长带来帮助。我想对各位也是一样。
你不用担心因为不会 Angular 而看不懂这一些列文章,它们基本上谈论的是应用架构——关于设计、组织、抽象,很少会落到具体的实现,即使有,连蒙带猜也能推测出一二。这也能从侧面说明我衷心想推荐这些佳作的原因:通过大段大段的代码阐述很容易;难的是几乎不用代码来跨越语言的说明更高层次的东西,比如 Martin Fowler, Uncle Bob Martin 他们的文章就能如此。
我不评价框架的流行和好坏,我只是把一切呈现在各位的眼前。它们并非和 Flux,Vuex 大相径庭,反而你们会看到它们的影子,但更多的是不一样的东西。我在里面看到了更好的职责划分和抽象。
在文中我会以引用的格式和“译者注”开头穿插一些我的个人备注和带给我启发性的问题,你可以理解为文章的“评论音轨”,但其中问题我不会给予回答。你也可以忽略这些评论
我自己是带着一些疑惑的问题去阅读这些文章的,我也分享给你们,会对理解它们更有帮助:
Angular 架构某些方面会比 Redux 更好吗?或者反之?如果好,好在哪?如果不好,欠缺在哪?当你阅读到在实现同一机制上 Angular 架构中的做法和 React 中不同时,你觉得哪种更好?互换一下呢?无论哪一种架构(Angular / Flux / Redux / Vuex)一定是最佳解吗?如果不是,哪些场景会不适合它们?如果给你一个机会去改进它们?你会怎么做?想象一个当前一个工作中你正在解决的问题,抛开这些架构,假设需要你来设计一个架构,你是否会比已知的这些架构做的更好?哪怕只是针对当前这个 case 而言?
正文
搭建可拓展性(scalable)的软件是一项具有挑战性的任务。当我们在思考前端应用的可拓展性时,我们会想到递增的复杂度,越来越多的业务规则,应用需要加载越来越多的数据以及遍布全球的分布式团队。为了应对上述的各种因素从而保证高质量的交付和避免技术债的产生,健壮及牢固的架构必不可少。虽然 Angular 自身是非常具有技术倾向性的框架,迫使开发者以恰当的方式进行开发,但是开发过程中依然容易犯错。在这篇文章里,我会展示极力推荐的基于最佳实践和经过实战检验的具有良好设计的 Angular 应用架构。我们在本文的终极目标是学习如何设计一个长期内的可持续的开发效率和增加新功能的简易程度的 Angular 应用。为了达成这些目标我们会使用到
应用层次之间恰当的抽象
单向数据流
响应式(reactive)状态管理
模块设计
容器(smart)组件模式和展现(dumb)组件模式
译者注:
我听过一种说法说 React 是类库,Angular 是框架,类库和框架区别在于类库是被你所写的代码调用,而框架是调用你所写的代码。然而这个对 React 真的成立吗?React 不能自成框架吗?一定要搭配的 Redux 使用?
smart component 和 dumb component 在 Angular 中也是成立的
目录
前端的可拓展性问题
软件架构
高层次抽象层
展现层
抽象层
核心层
单向数据流和响应式状态管理
模块设计
模块目录结构
容器组件模式和展现组件模式
总结
前端的可扩展性问题
让我们思考一下在开发现代前端应用中面临扩展性问题。当下前端应用不再“仅仅展现”数据和接受用户的输入。单页面应用(Single Page Applications)为用户提供了丰富交互并使用后端作为数据持久层。这也意味着更多的职责被转移到了软件系统的前端。这导致了我们需要处理的前端逻辑变得越发复杂。不只需求一直在增长,连应用需要加载的数据量也在增加。在这些现实之上,我们还需要考虑到脆弱的的性能问题。最后因为我们的开发团队在增长(或者至少在轮替,有人来有人走) ,让新加入的开发者尽可能快的融入也变得非常重要
解决上述问题的方案之一就是坚固的系统架构。但是这需要代价,代价是从第一天起就要拥抱架构。当系统非常小时,快速交付功能对我们开发者来说非常有快感。在这个阶段,一起都容易理解,所以开发速度非常快。但是除非我们关心架构,否则经过几轮程序员的轮替,开发完奇怪的功能,重构,引入一些新模块之后,开发速度会断崖式下跌。下面的图表展示了在我的开发生涯中通常遇到的情况。这不是任何的科学研究,只代表我对它的印象
软件架构
为了讨论架构的最佳实践和模式,我们首先需要回答一个问题,软件架构是什么。Martin Fowler 把架构定义为:“最高层次的将系统拆解为不同的部分(highest-level breakdown of a system into its parts)” 。基于此我会将软件架构描述为关于软件如何将它部分组合在一起并且相互间通信的规则和约束。通常来说,我们在系统开发中的架构决策在系统演进的过程中很难发生更改。这也是为什么非常重要的是从项目一开始就要对这些决策多加留意,尤其当是我们搭建的软件需要在生产环境中运行多年的话。Robert C. Martin 曾经说过:软件真正的开销在于维护。拥有牢固地基的架构能够帮助减少系统维护的成本
软件架构是关于如何组织它部分的方式以及相互之间通信的规则和约束 译者注:在上面的翻译中我将 parts 翻译成了“部分”。你或许会认为或者翻译为“组件”听上去更合适,但“组件(components)”在不同的编程语言中有更特定的指向。在 React 和 Angular 是我们最熟悉的那个概念,但在 Java 里可以是一个 jar 包。通常来说它是比类大但是又比应用小的一个单位。思考题是,如果技术上允许在 React 应用内存在这么一个单位存在,我们应该按照什么规则组织它?我认为打包时产出的 chunk 或者 bundle 不算,它们是打包优化的产物,而并非是你思考后刻意产生的结果。Martin 的曾经提出的几个问题能够引导你思考:
What are the best partitioning criteria?
What are the relationships that exist between packages, and what design principles govern their use?
Should packages be designed before classes (Top down)? Or should classes be designed before packages (Bottom up)?
How are packages physically represented? In C++? In the development environment?
Once created, to what purpose will we put these packages?
高层次抽象层
首先我们将通过抽象层来分解系统。下图描述了这种分解中使用的常见概念。根本原理是将适当的职责放入适当的层中:核心层(Core),抽象层(abstraction)或者是表现(presentation)层。我们独立的观察每一个层并且分析它的职责。这样的系统分解也明确了通信规则。比如表现层只能够通过抽象层与核心层进行交谈。之后我们学习这种约束带来的优势
表现层
让我们从表现层开始拆解分析我们的系统。这里是所有 Angular 组件存在的地方。这一层的唯一职责是呈现(present)和委托(delegate)。换句话说,它展示界面并且把用户的操作通过抽象层委托给核心层。它知道展示什么(what)和做什么(what),但是它不知道用户的交互应该如何(how)被处理
译者注:这一部分的开头其实给出了一个结论或者说的假设,已经把表现层的职责限定死了。如果我们把它的一部分职责转移给其它的模块会怎么样?可以转移吗?很多时候假设“没有它会怎么样”的思考问题的方式能帮助你更好的理解某些工作原理
下方代码片段展现了CategoriesComponent组件是如何将用户的交互行为委托给了来自抽象层的SetttingsFacade实例(通过addCategory()和updateCategory())的,并且将一些状态呈现在模板中(通过isUpdating$)
@Component({
selector: 'categories',
templateUrl: './categories.component.html',
styleUrls: ['./categories.component.scss']
})