# 谈项目中如何选择
框架和库
-----
(做为开场话题)我想谈谈在项目中如何选择框架和库。这里的“项目”是指公司项目,也就是规模比较大、协作的角色和人数比较多的商业项目。
------
做商业产品,跟做开源项目,个人项目非常不同。更像“实战”,(为什么)
一是,更加结果导向。在规定时间内,实现出高质量的产品,是前端工程师的职责和价值。开发过程中用开源库,还是自己造轮其实不重要,重要的是能高效高质量的实现产品设计
二是,成本和效率对于商业项目尤为重要,后面会讲到。
三是,迭代周期长,方案选择就要考虑长效性。对代码的可维护性要求高,特别是需要多人维护的项目。
商业项目的开发追求结果和伸缩性,能灵活应对需求变化。所以,方案的选择更务实。好比散打追求格斗效果,姿势是否优雅不重要。太极拳已经变成强身健体的运动,且具有一定观赏性,姿势必须优雅。所以不能简单的比较谁好谁坏。
有些工具、库或框架也是一样,中看不一定中用。中看的好处是,学习价值高,可以从中学到很多东西,理念也好、技巧也好。不中用是指当项目规模不断变大,并不能有效的化解复杂度,开始变的混乱或是无法满足后续需求。
## 基本前提:成本和效率
- 实现目标的成本和效率
- 团队协作的成本和效率
- 后续迭代的成本和效率
-----
怎么理解成本和效率:
一是考虑实现目标的成本和效率。不能说我要先学几个月再动手做。或是出于练手,挖了一个大坑。或是刻意不用别人的“轮子”,最后影响产品提交的时间和品质。
这里引出一个问题:我们总觉得什么功能都用现成的库实现,是新手行为。是不是非要自己造轮子,才符合老司机的身份?我个人认为设计代码比编写代码有意义,我看重两点:一是通过良好的架构设计控制整个项目的复杂度,二是最终产品完成的品质(设计还原度、可感知的效能和稳定性)
二是考虑团队协作的成本和效率。过于小众的,或在团队内部有分歧的技术,你用了之后,没人愿意接盘的不能用,至少要说服大多数人愿意用
三是考虑后续迭代的成本和效率。如果这个方案能有效提高可维护性,能适应产品需求的快速变化,长效价值就高,一次性投入的成本就是必要的
![](./pics/f1.jpg)
-----
这张图的意思一目了然。有人做了更合理的轮子,干活的人习惯了原有的工作方式,通常以项目时间紧张为由,不愿意用。
表面上看是干活的人有问题,保守、不愿意学习、拒绝新鲜事物。
具体干活的人这么做其实很正常,因为他们是一线干活的人,问题在于根本没有意识到,拉这车东西费劲是轮子的问题,还是路的问题,或是本身东西就很重。他们默认问题是合理的,打破这种规律反而带来不确定的风险。如果拿来的不是轮子呢,没有对症下药,岂不是事倍功半。
所以在做选择之前,首先搞清问题症结是什么。无论是找“轮子”,还是造“轮子”,都需要目的明确。
## 经常谈到...
- 模式
- 普及率
- 成熟度
- 体量
- 局限性
- 学习成本
- 性能
- 活跃性
- 周边资源
- 前景
- 契合度
- 文档质量
-----
谈到关于如何选择框架和库,我经常看到的是各种维度的比较。
架构模式的比较,MVC / MVVM / 组件化的优缺点。体量是轻是重。执行效率如何。发展前景如何,是否能持续流行下去。有多少公司(尤其是大公司)在使用。功能全不全,有哪些做不到。是否有人在一直维护。里面有没有什么坑,API是不是稳定。好不好上手。现成的插件多不多。文档是否友好…等等等等
这些维度没问题。问题在于,首先要以项目需求为出发点,而不是以工具为出发点。做选择时,这些维度的权重会随着要解决的问题不同而变化。有些项目不需要单页实现,有些项目性能重要,有项目兼容最重要等等。
不能是程咬金的“三板斧”,跟谁打都是那三下。我们都听过小马过河的故事,在选择面前,我们要有自己的分析和判断的思路,不能道听途说,盲目追逐潮流,无法判断就提前试一试。
## 选择的原则
1. 妥适性原则
1. 库的选择:
- 缩小依赖范围和向稳定方向依赖
- 避重趋轻、避繁逐简、以简驭繁、避虚就实
- 可替代性
1. 主框架的选择
:
- 没有不二法则
- 拥抱未来
- 经验价值高
- 架构上的优势为重
-----
怎么做选择呢?有一些原则可供参考:
1. 首先符合妥适性原则:一切从实际需求出发,避免过度实现。
如Yagni(雅格尼,You aren't gonna need it)法则所说:你想象可能会有的需求80%都不会发生。
库和框架的选择标准不同:
2. 选择库的原则:
2-1. 首先是节制,决定是否引入一个库的时候,要有个意识,每依赖一个库就增加一些不可控的复杂性。当这个库不稳定,发生冲突或出现bug,难以发现和调试。
从实际需求出发,比如,当数据对象复杂,或有大量公共状态需要管理时,Redux可以发挥作用。反之,则完全没有必要用。
向稳定方向依赖是指如果要依赖一个库,这个库越稳定越好,通常下载量大,普及率高的会更稳定。如果有变化要做有效的隔离。不建议用一些库或框架非公开的API和不推荐的用法。
2-2. 奥卡姆剃刀讲了四原则,是很好的参考:
1. 避重趋轻:功能单一,一次只做好一件事(注意,过重的含义不是指文件大小而是指冗余多少。好比健身不光看体重,健身实际是减脂和增肌)
2. 避繁逐简:接囗简洁,直接,没有太深的套路。文档过于复杂的,基本直接pass了
3. 以简驭繁:越基础应用范围越广。另一方面,引入一个库,不是为了解决一个问题而是一类问题。
4. 避虚就实:一是针对问题的实质、能切实有效解决问题,二是避免引入过多无形的机制解决一个问题带来更多新问题。
2-3. 可替代原则。引入一个库原本是为了简化实现,但是依赖太多库就会出现过多的代码冗余,依赖关系复杂,经常会发生版本冲突的问题。还会发生抽象渗透的问题,也就是当某个依赖的库出现bug时,难于发现和解决。在引用和组织代码的时候,可替换性是指当某个库有问题时可以方便替换。
比如可以用到SOLID的依赖反转原则解藕,高层不直接依赖底层,而是共同依赖一个抽象层。 举个例子,网络请求很常见,我会写一个空壳,对外接囗是一致的,具体实现有些时候是原生写的,有些时候会用像superagent实现。这样就具有可替代性了。
3. 主框架的选择,需要非常慎重,后期替换成本高。4点想法。
3-1. 没有不二法则。没有什么是独一无二的选择。我不想比较React和Vue哪个更好,哪个更值得用。李小龙在《生活的艺术家》一书中说“刻意迷恋某一技术是一种病态,不管该技术是多么的有价值。”他有句名言“以无法为有法,以无限为有限”。意思是,当你会了一种招式后总想用它,这是错误的。要忘掉招式,根据眼前的局面,自由运用你掌握的技术,这才是高手的境界。当然你要会各种“招式。
3-2. 向前看,顺应趋势。因果律说“若能确切的了解现在,就能准确的预见未来”,虽然不可能完全了解现在,但了解的程度决定了你的洞察力
3-3. 当多个选项都能满足需求时。考虑学习和使用某一个框架的经验,是否具有长效价值,是否可以转移到其它领域上。这也符合第2点,技术永远是向前发展的,符合这个发展路径的经验就具有长效价值。
3-4. 主框架的首要选择标准,首要并非是体量、性能,这些可以优化,也不是学习成本、文档质量,这些不是太大的障碍。主要是看,它在模式设计上体现的优势、是否针对开发痛点、是否真正能以简驭繁、设计上的规约所带来秩序是否能有效控制复杂度的增长。
-----
## 选择的原则 (新手版)
1. 妥适性原则
1. 库的选择,尽量同时满足以下条件:
1. 单一性
1. 普便性
1. 轻量型
1. 依赖少
1. 主框架的选择:做足调研和实践,多和老司机交流
1. Code Review 十分必要
--------
1. 新手面临的现实问题就是搞定眼前的项目。
2. 妥适性原则依然有效 还没有把握写好一个组件,需要依赖开源库实现功能。
2-1. 不要选大而全,要选单一职责,一个库只做一件事
2-2. 被广泛使用的。比如npm下载量大的
2-3. 可以理解为越小越好。不要直接安装,看一眼源码再用
2-4. 最好不再有其它依赖,或者依赖范围越少越好
3. 主框架选择按照前面的原则,调研,并且提前有所实践
4. CodeReview很重要,多和老司机交流
## 熵
------
时刻警惕软件熵的问题。
软件熵是用来说明软件在经过不断修改后,无序程度随之不断升高。
过度引入各种库和依赖笨重的框架,会导致代码的无序程度恶化。
项目开发的前后期都需要时刻关注。
前期: 本着前面所说的最简和可替代原则选择库。code的import-cost插件很好,我都想用code了
后期: 可以通过一些包分析工具,监控项目的依赖是否变重。经常性的做一些小规模重构。
## 35.4% vs. 64.6%
![](./pics/b2.jpg)
-------
我自己选用的开源库一般是这些:
- 扩展语言能力(像immutable.js)
- 基础功能性的(像Lodash)
- 解决兼容问题的(像core.js、各种polyfill)
- 少量成熟组件(像iscroll、moment)
自有代码 324.3k
开源项目代码 135.7k
通用的开源项目代码 454k
共 914k
(source-map-explorer --html dist/js/note_editor.js > tree.html)
------
做一个项目,选库和框架,就像拍一部电影,选演员。李安曾说过,他挑演员不是挑他的演技,也不是外表和名气。而是挑这个人的时候,脑子里就开始演戏了。
同理,在选一个库或框架时,它已经在脑子里执行了。
## 谢谢!
------
这就是我的一些想法。谢谢!