当前位置: 首页 > 工具软件 > Arale > 使用案例 >

Arale 背后的一些设计理念(引)

申昌勋
2023-12-01

引自:https://github.com/lifesinger/lifesinger.github.com/issues/106

阅读此文前,建议先看下这个 PPT:支付宝前端技术之路

缘由

看完上面的 PDF 后,好友 @拔赤 在微博上发了些感触:

ppt有点小失望哦,特别看到34页,真真就是kissy啊,不管是jquery式的包装器风格控件,还是kissy/yui系的工厂风格组件,真正的挑战是站在业务和开发者角度设计组件api,扩展性和灵活性是自然的结果而不是最初的技术目标,就像switchable那么细的分层,有人为他写过扩展吗?

到底谁才会开发出真正高质量的组件?1,商业控件开发团队,2,库和框架的作者。所谓社区贡献高质量控件,我不指望。找几个p7、8的人基于jquery提炼业务控件,就够了,呵呵,总有一种不详的预感,arale最后成为另外一个kissy,进而成为另一个yui,都是重量级的底层基础加贫瘠的上层建筑

yui现在明显走下坡路了,看最近狂发小版本,渐渐少了主心骨,在一个,yui的工具化已经很落后了,里面的组件也面临重构的压力,人才流尽的yui team啊,只剩回忆了//@adamlu: 直接用YUI得了,YUI多好啊~~

从普通开发者的角度,我只想了解一个控件有哪些方法,事件,参数,demo和文档是否详细,更不关心这个控件是怎么生产出来的,也不想知道某个功能算是plugin还是feature,所以jquery的思路反而更经受的住考验,外表简洁,内核肮脏,结构粗犷但健壮,内核的分层和所谓简洁无非将复杂度暴露给了开发者。

回复@adamlu:我了解你对yui的感情,其实yui的大部分api都固定了以至于现在想改进都难,比如yui的自定义事件冒泡,设计的确牛逼,我至今没见人用过,mix的那么多派生用法,就用过混合和扩充,所以,用yui就像一把青龙偃月刀,是很华丽,问题是,到底有多少"关公"呢,全中国有几个人能耍的动他呢?

所以,我挺想听听玉伯介绍下控件的api设计精粹的

拔赤提到的一些问题,不少是在做 Arale 的过程中,反复纠结过的。在 QCon 的分享上,因为考虑听众更多的是想了解 Arale 和 spm,因此有些地方省略或简单带过了。这篇博文尝试讲讲 Arale 背后的一些故事和设计理念。

开放

就如拔赤所说,看到 Arale 的 Widget 继承图时,咋一看,和 KISSY 没什么本质区别。为什么有了 KISSY,还要开发 Arale 呢?两者的区别究竟在哪?

首先,Arale、KISSY,包括著名的 YUI 等类库,都是前端组件库,通过一定的方式,对外提供了一套组件集。在 UI 组件(Widgets)层面,这些类库要解决的问题,以及解决问题的方式都是类似,表面上看没什么区别。

但在工具组件(Utilities)层面,Arale 与 KISSY、YUI 有着很大的不一样。Arale 里的工具组件,比如 jQuery、Handlebars、Moment 等,都直接来自业界,并且一定程度上是可替换的,比如在移动端,jQuery 可以被替换成 Zepto 库。

除了工具组件,部分 UI 组件,比如编辑器、日历等,Arale 里也可以直接来自业界,甚至可以直接移植部分成熟的 jQuery 插件过来。这在 YUI 和 KISSY 里,是不怎么被考虑的。

Arale 是真心开放的一个组件解决方案,这种开放性,我相信会是 Arale 的最大活力。

简单、易用

这个的确如拔赤所说,几乎所有类库都会这么标榜自己,但是有些只是标榜,并未真正做到。比如 KISSY 最开始很推崇 KISS 原则。但随着后续的发展,个人觉得目前其实已经背离 KISS 原则,没有做到保持简单。就如拔赤说的 switchable 组件,里面超细的分层和功能点是否真的有必要?前不久在群里还讨论过延迟加载组件的一个 bug,在某种特殊场景下,该组件存在一个 bug,作为程序员,好像会毫不犹豫的把 bug 就修复掉了,觉得天经地义,但我直觉里却觉得是否值得?即便也许只需要增加几行代码。

在简单面前,还有一个比 KISSY 更明显的反例是 YUI3。拔赤已经说了自定义事件搞那么复杂,理论上看起来很完美,但实际上却什么人去用。YUI3 是个典型的学院派风格类库,不光自定义事件,很多其他组件的设计上,都存在学院派式的完美主义情节。这个不多说,喜欢 YUI3 的可以继续用,但我的感觉和拔赤一样,类 YUI3 的类库路子只会越来越窄,最后自己把自己干掉。(当然,所有预言都是不靠谱的。)

回到 KISS 原则上来,回到经常提起的简单之美上来。对于 KISS,自从概念提出来就一直存在理解上的分歧,下面是一篇我读到过多次每次读都感慨的一篇文章:

文字比较多,还是不贴过来,请移步阅读:简单之美——系统设计黄金法则

中间有个故事很有意思:

一位 MIT 的教授一直困恼于 Syscall 处理时间过长出现中断时如何保护用户进程某些状态,从而让用户进程能继续执行。他问新泽西人,Unix 是怎么处理这个问题。新泽西人说,Unix 只支持大多数 Syscall 处理时间较短的情况,如果时间太长出现中断 Syscall 不能完成,那就会返回一个错误码,让用户重新调用 Syscall。但 MIT 人不喜欢这个解决方案,因为这不是“正确的做法”。

这两个流派非常典型,我还是忍不住再摘抄过来:

1)MIT Approach

  简单性:设计必须简单,这既是对实现的要求,也是对接口的要求。接口的简单要比实现的简单更加重要。
  正确性:设计在任何值得注意的方面都要保证正确。不正确是绝对不允许的。
  一致性:设计必须保持一致兼容。设计可以允许轻微少量的不简单和不完整,来避免不一致。一致性和正确性同等重要。
  完整性:设计必须覆盖到实际应用的各种重要场景。所有可预料到的情况都必须覆盖到。简单性不能过度的损害完整性。

我相信 MIT 的这套理念,是绝大部分程序员的默认意识。这这套哲学里,简单性不能破坏正确性、一致性和完整性。很多程序员见 bug 就改的习惯,潜意识里感觉是受完整性的影响。

来看另一种理解:

2)New Jersey Approach

  简单性:设计必须简单,这既是对实现的要求,也是对接口的要求。实现的简单要比接口的简单更加重要。简单是设计中需要第一重视的因素。
  正确性:设计在任何值得注意的方面都要求正确。为了简单性,正确性可以做轻微的让步。
  一致性:设计不能过度不兼容一致。为了简单,一致性可以在某些方面做些牺牲,但与其允许设计中的这些处理不常见情况的部分去增加实现的复杂性和不一致性,不如丢掉它们。
  完整性:设计必须覆盖到实际应用的各种重要场景。所有可预料到的情况都应该覆盖到。为了保证其它几种特征的品质,完整性可以作出牺牲。事实上,一旦简单性受到危害,完整性必须做出牺牲。一致性可以为实现的完整性作出牺牲;最不重要的是接口上的一致性。

上面这套理念,刚接触时,简直有点邪教的感觉。比如实现的简单比接口简单重要,以及正确性居然可以让步于简单性,还有最不重要的是接口的一致性。

New Jersey Approach 初看有点 naive,但我个人的感觉,通过 KISSY 的开发、SeaJS 的开发,越来越觉得 New Jersey Approach 可贵性。

可以说,YUI3、KISSY 等类库,遵循的都是 MIT 哲学,但 SeaJS、Arale 尝试的是 New Jersey 哲学。

这会带来很多不同。举一个例子简单说下,比如 Overlay 组件,在 Old IE 下需要增加 iframe 垫片,在传统的组件设计里,会允许在 config 里关闭或打开 shim 配置。但在 Arale 里,直接没这个配置,发现是 Old IE 时,默认就打开,否则则关闭。不给用户这层选择,用户也就不用去操心还有这么回事。这个设计,在内部讨论时,曾经被挑战过,比如用户有可能为了性能优化,希望在 IE6 下也不创建这个 iframe,因为用户很明确知道没垫片也不会出问题。Arale Overlay 的设计看起来是无法满足这个需求的,对完整性是种破坏,但是我们最后还是决定不添加这个配置,因为这样更简单。完整性可以为简单性做出牺牲。

这只是其中一个小例子,Arale 的组件配置与 YUI3 等相比,都会偏少,很多都是出于简单性考虑。但在 KISSY 和 YUI3 里,很多时候是恨不得把所有配置都暴露出来。

在简单性上,我们甚至会优先考虑实现上的简单性,比如 Mask 组件,就全局单例,因为这样实现最简单。

开放、简单,我个人觉得这在 Arale 里,是非常非常实在的东西。

支付宝的业务特征是,需要稳定、高效、灵活。我们的理解是,因为开放,所以稳定,比如 jQuery 的稳定性比自己折腾一个 DOM 操作类库会更靠谱,高效来自简单、易用,用起来爽,效率自然就高了。

至于灵活,更多时候也是通过开放来解决的,因此开放,同一类型的组件可以有多个不同定制版本,这一点,和 KISSY 通过 component 实现的灵活有很大不同。在 Arale 里更追求组件的独立性,下面细说下。

适度

这个在 PPT 里没说,在 Arale 组件开发里,是时时被强调的:

  1. 适度灵活
  2. 适量重复

适度灵活不多解释,Arale 里不会去构建万能组件,只会让组件适当的具备一定的可扩展性。比如 Arale 的 Switchable 组件,肯定不会去增加新建 Tab 的功能。需要复杂功能时,去使用另一个 TabView 组件就好。

第二个适度法则是适量重复。这个是我的切身体会,有悖于传统的软件开发思想,但我觉得在前端界,适量重复比 DRY 更实用。

是个程序员可能都听过 DRY (Don't Repeat Yourself),这条法则非常好,在大部分情况下都是对的。

然后在构建前端类库时,我觉得遵守 DRY 会很危险。

如果你追求代码的不重复,那么你在写 a 和 b 组件时,会把公用部分抽取为 c,不断重复这个追求,最后就会得到一个非常庞大的依赖结构图,比如 YUI3 就是这样。YUI3 追求颗粒化,表面上看颗粒化可以让自定义打包更灵活更优秀,但实际上,颗粒化的粒度非常关键,像目前 YUI3 的粒度太小,导致的问题是,实际上你若真去把 dom / event / node 等模块打包出来,其实会比 jQuery 大出不少,不光达不到实际的期望效果,还牵三挂四,开发起来并不方便。(虽然 combo 服务可以缓解一点)

对于 DRY 法则,我的理解是,必须要非常小心的把握好两点:

  1. 究竟不应该重复的是什么?
  2. 粒度如何?

在 Arale 里的答案是,不应该重复的是组件的职责,而不是组件的代码。 比如:

  • jQuery 的职责是 DOM 操作类库,那么在 Arale 里就不会再有第二个 DOM 操作类库。
  • Underscore 的职责是语言增强,那么在 Arale 里就不会有第二个语言增强组件。
  • jQuery 和 Underscore 是不重复的,他们的职责不同,主体功能不同。
  • 但 jQuery 和 Underscore 两个组件,可以存在部分相同的辅助功能,比如 each 等方法。

在这种对 DRY 的理解下,Arale 里的组件宁可 copy 一些代码,也会保持组件的独立性,而不会特意去追求代码级别的不重复。

这一点我们纠结过不少时间,但目前来看,适量重复带来的简单性是很不错的。

粒度的问题,在 Arale 里,实践的是粗粒度法则。 如果要复用某些代码,那么会以独立工具组件的形式提供,比如 position 工具组件,就提供一个静态定位方法,其他 UI 组件想用时,直接采用引用的方式调用静态方法就好,而不会像 YUI3 或 KISSY 一样,采用 mixin 的方式去做。Arale 的工具组件,推崇:

组合 > 混入 > 继承

这篇博客有点长了,回到拔赤的几个问题。大部分问题已经回答了,再来回答这个问题:到底谁才会开发出真正高质量的组件?这引出了本篇博客想谈论的最后一个议题。

生态圈

在《支付宝前端技术之路》里,无论 Arale 部分,还是 spm 工具部分,都非常强调生态圈的概念。对于组件的开发、贡献、筛选,在 CMD 模块生态圈里,就如 NodeJS 社区一样,是开放自由的,同时又是非常残忍自然的。

残忍自然是因为我们想打造的是生态圈, 生态圈是自然的,同时也是物竞天择、适者生存。 一个组件是否优秀,完全取决于它能否被生态圈认可。这和 GitHub 也是一样的,GitHub 上这么多项目,但通过一些简单的维度,我们还是可以比较容易的筛选出一套精品组件。

Arale 只是 CMD 生态圈里的一套模块精选集,并且这个精选集,目前是基于支付宝的需求去选择的。其他公司完全可以从 CMD 生态圈里,选取另一套模块精选集,比如叫做 CoolLib 什么的。

CMD 生态圈目前还没正式对外运作起来,目前只在支付宝和 B2B 初步尝试,等时机成熟后,会彻底开放出来。

我相信生态圈是解决组件质量的不错选择。

小结

在 Arale 里, 开放、简单、易用、适度灵活、适量重复、生态圈 ,这些概念是实实在在的,也正是这些理念,使得 Arale 与 YUI3、KISSY 等类库不同,我相信这份尝试会成功,并期待你的加入,一起为梦远航。

转载于:https://www.cnblogs.com/keva/p/arale-design-concept.html

 类似资料: