微信扫描登录
或者
请输入您的邮件地址来登录或者创建帐号
提 交取 消
GITBOOK.CN需要您的浏览器打开cookies设置以支持登录功能

如何看待 left-pad 事件

本篇文章整理自贺师俊(Hax)5月12日在『ITA1024前端技术精英群』里的分享实录:如何看待 left-pad 事件。

本期Hax大神分享时间持续了2个半小时之多,满满的内容与代码思想高度,希望对所有前端技术人有帮助。

enter image description here

介绍一下我所在的公司。百姓网,做分类信息的。

主要出没的地方:

github: @hax weibo: @johnhax zhihu: 贺师俊

大家熟悉我的会知道,我经常讲一些有“争议性”的话题,比如:

去年讲的 JavaScript: The World's Best Programming Language http://johnhax.net/2015/js-the-best/

今年也讲过 程序员的圣战之 TAB vs SPACE http://johnhax.net/2016/tab-vs-space/

对于有争议的话题,通常有两种典型态度:

“回避or嘲笑”

left-pad事件也是如此。 简单回顾一下 left-pad 事件。

简单说,就是一个叫 Azer 的开发者因为 npm 公司把本来他持有的 kik 包名字转移给了 kik 公司,一怒之下 unpublish 了他的所有包。其中一个叫 left-pad 的包,被 babel、react native 等依赖,于是它们就安装失败了,进而所有依赖它们的应用也都会安装和构建失败。 八卦 Kik是一个类似微信的 App,据说微信当初也参考了它,且腾讯去年投资了该公司 5000万美元。 详细一点的,这里有两个链接大家可以看看,一个是英文的,一个是中文的:

大家可以看到英文文章的标题是 How onedeveloper just broke thousands of projects。实际上因为left-pad 这个包的真正执行代码其实只有 11 行(排除了空行),所以甚至有 11 lines code break the Internet 这样耸人听闻的说法。

当然这是标题党了。比如,广大中国开发者其实压根没有受到影响。因为这个事件发生在北京时间早上 5:30,到 8 点之前 npm 官方就解决了。 (注:微信PC版的链接识别可能有问题,大家可能需要手动粘贴链接。)

即使受到影响的人,也只是安装包和构建失败,并不会产生任何线上事故。

不过这个事件还是引发了大量的讨论。最著名的一篇技术评论文章是: Have WeForgotten How To Program? http://www.haneycodes.net/npm-left-pad-have-we-forgotten-how-to-program/ 中译:我们是不是早已忘记该如何好好地编程? http://zhuanlan.zhihu.com/p/20707235

这个大家可以点开来读一读

这文章再一次提出了对 node.js/npm社区的小模块文化的批评,除了 left-pad 之外,还举了只有一行代码的 isArray ,和只有 4 行代码却有 3 个依赖的 is-positive-integer 作为反面典型。

文章的小标题也代表了他的观点:一个函数并不能被称为模块、第三方依赖带来的问题、我们应该尽可能减少依赖的模块。

类似论点的文章国内外都有许多,这里不一一列举,仅列一下知乎上相关的问题:

其中《The current stateof JS programming》比较有趣,属于高端黑。

大家可以花3分钟点开来看看。

不过我想先提一个小问题,大家一边看这些文章一边可以思考一下。如果说“一个函数并不能被称为模块”,那到底几个函数可以成为一个模块呢?三个可不可以?两个可不可以?边界在哪里? 八卦 那个The current stateof JS programming 的代码 fizzbuzz 是一个稍复杂的 hello world。可作为入门码农的面试题。

他那个代码呢,用了函数式组合的方式,黑npm小模块的同时也黑了函数式编程。

在技术讨论以外,也出现了行为艺术。比如

这个 left-pad.io 呢,就说,你们这个模块挂了,我搞个 http 服务给你。当然因为是服务,所以有限制的。free 版只能支持 1024 个字符以下。

当然这个是搞笑来的,后面两个库也是很搞笑的,而且是群体性的。你可以在他们的repo看到许多的PR。也有不少是咱中国程序员提的。

甚至其他语言平台的程序员也加入了狂欢,争相移植 left-pad: -Ruby -C# -Rust -[Haskell](https://hackage.haskell.org/package/acme-left-pad)

不过我要说,有些移植实在是太偷懒了,比如Ruby 移植,直接调用了 Ruby 内建的 rjust 方法。对此,我觉得讽刺也应该认真一点,否则只会显得比你要讽刺的对象更 low。

回到我一开始讲的,对于有争议的话题,很容易滑向“回避”和“嘲笑”。因为这是最省力的方法。就这一点来说,我的态度是:

wǒ jiù shì rèn zhēn 我 就 是 认 真

因此就有了我这个话题分享。

以下是我根据所看到的各方讨论所总结的一些话题:

  • 谁是这次事件的罪魁祸首?azer?kik 公司?npm 公司?
  • azer 是英雄还是熊孩子?
  • npm 公司是不是邪恶的公司?
  • 开源是不是注定不靠谱?
  • 包是不是应该有命名空间?
  • 我们都忘记怎么编程了吗?
  • 小模块是好是坏?
  • leftpad 本身应该怎么实现?
  • 第三方依赖是好是坏?
  • 是不是应该使用 shrinkwrap/lock(锁定依赖)?
  • 是不是应该使用 bundle/pack(打包依赖)?
  • 是不是应该自建仓库? -js/nodejs/npm/前端……生态是不是有问题?

因为分享时间有限,不能全部讨论,我尽量能讲多少讲多少吧。未尽之处,我们可以以后再找时间讨论。

先说这几个相关的问题:

  • 谁是这次事件的罪魁祸首?azer?kik 公司?npm 公司?
  • azer 是英雄还是熊孩子?
  • npm 公司是不是邪恶的公司?

大家先想想自己的观点。 (休息下)

因为我做过两次f2f的话题分享,我本来以为大多数人会认为 Kik 公司欺压开源作者,所以会归罪于 Kik。但实际调查下来,大多数人觉得这个锅应该是 npm 公司背。既然觉得 npm 公司是罪魁祸首,那么按逻辑说,应该认为 Azer 是反抗暴政的英雄才对。不过实际调查结果并不是这样。这样一种矛盾的调查结果,也许反应了大家在对待这个事情的时候更多是诉诸于感情从而产生了矛盾的情形。

我们优秀的工程师之所以优秀,是因为他们擅长做事实判断,比如代码写得是不是正确,性能好不好,口说无凭,得写测试。feature有用还是没用,数据说话。不过要价值判断的时候,就往往有点问题了。

言归正传,要进行价值判断很困难,但是至少我们先搞清楚事实。

这里有个:Azer NPM 撤包事件全信件 http://zhuanlan.zhihu.com/p/20671763

这里翻译了 Azer/Kik/NPM 的来往邮件。大家可以看看。

“我们找上你门来,是因为我们非常想将我们的产品名称「kik」用於我们即将发行的封包。不走运的是,你所使用的「kik」和「kik-starter」意味著我们用不了我们的产品名称、且我们的用户会被困惑得找不到我们的产品封包”

第一段读了好像我就气不顺。。。是不是觉得 Kik 很可恶呢?不过在此之前,我们最好看下评论。比如评论第五页上尤雨溪的评论。

尤说:这段翻译的误导性很强。"We'renot getting anywhere with this" 意思是『这件事情似乎没什么进展的可能』,"We don't mean to be a dick" 意思是 『我们不想做得太过分』。抛开这两句话,kik 方面的沟通其实还算比较合理,尤其是关于律师捶门的那一段,英语原文用的是虚拟语气:"ifyou … we'd have no choice…"。

其中 dick 这个有一些同学一看到就觉得是骂人,像我这种英语渣就只认识这个单词。 八卦 尤雨溪是Vue.js 的作者,目前在美国 Meteor 公司供职,在美国生活了10年。他对英语原文的理解应该是比较准确的,不过译者孙志贵也在加拿大生活过4年,所以作为英语渣渣的我其实很难直接判断到底谁说的对。然而,有一点,孙志贵并不讳言他的立场,基本上就是认为 Azer 是英雄,Kik是流氓,NPM是是是非不分助纣为虐的邪恶公司。

所以我倾向于认为这是一个立场先行的翻译。

那么这个里面的语气什么的,看的时候就要注意了。另外,尤雨溪也提出,这里缺少了 NPM 官方回应(blog)的翻译。

当然,孙志贵这个特辑本来也就是“全信件”,不翻译 npm 的 blog,也不好责难他。但是如果你要完整的了解事情,不看 npm 官方的表述,恐怕也很难全面的认识。

下面是一些第一手的资料链接:

第一个链接是 Kik 公司的 CoFounder 写的。他表示他们也栽了,因为用的 JSCS 也依赖了 left-pad。 (注:JSCS 是一个 JS 代码风格检查工具,最近刚刚并入 ESLint。)

然后呢,他就公布了一系列相关邮件。孙翻译的邮件很大一部分就来自于此。

显然,他既然公开了邮件,大约是认为这些邮件不至于太损害Kik公司的形象。这是一个合理推断。

第二个链接是 Azer 在 unpublish 之前发的 blog ,大家已经知道了。

第三个就是 npm 公司的官方回应了。

我暂时没有找到第三个的翻译。大家有见到的可以告诉我。或者有兴趣可以自己翻译下。

大家可以一边看 npm 的blog,我一边说一些我听到的问题。

一个是,我们知道最后 npm ununpublish 了这个包,那那个包的知识产权是 Azer的。npm公司这样做,在法律上是可以的吗?这有三点:

第一个是,Azer 在 unpublish 之前,改了他代码的 license。这个大家可以看 github的 commit 记录即可。他把 license 改成了 WTFPL。

什么是 WTFPL 呢?就是 What The FUCK PL。其实就是随便你拿我的代码干嘛!所以呢,这个代码你 fork 或者 redistribute ,法律上是没有问题的。

第二个,即使你的代码没有声明过license,或者你要求 npm 完全删除,其实也没什么。因为 npm 的用户协议里规定了,你只要上传到 npm 的代码,就授权了 npm 处置权。npm 不保证什么时候移除。

这个看来 npm 在成立公司后的法务也不是吃素的,未雨绸缪了。所以法律上没有什么问题。

第三个,npm 把kik包给kik公司,这个ok吗?其实npm这个动作他是有权力的。因为他的文档写了。他有一个 name 冲突的解决机制。如果有冲突,冲突双方可以先协调。协调好了,npm 配合你们转移所有权。没问题。如果协调不好(就是Azer和kik的情况),npm公司会来决定。

决定的 policy 也是老早就公开的。大原则就是用户期待这个包名应该返回什么。这个听上去好主观啊。

但是,至少他们是有policy的。并且一早就公开了。注意这个名字冲突解决方案和域名争端的解决是很不同呃。域名如果你抢注了,除非有什么商标权,通常是很难转移的。但是npm保留了这个权力,所以呢,抢注npm包名其实并没有什么卵用。

所以大家知道了,你如果看到一个包名不错,对方又从来没有真正拿这个包干过什么有价值的事情,你完全可以去要求转让。

谈不拢你可以找npm来解决。是有一定可能npm会把包转移给你的。那么具体到kik。npm的理由是kik有许多用户的。所以转移给他们应该是更合理的。

好,谈到这里,大家知道了。我的看法,npm公司的策略不是不可以讨论,具体做法也可以有不同意见,但是大原则上并没有什么问题。

kik公司呢,就像尤雨溪说的,主要是沟通语气问题。但是Azer的语气其实更差。所以最后要谈罪魁祸首,那只能Azer来背包了。

顺便,有些人觉得他都开源的,你怎么能够责难他呢?

我想说:

开源不是单向的贡献,而是互惠的。

所以开源者并不天然高人一等。人家给你提issue/PR,就是contribute嘛。就算不提issue/PR,我就是用你这个,传播你这个,就已经是在做贡献了。

No Warranty ≠无责任

我们都看到开源的license里写的,no warranty。但是那个是为了保护自己不被起诉。不等于说你没有责任。你发了一个东西,你就对使用的人负有道德上的责任。当然这是我的观点哦。

应该遵循 npm 的规则

当然我们也可以质疑 npm 的规则/行为/假设,比如 npm 有个假设是 我们基于社区的协作,大家都是善的。

有点像人性本善。这个假设是不是靠谱呢?

就有很多不同的看法了。

比如这个事情之后爆出来的所谓安全漏洞,就是npm 的生命周期脚本,比如 postinstall ,可能被利用。你可以搞个恶意的包,别人一安装,你就控制别人的的机器。

更严重的是可以搞病毒。比如我发现你有publish过其他的npm包,我就帮你发一个新版本,带了我的病毒。在搞安全的人眼里看来,这天大的漏洞啊。

不过呢,我个人看法,我们是否可能不是直接否定其假设,看看有没有其他方式解决这个问题呢?

考虑实际当中,安全漏洞的发现和修补机制。你会发现其实也没有那么恐怖。因为如果你用的是比较多人用的package。可能有其他人早就review和发现漏洞了。

最惨不过是大家一起死嘛。我这样说可能不太好。不过像之前的 heart beat 漏洞啥的,其实最后看的还是谁有意识快点补漏洞。也就是说,不一定需要直接否定掉npm的假设。

扯完npm,我再扯两句Azer,其实呢,Azer并不是美国人。

他是哪里人呢?大家看他的全名。Azer Koçulu,c下面有个小尾巴。这个姓,大家可以google一下,其实是个土耳其姓。

他呢,其实出生在伊拉克边境小村庄。战火纷飞啊!好在,虽然打仗,还是有人搞互联网的。后来他就跟着跑到土耳其去搞网站了。然后就开始搞开源。

他最早搞的是firebug。大家都很熟悉吧。但是呢,他其实跟我们一样,不是nativespeaker。不会讲英文的。最早跟firebug团队的邮件,都要靠别人帮他翻译。当然了,他现在移民到美国Portland了。英语肯定不错了。

不过,我有个脑洞大开的想法。

我们之前讲翻译的时候就讲到,一句话,同样在美国加拿大呆过的人,看法都不一样呢。那Azer也不是美国人,是不是有可能沟通中有一些误解呢?

当然这是一个脑洞。还有一个脑洞。

就是我们经常啊,觉得国内这个技术讨论很容易吵架。但是你到github上多看看,人家咋那么有礼貌。比如提一个issue。上来先说你这个项目太棒了,但是我有个小问题,我不知道是不是我用错了,或者哪里文档没看全 blablabla,最后讲完问题,再次感谢你的工作!

我ca,太有礼貌了。

那这个我有一个脑洞。就是国内吧,戾气比较重。

你平时吧要夹着尾巴做人。但是都上网了,都讨论我熟悉的技术了,当然要理直气壮了。我牛逼了嘛,谁知道你谁啊,说不定是北大青鸟刚毕业的。

那我就骂了你再说。那Azer这个小时候生活的地方,就不是戾气了,战争啊,不能想象,随时小伙伴就炸飞了。。。所以是不是因此就敏感一些呢。。。当然这个是我臆测,非常政治不正确,大家听听就好。

总之,我认为这个事情吧,就是:

冲动是魔鬼。

回到我们最初的问题,谁是这次事件的罪魁祸首?azer?kik 公司?npm 公司? azer 是英雄还是熊孩子?npm 公司是不是邪恶的公司?

那我的观点大家大概知道了,就不重复了。

我还看到一个说法,有人觉得:开源是不是注定不靠谱?因为你不能保证你用的哪个东西就是作者一不高兴,就来个unpublish。那商业公司,应该更有保障点。

其实呢,也未必。我们看这个: https://github.com/stevemao/left-pad/issues/4

这个是最初发现问题的issue。我们可以看到他的时间。北京时间5点35。那unpublish发生在5点29。也就是说,6分钟就有人发现并开了issue。如果你继续看,会发现,10分钟就有人republish了这个包。当然,republish并不解决问题。

因为你只能republish新版本。而不幸的是,line-numbers这个包里面对left-pad的依赖是写死了版本号的。这个前面没有说的是,其实babel等依赖的并不是直接依赖left-pad。而是通过line-number这个包间接依赖。

最后呢,是npm官方解决方案,就是un unpublish,大概是在2个小时左右。这个timeline,大家可以查阅npm的blog上。

快速发现问题 各方快速响应 自发的临时解决方案 npm 官方方案 事后追踪和改进

所以这是我看到的 。

那么,开源是不是注定不靠谱?

开源社区很靠谱!

商业公司在这样的事情上反应也未必那么快!快到其实全中国的开发者根本都没感知到。都是后来看了阮老师的微博你才知道的嘛。

时间有限,我最后就说说“我们都忘记怎么编程了吗?”吧。 https://github.com/sindresorhus/ama/issues/10

其实呢,这个小模块的问题,很早大家都问了。

像这个。sindresorhus是node社区很有名的。他有一个ama repo,所谓ama就是ask me all。就是什么问题都可以问。比如你可以去问问他的性取向。

那么就有人问了小模块问题,大家可以看他的回答:

LOC is prettymuch irrelevant.

It's allabout containing complexity.

这个是核心的两句。就是行数(LOC)不重要。重要的是包含的复杂度。

那么我们考虑一下当初举例的 isArray。他虽然只有一行代码,但是那个代码确实包含了很高的复杂度。

我为什么这么说,因为里面用了什么 Object.prototype.toString.call ... === '[object Array]'

这样的写法。

你跟非js程序员解释一下这个代码看看?

是不是很费劲,其实大家很难理解这个代码的用意。为什么这么写?

其实这是一个久经考验在无数种isArray写法中最后沉淀下来的。所以虽然短,但是复杂度其实是高的。

或者我们换一个更普通的说法,就是它具有抽象的意义。

当然,也不是没有反例,比如那个is-positive-integer恐怕就是个反例。所以在出了left-pad事件之后,也有一些不同的反思,比如line-number 模块的作者(就是那个依赖 left-pad 的module的作者)

在事件后改了readme, https://github.com/lydell/line-numbers/commit/711f6ad0eb1771341aecb59d83f139a24d862dba

This is arather silly package that I do not recommend using. (他说我这个库实在是silly了,大家别用了。)

这个时候我觉得大家还是需要思考的。比如 left-pad 本身做的事情,字符串操作,确实是有抽象价值的。

而 line-number是不是有价值呢?

line-number 做的事情是什么?

其实是给源代码加行号。

就是给每行前面加 1 | // my code

所以你知道他为什么要用 left-pad,就是为了对齐行号。但是这个事情是不是真的值得做成一个package?确实蛮难说的。

另外,刚刚那个ama的repo,也有人再次提问。大家可以看看。

AMA: Whatare your thoughts on the left-pad npmcase?

我的想法如下:

第三方依赖是好是坏?

有好,有坏。

关键是:

你总需要依赖他人,你不可能写的所有代码没有依赖,除非那代码太简单呃。

依赖意味着信任,所以当然这个是要付出成本的。

你需要找到平衡。

依赖的主要问题有如下:

  • 依赖太多太深,安装慢
  • 依赖链太深,安全隐患
  • 依赖太复杂,升级困难

好,看上去过多过深的依赖是个问题啊!

且慢,依赖这个事情也不是只有node.js/npm 有,其他语言平台也有啊,为什么他们没有问题呢?

这里我想讲一下我的想法,就是npm 依赖体系与其他语言平台的不同

npm 从很早就支持局部依赖,并很方便的安装管理包,大概是0.4版本开始。

而其他语言,比如python啊java啊php啊,在一开始都没有包管理工具。也不支持局部依赖。

所以这些语言平台上,依赖一开始就是一件很恐怖的事情。

开发者不会轻易引入依赖。那当然一定程度上就不会出现小包,因为你小了,自然就多了,很容易就深了。虽然今天这些语言平台也有了类似npm的东西,比如php有composer啊,但是习惯已经建立了。

另外,js因为历史原因缺少标准库,导致基础小包很多。再一点,js module和其他语言其实不同。js module是真正的local namespace导入。

像java/c#/php等,都是有global namespace的。也就是你一个类有一个qulifiedname,比如 com.hax.xxx.MyClass。php的:\HAX\MyClass

所以就算有composer之类的,你也无法支持多版本共存。为什么呢?

因为同一个库的不同版本,他的namespace是一样的。loader没办法load两次。在Composer的github repo里就有这个讨论,说我们要不要支持跟npm一样,多版本。

讨论下来,最后说,不好办。虽然不是100%没有办法,比如可以用代码重写。但是大部分人不接受,觉得太heavy。

Java也是类似的,也许你用自定义class loader或者OSGI之类的啥(我也不懂的)东西能做到,但是代价很高。

那多版本跟小模块和依赖深有什么关西呢?

大有关系。你想想,如果是小模块,很容易依赖深,很容易就产生在某两个依赖分支上出现同一个模块的多版本。

Composer社区现在的解决方案是,你们总是升级到最新版本。当然这是可以work的,可是开发者的负担很重。

顺便说一下,npm虽然支持多版本,但是不是说多版本就是一定ok。理论上是可能出错的。比如A依赖B和C,B和C依赖D的不同版本。如果B和C没有把 D里的接口暴露出来,也就都只是内部使用,那没有什么问题。

但如果他们最后传到上面来,在A里面互相调用了,那是有可能冲突而挂掉的。只不过js的尿性就是duck type,等到调用的时候再说。实际实践上,真的冲突的案例其实非常罕见。

我反正没怎么见到过。好,废话不说了,总结就是:

JS/NPM 的历史条件决定了,它和小模块方法论是相适应的,所以我们不能简单套用其他语言的经验来评判 JS/NPM(反之亦然)。

JS/NPM 给出了一种新的可能性,当然也会面对新的挑战,那面对这些新的挑战,我们刚刚说的依赖带来的问题,也不是没有解决方案。

比如安装速度问题。有 ied, pnpm,npminstall 等方案,速度比如npm3快很多,因为他们改了 node_modules 的布局。其中 npminstall 是淘宝的同志做的。

大家可能在用 cnpm,其实cnpm就内部用了 npminstall,所以你可能已经在用了。而深层依赖导致安全问题呢。

像david这个包,能检查你的依赖是不是outdated,有没有依赖是被社区标为有安全漏洞的。另外呢 alinode 这个阿里云的node托管服务,内部集成了类似功能,非常好。

至于升级的问题。大家可以试试用greenkeeper这个服务,我已经用了,很不错。他会自动检查你的依赖,如果有包更新了,会自动发pr到你的github repo。如果你已经写了testcase,配置了CI,那么github上PR会自动跑。通过的话,你就按一下merge按钮就好啦!

我自己用的两个小项目,90%的情况就是如此。只有10%的遇到break了,那么就第一时间发现和修复就好了。

这个自动化,就大大减低了你的维护成本。当然,所有这些措施不能说100%解决问题。也不是说这样就证明 node.js/npm 的小模块风格就一定是最好的。但是至少我们可以不用那么快就认为一定是不行的。

好了,因为时间关系,今天我就先分享这些。有更多一些话题,有机会再跟大家交流吧!

谢谢大家!

Q&A

问:node的版本依赖,什么是否用^,什么时候用~,什么时候用*,什么时候写死版本号?想听听贺老的看法。

Hax :写版本依赖这个,npm install -s 默认用的是 ^ ,肯定是有道理的,所以没有特殊需求,用这个就好了。那你不遵循这个就可能有后果,比如line-number写死了版本,也是让这个事故更严重的因素之一。

问:对于如何开始使用前端自动化测试,想请hax老师指点?

Hax: 前端自动化测试,如果说一般的单元测试,那多多益善。刚才讲的greenkeeper,也是需要你得有测试,才能真起到作用。没测试,那不要说依赖了,你自己代码变更也要听天由命啊。

问: 贺老怎么看sindresorhus的noop3?

Hax:我自己没用过,不过作者自己已经说了:This is both a joke and actually useful. when running tests it'ssometimes nice to be able to import an empty function if only to keep styleconsistent. 这个是作者自己说的。

实际上noop如果有用的话,可能是在某些函数式编程的场合。举个例子, id = x=> x.这个函数看上去没啥用,但是在函数式编程里,这个id有很多用途。当然,我自己写js并没有采用非常函数式的写法。所以我不怎么用noop/id之类的东西。我唯一一次用noop是在 my-promise 这个Promise实现中用的。当然因为很简单,所以我自己写了一个内部module,没有引用外面的。

问:想问下自建npm包的问题,感觉很有必要,但是有没有方式解决npm下载后固定路径为npm_moudles,可以进行自定义,谢谢。

Hax: 想自定义node_module目录名字为npm_modules?有什么特别原因吗?实际上这个不太好办,因为很早就有人提过,但是node.js这个部分是不能改的,且故意设计成不能改的。

问:前端单元测试一般都在测试什么?主要我虽然用了测试框架,但理解并不深,也没有体会到这种测试带来的好处,所以想了解下您这边如何看待和写单元测试的。

Hax:单元测试(或者现在流行的BDD或spec)的意义和写法,这个一句话很难讲清楚,简单说就是用测试来定义你的api的行为。我建议可以找一些书来看。我自己是很久以前看的Kent Beck写的那个TDD的书,虽然不是js的,且很老了,但是基本概念是一样的。当然你也可以找一些新的BDD的书来看。

问:如果是--save-dev的包,就没有办法进行自动测试和更新了吧?这样的开发工具包,有及时更新的必要吗?

Hax:我不清楚你说devDeps的问题。greenkeeper应该是会更新devDeps的。至于说devDeps是不是要更新。我个人的做法是,总是更新。不过可以等几天,因为有时候他们会出现问题,马上出patch版本。这样确保你更新的是比较stable的版本。之所以选择总是更新,因为整个node.js/npm的风格就是倾向于持续更新的。当然大版本更新是要慎重的,因为会发生不兼容改变(所以才发大版本)。

问:贺老,将来npm的包是否会朝着集中化的方向发展,就像出现jquery一样类似的精简大包,但不会很重,而是很复杂?

Hax: 说起来吧,其实node.js作为后端平台,比较无所谓加载的成本,反而是前端比较在意。所以按理说应该前端小包,后端大包。现在情况到好像反过来了?其实也不尽然。我觉得大家有时候有个错觉,似乎npm都是小包,实际上npm上也有很多的大包的。比如今天有人问我fs操作,我就说我常用fs-extra呀。这显然就不是小包。

所以我不觉得需要朝某个方向发展。如果说要发展的话,那么我预测(希望)包的颗粒度能更合理。比如lodash是一个大包,包含好多功能,但是lodash也发了小包,一个函数一个包。这两个颗粒度其实都不对。(也是为什么我不用lodash的小原因之一,嘿嘿)。

再比如left-pad我说了有抽象的价值,但是left-pad作为包的颗粒度是有问题的,为什么right-pad跟他是单独的?没有道理嘛。left-pad的实现和right-pad的实现明明是大同小异的。

所以至少他们应该在一个package里。那现在这个情况(大的很大,小的很小)有一定历史因素,我相信随着ES6module的普及,颗粒度的情况应该会变好一点。因为ES6 module就不需要迁就commonjs的弱点(无法做tree shaking)。

问:贺老,现在js的开发越来越依赖于各种工具和插件以及编译,这种情况会越来越成为常态,还是会随着js本身标准的进步和引擎的升级而回归到不需要预编译的状态?

Hax:某种程度的编译总是需要的,因为js还在不断发展,比如就算现在引擎都支持了90%多的ES6了,但是你要用async/await还是需要编译。然后就算支持async/await了,还有 for…on还有 bind operator之类更新的特性你想用嘛。反正我用了就是停不下来的节奏。

不过呢,现在确实有些环节将来不一定再需要了。比如合并。那http2上来了,合并其实无效反而对性能有伤害。我也做过这方面的预言:https://github.com/hax/hax.github.com/issues/34。希望能如我所愿,降低开发者的负担,同时又能获得更好的工程便利。

问:贺老,问一个很实际的问题,现在react,vue等各种框架流行,如果是您的团队,您觉得一个基础扎实但各大框架只是了解的人可以吗 ?

Hax: 我们团队里有很多人都是这样的。比如 CSS Secrets 的译者 CSS魔法。他对新框架算不上很熟,但是他 html/css/js 的基础非常扎实,就算要换用哪一个东西,也不会有什么问题。有时候你觉得他慢,但是他会有更深入的掌握。理想上每个团队都应该有这样的同志,能够稳得住。当然团队也需要有冲在前面很喜欢尝试新东西的同学。只要不是浅尝辄止,能比较专注的学习,就算我们换一个框架,过去学习的经验也不会白费的。

问:想问贺老一个问题,团队协作中,选择基础框架和技术栈的时候,是怎么平衡团队成员之间的技术能力参差不齐的问题的?毕竟有些东西学期起来有一定成本,想知道这个问题怎么处理,谢谢

Hax:这个问题确实有挑战。我想最主要的还是要营造学习的氛围。另外我个人倾向于就高不就低。就是优先考虑能力高的同学。因为我认为好的程序员是财富,大家都说好的程序员的生产力不是线性的,而是平方或者指数差异?或者有些东西只有好程序员会写,差的写不出来嘛。如果真的认为是这样,那么组织架构、开发流程、整个的体验应该优先考虑好的程序员嘛。但是实际当中也许大家看到的是另外一种情况,是要迁就团队的平均水平。我不是说要不管后进的同学,先进带后进嘛。当然这是我的想法,我知道很多人跟我的想法并不一样。谨供参考了。

问:贺老,请教个题外话,针对大json文件,封装成二进制传输,不知道有什么缺点吗?

Hax:不太清楚你说的封装成二进制是什么意思。如果你意思是转换为某种二进制格式,那是ok的。因为大json有很多问题。当然并不是一定要二进制,比如能流式的某种文本格式也不是不行。只是既然都大到一定程度,就是这个部分成为瓶颈了,也许二进制格式能解决更多的问题。你说缺点嘛,那就是二进制vs 文本的一般比较了。不过我觉得好的协议/工具比如protobuf基本上也都考虑了这些方面。当然这个也需要参考后端同学的意见。