no comments, do it!
提个醒,既然做成了 SPA,别的都好说最起码先把路由搞好,否则用起来会让人非常不舒服的。
举个例子,如果我向后翻几页(这个翻页也不太好用)然后进入一个贴子,等我退出来的时候你猜我在第几页?
有好书当然要抢,注册 ID:nightire
其实我看不太清楚你的意思——不是说你说的不清楚,我只是不知道你想表达的观念是什么。
我索性把我的观念说的简单明确一点吧(当然只能代表我自己,并没有对错之分):我学习(我认为练习就是学习的一个组成部分),既不是为了提高效率以避免或减少加班,也不是为了应对类似 Hackthon 这样的特殊场景,我学习就是学习,如果说为了什么,那就是为了满足好奇心和求知的欲望,我是一个纯粹主义者。然而话说回来,我认为像我这样去学习也足以满足避免或减少加班以及应对类似 Hackthon 等特殊场景的需求,只不过它们不是最原始的动机(就是我说的驱动因素),它们只是学习带来的增益效果。
可能对于一些人来说,减少加班或应对 Hackthon 会是非常好的驱动因素(这是很正常的事情,我不觉得是错误),我读第一遍的时候甚至都不觉得哪里有不妥(这种不妥不是针对所有人的),只是当我开始回顾自己的学习历程时才意识到:对于其他一部分人来说(比如我),学习可能是另外一种感受,用来驱动的因素可能会更抽象一些(而不是像加班或 Hackthon 这么具体的东西)。
所以请原谅我之前表述不够清晰,我认为的不适合仅仅是从我的角度来说罢了,不具有普遍性。其实我都不打算去解释这一点,因为我向来都觉得理解的人自然理解(因为是一类人),不理解也没有关系,因为学习本身就是蛮自我的一件事情。就是这样。
#15 楼 @darkbaby123 过奖过奖。
顺便广告一下,Babel 的用户手册和插件开发手册简体中文版已经基本完成,这份文档是我献给 JavaScript 社区的新年礼物,当然要先感谢 Babel Core Team 编写的英文版。
晚些时候我打算写一篇介绍 Flow Syntax 的文章,Babel 的最新版本刚刚支持了它,为 JavaScript 提供了注入类型注解/推导,静态类型检查等特性,从此以后不再是 TypeScript 的专利啦(或者说这是 TypeScript 为 ECMAScript 做出的贡献)。
手册的地址:https://github.com/thejameskyle/babel-handbook/blob/master/translations/zh-Hans/README.md
#11 楼 @mizuhashi 其实我早就看到这帖子了,但是之前并没有想要说点啥……是因为看了后来的一些评论才写的。
把对象的方法抽出来传这件事情并非习惯问题,而是 map()
函数本来就是接受一个一个函数的啊,又不能只把 stepper
对象传给它。在现实中我们经常看到:
[1, 2, 3].map(function(item) {
stepper.add(item)
})
这样的写法可能会比较贴合大多数人的习惯,然而说句不好听的,这纯属“脱裤子放屁多此一举”……可转念一想也怪不得人家,谁让 JavaScript 的 this
如此不接地气呢?像我上文的那种写法才是本来应该的样子,如果在定义接口的时候能预先考虑 this
绑定的使用场景,那么函数式的“范儿”就会足足的。
#12 楼 @darkbaby123 主要是看你回答了想补充一点,一开始也没想到会写这么多撒。
class 要使用私有变量,居然要包一层闭包,再用一个 WeakMap 去存
因为 ECMAScript 从来就没有私有成员这种概念,而闭包是确保变量不会泄漏的可靠方法,所以用闭包模拟私有成员是 JavaScript 的必修课。至于 WeakMap 来存并非是唯一的方案(不过的确是比较好的),比方说 Symbols 也可以(参见:http://exploringjs.com/es6/ch_classes.html#sec_private-data-for-classes)。
问题是连实例变量都没有,这个 class 究竟有什么用?
Are you sure?
class Point {
constructor(x, y) {
this.x = x;
this.y = y;
}
}
要类变量的话也是妥妥要包一层了
Again, Are you sure?
class Point {
constructor(x, y) {
this.x = x;
this.y = y;
}
static get ZERO() {
return new Point(0, 0);
}
}
或者直接 Point.ZERO = new Point(0, 0)
也是可以的。
还不如直接用构造函数呢
你想多了,其实 class
就是构造器+原型继承的语法糖而已,JavaScript 从来都不是基于类型系统的 OO 编程语言,这一点一直都没有变过。
我不喜欢用 Class
,不管是过去的构造器模式还是现在的新语法。不是因为对任何编程范式有偏见,本来 JavaScript 就不是 Class Based OO 语言,硬生生的去模仿就是会觉得别扭罢了。和 Java、C# 等语言不同,class
不是必需品,这也就意味着你完全可以不用。然而奇怪的是使用 JavaScript 的人很多却是不用 class
不行,这是不是对这门语言存在很大的误解呢?
更重要的是在实践中我们会发现使用其他的模式——比如工厂函数(Factory Functions)要远比 class
简洁、灵活,用它来替代 class
几乎总能得到更好的结果。
// person.js
export default _ => {
return {
greet() {
console.log('Hello world!')
}
}
}
用起来和一个 Class 几乎一模一样——除了不需要用 new
,这不算坏处吧?
import Person from './person'
const nightire = Person()
nightire.greet() // "Hello world!"
console.log
限制了 greet
方法的行为,为了不局限问候的方式,可以使用依赖注入——这是解耦的一种简便易行的方法。即使在现实中很多时候看不出需要依赖注入的迹象,我们也应该有意识的这么做。在定义一种“类型”的时候对外界知道的越少越好(于是就更容易复用、扩展、组合……)。
// person.js
export default ioStream => {
return {
greet() {
ioStream.send('Hello world!')
}
}
}
比如说我们可以把 console
封装一下,让系统内所有的 ioStream
都具有统一的接口,然后就可以直接使用:
import Person from './person'
import ConsoleStream from 'console-stream'
const nightire = Person(ConsoleStream())
nightire.greet() // "Hello world!"
这个是顺带一提的事情,因为我注意到不懂得处理依赖注入(或者说更高层次上的解耦概念)的人通常都会把单元测试写得无比蛋疼……实际上,对象字面量在很多时候胜过一切构造模式:
import test from 'ava'
import Person from './person'
test(`a person can send message to io stream`, t => {
const ioStream = {
send(anything) {
t.same(anything, 'Hello world!');
}
}
const anyone = Person(ioStream)
anyone.greet()
})
其实私有成员可以变得很自然很自然,闭包一样在用,只是不那么扎眼了:
// person.js
export default ioStream => {
let _message = 'Hello world!'
return {
greet() {
ioStream.send('Hello world!')
},
get message() {
return _message
},
set message(message) {
_message = message
}
}
}
用法就不写了,和之前没什么区别。getter/setter 也不是必须的,看接口设计需求了。
这才是对 OO 来说最重要的(相较于怎么定义/创建对象来说),总的来说组合总是要优于继承,工厂模式搞起来尤其轻松。
比方说我们已经有了一个动作“类”:
// action.js
export default ioStream => {
return {
wave() {
ioStream.send('(Waving Hands...)')
}
}
}
那么与 Person
的组合可以这样:
import Person from './person'
import Action from './action'
import ConsoleStream from 'console-stream'
const _console = ConsoleStream()
const nightire = Object.assign({}, Person(_console), Action(_console))
nightire.message = 'Farewell, my friend!'
nightire.wave() // "(Waving Hands...)"
nightire.greet() // "Farewell, my friend!"
这是我觉得最好的一个优点。由于 this
在 JavaScript 中是在运行时动态绑定的,如果使用你代码的人不理解这一点,那么他们就会犯错误(而且会指责是你写的不对……)。有些人是因为不理解 this
而不敢用,有些人则是为了迁就前者而干脆不去用,架构师会比较容易体会这类情况。
这是典型的容易犯错的例子:
// stepper.js
export default class Stepper {
constructor(offset) {
this.offset = offset
}
add(amount) {
return amount + this.offset
}
}
// main.js
import Stepper from './stepper'
const stepper = new Stepper(1)
[1, 2, 3].map(stepper.add.bind(stepper))
容易犯错的地方就是最后一行,如果不加 .bind(stepper)
的话最终 this
的指向就是错误的。但往往使用者并不理解这一点,反正看到你的文档就知道这个能加上初始化传入的 offset
就是了,除非你不厌其烦的在文档里强调:“注意上下文的变化,如有必要请用 bind()
明确 this
的指向“……啊,说不定你还得培训一下让大家都知道如有“必要”的确切范围。
然而你也可以这样来重写一下:
// stepper.js
export default offset => {
return {
add(amount) {
return amount + offset
}
}
}
// main.js
import Stepper from './stepper'
const stepper = Stepper(1)
[1, 2, 3].map(stepper.add) // [2, 3, 4]
于是无论是具体实现还是接口定义都能保持简洁一致。
这是一些使用工厂函数代替类型定义的常用场景,我不是说百分之百不要用 class
(或是构造器之类的),他们也有用武之地,只是人们在抱怨他们不如熟悉的 Java 等语言好用的时候也应该问问自己:我真的了解它吗?这是唯一的选择吗?
这个视频里 --skip-spring
了。
呵呵,我的垃圾邮箱里每周都会收到一两封来自世界各地的“公主”/“王子”之类的邮件,不要理会就是了。
点对点实时通讯还是蛮有意思的
不管哪个框架,不都是用 JavaScript 写的吗?对于 JavaScript 代码在浏览器端的调试总是一样一样的,不会因为换个框架或是库就变难了或是变简单了。但是说到 Ember,Ember Inspector 倒的确是比其他框架的辅助工具强太多了,可以一试。
说实话,我第一遍看这篇文章也是觉得非常赞同的,但是静下心来想一想却又觉得有些不妥,不妥不是因为论点——一万小时定律这个说法是没有问题的,让我觉得不妥的是论述的依据和背后的驱动因素。
一万小时、走出舒适区、不断练习、程序员需要练习的东西……这些都很好,但我始终觉得加班和 Hackthon 这两件事情不太适合用来驱动自己去达成上述的论点或是目标。
先说加班的事情,加班是一种现象,在国内特别是初创型企业和那些把加班当成是“企业文化”的公司里屡见不鲜。但是【效率是导致加班的重要因素】这个观点有待商榷。我不否认有一部分非受迫性加班是由于自己的效率不够高的缘故,但我觉得这是非常小的一部分。
我仔细回忆了一起共事过的同事们,只要大家不是太陌生(比如新来的),那么各自的水平有几斤几两彼此之间应该是心知肚明的,所以在单位时间内各自能做完多少事情能做到什么程度也是可以估计出来的。于是问题就来了:如果这个是可以度量的(哪怕不够精确,但大致有数),那为什么还要把工作安排成非加班不可?
这就好像你做一个老师,却不是因材施教;做一个厨子,却不会看菜下饭;做一个领导,却不会因势利导……你不看生产力现状如何却总是一味的以主观倾向来调配资源和安排计划,怎么可能不加班?因为这种情形而加班的,本来人的心情就很不愉快,能够调整自己积极应对固然是好事,可这种事情却只能期待而不能指望。
如果因为不能正确评估生产力水平而错误的安排计划和调度资源从而产生了无休止加班赶工的恶性循环,这是项目/工程管理的问题,而不应该简单的归咎于从业者效率不够高,更不应该以此为驱动因素去要求从业者主动地忘记加班带来的身心负面影响并且还要发挥主观能动性去提高自己的效率。
反之,如果能够正确的评估和安排计划,在现有生产力的基础上实现不加班并且合理有效的完成计划,那样就可以先杜绝加班或是少量的加班。在此基础上通过激发员工的成就感等方法来唤醒他们希望自我提升的意识并且给予合适的培训和学习环境,那么才真正有希望做到自主自发的去提高每一个人的效率,进而提高团队的生产力……这才是良性循环。
对此我只能说:意图是好的,但是用错了激励方式或引导方式。我想这大概是不同的人对“以人为本”的不同理解吧。
Hackthon 这种活动我没有亲身参与过,其实并没有什么有分量的发言权,不过这种活动形式倒是让我联想到了自己所熟悉的音乐创作。音乐创作在很多地方都和编程开发有相似之处,你看大部分的产品都需要时间精心打磨,本质上这和一万小时定律是一样的,但是由于产品的特殊性(需要市场考验),所以它也有 MVP 这样的快速迭代的创造形式。音乐也是如此,一首名作必然是经历反复推敲打磨才成型的,但由于音乐本身也具有特殊性(比方说舞台上会需要即兴演奏),所以你也得学会和练习一些“套路”……我不知道这种对比是否能让大家 make sense,组过乐队写过歌的人应该能有所体会。
但我真正想说的是,那些历经一万小时锤炼而成的大神们,他们的初始动机绝非是为了在 Hackthon 上能够游刃有余;正如同那些音乐领域里的大师们,他们磨练自己的技艺也并非只是为了应付舞台上的即兴表演。
当然了,因为经历了 Hackthon 或是即兴表演从而认识到自己的不足,进而知道需要刻苦练习,这本身是一件好事。然而有些事情不能因果倒置,迷失了初心的话倒有可能又走一些弯路也说不定的。
另外,一万小时究竟应该练什么我觉得是要因人而异的,好的老师都会因材施教,所以不是一套方法总是适合所有的人。我自己经常看大神们的视频,实际上大神们也总是会去查 API 文档的,我无数次在各种视频里见证过这些东西,所以……
总之,观点没问题,论述的依据和方法个人还是觉得没走到点子上。
#17 楼 @rudy 其实我理解你所说的,遗憾的是当下的社会有一个无法忽视的客观因素:人太多!
理想的状况下,企业的确也应该承担教育和辅助成长这样的社会责任,来帮助学生适应社会和工作,为这个校园 <-> 社会的过渡搭起一个桥梁——实际上这并不罕见,硅谷每年都有大量的工程师去各个学校招收实习生、上公开课,这些都是此种社会责任的体现。
然而,第一中国不是美国,第二这是另外一个话题。
现在人多到什么程度?就连通过实习来成长的机会都要首先经历千挑万选刷掉一层又一层才可以。如果能有越来越多的企业大力在培养和积蓄储备力量上下力气当然是好事,可回顾一下当下的环境觉得现实吗?我的上一家公司,一个产品团队里真正写代码的只有三个人,而我一个人最多时候就带了四个实习生,实习的比正式工还多,我每三个月都要给其他项目组“贡献”一批速成培训学员,这些事情是我主动承担的,没有因此多挣一分钱。我对所有的实习生都很严苛,一个星期让我觉得没希望的立刻劝退。真的不要怪我没有人情味,我忙不过来,所以其实被我刷掉的更多……有时候我也觉得很不是滋味,可能怎么办呢?谁来鼓励我一下撒?
所以像楼主所面临的情况是这样的,就算你想通过实习来快速成长你也得首先证明你能获得这个实习的资格。资源总是有限的,就连学校里的老师都缺的不行,企业里面能有余力让你通过实习来成长的资源就更是少之又少,僧多粥少的情况下,包容和鼓励反而毫无用处,只有不断的给予压力才能逼迫着你脱颖而出,这他妈的就是现实,清醒呀少年们!
小时候听说过一个故事,狐狸的父母会把幼小狐狸推下山崖然后让它们自己往上爬。这是为什么?不用说了吧?
离开大学走向社会是每一个人 22-24 岁 这个阶段要面临的挑战,不要怪你的前辈们给的鼓励不够,前面 20 多年已经给够了鼓励和宽容了,现在就是要把你们推下山崖的时候。
另外我想点出一个误区:很多人都觉得进入公司跟着别人做项目能迅速找到最正确的方式学习,这是一个伪命题。可以说有一定几率能够找到最正确的方式学习,但是这个几率非常低,甚至可以说有几分碰运气的意味在里面。反而在我的经历中,冒冒失失就跟着别人做项目结果把人都给教坏了的可能性更大。但是这个也没有办法,分辨这一点需要一些运气,一些天赋,但是我自己的观念是这样的:想要出人头地,要靠自己,不能靠别人。别人靠得住是运气,靠不住是正常,如果自己都靠不住,那就啥都别说了。
所有所谓的“纯小白”其实都应该思考这样一个问题:
像 Ruby China 这样的社区里,有哪些人没有经历过“纯小白”的过程?他们是如何进化的?他们是如何找到工作的?他们是如何获得肯定和赞赏的?
思考这样的问题完全不需要具备任何专业技能,而且能够思考这样的问题的人就算不具备什么专业技能也会有很多公司抢着要,因为人类社会尊重一个朴实的道理:优胜劣汰。
就像 @martin91 的回答所体现的,尽管客观来看好像是要求苛刻了些,但反过来想想:我为什么找不到工作?是不是就是因为我并不了解 @martin91 所说的那些东西呢?
我是知道 Github,可是我了解 Git 吗?了解 Git 的人又会是什么样子的呢?Git 工作流又是怎么个情况呢?为什么学校老师从来/很少提这些事情呢?我会用 jQuery,可是我知道 jQuery 插件是怎么回事吗?如果我自己写一个能写的出来吗?
如果每一个纯小白在面试碰壁之后都能思考一些这样的问题,何愁一份工作?人都是有并且应该有主观能动性的,为什么一定得真正找到工作之后才去学习和思考?凭什么?
年轻的时候我特别讨厌别人说教,但是等到没人教的时候我才知道后悔,有什么办法呢?我只好自己对自己狠一点才能活下去。那时候我是多么希望有人能在我身边每天对我苛责多一分?我真心的希望每一个人不要到后悔的时候才明白这个道理。
顺便一提,其实我还有一个隐藏的 bonus 等着楼主挖掘的,然而说出来就没什么意义了,点到为止。
#4 楼 @hemengzhi88 这个”精湛“一点关系都没有,楼上说的都是一些最最起码的要求,要怪就怪学校教育和社会需求脱钩太离谱吧,换个简单的说法:我不关心你都学了什么(因为我无法快速验证你学的成效),我只关心你能做什么,做到什么程度。
从这个角度去展示自己就会更容易获得机会。顺便一提,比方你做的那个 Blog,你为什么只给一个浏览的地址?代码在哪里呢?
再举个例子,用 Chrome 打开你的博客,地址栏右边会出现一个“加载未知来源的脚本”的警告,你做的时候注意了吗?知道为什么吗?想过怎么解决吗?
如果我现在面试你,你给我看你的博客,我第一眼扫过去就会产生这些问题,如果你当时回答不上来我还会给你十分钟去试着找出答案,如果还不行的话……你告诉我你学了这学了那有什么用?
#28 楼 @hi2016 这是因为你没有做好 Isolation,而不是测试本身太难写。推荐去看看 https://www.destroyallsoftware.com/screencasts
Everything could be future, future is a circle.
#27 楼 @ugoa 你还别说,最近我换到 Windows 平台,Vim 还有很多坑没填好,所以也在用 Atom 试水,Windows 环境下干活还需要适应一阵子呢。
年前的这一段时间里打算录录视频神马的,老是写长篇太累了。
给你介绍一个视频:https://vimeo.com/148529508
里面主要是讲一些关于 Components 的最佳实践的,之前我挖了个关于 Components 的坑暂时停了,因为有一些东西我找不到答案,最近也在和这个视频的作者探讨一些这方面的事情。这个小妞很牛哦,华人,在 Dockyard 工作,Ember 专家啊。
#12 楼 @darkbaby123 就像 @ugoa 所说,刚出来的东西配套不够完善,我们之前是做了一个 Spring 的实现,的确也遇到不少问题。
你说的那个 gem 我没用过,不知道重到什么程度。Rails 的话其实 ActiveModel::Serializers 就可以了,只不过这货不更新了?还是准备并到 Rails 5 做 default 了?其他的 Ruby 实现很多啊,看这里:http://jsonapi.org/implementations/#server-libraries-ruby,要不你来调研一下吧,哈哈
细粒度不是问题,获取数据规范定义了 Sparse Fieldsets,更改(局部)数据规范明确定义了 PATCH
的用法
对于批量动作,JSON API 是使用扩展来支持的,扩展的好处就是隔离特例和常规用途,并且允许第三方定义和实现扩展。批量动作是一个官方扩展:http://jsonapi.org/extensions/bulk/,问题是各种 implementations 是否支持了官方的扩展这就不一定了,得看它们的实现程度和未来计划。
关于 Pods 的话题前两天有一个帖子里我刚回答过(可是我找不着了,脑残 ing),Robert Jackson 前几天有一个 presentation 在油管上你找来看看。大体意思就是现在的 Pods 也还不完美,还有一些大家特别渴求的场景无法实现,比如说嵌套的 Components。
就我个人而言,用不用 Pods 都无妨,对于 Ember 来说无非就是不一样的 Resolving 规则而已,你理解了这个规则就很容易理解不同的方式如何组织文件。
用 Pods 的最大好处对于我来说就是不同类型的文件(hbs/js/css)都在同一个目录下,好找——但也不是绝对的。基本上选择哪种方式最直接的影响就是找文件,这个怎么说呢?我觉得根源在于你对所用的编辑器够不够熟悉,还有你找文件的方法够不够多。
比方说我是用 Vim 的,不管用不用 Pods 找文件这种事都是小菜一碟,我有两个环境,一个是 MacVim,一个是 Windows 下的 gvim,前者我用 NERDTree + CtrlP,后者用 Unite,再配合 Sessions 那是想怎么找就怎么找,直接搜索代码用 the_silver_searcher(Ack 的增强版本),我自己是没觉得这有什么难度或痛点可言。
同事们有用 WebStorm 的,倒是跟我提过文件不好找的事情,那我就用 WebStorm 一段时间,默认的快捷查找(双击 Shift 哪个)也不错啊,就是有点慢。后来我又找着一个 Plugin(那里面的 Ember Plugin 就那一个),找文件也挺强的,就是有 Bug 还在逐渐完善中。另外我发现他们都不太会用 WebStorm 或者说 Jetbrains 家的 IDE,它家的 IDE 是有一个 Task Context 功能,做一个功能可以新建一个 Context,所有相关的文件及其变更都可以随着这个 Context 走,你切换 Context 就好像切换 Vim 的 Session 一样,这些工具提供的便利如果你学不会去用那也没办法,再牛的 Pods 也救不了你。
至于以后,Pods 还会有一个大的调整,现在就在进行中,Github 上有几个 PR 都和此有关的。但这个改动不会很快(比方说下一个小版本)就完成,主要是因为这个调整要随着 Routable Components 和 Glimmer Components 走的,后两者的最终实现会影响 Pods 的实际设计。
所以对于你的问题,怎么说呢……我个人是无可无不可的,无非就是怎么组织文件呗,还是看你们小伙伴们的意见吧,大家都认可就行了。
#10 楼 @jesktop 我在上一个团队了帮助后端实施了 API 的重构,搞了一次 JSON API,你所顾虑的问题我们在这个过程中都有遇到,以下是我个人的一些体会:
几天前 Robert Jackson 在一个新的 Meetup 上讲了 Pods 的前世今生以及未来的改进计划,这会儿赶时间等晚点把链接贴给你参考。