在JavaScript中应用Mixin模式

编程中Mixin是什么?我最近看到这个词,有点感兴趣起来。我以前也见过这个词,依稀记得是在介绍Ruby的文章当中,但是JavaScript中的Mixin干什么用呢?有些公众号提到express.js和vue.js的实现应用了mixin模式,我最近主要也是做这些方面,所以得关注了解啊。

最权威的还是先看看wiki怎么说:https://en.wikipedia.org/wiki/Mixin 头一段说明有点绕,不是很容易理解,那就看看JS代码吧。Wiki列出了三种实现,分别是extend,Object.assign以及Flight-Mixin。

第一种extend方式的参考实现,就是把源对象上面的key,逐个赋值到目标对象上。其它的两种大致也都是如此,Flight-Mixin模式其实就是IIFE直接执行的变形。

剥掉了神秘感,剩下的就很简单了。有什么限制呢?首先,mixin的源对象操作this的属性,一定要在目标对象上存在,否则就会出现undefined问题了。其次mixin在JS这种动态类型的编程语言是合适的,如果用在c#这样的静态类型语言,就可以用扩展方法来实现,更灵活的就得用dynamic来定义this了。

那mixin的用处,大致就是mixin源对象可以定义behavior,然后可以动态的绑定到其它对象上,只要这些对象满足mixin的constraints就可以了,把行为抽象出来。就此推论,mixin也很容易实现成decorator。mixin还要注意的一点是,它实质是一种浅拷贝,浅拷贝可能有的问题它也会有。

在core-decorators项目中的代码更加完整 https://github.com/jayphelps/core-decorators/blob/5b754256a30c23a0aef846c1b45f261e0c7b21a2/src/mixin.js,其中使用了getOwnPropertyDescriptors以及defineProperty这样更为特定的函数处理不同的情况。

mixin有什么问题么?当然有,什么设计模式都有局限性和适用的场景。比如react就提到https://reactjs.org/blog/2016/07/13/mixins-considered-harmful.html 简单说,mixin在大的codebase中增加了隐形依赖复杂度(Mixins introduce implicit dependencies),命名冲突问题(Mixins cause name clashes),滚雪球复杂度(Mixins cause snowballing complexity)。所以在express.js这样的轻量级框架中使用mixin说的通,但是复杂的企业级应用,就不得不考虑复杂度带来的各种问题。

我的建议是如果软件超过7个人开发,那就考虑angular/TypeScript/rxjs这一套。如果是小项目,可以考虑react或者vue.js,但是最好也配上babel加ES最新标准。

感兴趣的可以留言讨论。

通过awesome和alternative学技术

编程技术学习到某个程度,就需要扩展眼界,这样才能把自己锻造成T字形人才,有深度有广度。

我这里推荐两个方法可以扩展某个领域的知识面,一个是Awesome,一个是alternative。

比如我想了解更多关于angular方方面面的知识,可以直接在github敲入awesome angular搜索,就可以找到这个repo https://github.com/PatrickJS/awesome-angular 如果感兴趣rust,就能找到https://github.com/rust-unofficial/awesome-rust 。Awesome类知识汇集有点类似百科全书,或者是以前的dmoz(还有人知道这个么?),有空就可以瞅瞅,对于某个项目/库感兴趣了就深挖一下。

alternative的用法又不一样了。我经常收到领导的要求,其实也是架构师常见的工作,就是比较不同产品或者框架的优缺点,做一些比较或者雷达图什么的。这时候就可以搜索关键字加“alternative”,比如想了解aws的竞争者就在谷歌搜“aws alternative”,然后点开结果页面看看。还有一个网站https://alternativeto.net/ 就是专门做同类型软件比较打分的,还算客观。

周末玩玩技术

我很久以前玩过一段时间的google appengine,用它来连接rss填补google reader的空白。前两天趁着周末又捡出来把玩了一下,现在的感觉却不怎么好用了,难怪google的云计算赶了个大早,却被后来者azure居上。

简单的crud应用,比如todo或者记事本甚至是proxy,appengine还是可以用一用的。但是它有几个问题,一个是standand环境的编程比较复杂,开发者要了解一大堆东西,总算把google datastore在nodejs上跑了起来,但是运行起来才发现javascript版本的rss parser不给力,不如python的feedparser成熟。而python想找一个在appengine稍微能用的blog或者cms几乎是不可能的,大多数的github项目都是11、12年甚至零几年的。另外的问题是如果不付费很多功能都阉割了,即使google cloud赠送了300美元一年的试用,可是我不想浪费时间在这个没落的平台上了。

于是又想到了新型的平台zeitnetlify,它俩都支持连接到github直接拽代码部署,命令行直接搞定,试用了一下部署一个coreui的angular demo棒棒哒。如果是纯js项目可以考虑这两个平台。

做toy project的开发者还可以考虑heroku,这个老牌平台虽然有着google cloud同样的缺点,但是它上面一些开源项目却很实用,比如部署了一个下载youtube视频的应用在上面,还可以支持v2,前面挂上cloudflare那就可以特殊情况下应应急。

TypeScript+Babel+Webpack企业级应用开发的感想

所谓的企业级应用,从技术是说要支持极为广泛的用户浏览器,比如IE11,Edge,以及对ES6支持更好的Chrome/Safari等等。

旧的浏览器只能支持ES5是一个极为糟糕的痛点,不得不通过各种办法翻译代码到ES5。我的选型就是TS+Babel+Webpack,基本上也是前端的标配了。比较坑的是这里面配置文件的设定要花一些时间,消耗了我不少脑细胞和时间去搜索和尝试,感兴趣的可以留言交流具体的问题。有一个小窍门,是参考其它框架的工程实践,比如vue的https://cli.vuejs.org/zh/guide/browser-compatibility.html 这里面就列出了一些可以借鉴的要点,包括参考vue-cli的源代码,也可以借鉴(copy)那些babel插件可以用,如何配置config文件等等。

关于production环境发布部署,可以参考这篇文章https://philipwalton.com/articles/deploying-es2015-code-in-production-today/ 主要是利用浏览器对于“module”关键字识别与否,条件加载转译到ES5的或者直接就是ES6的代码。现在还没有用在当前项目,不过以后如果遇到性能问题的话,就要考虑这个点了。

最后要注意的是如果考虑浏览器兼容性,一些新的特性可能就无法使用,比如Proxy这样的根本就没有比较好的polyfill方案,用了也许就支持不了IE11。当然,我的建议是用户也要与时俱进,把这些老旧浏览器赶紧的丢进垃圾桶吧。

程序设计原则

YAGNI – You Aren’t Gonna Need It
https://en.wikipedia.org/wiki/You_aren%27t_gonna_need_it
https://martinfowler.com/bliki/Yagni.html
“Always implement things when you actually need them, never when you just foresee that you need them.”
“你不需要做这事”原则,但是也需要权衡短期就需要的灵活扩展可能性。
建议:对于需求之外的扩展,可以经过小组讨论决定是否需要。

Don’t repeat yourself
https://en.wikipedia.org/wiki/Don%27t_repeat_yourself
“别重复自己”原则。
通过自动化测试替代反复使用的手动测试。
通过设计模式,抽象,继承,重载,公用函数来减少代码重复。
提醒信号:再一再二,但不能再三再四。如果一件事,一段代码,一个需求,一个手动测试反复出现,就可以考虑应用DRY原则。

KISS – Keep it simple, stupid
https://en.wikipedia.org/wiki/KISS_principle
“保持简单”原则。
对于一个需求,如果有两种实现,一种较为简单,一种比较复杂,尽量选择简单的实现。
参考“奥卡姆剃刀” (https://zh.wikipedia.org/wiki/%E5%A5%A5%E5%8D%A1%E5%A7%86%E5%89%83%E5%88%80 )

If it ain’t broke, don’t fix it
https://en.wikipedia.org/wiki/Bert_Lance#If_it_ain’t_broke,_don’t_fix_it
“没坏就不修”原则。
一个设计或者代码,虽然不够好,如果满足需求还能用就不要动它。
反例:如果新的开发要修改以前代码,可以考虑一起把不够好的部分修掉。