• 我想来简单地评述一下这篇文章,这篇文章我早前已经读过,现在我希望尽可能站在中立的角度来描述一下作者提及到的几个方面,然后从一个具备一定经验的 ember 开发者的角度来解读一番。

    和作者一样,我不打算批判任何 ember 的“竞争者”,因为仅就普及和接纳的程度而言,ember 根本就不是 angular 或 react 的对手。但是从另外一个角度来讲,我所认识的 ember 开发者们对于其他框架的了解程度要远远大于反过来的情况。背后的原因是在我看来,ember 社区接受和学习其他框架的优点的愿望和能力是很强的,但却不会强到要改换门庭,因为 ember 有一些独特的价值是其他框架所不具备的。而对于那些外来的精萃,ember 社区在理解的同时也会很谨慎得来吸收并完善自己,而不是毫无主张漫无目的的全盘接纳。

    对我来说这一点非常有趣,在很大程度上非常类似于今天的中国是如何在保持开放式发展的同时还力求塑造自己独特的文化。

    事实上,我非常理解 TypeScript 的价值,前端开发的环境的不可控性是非常高的,TypeScript 这样的工具的确可以帮助很多开发者减少这些风险带来的影响。比方说很多人经常会写出“想当然”的代码,比如说假定入参是一个数字,于是不假思索的对其进行数学运算。大多数时候可能不会有问题,因为 JavaScript 有着很有趣的隐式类型转换,它可以在很多时候悄悄的完成你都没意识到的工作,可它并不能保证百分之百正确,更可怕的是有些时候所引起的逻辑错误并不是语法或是运算结果的错误,所以你可能需要很久才会发现这里有问题。

    比如说很多人都没意识到如果把数字通过数据绑定关联到表单元素之上,等你把它拿回来的时候它们就已经不再是数字而是字符串了(即便你的表单元素是 Number 类型也不例外)。DEMO

    TypeScript 的最基本的价值就在于迫使开发者考虑输入输出时的类型匹配问题,我认为如果你在做一个正儿八经的项目,同时参与的人又不见得能轻松驾驭 JavaScript 的各种特性的情况下,TypeScript 还是很管用的。而且它的价值还远不仅如此,Glimmer 2 是 ember 框架所采用的新一代渲染引擎,它就是用 TypeScript 开发完成的,core team 对其表现的反馈相当良好。

    而 ember 社区很早就有了支援 TypeScript 的 addon,不过我自己没有用过就不多说了。我相信使用 TypeScript 来开发 ember 应用程序应该是很容易的事情。

    至于 jsx,我同样非常理解 React 所作出的决定,因为它根本就不是模版而是函数体表达式的替代语法,和 ember 相比完全是两种不同的工程思维,所以并不好直接对比。不过在“结构描述可用的逻辑表达能力”这件事情上,一个是给予完全的自由(jsx),一个则是默认限制但允许扩展(通过 htmlbars helper),这种看起来两个极端的对比也的确很有意思。对于新手来说,或许会觉得 ember 在模板上的限制会让人束手束脚,可是这种决策背后的原因是需要你去理解的(当然如果你不能理解,React 欢迎你),这一点原文的作者已经描述过了。进一步来说,一旦你具备了一定的知识水准,你会发现其实 ember 也能写出兼具强大逻辑和易读语义的模板,区别仅仅在于是一下子就丢给你还是一步一步引导你罢了。

    从这个意义上来看,反而是像 React 那样的理念对开发者水平的要求更高,因为它很容易失控。

    至于说“ember 使用了 pure javascript,没有额外的语法”,well,在我看来这得看从什么角度来说了。

    如果你只是 average javascript developer,ember 的确蛮“传统”的,语法上不会有太多的“惊讶”,这是好事。可是你不要以为 ember 永远会这样,因为这些传统中的一部分也在拖累着 ember,并且因为由来已久很难快速的根治,因此才拖延至今罢了。

    比方说对于 ES2015 的语法的接纳,可能很少人知道这样的传统写法:

    import Component from 'ember-component';
    
    export default Component.extend({
      init() {
        this._super(...arguments);
      }
    });
    

    已经可以写成这样了吧?

    import Component from 'ember-component';
    
    export default class extends Component {
      constructor() {
        super();
      }
    }
    

    这倒的确是事实,但是我会劝你现在先别这么做,因为你很快就会注意到更换了语法之后很多东西就“坏”掉了。

    原因是 Component(已经它的其他同胞)并不是完完全全的 ES2015 Class,换句话说它们并不是传统意义上的构造函数(前提是你明白 class 只是传统的构造函数 + 原型继承的语法糖而已)。

    在 ember 诞生并成型的时代 ES2015 还在娘胎里,ember 不能等它呱呱落地才开始自己的成长,所以它大量使用了 ES2015 之前的很多 magic trick 来实现现代 JavaScript 所实现的东西,其代价就是今天想要摇身一变就得需要时间。你可能会说 React 也经历过这种转变,但是它就很快啊?可是从框架复杂程度上来看 React 根本就不是一个级别的啊——如原文所说 React 都不算是一个框架。

    当然这一类的变化也没有超出 pure javascript 的范畴,不过 impure 的语法也不是没有,比如说:

    // Computed Property
    incomplete: computed('[email protected]', function() {
      let todos = this.get('todos');
      return todos.filterBy('isDone', false);
    }).readOnly()
    

    即便从传统语法的角度来看,这种属性定义方式也是够离经叛道的了,如果换成现代的方式应该用一个 decorator 会更加优雅。事实上 ember 很早就有对应的 addon 实现了,它看起来是这样子的:

    import computed from 'ember-computed-decorators';
    
    @computed('[email protected]')
    incomplete(todos) {
      return todos.filterBy('isDone', false);
    }
    

    甚至更好:

    import {filterBy} from 'ember-computed-decorators';
    
    @filterBy('todos', 'isDone', false) incomplete
    

    但是这样的东西一直都是以 addon 的身份存在着(作者和维护者就是 core team member),为什么 ember core 迟迟不接纳它成为正式成员?拿 decorator 来说,它就曾经被 ECMA 废止过,现在它经过重新完善再次进入标准委员会的待选名单,但是何时落地尚未有定论。对于 ember 来说,它不是不能用,但是要小心的,有选择性的,理解潜在风险的去尝试,所以到目前为止它只能是一个 addon。

    我认为作为一个有责任感的团队做出这样谨慎的决策是非常理智和正确的,这也是长久以来 ember 可以保持平稳升级不给开发者造成太多麻烦的重要保障基础。在现实中有人称赞 ember 的坚实可靠,考量周全,当然也会有人批判 ember 略显保守,不思进取,两种声音都有道理,却也都不够全面。ember 团队的理念是(个人解读):最终我们要成为 web 开发的最好选择,无论是关注稳定还是关注特性的人都可以得到满意的结果,只不过 JavaScript 现今正处在不断变革的时代,所以我们要采取一步一步稳扎稳打的策略来朝着目标前进。

    对于身处一线的开发者来说,任何一个框架都不可能满足他们全部的需求及渴望,同理任何一个框架也不应奢望能够干掉所有对手来独占所有的开发者用户,这和良性的市场竞争是同样的道理。有些工具并不是以获取更多的关注来作为自己的价值体现的,使用工具的人其实应该很容易理解这一点,否则的话大部分的开发者其实都可以回家种地了。

    约定优于配置/强制性的最佳实践

    Ruby 社区的人对这个概念是最熟悉不过的了。我自己对它的理解长期以来都存在一个问题:约定究竟是谁说了算?是不是也应该民主表决一下?

    不是没有人对 ember 的约定表达过意见的,这种情形非常多。通常他们都会带着另外一个框架/工具的特性来问 ember team:为什么我们不能这样做/为什么我们没有这个?

    最典型的例子就是 webpack,我已经见过很多次有人提出要用 webpack 替换 ember-cli 现在所使用的 broccoli 了,这里面有一些人甚至做出了自己的尝试,当然也有人态度非常恶劣就好像反对素食主义者的极端分子一样。问题是极少有人真正理解 webpack 和 broccoli 的区别是什么,甚至连 webpack 究竟是什么他们都未必一清二楚。

    从功能性上来讲,broccoli 只做了 webpack 能做的一部分,而且这一部分它做得非常好(构建)。但是 ember-cli 可不是这么简单的东西,webpack 最重要的核心就是模块打包 (module bundler),由于众所周知的历史原因,JavaScript 的模版系统曾经极度混乱,webpack 是众多解决方案之中的佼佼者,后来居上干掉了所有的对手。它的做法本质上就是一个 adapter,定制了一套机制来兼容所有主流的模块规范,然后在公共接口上向真正的标准(ES 2015 Module System)靠拢(先是以 CommonJS 接口为准,然后逐渐过渡)。

    然而在 webpack 被广泛接纳之前,ember-cli 早就成为 ember 系统里的事实标准了,broccoli 在其中只负责一些具体的流程工作,真正的核心还是 ember 自己的 module resolver。其实 ember-cli 也面临着和 webpack 一样的挑战:作为一个前端框架,ember 当然要拥抱占据主流的前端技术栈,然而另一方面作为一个强调约定的 opiniated framework,ember 还要给自己的开发者用户接近无感知的使用体验(意思是你不需要理解各种不同的模块是怎么工作在一起的,你只需要使用约定的接口去引入它们即可)。

    谁敢说 webpack 的配置是“无感知”的?(客观地说,webpack v2 已经好很多了,但这不也是一步一步走出来的?)如果你非要让 webpack 成为 ember-cli 的基础,那么会有两种结果:

    1. 你必须花时间去学习和理解 ember 内部的模块解析机制,然而正确的配置 webpack,从而实现 ember 所提倡的约定——这么一来“约定优于配置”就成了笑话
    2. ember 花力气用 webpack 来适应自己的模块解析机制,把复杂的配置隐藏在 ember cli 的后面,用户并不需要知道 webpack 是怎么工作的,也就不需要配置——可是 webpack 的拥趸们喜欢的就是 webpack 近乎“无所不能”的可操控性

    我想问问 webpack 的拥趸们:你们可以代表其他开发者吗?你们以为所有的人都喜欢折腾天书一般的 webpack configurations 吗?不用质疑我,在我去年打造 React SSR 全家桶的时候就已经把 webpack 玩得炉火纯青了,我非常理解他们的 G 点在哪里。可是反过来当我面对我的同事的时候,我宁可去教他们如何把 React 写得有条有理也不愿意教他们 webpack“真经”,因为这并不是什么愉快的体验。

    这是一个例子,细心敏感的朋友大概能读出我在影射什么,不妨坦白说,就是所谓的“民主自由”。以下是我和另外一位同行对话时的节选:

    我的观点是:这个世界终究是有序的,否则 webpack 的终极目标应该是推翻 ES2015 Module System 而不是顺应它。约定优于配置的精神意义就是,无论哪种行业,大部分人关注的是有序的创造而不是无序的折腾。且把后者留给那些生来就喜欢折腾的人吧(其实我自己就是),而他们也不应该把自己的偏好强加于人。

    也有“光明”的一面,其实 ember 社区一直都走在民主自治的最前端。从基因上来说 ember 出自社区,它从来没有忘记自己的起源,也没有忘记自己的责任和义务。它是第一个推行 RFC 制度的前端框架,自施行以来所有涉及到 API 或是架构机制的增订/修改全部都经历了严格 RFC 流程,任何人都有权利参与这些改变的全过程,任何人也都有权利发表自己的见解。我们只需要明白两件事情:

    1. 你需要尊重整个社区的价值观,社区对你的提案接纳与否取决于社区其他人的态度而不是身份。举例来说,ember-engine 是有来自 Linkdin 的工程师主导开发的(但他还不是 ember core team member),它在架构上遵循了 ember-cli 的体系标准,因此可以顺利的搭载在任何一个 ember 应用程序上。等到它足够成熟(目前是以 addon 的身份存在,core team 协助开发)的时候就会成为 ember system 的正式组成部分(事实上已经公认了)。
    2. 如果你有想法,RFC,slack,community forum 全都对你开放,just play by the book。

    关于缺点

    如我之前所说,ember 社区的文化向来是广泛吸取各种建议和经验然后尝试为我所用的。有些时候你会觉得 ember 给出的方案貌似和“主流”不太一样,那是因为 ember 自身就很庞大和复杂,ember 社区的解决方案一贯都是以解决“自己人”的问题作为第一优先级,而不是为了提供“普适价值”。而一旦 ember 有了对整个 javascript 社群都有借鉴价值的产物,ember 社区也从来不会吝啬贡献自己的力量,比如说 ember-cli 的理念就影响了 react 和 angular 两大社区。

    另外 ember 社区的多样性是非常广泛的,不仅仅局限于 javascript 一隅。比如说 Elixir 兴起之后,很多人体验了不同于其他 web 框架的 Phoenix Framework,其中 Ecto(强调一下,Ecto 不是 ORM!)里的 changeset 对于具有一半 FP 血统的 javascript 来说就很有参考价值。于是 ember 社区立刻就出现了相似的 ember-changeset,对于很多传统的 ember 开发者来说,这就是一个脑洞大开的尝试,而且实际效果也真的很不错。

    实际上,有进步或是变革就代表着有缺点,而且在努力的改善着它们。而那些广受关注的正在改善过程中的缺点相信是更多人比较关心的,即使我此前已经在各种渠道说过很多遍,在这里我还是借这个机会再总结一遍,因为在内心深处我当然期待更多的开发者成为 ember 社区的一员,所以除了画饼之外我当然也应该把挑战摆在面前:

    陡峭的学习路线

    让我们面对现实吧,ember 不是那种用来做 demo 的工具,在你准备使用 ember 来开发你下一个 big idea 之前你至少应该摆弄过各种各样的 demo 很多次了。这不是一个给初出茅庐的毕业生准备的拟真游戏,所以如果你觉得 ember 很难学,那不是因为 ember 有意要给你难堪,而是它的目标受众群体不包含你在内。

    其实 ember 已经拥有了最完善的指南和 API 文档,只不过它很大所以读懂它们需要时间。路线其实不陡峭,只不过爬坡的距离长了一些,如果你只是偶尔徒步健健身,你当然会觉得这座山峰不可逾越。实话讲,我“试图”征服这座山峰的过程并不顺利,前两次我都半途而废过,好在我很有“野心”所以又第三次契而不舍的去征服它。事实上,前两次的失败给我了很多宝贵的启示,我知道自己欠缺的基础知识是什么,然后就可以通过对于其他工具的实践来完善自己。

    所以我觉得这就是个态度问题,你对你自己的态度,你觉得自己不能攀上高峰是山峰的问题还是自己的问题?同时没有人强迫你一定要上去,如果今天力有不逮,那就回去锻炼锻炼再来呗。除非你的志向不在于此,否则陡峭其实只是一个逃避认输的借口罢了。

    稍慢的页面渲染

    这是事实,作为客户端 SPA 框架,首页加载会慢是公认的事实,ember 在这方面的表现也不意外。不过认真细致的分析的话,实际上渲染很快(无论是首次还是后续),拖后腿的是静态资源的加载耗时以及 js 代码的执行消耗。

    具体的分析我就不扯了,我只说应对方案。

    解决静态资源加载耗时问题其实有两种不同的思路,第一种是从资源本身入手,削减它们的体积或者是有效的分离它们然后按需加载;另一种则是绕开加载耗时,先于资源加载呈现内容然后让资源在后面悄悄加载,对于用户则是无感知。

    这两种方案其实是可以共同作用的,并且它们带来的收益也各不相同。ember-engines 是第一种方法的解决方案,它的原理是允许让开发者按照自己的需求将应用程序分割成若干部分,对应的静态资源也会随同一起分离。当然它能做到的不只这么简单,简要列举如下:

    1. 被分割的部分可以定义自己路由,因此它们的衔接就如同一体的 SPA 一样流畅,而中心化的 data store 也可以由它们共享;当然它们也可以是非路由的,那么就好像一个分离的组件一样随着自己的载体而渲染。
    2. 分离的静态资源按约定被输出到项目的物理空间之下,并且会形成一份统一的 assets manifest,因此它们是可以集中管控的。这意味着你可以自由决定何时何地加载它们,也可以让它们 by default 的随着所属的 engine 惰性加载。
    3. engine 本身也是可复用的,当它们 mount 到宿主应用的时候可以为它们分配各自的“命名空间”,对于用户来说就像不同的子域名/子目录,但实例并不需要重复。
    4. 你可以决定哪些 components / services 是共享的,engine 系统不仅仅是为了分离,同时也是为了共享。

    因此,基本上 engine 就是自带路由体系和静态资源管控的高级 addon,事实上它真的就是 addon,所以你想用它的时候并不需要更改已有的架构,只需把你选定的部分按照 engine 约定重新安排一下就好了,除了 engine 独有的特性,其他的一切都遵循着 ember 的既有机制。简而言之,这就是大家经常说的:惰性按需加载。

    现在你就可以打开 Linkedin,不声不响之间,Linkedin 全站已经 ember 化,而率先使用 ember-engine 就是它的最大亮点。之前我提到过,ember-engine 是由来自 Linkedin 的工程师主导开发的,再一次体现了 ember 社区的务实特性。

    ember-fastboot 则是第二种方法的解决方案,从底层来看它是一个服务端渲染引擎,同时也是一套 isomorphic javascript 的解决方案(但是并不要求你一定要在服务端也是用 javascript,只是一个可选项)。最近也有一些讨论,大致的方向是客户端框架搞服务端渲染等于走回老路,纯属多此一举。从保有此种观点的人的角度来看,我个人能够理解,可是反过来我不觉得他们理解客户端框架的诉求,或者说他们日常工作的场景用不到所以也就不会在意这方面的诉求。

    诚然追求快是所有人都认同的目标之一,但是对快的定义也不必追求的那么苛刻。就性能这个词来说,我作为程序员或作为产品人,扮演不同的角色的时候对它的考量角度也是不同。身为程序员我能把加载时间缩短 100ms 都会获得莫大的成就感,但是身为产品人我不禁要问我花费了多少资源在这上面?而我的用户会对这个变化产生多大的认同感?能对我的产品价值的提升带来多大的帮助?

    如果我的产品平均加载时间超过 5s(假设),那么我缩短 1/5 会是一个了不起的进步,我的用户也可以直观的感受到这一变化;但如果是 1s,缩短 1/5 对于除我之外的人来说很难感觉到什么。可是让 5s 缩短 1/5 和让 1s 缩短 1/5 所付出的努力却是不相称的。如果在用户价值和商业价值上我没什么可追求的了,那么我愿意倾尽全力来让 1s 缩短 1/5 甚至更多,但显然这不是产品的核心价值,它只是影响用户体验的一个因素罢了。

    现实则是非常多成功的客户端 SPA 应用并没有让用户觉得很慢,这并不是说在一些性能指标上客户端框架已经无可挑剔了,而是价值判定的标准并非如此单纯而已。

    从另外一个角度说,如果传统的服务端渲染已经到了没必要改善的地步,那么像 turbolink 这种从客户端技术移植过来的东西又代表着什么呢?我们没有必要认为一种技术向另外一种技术取经就是多此一举,因为这不是在遮掩自身的不足,而是取长补短,在不影响自身价值的前提下更加全面的完善自己。

    fastboot 就是这样一种完善自身的有益补充,从务实的角度来说 fastboot 不是必须要做的事情。一些 SPA 应用的天性就是允许一定程度上的妥协,因为对于它的用户来说,它带来的功能和体验足以让用户接受不是那么极速的首屏渲染时耗,也不依赖搜索引擎对其内容的索引。如果这些诉求对你的用户来说至关重要,那么你选择 ember 这样的客户端框架岂不是盲目之举?然后你再反过来抱怨“到头来我还是得用服务端渲染技术”,这能怨的谁来?

    ember 的生态世界里有非常多的工具和特性值得探索,它们可以从不同的剖面来帮助你提升产品的质量和体验。作为一个从底层一点点实践过服务端渲染 SPA 应用的工程师,我的建议是最好把 fastboot 放在 todo list 靠后的位置去,除非你的技术实力够硬。

    框架体积庞大

    这是另外一个影响加载时耗的因素,它即消耗请求加载的时间,也消耗代码执行的时间,我的观点是在性能层面这应该是 ember 要去解决的最高优先级问题,那么为何直到现在这一点还在“罪恶黑名单”上高居榜首呢?

    首先,我列举一些事实:

    1. 去年我完成 React SSR 全家桶之后拿最终的体积和 ember 做了一个对比,实际上 ember 的体积并没有大多少(大了 10% 左右),但是提供的功能要比我精挑细选的全家桶多多了。
    2. 一年以后最新的版本(v2.12.1)默认构建出的体积已经小于我自己做的全家桶了,当然这段时间以来我并没有更新 React 全家桶的依赖,所以这个结果不够客观。
    3. 在开发模式下,ember 构建出的 js 文件是 500k 出头,代码行数 70k+,而产品模式之后,体积骤减到 160k+,代码行数仅剩 30k+,这其中还有至少 1/3 是完整版的 jQuery。WHY?因为在开发模式下,源代码没有去除代码注释,这相当于集成了一份完整的 API 文档。
    4. 精简版的 jQuery 是可以直接替换进来的,我在 codepen.io 上做过实验没有任何问题。但是 ember-cli 没有提供选择精简版的 jQuery 选项,因为考虑到这些年来庞大的 addons 有很多都在依赖 jQuery 的各种功能。
    5. 事实上,除了为兼容第三方插件的考量之外,ember 框架本身对 jQuery 并没有强依赖,默认集成 jQuery 是历史包袱的结果。当然在 Component 之中还存在 this.$() 的公共 API(用于获取组件根元素的 jQuery 封装对象),可这是一个可选项,如果你较真的话你完全可以不用(想想操作 DOM 的时候你需不需要考虑利用 jQuery 强大的兼容性吧,在今时今日很多时候这已经是一个可选项了)

    这并不是说 ember 框架自身已经足够好了,抛出上述经常被人忽略的因素之外,ember 框架内部的耦合性也是导致迟迟无法高效瘦身的重要原因,这是一个规模很大的问题,ember core team 并没有放过它,只是花费了很长的时间。

    Glimmer 2 是独立于 ember core 的,意味着它可以独立使用。ember 的内部组成部分已经被逐渐拆解为各自独立的 npm package。自 ember-cli v2.11 之后,bower 已经成了可选项,ember-cli v2.12,默认已经取消了对 bower 的任何依赖,ember-cli v2.13 之后 bower 将从默认配置里被剔除。

    在这些准备工作完成之后,下一步将会/正在执行两个重要的 RFC,它们的实现将大大缩减 ember 框架在应用中所占的体积。

    第一个:JavaScript Module API

    迄今为止,所有的 API 都通过一个庞大的树形架构寄生在顶级的 Ember 命名空间之下,这种古老的软件架构无法享受现代的模块处理机制,比如说自动削减未经使用的模块的技术(Tree Shaking)。不过 ember 框架的内部早已经逐步完成了各组成部分的模块化,而且早就通过 shims 的方式实现了语法上的模块导入/导出,现在到了最后一步:一旦 ember-cli 完成了新的模块管理机制,就可以实现真正的可剥离式的模块化框架架构了。也就是说,一俟完成,以后 ember-cli 就可以帮你把你没用到的模块自动剔除出去,在根源上削减最终的框架体积。

    看看这份列表吧,之后你就会意识到一直以来 ember 框架提供多少丰富的工具库。一方面因为技术限制它们不能很好的按需使用,可另外一方面又有多少人确实有效的利用好了这个全功能的框架呢?如果你也摆弄过类似 React 全家桶之类的东西你就能明白做一个扎实丰富的 web 应用需要多少第三方资源的辅助,它们哪一个不占用应用最终的体积?ember 只不过是事先帮你都准备好罢了。体积和功能就像天平的两端,过去的声音一致集中在批判体积过大上面,却罕见有人来褒奖 ember 的周到和全面,我想这大概是 ember 框架最被误解和无视的一点了。

    第二个:瘦身构建计划

    这是一个相对简单的有益补充。为了保持框架在持续发展的同时不会影响旧有应用的运行,对于 API 的废弃 ember 从来都不会粗暴解决,而是使用一些内部机制来给出渐进式的提醒。然而随着时间增长,即使是这些善意的措施也会变成问题,越来越到的 deprecations 堆积在框架内部,也占用了很大的体积。这个问题其实早有讨论,在动手之前需要有一种妥当的机制来告知用户什么时候会做这些“破坏性”处理并且给他们足够的响应时间。

    去年,ember core team 开启了 LTS 版本的支持,同时也预告了消除这些废弃代码的 deadline,现在正是时候。目前已经开始清理这些代码了,从开始有废弃机制开始一直到最近的 LTS 版本(v2.8)为止,所有上述的垃圾都将被一次性清除,因此称为瘦身构建计划。


    好了,最后总结一下。上面我说的东西,一部分是历史,一部分是正在发生的变化,还有很多很多远的近的未来的计划。让我最爱 ember 社区的一点是:所有的计划都是摆在那里的,你不会担心被蒙在鼓里或是一觉醒来发现天变了。这其中有些计划会受到质疑被取消,有的会因为其他因素拖延进度,有的会保持开放性探讨直到确凿无疑,but anyway, developers are always under developing, it never stop in the past, the present, and the future. This is the reason I love about ember and its community.

    BTW,Ember Conf 2017 马上就要开幕了,还有很多新鲜的信息正在路上。

  • 坦白说,要看两样东西:

    1. 看水平。必须要承认 Ember 很难,React 本身不难但是折腾全家桶也很辛苦,Vue 其实和 React 是很类似的东西(不说一些原理上的区别,只说量级),不过它还是很照顾初学者的(在这一点上不能不考虑爱国因素,的确有很多地方对中文用户友好啊)。Ember 和另外二者并不是一个量级上的,我这么说不是要暗示 Ember 更厉害,只是从软件的全面性和复杂程度来对比的确不是一个量级。

    2. 看需求。很大一部分都会说像 Ember 那么“重”,一定会很慢,必须要承认那些套路式的性能对比 Ember 肯定不占优势。然而我觉得应该反向思考一下(特别是 Ruby 社区的群众,因为感同身受),比方说 Rails 在各种性能对比中也不占优势,我们为什么喜欢用它,愿意用它?

    在现实工作中,我们大量使用 Ember 及其生态系统,但不代表我们不用别的。前段时间做了一个小项目我们也用了传统的后端渲染(Phoenix + Pure JavaScript),所以我说看需求就是这个意思,看菜下饭。

    当然你问的是“入门 MVC 框架”,那么重点如果放在“入门”上,可能 vue 会比较容易上手,容易树立自信心;若是再加上本身你的工作对于应用复杂度的要求也不会很高的话,学 vue 没什么不好的。

    我的建议是,如果对于“比较”这件事情没有什么把握的话,那就什么资料多学什么。无论从哪个开始入门,只要自己努力,学得其法,终究会达到用哪个都无所谓的程度(当然会有个人偏好,也会有看菜下饭的考量,我的意思是条件不允许的情况下,用任何一种都可以 GTD)。

    ===

    再多补充一点:我不清楚大家想要学各种客户端框架的初衷是什么,只是我觉得大部分人做得东西其实都用不着框架——复杂度不够,体现不出框架的优势。近些日子我看到好多好多用 vue / react / ng2 ... 去复刻某论坛/某社区的案例,我真的不明白这么做有什么意义?如果只是为了入门练手,做一个稍微完善一点的 todo list / note book 就足够了。论坛社区这样的东西原本就是内容为主的,根本就不适合各种前端框架发挥它们的优势。

    如果你的确是要做“野心勃勃”的东西(就像以前 Ember 的 slogan 说的那样),那才是认认真真学一门前端框架的合适理由,酷炫的交互,复杂的状态管理,完备的数据通信……这些东西是没办法用复刻内容性网站的方式去充分体会的——当然,如果说复刻一个 discourse 的话那还差不多。

  • 不方便翻的可以看这里:http://space.bilibili.com/16910485 以及这里:http://i.youku.com/verygeek

  • @5swordsnightire 这是在讨论性能吧,这方面的讨论我向来都不太感兴趣,最近也忙,没空。

  • @5swords 找我?

  • Git 提交问题 at 2016年12月18日

    咱们简单点,就分两种:feature 和 target,后者可以是 master / staging / testing ... or any names,反正是你要最终合并的目标。

    Now,问自己一个问题:我为什么要把(目前还在本地的)feature branch push to origin/feature branch?我没有假设什么标准答案,这个过程有没有完全取决于你或你的团队的工作模型。在某些情况下,这个 pushing 是有必要的,比如说:

    我的 feature branch 提交的粒度很细致,step by step 的;并且我们团队有 code review,boss 要求我们在合并到 testing 之前一定要有人帮我做 code review。那么,我势必要给他一个远程可访问的分支,所以我需要先 push local feature branch to remote feature branch

    类似的情况也有别的,根据实际情况自己脑补。接着假设这些前置要求都满足了,该进行合并了吧?但是这又会有变化:我能直接 merge target 吗?这个问题同样没有标准答案。有些团队要求的比较严格(比如说很多开源项目),一定要你用 PR 的方式来合并代码,那么这时候你在本地合并 testing 也没有卵用,因为即使你 PR 了 local merged testing,也许你没有 rebasing / squashing 一样会被拒绝并要求你做出正确的 PR。

    所以归根结底,git 只是工具罢了,没有绝对的应该不应该,最终还是要看团队的具体要求和执行能力的。

  • #1 楼 @fubu git-remote 有 get-url 子命令,可以 man 一下看看。

  • 有句话说的没错:

    不要让世界适应你的模型,而要让你的模型适应世界。

    极端的 OO 和 极端的 FP 都有问题。

  • @darkbaby123 是,我刚才看到了,我自己的选定语言里没有添加它,所以一直以为没有呢。

  • @darkbaby123 啥时候有 Elixir 版啊

  • @panxiubin 不是 running /usr/bin/xcodebuild 而是直接 /usr/bin/xcodebuild,你没发现下面在提示:

    command not found: running

  • #48 楼 @ugoa 抛开 Redux 不谈,“集思广益”其实并不一定能“加速促进”,Ember RFCs 就是很好的例子。

    一个 Idea 的提出要比真正实现它容易得多,特别是在没有别人参与的情况下。然而这种速度却未必是好事,也许你的 idea 不够周全,也许你忽略了一些非常必要的应用场景,也许你根本就想歪了,其实还有更好的方式能达成目标。

    RFC 的意义就在于最大可能性的排除或削减上述“也许”所带来的副作用,而这种副作用恰恰是很多看似繁荣的社区最大的隐患。

    炒得火热并且用的人多并不一定能实现“集思广益”,因为这个词真正的核心在于“集”,而它要体现在两个方面:

    1. 用户知道哪里应该是集中探讨 ideas 的地方——比如 https://github.com/emberjs/rfcs
    2. 官方应该明确被广泛关注的 ideas 终将会得到官方的支持,或者有普适性足够好的周边支持,比如 ember addons

    而一个 idea 要想足够成熟,它必然要经过探讨甚至争论的“集思”,然后要有人提出相对严谨周密的 solution,要有人写 demo,要有人测试,要有人拿去实战检验……之后才能变成正式的方案交给大部分人使用,让大家一起“广益”。这才是一个靠谱的、负责任的社区应该做的事情。

    没有这些前提,如何把思“集中”起来并广益呢?你引用的 Redux 的例子,其实只是在你看来它很繁荣罢了(因为你其实也对它不是十分了解),可是它并没能做到“集思广益”,说好听一点顶多是“百花齐放”,观赏性挺高罢了。

  • @ugoa 趋之若鹜又能怎样呢?能因此而证明从此便能健康的发展下去吗?

    关于 Redux 造成的问题我在很多回帖里都谈到过,不知道你怎么看,依然认为这些不是问题吗?

    即便使用 Redux 的人很多很多,但是真的懂透彻了,能用好的(包括围绕其周边的一系列 middleware 或 packages)却是少之又少——那么这样就可以满足了吗?事实上,你看看现在讲 Redux 的教程,十之有九还是在基础的 reducer 上绕,翻来覆去都是 todo list / counter 这样的例子,有几个正儿八经谈谈真正复杂的场景的?而 Ember Data 这些年来已经发展到常见的场景都有 adapter 并且几乎都有实际运行的真正的项目(因为这些 addon 都是在实际开发中抽象出来的)。就连 Dan Abranov 自己都说了:You Might Not Need Redux

    事实上,从 Dan 推出 Redux 以来这么久了,有什么本质上的进步吗?这么久了!趋之若鹜的人们大多还在门口绕圈圈,看看 SF/SO 上关于 Redux 的问题都在问些什么吧,绝大多数人都还搞不明白怎么把一个 store 里的状态渲染到视图里,或者怎样发一个异步的 action

    再去 google 一下:github redux async/ajax/promise,看看你能找出多少“解决方案”?一年过去了,分出高下了吗?选出最优了吗?

    所以我不禁要问了:这样的繁荣有多少实际价值呢?Dan 因为 Redux 声名远扬,也加入了 React Core Team,So What?Redux 成为 Official Guaranteed 了吗?非但没有如此,又冒出一个 Mobx 来。这样的循环还要搞多少次?

    一方面喊 Frontend Fatigue,另一方面什么火就往什么冲,我是真搞不懂这种现象 Ember 社区有什么必要好好学习一下的,我还是喜欢现在的 Ember Community,steady as the beating drum

    BTW,上面的话只是借你的话题说说感受,不针对你的评论哈。

  • #39 楼 @jesktop 不是 routable component 出不来,而是 glimmer 引擎最初的设计有错误,但直到和 htmlbars 一起启用之后才被发现,原本这个时候 angle brackets components 已经都做好了(我还曾经写过一篇介绍),下一步就是测试 routable components,却因为这个失误导致了后面的计划最终全部推翻重来。

    但是本来也有机会就这么上了的,但这个失误影响的范围其实很广。routable components 只是一个名字,其实它可以是很多种风格,比如说是 container 风格的组件,还是 bridge 风格的组件。那么当时对于 routable components 最终的走向也是意见不一,这也是推迟发布的原因之一。

    另外,估计你对版本的理解和我们不太一样(或者说和 semver 不太一样)。不是说有了新特性的更替就是 x.0,重点是有没有 API 层面上的 breaking changes。glimmer 2 替代 glimmer 就是一个非常大的特性更替,但由于新的引擎在设计方面非常小心谨慎,所以最终完全没有 API 的改变(有一些 deprecations),所以 2.8 -> 2.9 的升级对于用户来说就是透明的,而不是非要搞个大新闻上到 3.0 才甘心。

    routable components 也是同样的道理,组件那一层面的事情已经尘埃落定了,路由那边则是由于在 glimmer 2 研发期间,一些新的 rfcs 收到了广泛的关注,比如说 virtual dynamic segments 等等,这些东西要不要随着 routable components 上,还是制定计划慢慢上?这些问题都是需要考虑清楚的。

    我之前也提到过,Ember 对于一些重大/敏感特性的改动的确给外界一种反应比较慢的印象,这确实是令人不爽的一点。不过在我用 Ember 做过一些大型项目之后我也逐渐能有所理解,因为它完整而庞大所带来的一个副作用就是牵一发而动全身,这势必会造成 breaking changes 无法迅速完成。只能说没有完美的事吧。

    其实处理现在 controller 的问题很简单,那就是把目前直接展开在路由对应模版的内容用一个 component 包装起来,且把这个 component 当作是 routable components,只不过涉及到 queryParams 的部分要交给 controller 就可以了。涉及到 route actions 的可以用一下 ember-route-actions 这个 addon,或者自己写一个 patch,很简单的(参考这个 addon)。

  • @gazeldx 我觉得你的理解浅了一层。我说主观的好恶免不了,并不是说没有主观的好恶,而是在评价一项事物的时候能否足够客观。

    因为这句话的上下文是说,因为工作场景的需要不得不用自己不喜欢的工具……那么这个时候你评价该不该用这个工具是顺着自己的偏好来呢?还是一概安之若素呢?

    人非圣贤孰能无过这个词已经是一个成语了,有很多引申的用法。人们对“过”的评判也是无法统一的,有人认为束缚个体性格是一种过,也有人认为不遵守公共规则是一种过。按你的标准是圣人的,按我的标准就可能不是,按他的标准甚至可能变成了小人。

    说这么一句无非就是修饰一下罢了,若有文过饰非之嫌,实在是笔力不足,惭愧了。

    我再重新读了一遍那个段落之后算是明白我们的误会在哪里了,你的说法自有你的道理,但用在我这里却是强人所难了,且容我分析:

    人非圣贤,孰能无过

    套一下模板变成:

    人非圣贤,还能没有个人好恶吗?

    按你的说法,圣贤是有好恶的,所以这么说不通。那么我是不是也可以说,圣贤是有过的,左传这么写也是说不通的。对吗?

    古人眼中的圣贤就是“白莲花”一般,没有过错的吗?肯定不是这样,孔孟老庄在史书当中的记载也不是完美无瑕的,左传中的圣贤指的不是你说的圣贤,而是一种虚指,说的是那传说中的“完美”人物。而我所说的圣贤也是那种仅存于理论中的,分析评价事物百分之百客观不参杂个人好恶的楷模——我们都知道这是不可能的,就和左传中的圣贤一样,古人也明白这个道理。所以这就是一种 conventional 的修辞手法罢了,不必较真。

  • #37 楼 @darkbaby123 其实就是一个人和多个人的区别,自己折腾就不太会担心这个。

  • @ugoa 这些具体而微的点我在正文里都会有提到,可能我不会开个单篇来批判,因为问题终将都有解决办法,无非就是有些来得慢了些罢了。

  • @darkbaby123 我就说一件事情,redux 自己不管异步的,OK,这可以理解。我在做 Univera 考察 middleware 的时候,候选对象多少个?13 个!这还不包括后居而上的 redux-saga,并且你也知道现在的势头又变成了 mobx 大有取而代之的意思。

    其实平均每一个 project 代码量也不过就是百行左右,我当时真的是全部看了一遍,外加所有的 active issues。问题是没有一个能 cover 绝大多数常用情景的,要么就是能但是抽象层次很低。一定的 glue code 并不是无法容忍,但是每加入一个碎片就要来点 glue code,加到一定程度之后才发现之前的一些东西要么想得不够周全,要么路子不对,咋整?

    最终让我感到厌倦的最主要原因还不在这里,我记得跟你说过,如果只是我一个人玩那变就变吧,反正从头到尾演进的过程都在我脑子里。可问题是我们搭一个架子的目的是要提供给团队来使用的,我记得当时在一个月内光是 router 上面的 breaking changes 就给小伙伴们开过三次会——我真的很讨厌这种无休无止的改来改去。

    在一个团队里,能做到随机应变并且还可以始终遵循一些 best practice 的终究是少数,大多数人在遇到 confusion 的时候还是会以寻求帮助为主。框架的一个重要的职责就是给出这样的 guides,它未必是最先进的,未必是最具吸引力的,但它应该是成熟的,经过验证的,足够稳定的。否则有的时候我连 code style 都没法写清楚。我希望我们用到的东西应该是约定一次就足以长久的应用下去,并且可以适应绝大部分场景。那些 edge case 我可以来写一些 layer 来适应它,而这些 layer 也要给予 base api 的稳定和有计划性的演进。

    Ember 有 lts,有 half year releasing 的计划,至少我知道即使有什么东西被 deprecated,它也不会在一次 npm install 之后立刻就引爆,我们可以合理的安排时间去修正这些地方,而不是不断的 breaking changes。

    我并不认为 React 社区是完全错误的,你提到的那些 shining parts 我也一样关心,即便目前我们已经停用 React 了,我依然对 React 的核心进展天天关注着。但我不再会关注它的那个混乱的无组织的生态圈了,即使 Redux 的作者也是这么觉得,我在 twitter 上看到他在呼吁所有的周边作者们要多一些的全面思考和责任心。

    举一个对比的例子,Ember Addon 刚兴起的时候,一瞬间就出现了 3 个 addon 是做 deploy 的,各有各的特色。Ember 社区怎么做的呢?在其中最受欢迎的那个 addon 发了个 issue @ 了其他两位作者,询问是否可以把大家的力量汇集起来共同做好一个 deploy addon?最终的结果是现在大家都知道那个最好的,并且它自己也形成了统一的扩展接口,任何 deploy concerns 都可以作为 plugin 补充于其上,而开发者只需要挑选自己需要的 recipes,然后 ember install 就可以了。这里面也会有 configurations,你可以按照你的实际情况来微调,如果微调不满意你可以开发补充的 plugin 来增强这个过程并且能分享给其他人。

    为什么 redux async middleware 不可以这么来做呢?为什么要分裂十几个,各有各的想法和套路呢?难道这么做会阻止你社区繁荣?思想碰撞?I don't think so,在我看来可能唯一的 drawback 就是新的 idea 不会 landing 的那么快,就像 RFC 一样,可是我们的实际工作也不是前沿科学,也不需要追求那么快啊。

  • @u1440247613 刚好这两天有一篇文章挺火的,这是另外一个角度来阐述了选择 Ember 而不是 React 的原因(此前一直用 React 两年半),可以作为第三方参考:https://blog.instant2fa.com/choosing-ember-over-react-in-2016-41a2e7fd341#.x6jcrj8es

    特别是里面提到的“选择疲劳症”,由于我个人之前从头开始搭建和维护了一个 React 的全功能框架 Univera,对此的体会简直可以说是刻骨铭心。我对 Ember 的诸多不满意之处是促使我深钻 React 的初始原因,可是等到钻完之后我的感想却变成了:我再也不想维护下去了。

  • @darkbaby123 俺只有一个好字奉上

  • #27 楼 @u1440247613

    1. 笼统归纳的场景只有一个,但这个场景可做的领域实在太多了,而且事实上这个场景在逐渐占据着主流,可以看看国外内容型朝应用型过渡的趋势就知道了。另外 sass 是一种提供服务的形式,但其实应用本身可以不局限于以 sass 的方式提供。比如说我们的巧思吧,主服务是 sass,但也可以变成内部/私人服务部署,可以打包成桌面/移动应用,甚至可以离线使用(虽然还没实现……顺带一提,传统的服务端渲染做离线是很麻烦的哦)。

    2. 考量维度的事情,交互只是一个因素,状态的事情我后面还会单独讲。事实上这两者并不矛盾,因为交互复杂必然对应着状态复杂,无非就是使用不同的工具对于状态的抽象描述不同罢了。细分的话,状态还可以分成 UI 状态和数据状态,因此我先说 UI 的部分,也就是强调交互复杂性的原因。事实上,很多人都把交互理解为用户可以操作的部分,然而并不是单纯这样。交互是双向的,除了用户主动操作的部分,应用程序的反馈也是其中的重要组成部分——这我就不细说了,有机会我可以单独谈谈设计与交互方面的话题。另外,用 jQuery 去修改 DOM 不就是把状态强行映射为动作么,只不过在 jQuery 程序员的认知里,很多状态都是“隐性”的,只存在于他们的瞬态思维里。如你所说:可以用 jQuery 编写的网页,用 jQuery 也会做得很好。但是一次性做得好并不代表其扩展性也好,复用性也好,可维护性也好。我后面有计划写我用 Ember + d3 实现 100% 可定制性交互图表,实际上现在就有一个可以交互的 demo:http://ember-d3.surge.sh/sandbox ,技术上讲,d3 和 jQuery 在操作 DOM 的层面上是非常相似的,然而我几乎没用它操作 DOM,而只是利用其丰富的函数来做数据结构和比例变换计算,Ember 来负责数据与视图的绑定和一些必要的 DOM 操作(比如支持 SVG 响应式)。我绝对可以想像得到如果没有 Ember(或其他等价功能的框架)而单纯用 d3 或 jQuery 的话,这种东西写起来或是维护起来该有多复杂。而现在的代码呢?由于是商业作品,开源估计是够呛(未来也许会开源部分定制化的 Ember Addon),不过可以先看看还在整理中的 API doc(上面的域名后面改 docs),看完之后你不妨告诉我,这样的局部应用(还不牵扯到数据层状态维护,单纯是 UI),以后还会不断增加几十甚至上百的定制项与图表类型,你是愿意用 jQuery 还是基于状态管理的框架呢?所以说了,能写得好不代表没有更好的,选择总是要跟着需求走的。

    3. Virtual DOM 这个事情没有那么“神话”,如今的主流框架其实都是 VD 化的,Ember 早在前年换成 Glimmer 引擎的时候就已经是 VD 了,事实上单说 VD 方面的发展,React 都已经落后于很多竞争对手了,React 自己现在都在重写渲染和 diffing 的核心算法。单比较极端的渲染性能(比如说大量的——千以上级别的——组件重绘),Ember 在 Glimmer 一代的时候就已经打平 React 了,而马上 Glimmer 二代又要更新了,今年三月的 EmberConf 就已经放出了渲染性能的对比 demo,React 已经不是对手了。你可以去找油管上的 talk,里面还有 demo 的链接。

    顺带一提,Ember 可以做到核心渲染层不断替换升级,模版层也不断替换升级,但模板语法和组件 API 始终不变,对开发者来说这种性能提升的代价(我指的是代码的编写和维护代价)几乎为零。所以说到“优雅”——这方面是一个神话。

    而说到 unidirectional data flow,这就更是一个“神话”了。首先,这不是 React 独创的技术(实际上也是一种思维,而不是特定的技术),不过 React 的确是把它正规化、明确化、标准化的领头人。然而 React 做出了强制单向绑定的决策——在大部分情况下都是可以的——则有点矫枉过正的意思。事实上双向数据流在 UI 编程的领域是很有用也很重要的模式,真正有问题的是不加节制的滥用双向数据绑定,这种风气是 Angular 1 带动起来的,我不知道 React 做出这个决策是不是有和 Angular 唱对台戏的意思,但我可以负责任的说:丢弃双向绑定是一种很傻的行为。而实际上 React 没多久就妥协了,只不过把双向绑定的机制搞成了 mixin,默认还是不给你。

    后面我会用一些例子来详细阐述这一点。问题在于很多开发者并不能够理解使用它们的时机和它们各自的 pros & cons,所以不管是 Angular 还是 React,他们的做法至少可以让最早一批实践者在理解这件事情时的心智模型变得简单一些。随着人们的认知不断的深化,我们现在可以看到大把大把的教程文章来介绍在各种默认双绑的框架里实现单绑,或者在各种默认单绑的框架里实现双绑,等等。

    Ember 呢?Ember 一开始的时候 CP(计算属性)就是存在单绑模式的(ReadOnly),但那时候没多少人理解这东西的意义。后来等到 React 火起来之后,所有的数据绑定都是可以在三种方式中切换的:默认双绑、单绑(readonly helper,相当于后来 ng 里的 ::,以及 React 的默认绑定)、解绑(unbound helper,等于数据拷贝)。我在 Ember 群里发过一个讲解数据绑定关系的视频在线 Demo,这件事情我光在 Ruby China 就已经讲过许多次,其他网站的科普文章更是不计其数,我也不知道为什么到今天还是有很多人认为这是 React Exclusive 的概念,大概 React 社区对这个概念的“洗脑”实在是太成功了吧——一个技术型营销的优秀案例。

    总而言之,如果你想,你现在就可以在 Ember 中完全践行 unidirectional data flow,丝毫不带缩水的。并且顺应潮流的趋势,Glimmer 2 引擎面世的时候,所有组件的数据绑定将会是默认单绑,可选双绑(mut helper)——这就和 React 组件是一样的了——并且 Glimmer 2 的 diffing 的最小单位是每一个 getter(比如组件模板里的一个 {{}}),相比之下 React 的最小单位是一个 render 函数,我还不确定新的算法是否会改进这一点,但 Glimmer 2 已经做到了,按照 Vue 的文档描述也应该是这样的,但是 diffing 只是影响渲染性能的一个因素,请不要以点带面。

    除此之外,如果你还想要 single data source,那么 ember-data 本来就是这样的(但不是函数式 reducer + 不可变数据结构,而是 纯正的 OO 式),而且 ember-data 和 ember 的整合是非常自然流畅的,你可以使用 container 的模式(data link 在最顶层单向往内层传递,action 向上),也可以仿照 flux,哪里需要往哪里 link,在这个方面有很多细节在 ember 里都是天然支持或者默认优化的,比如说路由的 model hook 天然支持异步(根据 promise 状态决定渲染树的走向)等等。而 Redux(或其他 data store)和 React 的整合需要人工调整的地方就琐碎的多了——这种事情对于架构师来讲自然都是份内之事,可问题是目前有多少靠谱的前端架构师呢?Ember 和 Ember Data 可是开箱即用的,你完全不需要事先理解它们是怎么协同工作的才能开始写具体业务。

    再往远了说一步,你以为 Ember 就不能用 Redux?Redux 可不是 React 的禁娈,Ember 也是可以用 Redux 的,甚至 Mobx!(Mobx 本身还没有人做 addon 整合,但是 Rx 的套路明白了,实现 Mobx 方式的 state management 也并不困难,且不说 reactivex 是已经可以直接整合在 Ember 里的了)。这些还只是冰山一角了,UI 编程的各种思想和模式在 Ember 社区里都有广泛的采纳和实践。Stream?Concurrency?(ServiceWorker)Partial App?(Engine)SSR?(FastBoot),所有这些都只需要一句 ember instal xxx 就可以立即体验——当然,你要想玩转它们肯定还是要深入学习一下的,它们本身都是比较新鲜的概念,Ember 社区也只能说是身先士卒帮你踩坑罢了。

    所有的这些不是为了替 Ember 吹牛皮,而是想说明一点,Ember 的好不是在于它立了什么 Flag,或是洗了什么脑,而是它的社区文化是以开放包容的心态广纳四方菁华,并尽可能的消化它改良它,最终为我所用,所以我们从来不喜欢说如何比 xxx 更好,因为我们不喜欢把自己摆在任何一个 xxx 的对立面。我们更喜欢说:xxx 哪里做得比较好,好在哪里,和我们的契合点在哪里,是否可以学习采纳,是否可以有更好的方式来实现这个需求。

    去看看 Ember RFCs 吧,这才是一个技术社区该有的样子。

  • #25 楼 @darkbaby123 老实说我更了几个章节之后就觉得我有必要换成 gitbook……

  • @academus "React 不鼓励用户直接使用 JS",这句话不知从何说起,JSX 其实只是一个语法糖罢了,都不算是一个完备的 ?xml。如果可能的话,React 巴不得所有人都直接使用函数而不是 JSX,但毕竟要照顾很多人的底子和情绪,再说文档结构复杂的时候,嵌套的函数调用写起来并不舒服,所以最简单的方式就是不要把 JSX 当成 HTML 的替代品。如果学过简单的模版引擎实现原理,那么就当 React 的 JSX 是直接 compile(template) 里面的部分(其实就是),而 template 才是之前的 HTML 或其他模版语法。

    因此 React 也并没有发明新的语言,它只是把过去模版编译的中间过程直接暴露出来了而已,并没有那么极端。也就是说 render 函数既是模版的解释和编译,也是渲染调用。我们可以说它解耦的层次太高不够清晰,但发明新语言的确是假说。

  • 👍

  • 在线培训的收费模式 at 2016年11月17日

    @ccok 我没有曲解什么,也没有必要曲解,又不存在商业竞争关系,我只是复述原文罢了。

    而且我说的恰恰不是什么鸡汤,而是特别实际的事情:和用户感同身受。蛋人网第一次在这里宣传的时候我就注册了,借着初始免费时间我也看了所有当时你们发布的视频。你说观看的国外视频比较多,说实话我是持怀疑态度的,但我怀疑的不是数量,而是质量——要么就是你们录制视频的人可能感受不到这个质量上的差别。

    我来算一笔账:CodeSchool 我的订阅时间已经长达 4 年了,很有发言权,且不说 CodeSchool 的课件设计、交互式练习、外加主讲 Greg Pollack 的水平(说句恶俗的话,这些方面都能爆国内视频不知道几条街)——这些因素都不算,单说订阅价格。

    CodeSchool 初期的收费是 19 刀/月订阅制,而且那时候每一门课程学完之后都有 5 美元的下月订阅折扣(这个优惠持续了很久,至少头两年),第一次注册还有三个月限免(现在这种限免每年都会有好几次,每次 1 - 3 月不等),换句话说头一年的花费是多少呢?(19 - 5) * 9,折合人民币 800-900 之间(几年的汇率浮动我就不细细算了),和蛋人网持平,但是质量相比呢?当然现在 CodeSchool 是贵了,不过毕竟国情不同消费能力和习惯本就没有可比性,但是单独对比创业初期的收费/质量比,也能说明一些问题了吧?

    说句公道话,蛋人网的教程里有些地方的深度是要优于 CodeSchool 的,这一点也应该算到“价值”中去。不过从 CodeSchool 的角度来看人家的定位非常清楚,就是主要为初学者服务的,在乎深度的目标用户也不会过分依赖 CodeSchool。

    我其实是很赞同在线大规模教育并且希望这个行当能挣钱的!希望不要有人误会我的动机,在每个月只能赚 3000+ 的时候我就愿意申请信用卡去订阅 CodeSchool,现在收入翻了好几番早就不在乎为技术投资这些钱了。但是作为消费者,我肯定是要在乎花出去的每一分到底值不值,值多少的。所以我才说我怀疑你们观看的国外视频课件比较多——除非你们看得都是免费的,没有这方面的体会,那也就不奇怪了。

    所以我现在看到国内有一大堆质量粗糙的教程收费却一点都不含糊,我就觉得这个前景不怎么看好了,似乎我们总有这个本事把一门好好的生意做到烂——我不是说蛋人网,我只是说这样一个现象,希望蛋人网能够打破这个现象,真正让大家觉得这个钱花的值。

    其实目前来看做收费还是有优势的,因为大多数有这方面需求的消费者并不知道“外面的世界”有多精彩,所以只要课程质量真的好,想让他们掏腰包并不会太困难。问题是质量真的够好了吗?作为课程内容的实质输出者,我们都应该扪心自问这个问题。我自己也在录视频教程,但是自认水平不足以卖钱,所以全部都是免费开放的,因此我也经常扪心自问这个问题的,以此共勉。

  • 在线培训的收费模式 at 2016年11月17日

    @ccok 多说一句可能不中听的话,创业不是视死如归 + 坚持就一定能做好的,能够吸引用户,能够“说服”用户买单,这本身就是一种智慧,一种魅力。这不是靠“我比所有人都更努力”就能成就的了的。我不知道用收费视频来创业的你们看过多少收费视频,或者说为多少优秀的教学视频买过单,如果这个数目本身还不如你们的消费者或潜在消费者多,那个人实在不看好这个前景。原因很简单:在消费视频教程这件事情上,你们和用户感同身受了吗?

  • 在线培训的收费模式 at 2016年11月17日

    @uxgnod

    这和主讲的偏好有关,Jeffrey 在 envato 的时代就是喜欢讲各种开发工具和工作流出名的,他个人的兴趣爱好就在这里,单飞之后延续这种偏好也是正常的。

    但是你说 egghead 没有那就有失偏颇了,John 本身就是 jetbrains 的布道师,他在讲 ng1 系列的时候就不断的在介绍 j 系 ide 的各种用法和技巧。之后 egghead 也推出了前端工作流、构建工具、环境搭建、st、vim 等专题。单就风格而言,差别并不在这方面。

    就讲解技巧来说,Jeffery 是行内翘楚,egghead 则是大杂烩,在这方面的确 laracasts 更胜一筹。

    国内的视频教程通病都是一样的,就是表达能力弱,打比方举例子经常说不到点子上,录制前的准备工作明显也都仓促。作为一个经常看视频的人,我还真没有看过有哪些收费的视频能达到 Jeffery 或是 Gary Berndhart 的水准的,特别是后者,看他的现场 talk 就知道天赋异禀了,直播都不带卡顿的,流畅的就像提前背过一样。

    当然也未必要把要求放得那么高,这毕竟是看人的。至于说是订阅还是买断,个人感觉时效性强的课程我会选择订阅,主题性强有反复重看价值的则会选择买断。另外如果提供了订阅,就要有频次和质量的双重承诺,达不到这种承诺的我会立即取消订阅,而且还会写评价说明为什么取消,这种事情我做过两三次,基本上都得到了退款或是合理的解释。

    订阅是一种长效契约,代表了一种信任;而买断则大部分取决于购买者的眼光。

  • #17 楼 @jimmy0017 其实不存在 vs,因为一个是 FP 一个是 OO,并没有绝对的高下之分。

  • #18 楼 @williamherry 中间表映射为 Model 就可以了,两边 hasMany 或者 belongsTo。你要知道 Ember Data 不是映射数据库的 ORM,它是映射 API 的,如果 API 已经可以处理中间关系查询,那就直接 Model 映射 API Endpoint 就行了,是否用中间表这件事情对于前端来说是透明的。

  • #16 楼 @franklinyu WebStorm 有一个 ember 的 plugin,可以方便的调用 ember cli 的命令,至于模板,WebStorm 是可以自定义的呀。