漫谈 JavaScript 方言与派系

JavaScript 近几年的表现十分优秀, 语言还是那个语言, 可给人的感觉已经有了很大不同. 前端摩尔定律里, 每18个月前端的难度就上升一倍, 现在看来似乎也不是没有道理.

按照前端摩尔定律, 自我接触 JavaScript 以来, 前端的难度已是一开始的16倍. 从 jQuery 一统天下, 到 Vanilla JS 的崛起; 从第二次浏览器大战初出茅庐便震惊世界的 Chrome, 到现在坐拥浏览器份额宝座的Chrome; 从在浏览器里都没人愿意多看一眼的编程语言, 到现在哪都能用的万能胶水语言, JavaScript 经历了太多太多, 而它的传说似乎才刚刚开始.

这篇文章我将谈谈自己对 JavaScript 各种方言的感想以及对于现在前端生态圈割裂为几个派系的态度, 文章比较长, 但内容不算特别深入, 权当抛砖引玉.

语言分化

原本的 JavaScript 太过于落后, 它得用火箭发射的速度才能赶上那些比它优秀的语言. 现如今, JavaScript 拥有着全世界最强的生态环境和海量的开发人员, 而且和那些老旧的语言不同, JavaScript 的更新速度越来越快, 方言和转译工具也越来越多. 作为使用 JavaScript 作为主力语言的开发者, 我在感到欣慰的同时, 又十分恐惧——变化太快了.

这些年, 且不说各种编程范式和架构模式上的变化, 光是 JavaScript 的语法就发生了很多变化. 从最开始的 ECMAScript 3 标准到 ECMAScript 5 标准, 到后来的 CoffeeScript 方言, 再到如今的 TypeScript、LiveScript 方言, 以及最丧心病狂的 —— Babel 和 Webpack 在 Facebook 的引领下共同开启的 JavaScript 语法转译器插件化的时代, 更是把 ECMAScript 6/2015 和 ECMAScript 7/2016 标准的利用率推向了极致, React 另辟蹊径的 DSL —— JSX 更是作为重要角色掀起了一场席卷全球的巨浪.

CoffeeScript / LiveScript

CoffeeScript 是 Ruby 社区创造出的 JavaScript 方言, 也是流传最广, 使用者最多的方言. CoffeeScript 吸收了 Ruby, Python, Haskell 语言的设计思想, 将 JavaScript 的代码变得清晰简洁, 盛极一时.

我个人是比较抵触 CoffeeScript 的, CoffeeScript 推出的时候我刚刚掌握 JavaScript 较为深层的内容, 我认为 JavaScript 本身的一些设计已经足够复杂, 也足够应付可能遇到的问题(比如 Holy Grail 继承模式), 选择 CoffeeScript 意味着程序员在逃避 JavaScript 复杂的部分: CoffeeScript 的 class 关键字作为语法糖舍弃了 prototype 各种有趣的 trick, 固化了编写代码的人的思维模式. CoffeeScript 能为我带来的唯一好处就是它可以让我少写一些没必要的 JavaScript 代码, 比如各式各样的括号, 这确实能节省下很可观的时间, 因为这一点, 我也就慢慢去接受了这门语言, 但每当有不熟悉 JavaScript 的人想要涉足 CoffeeScript 时, 我还是会建议他先学好 JavaScript, 掌握基础的东西, 总是没有坏处的.

CoffeeScript 诞生 1 年左右的时候, 国内的前端界出来了很恶心的一批大力鼓吹 CoffeeScript 并贬低 JavaScript 的人, 你知道中国每个时代都有这些货色, 这些人放在几十年前是红卫兵, 现在是红卫兵的继承者. 特意去鼓吹一门语言是很傻逼的事情, 我怀疑这些傻逼中有不少人现在转 TypeScript 了, 关于 TypeScript 我稍后再谈.

到了今天, 已经没有多少人想要用 CoffeeScript, 如果之前学习了 CoffeeScript 却又对 JavaScript 一窍不通, 那就很遗憾, 差不多还得重学一次 JavaScript. LiveScript 算是 CoffeeScript 半个继任者, 语法几乎一致, 额外提供了很多函数式编程特性, 但 LiveScript 的上手比 CoffeeScript 要难很多, 并不是一个能够拿来让初学者使用的语言, 所以也没有像 CoffeeScript 那样流行.

回想起来, CoffeeScript 一个罪大恶极的地方便是诱导程序员放弃函数声明, 直接导致 CoffeeScript 代码里所有函数都变成了变量. CoffeeScript 的变量都会在作用域的顶部声明, 这样就放弃了原先的声明提升的优势, 强制让代码的书写顺序变得十分重要, 而这些在 JavaScript 里是完全不必担心的事情. JavaScript 声明式定义的函数, 有着享受作用域内声明提升的巨大优势, 更符合人类的思维, 同时在视觉上也有利于将变量与函数区别开. 如果你从 CoffeeScript 转回 JavaScript, 还在用赋值的方式定义函数, 便是被 CoffeeScript 毒害了思想. 讲道理, CoffeeScript 当初如此设计是为了方便做函数式的 compose, 但是结果显然有些弄巧成拙.

LiveScript 解决了 CoffeeScript 的很多设计问题, 越是深入 LiveScript, 就越会觉得 CoffeeScript 不可理喻, LiveScript 是允许开发者定义式声明函数的. 但遗憾的是 LiveScript 的部分使用者仍然选择了坚持赋值的函数定义方式, 在我看来, 这会促使程序员在编码时过于依赖词法作用域, 导致各个词法作用域互相引用上下文, 影响代码可读性, 同时离纯函数的道路越来越远, LiveScript 的编码风格指南也没有在这方面定下规范.

CoffeeScript 虽然取消了 JavaScript 的花括号, 但如果不注意留出空行, 代码会变得相当密集, 导致可读性变差, 其规避函数声明定义的作法, 会在无意之中减少变量和函数的差异, 降低了代码的辨识度. CoffeeScript 本身的变量作用域还严重依赖于首次赋值的位置, 容易出现意想不到的新变量, LiveScript 虽然提供了穿透作用域的语法, 以及声明式的定义方法, 但也可以看出是不鼓励的, 毕竟不用写声明定义在某种层面上更加吸引人的目光, 但如果舍弃的是代码的可读性, 那未免有点舍本逐末了.

LiveScript 和 CoffeeScript 函数调用可舍弃括号的特性着实着迷, 但在书写时难免会与传统命令式混合, 最后出现代码仍然会用括号标记, 同时混杂着空格和逗号, 让代码变得不再优雅, Curry 情况下逗号与空格相同的语义会让人放下提防, 出现错误后也更难排查. 而放弃命令式, 又会让很多代码无从下手.

CoffeeScript 的另一个问题是它会默认将函数执行过程的最后一行代码的结果作为函数返回值, 即认定所有函数都是函数而不是过程, 虽然节省了写 return 关键字的功夫, 但有时会带来大的问题. 我们知道 JavaScript 有很多异步调用, 而一些库的设计理念是这样的 —— 如果一个函数返回了 XX, 那么将这个值作为结果, 如果不存在返回值, 则等待回调函数被调用. 在 CoffeeScript 里这个情况往往就变成了 —— 一个函数不但返回了结果, 还调用了回调函数, 如果库的设计不严谨, 那么就相当于返回了 2 次, 于是调试时便有可能遇到莫名其妙的问题.

LiveScript 代码书写起来非常舒服, 和 CoffeeScript 一样简洁, 它与 CoffeeScript 不同, 是真的在以函数式的书写方式写代码, 秉承了函数式的学院派气息, 在语言设计方面有着足够的前瞻性. LiveScript 也解决了我以前在文章里提到过的关于 CoffeeScript 注释的问题, 它用 /**/ 替代了 CoffeeScript 的 ###, 解决了注释块混乱的问题. LiveScript 本身的更新已经不活跃, 很可能像 CoffeeScript 一样就此止步了. 随着 ECMA 的发展, LiveScript 的功能已经不再有优越性, 也许会在不久后彻底落伍, 只能惋惜了, 我今后大概也不会继续用 LiveScript 开发程序了, Gloria 恐怕就是最后一个了.

TypeScript

TypeScript 是 Microsoft 推出的编程语言, 项目由大名鼎鼎的 C# 首席架构师 Anders Hejlsberg 操刀. 它的特点是在 JavaScript 的基础上实现了强类型和静态类型检查, 加入了很多静态语言才有的概念.

老实说, 我不喜欢 TypeScript, 它给我一种被绳子捆住的感觉, 我对这个语言的厌恶程度相比 CoffeeScript 是有过之而无不及. 与之相反, 我觉得 C# 很不错.

没错, 静态类型下的 TypeScript 在 Visual Studio Code 里的提醒功能是很强悍, 但那又怎样? 我一点也不想要将自己的时间浪费在书写"一劳永逸"的类型定义文件上, 尤其是我的代码依赖开源项目的时候: 自己写定义文件? 开什么玩笑, 我只要看看文档就能用了. 在 TypeScript 提供 AllowJS 选项之前, 以 JavaScript 的风格编写 TypeScript 的过程是极度痛苦的.

想要让一个由动态语言组成的生态环境支持一个静态的异类, 难度真的是很大, 看看 DefinitelyTyped/DefinitelyTyped: The repository for high quality TypeScript type definitions. 就知道了, 定义文件的量虽然大, 但版本却未必能够跟上实际中的项目, 还是不完美的, 有的文件落后于项目实际的版本, 有的文件不全(因为一些模块的定义难度大), 每一次升级都有可能需要重写定义文件, 除非 TypeScript 能把 JavaScript 灭掉(这是不可能的), 否则别想指望每一个开源项目作者都给你提供类型定义. 那些 TypeScript 志愿者们在一个又一个项目里添加类型定义文件, 干着他们最喜欢做的重复劳动, 我都替他们感到悲哀.

TypeScript 根本无法优雅的为一些 JavaScript 书写定义文件, TypeScript 的定义仅限于"有限"的世界, 不适用于"无限"的世界, 它既然只是一个把自己装成 JavaScript 的支持类型标记的动态语言, 那么为什么干脆不做成单独的语言? 因为 TypeScript 急于用 JavaScript 的生态环境获取成功, 所以放不下脸去创建一个新的编程语言(不过那些放下脸去做的新语言也基本都死光了), 但坚持编译到 JavaScript 的路径实在是过于艰难了, 写定义文件, 就意味着陷入被动.

为了追赶 ECMAScript 标准, TypeScript 最近几个版本终于支持将 Async/Await 的语法糖编译到ES5, 之前只能编译到ES6, 反正我是不知道在那个大多数解释器都不支持 ES6 的年代编译到 ES6 有什么用处, 只能说 TypeScript 本身在追赶 ECMAScript 这件事上和 Babel 相比是不及格的. 追赶 ECMAScript, 也是陷入被动, 而且很可能被 ECMAScript 革掉自己的命.

TypeScript 本应是一个单独的程序语言, 不应该是 JavaScript, 这两者甚至相去甚远, 现在的情况最后很可能就是导致 TypeScript 阵营固步自封, 因为 JavaScript 的大环境是动态语言的, 而且是高速发展的, 没有那么多人愿意为 TypeScript 写类型定义, 大家都忙着改变世界, 哪里有心思干这些底层工作. 静态类型终归是静态类型, 是没法和动态类型完全相容的, 不然别的编程语言也这么做了, 用静态语言的设计思路去制约 JavaScript, 只会被更强大类型标记和检查工具替代, 到那时那些鼓吹 TypeScript 的二五仔估计又要当一切都没发生过的去重写一大堆东西. 当然, 你也可以认为这些都是我的偏见.

TypeScript 给人的感觉也与 JavaScript 有很大不同, 它的表面是 JavaScript 语法, 但内在的编程思想是静态类型的, 二者并不能兼容, 我知道很多不懂前端的后端看到 TypeScript 会感觉见到了大救星, 但事实上如果有后端人员使用 TypeScript 加进来编写代码, 只会带来更多麻烦. 如果光拿 TypeScript 写后端, 效率又会出现问题, 而且 Node.js 在后端主要是充当一个中间件的作用(而中间件一般也没有那么强的类型检查需求, 测试写完善比啥都强), 不适用于很多 CPU 密集的场景(这些场景最终还是要 Java 和 Scala 扛起大旗), 所以后端学会了 TypeScript, 意义真心不大.

像我这种静 / 动态语言, 强 / 弱类型语言, 命令式 / 函数式编程, 面向 XX, 前 / 后端开发全都接触过的开发者, 也很难转换各种情况下的思维, 而且不知不觉就会更加倾向于使用 JavaScript. 用静态语言的时候我觉得解析 JSON 真他妈麻烦, 类型声明无论显式声明还是类型推导都过于拖泥带水, 全面 OO 简直教条主义思维僵化, 函数式用起来都感觉是在参加残奥会(没有任何歧视残疾群体的意思), 闭包的实现还基本都是错的, 有的语言明明是语言设计差, 还非要整数据结构和设计模式, 偶尔会冒出几个塞满语法糖的手感好一点的静态语言, 可生态环境又都很难起来. 用动态语言的时候觉得这个变量在经过这段代码之后类型变得难以预测, 程序的执行顺序难以捉摸, 经常抱怨调试工具和开发环境不够智能, 经常出现神奇的问题, 同一种功能的实现方式太多, 开源模块很多但质量普遍不高(因为整个动态语言的开发环境所致), 用多了会慢慢丧失编程能力. 讲道理各种程序的理论模型在几十年前就已经设计好了, 这几年业界也是翻来覆去的炒冷饭, 最后发现还是印证那句老话, 没有银弹.

转眼看看 Microsoft 的其他开源项目, 我觉得 TypeScript 离软粉们的宏伟蓝图还差得远着.

ECMAScript 6, 7 / 2015, 2016 / JSX

我是在 ECMAScript 6 出现的时候放弃的 CoffeeSCript, CoffeeScript 虽然有着很多与 ECMAScript 标准相似的语法糖, 但终归还是不如 ECMAScript, 比如说 ECMAScript 的 Generator 在同期的 CoffeeScript 就没有, 我知道有人会说 CoffeeScript 有这个功能, 但实际上这个是后来 CoffeeScript 添加的, 同样的情况之后也继续在 CoffeeScript 上出现, 既然 CoffeeScript 在追逐 ECMAScript 的新特性(TypeScript 也是如此), 那为什么我们不直接用 ECMAScript 呢? 在对 CoffeeScript 的缩进语法郑重道别之后, 我义无反顾地投身于了新 ECMAScript 标准的 JavaScript 编程.

如今 ECMAScript 的新语法, 已经非常好用, 而且在最新版本的 Node.js 和现代浏览器里也得到了语法支持, 去年我们还需要用 Babel 或是 Trucer 转译的语法, 如今都可以直接运行, 真的是很欣慰, 不过有些涉及底层的特性还没有被正确实现, 相信时间会解决问题.

JSX 是一个好的语法糖, 但 JSX 只适用于 React, 如果没有 React, JSX 就很难有所作为. 我不欣赏 React 试图将一切丢进 JavaScript 解决的风格, Facebook 为 React 提供的一整套工具链都有着这个风格, 但很实用主义. 我用了很久, 可还是认为 Polymer 的方案比较优雅, 从 Polymer 取经的 Vue.js 用的也是 Polymer 的方案, 但还没正式推出的 Vue.js 2.0 已经倒戈 JSX, 可见 JSX 在语法上对整个 JavaScript 生态环境的辐射.

派系之争

谈到 JavaScript, 就不得不说它的生态环境, 说到它的生态环境, 就不得不说它的两大派系:

  • Facebook 派系: React, React Native, Immutable.js, Relay, Redux, Babel, Webpack, Nuclide...
  • Google 派系: AngualrJS, TypeScript, Ionic, Polymer, NativeScript, Dart, V8, Chrome...

这两大派系里的东西并不完全都是这两家公司生产的, 有的只是有很强的关联关系, 比如 TypeScript 同时属于 Google 和 Microsoft 派系.

Facebook

Facebook 派系不得不说还是牛逼, 自从造了个 React 出来, 整个前端界都跟着进步好几年, 但是路子比较野, 算是继承了 JavaScript 走野路子的传统, 同时造了很多有趣的新轮子(主要是把各自编程思想融入前端开发领域), 目前发展最好的就是它了. Facebook 派系的版本号刷得也特别干脆, 大步流星, 很有当年 Chrome 的气势, 很难说前端领域的下一个时代不是 Facebook 派系的. 如果说 Facebook 派系下的开源项目是青壮年, Google 派系的只能算是老年人.

React 分离了视图层, React Native 在 React 分离视图层的前提下攻入移动端, Immutable.js 和 Redux 用邪道拿下了状态管理, Babel 和 Webpack 搞定语法支持, Relay 和 GraphQL 试图用颠覆前后端的查询方式干死 REST(不过暂时还没有得逞). 整个 Facebook 派系给现代前端领域做出了卓越贡献, 近几年来爆炸式的发展和这些开源项目关系密切. 太优秀了, 以至于没什么话好说, 埋头去用就对了.

Google

Google 派系终日有一股难言的痛苦: 是我, 是我先, 明明都是我先来的...MVVM 也好, 组件化也好, 还是推出新的编程语言, 明明都是我先来的.

明明都是你先来的, 可为什么至今 Google 派系仍然只能屈居老二? 一想到现在 Angular 2 和 Polymer 工具链都是用 TypeScript 开发, Dart 在一旁蹭吃蹭喝, 我就悲伤逆流成河. Google 近来的表现实在是不争气, Android 也好, Web 也罢, Google 自家在技术领域搞的东西都乏善可陈, 只有 Material Design 还算可以. 每次 Google 出场不是带节奏, 就是画大饼, 没一点全力以赴上心去做的东西 —— 总是先用一副未来世界的美好蓝图催眠你, 然后再用现实的砖头把你拍醒. Google Glass 和 Project Ara 现在几乎神隐的状态, 出售旗下机器人公司 Boston Dynamics, I/O 大会发布了一个没人爱搭理的 Daydream, 这些都很好的诠释了 Google 变身为 Alphabet 之后的情况, 前几天 Chrome OS 以外平台的 Chrome App 被砍的消息, 宣布开发新操作系统 Fuchsia 的消息, 你会发现你越来越不能理解现在 Google 公司的作为, 仿佛 Larry Page 在带领 Alphabet 走向毁灭, Google 已经不是我们以前认识的那个 Google 了.

Google 的开源项目团队一向以理念古怪著称, 从 Angular 1.x 时代那一股浓浓的 Java 味, 到现在 Angular 2 追随 TypeScript 后搞出来的四不像, 让我这个 Google 粉丝都很难接受. 几乎没有例外的是, Google 各个开源团队不是不喜欢写文档, 就是写文档的水平奇烂无比, 开发人员想配合他们的步调都不行, 理念古怪导致了文档难写, 文档难写导致了上手麻烦, 上手麻烦导致了生态环境恶劣. 你要是拿 Facebook 的那一堆东西跟 Google 的这堆东西比, 换作去年我还持保留意见, 现在我只觉得差不多可以秒杀吧.

我就想看看 Google 手下这堆东西还能撑到什么时候, 在半壁江山已经被 React 打下的情况下, 至今还处于 RC 版本的 Angular 2 还有什么能拿得出手的. 每一个跟 Microsoft 混的现在几乎都不成样子, 既然当初 Angular 2 选了 TypeScript, 那么就应该做好被消灭的准备了. 我觉得 Larry Page 啥时候有空可以和 Satya Nadella 商讨下把 Alphabet 的产品关闭部门和 Microsoft 的改名部门合并, 这样应该就能拿下整个互联网了.

再谈我之前比较看好的 Polymer, 浏览器原生支持, 还是照样被 React 干翻. Polymer 没有发展起来, 原因其实挺多的, Polymer 有着许多缺陷: HTML Imports 出错会静默失败, 调试难度大, Shadow DOM 只能隔离 CSS, 不能隔离 JavaScript, 需要重新走 RequireJS 模块化的老路, 或者是跟 Facebook 阵营一样依赖 Webpack 的打包实现, 而且对于移动端压力显得还是比较大. 总的来说对比 Facebook 阵营邪魔外道的 CSS 模块化和万物皆可打包的技术, 并不存在明显的技术优势, 同样需要接受新概念, 开发难度没有明显改善.

Polymer 最后可能还是沦为可有可无的 Widget 开发框架. 加上 Google 从来写不好文档这一点(以前 Angular 1.x 时代很陡的学习曲线就是拜其所赐), 整个生态都没有被带起来, 我现在甚至都觉得 Web Components 的那几套标准都岌岌可危了. Polymer 生态最牛逼的地方就是, 我之前用到1.6版本, 结果一届 I/O 大会就直接把版本号重启到 1.0, 搞了一套工具链, 结果最基本的 Polymer-CLI 到现在还没开发完毕, 而且它们的自动化测试要用到 Java, 唉, 想想都感觉可怕.

Google 派系有一个好, 就是 Chrome 是自己家的, 跑得比谁都快, 浏览器界的老大, 可惜没卵用, Polymer 仗着浏览器原生支持都没能起来, Dart 尸骨未寒, 很难相信其他由 Google 提出的标准不会被玩坏. 反而是 Mozilla 那边夹缝里求生存日子过得舒坦, 他们搞的那个 MDN 啊, Excited, 给 Google Chrome 写代码还得天天翻人家的文档, 不知道比 Google 上心多少倍.

小圈子

除了两大派系, 也有小圈子活的比较滋润.

Microsoft

这几年随着个别软粉颠倒黑白孜孜不倦地布教, 还真有一小撮人投靠了 Microsoft 的工具链, 可不得不说 Satya Nadella 上任后, 我看到的 Microsoft 和 Alphabet 越来越像了(也越来越烂了). 不过同样是带节奏画大饼, Microsoft 相比 Google 就不地道很多, 可能是 Microsoft 帝国的血脉所致: Google 画出的大饼第二个月就可能可以吃到实物了, Microsoft 的大饼画完一年后才出炉, 出炉后可能还要你另交钱, 交完钱尝到饼, 发觉很难吃, 正想投诉, Microsoft 当着你的面就大手一挥说我家的饼现在免费了, 大家随便吃——基本就是一种耍猴的心态, 联想到 Windows 10 的测试团队被 Satya Nadella 全部砍成研发团队, 让用户当小白鼠的消息, 差不多就可以预测出 Microsoft 的下一个十年了.

Microsoft 在前端领域能打的不是很多(不如说 Microsoft 在每个领域都差不多是这样), TypeScript 算一个, Visual Studio Code 算一个, 这很符合 Microsoft 的一贯作风——开发环境和程序语言双剑合璧, 刚推出时乍一看是种我已经天下无敌了的架势, 但现在看来还是有些理想化了. 除了 TypeScript 和 Visual Studio Code, Microsoft 在前端领域还要有一个 RxJS 可以一战, 这个东西是 Microsoft 的 FRP 语言实现 Reactive Extensions 的一部分, 如果你学过 Android 开发, RxJava/RxAndroid/RxKotlin 应该已经耳熟能详了. RxJS 说实话在 JavaScript 中没有特别大的用处, 属于一个辅助框架, 地位不是很高, 一是因为 JavaScript 里 Promise 的理念和 RxJS 类似, 二是 RxJS 现在实现的具体功能差不多都被其他模块完成过一遍, 虽然 RxJS 是自成一体的框架, 却显得有些鸡肋, 尤其在浏览器的 Object.observe 被砍之后(被 Proxy 替代), RxJS 的处境就更加尴尬了.

RxJS 的思想还是足够先进的, 其不好理解的思想, 刚好满足了一部分人学完拿出来装逼的需求. 当然 RxJS 在一些场景下是真的很有用(只是很少遇到这种场景), 也引出了一些 RxJS 组成的 FRP 框架, 但都处于不温不火的状态, 估计今后也难有起色了.

Vue.js

Vue.js 目前发展得比较好, 有与 React 分庭抗礼的趋势, 其工具链一定程度与 React 的工具链重合, 师夷长技以制夷, 国内接受程度很高(有中文文档是一个主要因素, 同时文档质量也的确挺高), 国外也还不错.

Vue.js 2.0 目前还没有正式发布, 更新内容主要是在一些特性上与 React 靠拢, 同时也坚持了一些与 React 不同的理念, 继续保持 Vue.js 的小而美.

值得注意的是阿里巴巴搞了一个 Weex 试图把 Vue.js 2.0 跟 React Native 一样在移动端做 Native 渲染, 可以说这是一个里程碑式的进步(要知道 Vue.js 本来的主战场就在移动端). 但由于 Weex 是阿里巴巴做的, 再加上前阵子我上 Weex 的网站看了一下, 感觉还是有很长的路要走, 基本上可以不指望了.

结语

终于写完了, 我真是不想再写这么长的文章了. 最后的最后, 再发点牢骚.

为什么这个由软件组成的世界这么糟糕?

这是一个能把 Markdown 编辑器翻来覆去做出几十上百种的世界. 搞 Markdown 的那一批人自己恐怕不怎么会写字, 天天就是在折腾语法 / 特效 / 插件, 什么语法检查啊, 写作流程的优化啊, 统统不顾, 我承认字体的显示效果和排版确实很重要, 但这些你们几年前就已经做过了, 咱能不能搞点新鲜东西出来? 这篇文章字数上万, 我却没有从各种编辑器里得到过任何的帮助. 大部分做桌面软件的人都在避重就轻的假装解决一些问题, 实际上却什么都没有解决, 反而让别人以为这一切本就应是这个模样.

为什么这个由软件组成的世界这么糟糕? 因为人们最常接触到的东西太糟糕了. 可以说那些看不见的技术都还是发展得很好的, 但看得见的技术都已经沦落到互相比烂了. 太过于依赖平面设计, 以至于没有功能上的创新.

现在看来, 编程门槛的降低, 并不总是件好事.