这是又一篇臆想文
如果看到文章的您,觉得给您带来了帮助,那纯属瞎猫撞上死耗子。

TL;DR

  • 组件化在做什么,组件是什么
  • 因为 toB 大型应用的历史原因,前端开始需要前端架构设计。或者说前端工程本就应该要架构设计

所以是什么时候前端开发也发展成需要「软件工程」的时代了,还不是现在用户的电脑越来越 nb 浏览器越来越 nb

工程实践变成燃眉之急绝对是近几年「是个🔨就要上云」造成的 —— 应用都希望变成 SaaS;都希望敏捷无感更新;都希望多端同步(这里不指跨平台)……

演变到这就产生一个问题

问题

印象中的 toC 应用,它对于「历史包袱」的处理可以非常简单粗暴:

都拖油瓶了,这不重构?顺道抬 KPI
既然都重构了,那整点新家伙,干活不累顺道抬 KPI (x2)

所以 toC 应用总是会用上最新的技术,而且 toC 应用毕竟是直接面向个体用户的应用,所以无时无刻都在优化体验也说不定

但 toB 或者内部平台可不能说整就整,至少会遇到这些问题:

  • “能用就行”
  • 使用时间非常长,甚至可能公司开多久软件用多久

如果再遇上几个持有「Promise 没用过,应该是 vue 新加的功能」[1]观点的优质前端,这个应用的代码最后只能是 shit 了

组件化

我的二面可能会问一个没有什么正确答案也没什么理由的烂问题:

如何理解组件化?

但总能得到典型回答:

工作中经常重复出现的功能成组件

甚至是非典型回答:

因为现在都用 vue,每一个 .vue 都是组件,这是 vue 要求的

其中最经常得到的答案中,有一个关键动作:抽。所以又是什么时候组件化的定义变成了“抽组件”

何为组件

在「C4模型」的官网中,关于组件的第一句话:

The word “component” is a hugely overloaded term in the software development industry,

很多地方其实都有组件概念,包括不限于 sketch 等设计应用都有组件概念。但一切都有相似之处:它们都可以是一个原子,一个单位,一个定义了接口能优秀完成某一部分工作的单位或者说 group。同理也适用于 sketch component —— 你定义了一个组件应该是怎样的元素构成与可变

所以上面的那句话,有后半句的:

but in this context a component is a grouping of related functionality encapsulated behind a well-defined interface.

If you’re using a language like Java or C#, the simplest way to think of a component is that it’s a collection of implementation classes behind an interface. Aspects such as how those components are packaged (e.g. one component vs many components per JAR file, DLL, shared library, etc) is a separate and orthogonal concern.

为什么开始强调组件了

确实没错,当前流行三大视图框架中,都有组件概念,即一个 vue 文件之于 vue,一个函数之于 react,一个 component 之于 ng 都是各领域定义的“组件”,甚至是「一切都是组件」。但这仅是强调了这是某个框架的原子,而业务形态的组件是由业务的,而不是框架决定的

所以一个组件,并不是把代码放在一个 vue 文件,这个就是组件。毕竟你这个时候你可以问:你的应用下是不是有一个 pages 目录?下面也有一堆 vue 文件,他们每一个都是组件?接着你就尽情围观前端圈内最大双标现场

怎样就是一个组件

我自己给定义了几点:

  • 输入输出是确定的(像函数)
  • 可单元测试的
  • “高内聚,低耦合”(现在还写这句话都觉得有些羞耻)

举个例子,拿我以前很喜欢的某公司的官网做栗子(我觉得还是憋猜是哪个公司了吧,我给🐴成这样还猜得到?)

这张图,大多数前端会认为,红框可以是组件。甚至认为绿框在某开源组件库能找到

放心我没⭕️ 错,很多前端都会这么想的。全都 margin-top 给它安排得明明白白,这样最后一个就不用处理了

但总有一部分的前端会这么认为:

这样做几个好处:

  • 因为可以让组件弹性方便布局。
  • 那个小标题肯定复用很多,别的地方也会有类似设计
  • 上下边距啊,在 page map 组件的时候给套上不就好了

所以很少前端会想到以下甚至更多:

所以先弄清楚:谁是原子

也就是「哪些是组件?」这个问题在设计阶段就应该确定了,而不是“抽成组件”

所以在软件开发上,本就没有所谓的前端后端啥端的区别,软件该怎么写就得怎么写。一个组件可以是一个对象

而这还只是布局而已,也就是所谓前端工程师的「核心工作」

工程化

说实话,当今被冠以「工程师」之名的前端开发,没有几个懂工程(包括写这篇文章的five)

问题在于越来越多的软件都希望以浏览器为容器运行。所以并不是前端需要工程化,而是软件形态在发生改变。而这也可以继续解释下来会发生的事情 —— JavaScript 会越来越不顶用,需要 WebAssembly 做更多事情;使用 Web Worker 做跟渲染无关的事情等等等等

再同理,并不是开始要求前端开发需要懂工程了,而是这是一个软件工程师要知道的东西

什么时候前端也要工程设计了

是个应用就需要设计,或者说前端一直需要工程设计,只不过长时间被认为不需要和不被理解

最近的「微前端」更多的适用场景也是建立于此 —— 太旧的应用你实在维护不动了,新增的东西就以「微前端」的形式加入,这样做不破坏原本的应用,同时可以用较新的技术维护新功能

toB 大应用,在「前端」内容中更多是表单表格,以及很多弱交互的东西,可能最重的交互也就可视化配置。其注定了不需要设计驱动,更多的都在数据处理上,也就是「弄清数据流」。并且这类应用只会越做越大 (直到流产,或者换老板),而且它的直接用户是另一个企业,甚至可能是以「私有部署」的形式售卖。所以要做的是尽可能稳定与高效

所以为了运行稳定不背锅,不让数据水乱流,只能跟传统软件,甚至是最亲近的后端服务的做法一样,做架构设计

而那些认为「按照原型实现 page component」的前端们,看看你的应用,是不是正在 「同一个接口在同一时间请求了好几遍,甚至是开一个弹窗再把相同数据请求个几遍?」。就这还敢把 Angular 作为鄙视链底层,谁给的勇气?所以胆小的已经在用 dva(umi) 了

我又突然想到一次经历,我问过一个问题:

你这里写了期望是前端架构师,精通前端架构。那你觉得前端架构需要做到什么?

然后我得到一个非 常 满 意的回答:

前端架构就是制定目录结构,接着指定代码规范,用什么组件库 balabala…

那行呗,你开心就好,现在连 webpack 都不兴提一嘴了

那咋做嘛

提前说明,前端工程逃不过使用很多工具,包括构建与编译等。这里不讨论以上问题,只有编程「思想」

扒拉一段软件工程的含义:

应用计算机科学理论和技术以及工程管理原则和方法,按预算和进度,实现满足用户要求的软件产品的定义、开发、和维护的工程或进行研究的学科

另外,IBM 的大型机之父布鲁克斯发布了《没有银弹》:

从软件危机被提出以来。人们一直在查找解决它的方法。于是一系列的方法被提出并且加以应用。比如结构化程序设计,面向对象的开发,CMM,UML等等

这里提到了「结构化程序设计」:

结构化编程,一种编程典范。希望借此来改善计算机程序的明晰性、质量以及开发时间,并且避免写出面条式代码。

其实说到底总会有几点:

  • 高性能
  • 高可用
  • 高稳定
  • 可维护

关于可维护,这个时候可以来几个经典问题,问问自己,我现在在写的这个应用:

  • 是否有自动测试:unit test, e2e test?
  • 是否会出现:点一个地方,哪哪都在 loading?(排除你偷懒连 loading 都不给)
  • 一样的模块,在不同地方显示是不一样的?
  • 一旦有一个样式改动,需要改十几个文件?

这个时候,「组件」思想又被抬上台面,毕竟 组件化即一种分治思想。如果逃离了这个,那么单元测试就无法实现,因为此刻不存在单元,第一个问题不攻自破

接着,因为在应用之初根本没对应用进行设计,每个人拿着原型就开始整,最后各自写各自的,数据流都在某个组件里维护。接着产品经理要求「各数据展示需要同步」的时候怎么办?还不是指着产品骂娘然后做了一手操作:在产生 update 的地方后再 fetch 一次数据。所以第二个问题接着不攻自破

那怎么做其实非常明了:

  1. 应用设计:在应用之初规划数据流
  2. interface:看起来像爽哥,声音像爽哥,那就是爽哥

数据流在设计之初就很好办,遇事不决先抄一版 flux —— 用 store 管理各种列表的数据和状态;列表页可以 keep-alive,根据 route 流向决定 store 的更新;VM 做成订阅/发布模型,这样,数据发起更新后,正在订阅数据的 V 可以做出更新……

别信某些平台的前端爽文。什么 vuex/redux 等被称为状态管理的 library,只能用来管理共享状态,不能用来存放业务数据。Angular 看到这场景不得当场笑裂开

到这也会发现,各种「台」的大型应用,最后也都是面向对象的思想。应用一旦复杂起来就需要一个充血模型。那就更好办了,前端也直接 DDD !直接嫖了后端的架构设计图

(顺便非常推荐《人月神话》,即使土,但45年依然流行是有道理的,其对于软件工程和项目管理的经验还有参考价值)

最后

本来写这个文章的时候是想把遇到的事情都嘴臭一遍的,最后还是把这部分都清干净了,作为一个可能有用的文字。在此特别感谢若干 toB 项目,这几年在 toB 的公司中摸爬滚打带给我的一些新(旧)灵感(都是嫖后端和 GUI 应用的),终于让我这种杂学玩家体现出一点点作用

同时践行「敏捷开发」也有一段时间了,足够扎实的设计才能敏捷,不然就变成永远在填坑,而不是敏捷

所以这篇文章也作为开始,现在正在实践把「领域驱动设计」和「C4 模型」带到前端开发中。没错,又想开一个博文坑…

越来越觉得,前端架构设计可以参考 rusttrait,或者 swiftprotocol,以及他们的设计模式。主观上觉得他们在思想有点相似

(不知道下次轮到我去面试时,恰好我的面试官看了我的博客,拿这玩意儿狙我…)

参考链接


  1. 一次面试发生的真实案例。并提出了「async 要配合 axios 才能用;ajax 没人用了」等理论 ↩︎