《Eat that frog》笔记

这是一本关于时间管理的技巧性书,书中有21个技巧来克服拖延。本来不打算写读书笔记的,因为最好是按照书上方法亲自实践的一番。这个总结摘自邮件,顺便整理了一下。
本书内容概况来说就是思考和定义目标,制定周详的计划,任务拆分,设置优先级,专注最重要的事情。

  1. Set the table
    写下你的目标,仔细思考你的目标,越清晰越具体越好。拖延的主要原因就是没有目标,没有动力。所以首先要做的就是树立清晰的目标。可以是提升专业技能,或者学习金融知识,或者是抚养孩子。写下来并设定截止日期,列出你可以做的任务以达成目标。组织优先级和顺序。立即执行,每天完成一些任务以达成目标。

  2. Plan Every day in advance
    制定每日,每周,每月计划。每天晚上休息之前可以制定第二天的计划。这是必需的,花在计划上的一分钟都会节省你之后的10分钟。

  3. Apply the 80/20 Rule to everything
    利用二八原则。时间管理就是个人管理,人生管理。

  4. Consider the Consequence
    这个是在强调思考重要性的时候,想一下结果。尤其是长期结果,可能看起来重要的事情长期来看没那么重要了。

  5. Practice Creative Procrastination
    针对优先级低的任务有意的拖延。

  6. Use the ABCDE method
    任务划分优先级:
    A1 A2… must
    B1 B2 … should
    C1 C2… would be nice
    D… Delegate
    E …eliminate

  7. Focus on Key Result Areas
    专注于只有你才能做的事情。(工作上)思考因为什么公司付你薪水。

  8. Apply the law of three
    80% 的人共同的三个目标:财务和事业;家庭和个人关系;健康和体质。可以接着思考三个重要的财务和事业目标,三个最重要的健康目标,可以做的三个任务以达成某一目标。

  9. Prepare thoroughly before you begin
    好好准备,包括清理桌面。只留下与最重要目标相关的东西。一句话就是,桌面就是为目标准备的。

  10. Take it one oil Barrel at a time
    一次迈一小步。列出你需要完成目标的步骤。

  11. Update your key skills
    持续学习。每天阅读至少一小时在自己的专业领域上。在通勤时听音频节目。参加一些课程。

  12. Identify your key constraints
    找出实现目标中最大的不足,

  13. Put pressure on yourself
    设置deadline 想象自己在某天之后出门等等。

  14. motivate yourself into action
    激励自己

  15. Technology is a terrible master
    拒绝成为科技的奴隶。每天早上和下午关掉手机和电脑一个小时。可以尝试坚持在就餐时放下手机。

  16. Technology is a wonderful servant
    每天只检查两次邮箱。

  17. Focus Your attention
    集中注意力

  18. Slice and Dice the Task

  19. Create large chunks of time

  20. 培养紧迫感
    进入’心流‘状态

  21. 一次完成任务
    一旦开始就不要停下。考验自律的时候

对我来说,我没有制定每月计划,每周计划从季度 OKR 里分解。每天早上几分钟列出任务,然后完成早上的一个学习任务之后才能看手机。晚上10点之后不用电脑和手机。对于长期任务比如健身和学习,只有分解成切实可行的小任务并且定在每周计划上才有作用。

《高效能人士的七个习惯》笔记

老实说,在读这本书之前以为这本书会讲如何提高工作效率。之前很不屑励志或成功学类书目,因为往往这类的书都是在谈论一些空洞的原则,读过之后无所裨益。问题是,一个人的心智并不会随着生理的成熟而自然的成熟。对个人成长至关重要的东西从来不曾系统的出现在教育课程上,父母对这方面的教导可谓极其有限。

这本书第一章在抛出一些问题之后,就指出现代成功书籍与经典的差异,经典书籍像富兰克林自传非常强调个人品德修养,而现代书籍则重点强调技巧和个性。这是一个非常有意思的点。小时候听故事,浪漫主义文学,都会阐述好人有好报,美好的品性总会得到回报。对名人随笔,语录并没有多深的理解,但也不作怀疑。不及长大就识人性贪婪可憎,也不再将古人所言奉为金科玉律。这本书重新强调了品德的重要性,也是做一切事情的根本。比如我们知道应该多去赞美他人,但是怎样做的发自肺腑呢?这就要看个人的修养了,否则会有假装的嫌疑。本书强调自内而外反求诸己,我们需要认识到我们的观念影响到我们的认知,我们需要检讨自己的观念的和接受他人的观念,以此逐渐变得客观。文中讲他的一个经历,在车上遇到几个熊孩子而父亲不管不问,他感到不耐烦,就对那位父亲说,你是不是应该管管你的孩子。当他得知这位父亲刚刚失去自己的妻子时,观念立马改变了。这就是观念转换的力量。观念应以原则为中心,这些原则包括公正,诚实,正直,尊严,服务(贡献社会)以及卓越。
这本书将习惯解释为知识,技巧以及欲望的结合,知识决定为什么做和做什么,技巧决定怎样做,而欲望是动机。

七个习惯

习惯一:积极主动

我们的行为取决于自身的抉择而非外界环境。这其实很难做到,我们的心情总会受外界影响,天气,外人评论,老板,但是我们总是有选择的,我们可以选择积极应对。书中一个例子影响颇深,一个学生请假说自己不得不参加网球活动。于是他让学生权衡利弊自己做决定,并说自己也会选择网球队但是不会说自己是被迫的。大部分都很讨厌负能量的人,遇到问题只会抱怨不会想着改变。自己也在追求客观不受外界影响,有时发现真的很难说服别人做出一些改变,有些人整天抱怨,你劝说他做出一些尝试,而他又总会有各种理由。

习惯二:自始至终

想象一下参加自己的葬礼,你希望得到怎样的评价,你希望成为怎样的一个人。类似的测试还有,你不久于人世,写下你想做的事情。想想就很沮丧,这个季度的个人 OKR 首先就是改善自己与亲人的关系。看到这个测试之后,就加一条关于朋友的。这一章需要确定给自己的原则最终目标,以及个人宣言。

习惯三:要事第一

事有轻重缓急,主要问题是我们往往把忽略重要而不紧急的事情,往往一再拖延,而这些事情长期来看能够带来显著的变化。比如健身,比如读书等等。还有就是对琐事不忍说不。一个办法就是我们每周设定目标时将这些重要的事情列在清单上并认真对待。最好从长期目标上分解出来一些任务出来。(没有什么可以授权帮助提升效率的)

习惯四:利己利人

一般来说,与朋友比较容易相处,在选择朋友的过程中就已经确定了他的品行,所以在相处时问题也不大。但是往往在与亲戚的相处时非常困难,很难达到利己利人。往往会有一些亲戚得尺进寸,明明占了便宜还不领情,做不到利己利人最起码要独善其身或者好聚好散,又或买卖不成仁义在。五个要领:品格,关系,协议,制度,过程。书中提到对协议的利用:与儿子协议整理庭院,协议的五要素:预期结果,达成目的的原则限度,可用资源,考评标准与期限以及赏罚。再次感觉到现代企业经营中的思维方式运用到日常生活中。

习惯五:设身处地

这个和开头提到的观念转移相呼应。有效沟通四个阶段:复数语句表示专心聆听;加入解释;掺入感情,体会对方心情;既加以解释又带有感情。古希腊人认为:人生以品格第一,情感居次,理性第三。表达自己也应循着这三阶段。其实男女沟通的时候往往就有很大差异,女性往往强调感受,男性则想着解决问题。所以男性在表述之前,应该体会对方的感情。

习惯六:集思广益

最开始讲人际关系的阶段:依赖,独立,互赖。集思广益就对应着互赖。首先需要理清双方将各自的诉求,在此之上提出双方可以接受的方案,需要双方都做出妥协。

习惯六:不断完善

工欲善其事必先利其器。准则七就是磨炼自己,从身体,精神,心智以及待人处事四个方面:锻炼身体,陶冶精神(冥想),自我教育,历练待人处事之道。帮助他人。

总的来说,读完此书觉得有点泛泛而谈,道理大家都懂,但是不妨做出一点改变,锻炼自己的心智。

Distribute tracing - newrelic

newrelic 提供的 Distribute tracing 功能非常实用。阿里内部使用的是鹰眼系统,因为一直做前端开发所以我并不是很清楚到底怎么工作的。虽说之前也多少翻过一些文章介绍大概的系统的架构,但是一直以为在调用下游服务时是显式传入当前 TraceId 的。直到最近使用 newrelicDistribute tracing 追踪才了解到还有一种无侵入的方案。

比较流行的全链路监控方案 Zipkin Pinpoint Skywalking 也有完全无侵入的方案,但都是 JAVA 编写的。而且在搜寻对应的 Node.js 实现时,找到的仓库代码往往并不齐全。无奈只能在 newrelic 源码中寻找线索,果然发现大量的 instrumentation,其中就有对原生 http模块上方法的拦截。这样就可以解释为什么我们不需要显式传给下游 TraceId

或许不难猜到,在发起新请求时,只需要把当前的 traceId 附带到请求头上即可。在接收请求时解析请求头上信息,并将其传给当前新建的 transaction 作为 parentId。
但是还有一个问题:如果有多个请求同时处理,如何保证传给下游正确的 TraceId。假设服务端的伪代码是这样的:

1
2
3
4
5
6
app.get('/frontend', (req, res) => {
asyncTask((is) => {
const result = await http.get('/downstream');
res.json(result);
});
})

如果同时有两个请求 /frontend(1) /frontend(2) 怎么保证调用链不串呢?因为我们并不能保证异步任务的时间,完全有可能第二个请求先调用了下游服务。 Skywalking Node.js 就有这样的问题

继续查看代码又有新的发现,newrelic 同时也对很多基础模块进行了拦截,包括我能想到的 Timer, Promise Async, FS 等等, 包装回调主要目的在执行回调之前找到当时的 segment。

这么多的拦截代码想当然的会需要一定的开销。暂时未见到 newrelic 上关于这方面的文档。

更多链接
https://juejin.im/post/5a7a9e0af265da4e914b46f1

读《见识》

很惭愧的说,《见识》是我读的第一本吴军的书。《浪潮之巅》因为太畅销的缘故,一直未曾列入个人书单。书名《见识》,内容由《硅谷来信》专栏文章整理而来,所以话题很泛。就单一方便而言,不如名家随笔随想深入,但是非常贴合日常生活的缘故,观点非常中肯,非常有说服力。需要指出的是,即使所讲道理相同,不同的人在不同的阅历也会有不一样的感受,于我而言,受益匪浅。

序言中讲《命运》,提到他朋友说他去腾讯是一个不错的选择,原因是:这家公司有独一无二的价值。读到这儿时,触动很大,回想自己过去在做出选择时从来没有这样的眼界。我们常常说有时候选择比努力还重要,对一个人来说 10 年前选择阿里巴巴或者一家更高薪的小公司,现在看可是云泥之别。当然,我们并不能预料到今天阿里巴巴能够这么成功,如果一个人做错了选择我们也不能因此说此人没有眼光,因为不少聪明的专业投资人都错过了,何况我们呢?不可否认的是,就是这样的见识往往对我们的命运影响巨大。(想下自己目前的公司就不符合这一原则,甚是惭愧)

这本书首先谈幸福与成功,这样的安排很有心思。在《人生的智慧》中讲,人生的智慧就是最大程度的追求幸福。我们必须思考为什么活着,然后找到自己的答案。死亡是一个沉重的话题,但我们必须学会面对。非常朴素的道理非常难懂,对我而言至今依然没有顿悟。或许太多人想着逆袭,太多人愤愤不平,作者在《这个世界并没有欠你什么》给予回复,以正三观。婚姻和家庭在幸福中至关重要,不得不说在我们选择伴侣的时候太不成熟,而大多数人没有意识到人生是不断学习和提升自己心智的过程。还有一篇谈让父母成熟起来,我自己也承认在与父母沟通这方面做的很差,慢慢地才发现与父母之前的隔阂越来越大,以至于经常普通的问候都不想重复。人到中年,这些都是需要面对和解决的问题。

人生需要做减法。为何硅谷有这么多印度高管,作者给出的解释不错。我想补充的一点是中国的文化制度和在这种教育体制下培养出的人才性格也是一个很重要的原因。个人认为,若比较专业人才我们一点不差,但是成为高管需要的是软实力,这些恰恰是国内高材生最为欠缺的。国人选择太多,人太浮躁其实大家也知道因为我们喜欢攀比,聚会时经常打听谁谁换了新工作拿的薪资有多少。作者在《西瓜与芝麻》中讲的捡芝麻行为,作为一个珍惜自己时间的人很少这么做,时不时也会有这样的行为。对抢月饼一事,我也有不同的看法,说他们捡芝麻不无道理。对我而言必须时刻警惕,回想下过去工作中,有太多时间花在自认为一文不值的功能上。而现今所在公司想做一个平台,或许真的不如聚焦在一个产品上来的好,把自己所擅长的做到极致。之前读的一篇关于德国制造的文章,也讲到同样的事,德国聚集了非常多的行业第一的小企业,他们在经济危机中有更强的生命力。如果什么都想做,可能什么都做不成功。

玻璃心,输不起。记得之前读的一篇文章讲陈浩南为何能够东山再起,就说到愿赌服输,甘心受罚。说实话,一般人还真难做到这点,输了总是不甘心。无论贫富,父母要培养孩子:有见识,有爱心,守规矩。

不做伪工作者。衡量伪工作可以比较最终效果与投入。英文我们会强调 outcome 而非 result, 这儿是有差别的,可以将 outcome 理解为长远的最终效果。在刚开始工作时, 可以说我和普通的大学生一样对工作缺乏一个正确的认识,只是想着把交给自己的事做完就好了。在过去一年才读了一些关于管理的书,这一章的第一板斧让我想起了《Making Yourself Indispensable》,这本书确实非常实用。OKR 也是今年才在公司内部推行。对我来说是,知易行难,一直没有认真对待。关于职业的误区,可以说这些问题自己都有,过去一年改善很多,与领导的沟通交流,以公司视角去看问题都有所提高。有些经验教训都是花时间获得的,所以可以说如果职场新人在第一份工作中就有人传授这些经验,可以少走很多弯路。现在对我来说,选择一家公司,需要考虑的就是:公司或者产品是否独立无二;其次才是团队。

关于投资,年轻人最好的投资就是投资自己,这句话一点不假。同时我们自己有点闲钱的时候就会蠢蠢欲动,我自己也损失了不少钱在股市。但是年轻人迟早要载跟头,不如早一点犯错,早一点吸取教训。很多人说炒股犹如和自己的欲望博弈,很多人根本做不到理性。就像一个赌徒,连续赢了 10 次之后就觉得自己的技术高明一样,但是归根结底这只是一个零和游戏,最终依靠赌博发家的毕竟是少数。我们也能找到少数的幸运儿,但这和中彩票的概率是一样的,只是中了彩票之后我们会把它归于运气。成功时必须看到运气的成分,失败时从自己身上找原因。

说话与沟通,凡事莫争,就算争赢了也无济于事。所以说,讲话要达到目的。

一个内存泄漏问题分析

一般来说,借助于强大的 GC 和 lint 工具,前端还是很少会碰到内存泄漏问题的。这篇文章说下我最近遇到的例子以及排查的过程。

内存泄漏的检测还是非常容易的:打开 Chrome DevTools 选择 Memory 选项,点击 Take heap snapshot 等待查看内存大小。重复这个步骤,如果你发现内存大小定期增长,或者增长的很有规律,那么八成出现内存泄漏了。这个是 Google 的 文档

问题检测

我们的应用是这样组织的,采用微前端架构,涉及到几个项目,一个 Shell 负责管理具体渲染哪个页面,应用默认是 Documents 页面,还有一个 Teams 页面分别属于不同的项目。 在 Teams 页面采集内存信息,回到 Documents 页面等待页面加载完成再回到 Teams 页面再次采集内存信息。重复这个过程几次,这是结果截图。为了确保数据准确,在隐私窗口测试以免受插件影响,在每次收集之前都点击 Collect Garbage。每次都多次采集直到得到 4 个相同的值表示内存大小稳定。这个截图上,5,6,7与8相同就移除了,不过足以说明应用确实存在内存泄漏了。

memory snapshot

问题诊断

现在我们知道有内存泄漏,先比较下 Snapshot 19 和 Snapshot 15 的内存信息. 😱 好吧, 太多对象了,几乎是组件树上的所有示例都有在列,毫无头绪。因为涉及到三个项目,完全不知道如何下手。不过不管怎样,先从可以做的做起,先把开发环境准备好。当然开发环境本身就有更多干扰因素,不过好歹还是有了第一条线索。当我尝试复现问题时,根本不等 Documents 页面完成渲染就切换页面,控制台有一个警告信息:

Warning: Can’t perform a React state update on an unmounted component. This is a no-op, but it indicates a memory leak in your application. To fix, cancel all subscriptions and asynchronous tasks in the componentWillUnmount method.

因为有错误堆栈信息,所以很快发现,这个错误时因为没有清理定时器导致的。虽说本书是有逻辑来清理定时器的,但是没有考虑到这些逻辑因为用户页面跳转中断。所以说最好还是在 componentWillUnmount 完成所有的清理工作。

修复这个问题并且排查了所有的定时器之后,发现内存泄漏还在,看起来没那么容易解决。

为了方便问题排查,先修改 Teams 为仅渲染普通文本,依然稳定复现内存泄漏。不过其次最为可疑的就是全局的事件监听,排查一遍发现有些监听未被移除。幸运的是,发现一个低级错误,本来 componentWillUnmount 应该移除监听结果又添加了一遍:.

1
2
3
4
5
6
componentDidMount() {
window.matchMedia('print').addListener(this.printHandler);
}
componentWillUnmount() {
window.matchMedia('print').addListener(this.printHandler);
}

把 addListener 改为 removeListener 之后重新检查一遍,发现还是存在内存泄漏。

检查了所有的事件监听之后,确信没有遗漏,在查看内存信息的时候看到 onLoad 事件回调,对了,on 事件给漏了。在 shell 里一些可疑代码:

1
2
3
4
5
6
7
const tag = document.createElement('script');
// ... some code
tag.onload = () => {
resolve();
};
// ...
document.body.appendChild(tag);

不管怎样,我们应该清理到这些事件:

1
2
3
4
5
6
tag.onerror = () {
tag.onload = tag.onerror = null;
};
tag.onload = () {
tag.onload = tag.onerror = null;
};

重新检查内存泄漏,发现还是存在。上面的代码因为只允许了一次所以不会导致内存大小变化。这个时候都怀疑是不是第三方库的原因了。不过还是当把 Documents 页面换成普通文本时发现,没有问题了。所以问题肯定在 Documents 组件上。 为了进一步缩小范围,试着把 render 方法移除,发现问题这样都有问题。 所以说,问题还是在 componentDidMountcomponentDidMount 上的事件监听上. 但是看起来一切正常。 因为对 matchMedia 这个实验特性不熟,又再次查看了下文档. 这次注意到:它说每次都会返回一个新的对象 …

意思就是 matchMedia('print') !== matchMedia('print') 这也就是为什么 matchMedia('print').removeListener(this.printHandler); 压根没有的原因。修复这个问题之后,再次检查就没有内存泄漏的问题了。

总结

内存泄漏很少碰到,当然也很难调试犹如大海捞针。 除了排查定位:定时器,全局的事件监听,以及全局对象是优先排查的对象。

工作在澳洲

在对澳洲一切习以为常之前,记下最初感受不同的地方。
首先,说下澳洲的互联网状况,在来之前听说过的公司只有 atlassian 一家,后来发现也有不少的小的初创公司。另外就是整体的感受,不像国内能够时不时感受到互联网切切实实的给生活带来变化,随处可见的二维码在澳洲也没有。澳洲节奏很慢,找工作也慢,不比国内很多公司通知面试几场谈下来当天就通知结果。我刚到澳洲时,签证和英语都是一个问题。当时的想法也简单:随便找家 local 公司,练练英语也好。

说说我刚到澳洲时的英语水平,虽说大学英语六级一次过,但是听说真的很水,几乎没有开口说过英语,接到中介电话都听不懂说什么。所以,最开始也只是熟悉下这边的生活,找机会练练英语,有事没事参加下 meetup 。技术类 meetup 一般都提供 🍕 和 🍺。语言类 meetup 大家英语都不好,所以也没什么顾忌,参加的多了,跟人说英语的时候就不会慌。同时你也会发现来自世界各地的人都是一样程度的烂,但是他们很多人更为积极主动,即使说的很烂也很有自信。

开始的一段时间,除了学英语,还在家做饭做家务,十分受气。因为签证只能找短期工作,开始在 seek 上投简历,目标是一份短期合同工作。这边的合同工很普遍,工资相对较高。另外,很多资源都是在中介手上,不过中介还是相对靠谱的。开始的进展很不理想,中介联系之后大多不了了之,到后来才发现,其实合同工对我来说更难,因为英语和签证的原因,对他们来说风险很大,倒是大公司才愿意也有能力承担这些风险。所以,之后就只看全职工作了,LinkedIn 上也比 seek 上更有效率。

之后接到几个面试,开始的时候也不清楚这边都是什么套路,整体慌着学英语,也没时间做很充分的准备,在面试之前就做些编程挑战题目,还有浏览一些面试题。总共也没经历几次面试,比较有含量的就是面试本地一家独角兽企业(事先并不知道,中介通知我面试之后跟我介绍才知道)。中介还是很负责的,给些建议,练练英语。第一次面试就是和 HR 聊一些面试问答题,说实在答的并不好,因为有些记忆性的问题没有准备,还有就是可能当时只说了一个点,面试完了坐在车上想的时候,觉得没有答好。不过反馈说还好,然后通知二面结对编程(之前只在书上看到的概念)。实际就是出题编程,总的来说没什么难度。之后就通知最后一面三小时。了解了这家公司之后,他们也将在中国设立分部,对它还是蛮有兴趣的,于是最后一面花了不少时间准备。最后一面分两轮:第一轮实现一个简单游戏,现场投屏写代码。当时压力很大,加上又对那次机会很重视有点慌。不过第一轮还好。第二轮让实现 Virtual Dom 的 diff 算法,这个与我之前预料的不同,现场不可能好好思考,感觉脑袋完全懵逼。结果就悲剧了。当时觉得很可惜,如果之前不准备这么多,可能面试也不会这么慌,也不会感到那么遗憾。面试完之后接到另一家公司(现东家)电话准备最后一面,不过没过多久就取消面试直接签合同了。因为这家公司说为我做担保,并且支持我上英语课,当时还挺满意的就没有继续找其他机会。

就我仅有的经历来说,澳洲求职还是很可能要与中介打交道的。与国内相比,机会少一些,但是有不少合同工薪酬很不错。面试过程比较可能会要求现场编程,甚至于稍微复杂比如一个小游戏。

再说说这边的工作情况,越是小公司可能越是不尽相同,这家公司人与人之间相处很融洽,你会觉得自己受欢迎。当然这是企业文化的一部分,但是就想这么小的一家公司就如此重视企业文化,想想国内几千人的公司从来没重视过这些东西。办公环境不错,就在 Rock 区,有健身房,很多人觉得最棒的是咖啡机。入职时送一个小 Kindle,每季度会选一本书,当然与管理文化相关。

最开始写了一段时间的 E2E 测试,QA 是质量辅助,测试还是要开发写的,测试已经帮助梳理好了关键 Case,剩下就是用代码实现了。这个国内很少有执行的,有些大公司喊着去测试,结果是测试转开发,开发也不写测试,测试交给外包来做。个人认为就国内情况而言,在野蛮疯长阶段,舍弃部分代码质量是有必要的,但是当客户稳定时,代码质量不容忽视。不止是 bug 带来的隐患,还有人员交替频繁,技术债早晚都要还的。

之后 bootcamp 临时加入其它小组 1~2 个星期,也算是帮助熟悉业务和同事。

敏捷开发毫无疑问是主流,在国内的时候团队也尝试过,结果不尽人意。这个也跟文化和管理方式有关,国内的企业才多久,百度什么时候才提出自己的愿景。敏捷开发对个人素质和能力都有要求,每个人能够充分发挥自己的作用。国内情况很复杂,有自己的特点,人情社会嘛。但是不管怎样,个人觉得必须有一套自己的方法论,拍脑袋分任务未免太初级。

还有一个比较有意思的是,每季度公司会组织一次 Smash it, 两周时间放下手头工作搞创新,做你觉得能创造价值的任何事。后来才知道这个是政府支持的,其它公司也有类似的活动。–《浪潮之巅》讲成功的基因时 3M 成功的秘诀。

管理文化,公司完全信任员工,允许远程办公。推崇 Ownership 每个人都是 Owner,而不是一颗螺丝钉。Ownership 中, 不是 Boss 指挥你做什么,而是员工告知老大自己要做什么。可能因为没有绩效之争,员工之间也比较和谐,Manager 很少管,更多的是怎么支持你的工作。两周组织一次一对一谈话,帮助你 review 或者哪些能够支持你的工作。

前端小组,两周组织一次会议,基本就是一次 Catchup,你可以添加一些话题,比如引入新的工具,新的规范或者技术上的问题都可以在这个会议上讨论。

烦人的 Flow.js

不管怎么说,Javascript 构建的项目越来越大且越来越复杂,弱类型这个短板显得越来越为致命。而 Flow.js 提供了一个向强类型过渡的方案。

  1. 挫挫的枚举类型
1
2
3
4
5
6
7
8
type Color = 'red' | 'blue' | 'green';

const Colors = Object.freeze({
Red: 'Red',
Blue: 'Blue',
Green: 'Green',
})
type Color = $Values<typeof Colors>;
  1. 莫名其妙的严格
1
2
3
4
5
6
7
8
type Vehicle = { name?: string }
const car: Vehicle = {}; // It works

type Vehicle = {| name?: string, color?: string |}
const car: Vehicle = { color: '' }; // It works

type Vehicle = {| name?: string |}
const car: Vehicle = {}; // Error
  1. 不严格的类型和里式替换

我们知道,在 flow.js 中,当我们定义一个类型时,type Vehicle = { name: string } 只是意味着这个对象至少有 name: string 这个属性,你可以这样 const bike: Vehicle = { name: 'bike', brand: 'phoenix' }。就是因为太不严格,所以我们会选择严格类型 type Vehicle = {| name: string |} 不过接下来就遇到麻烦了。

1
2
3
4
5
6
7
8
9
type Vehicle = {|
name: string,
|}
type Car = {
...Vehicle,
wheel: number
};
const car: Car = { name: 'Toyota', wheel: 4 };
const vehicle: Vehicle = (car: Vehicle); // Cannot cast `car` to `Vehicle`
  1. 三方库依赖问题

有次突然发现我们漏掉了 import * as React from "react"; 但是可以直接使用 React.Node,flow.js 竟然没有报错。当然,它只可能是默认的 Any 类型。很快就定位到在 flow-typed/npm/enzyme_v3.x.x.js 包含有:

1
2
3
4
import * as React from "react";
declare module "react-redux" {
// Here will use React type
}

看样子是,只要在声明文件中导入之后,类型就被污染了。被污染的还有:Dispatch, Store, React, ComponentType and ElementConfig 不难猜到越是流行的库越可能被污染。而这一切发生的时候,flow.js 没有任何警告信息或错误提示。
Known issue: https://github.com/flow-typed/flow-typed/issues/1857

  1. 第三方库

时不时的第三方库导致 flow 错误,又不能 ignore 所有的 node_modules 文件,每次遇到新错误,都只能加载后面。甚至 node_modules/**/test/*.json 都有可能导致 flow 错误。 目前没有什么优雅的办法:https://github.com/facebook/flow/issues/869

1
2
[ignore]
.*\/node_modules\/draft-js\/lib\/.*.js.flow.*
  1. 关于 $FlowFixMe

有时 flow 不够聪明,即使我们知道没有那个逻辑,当然有时我们可以绕过这些报错。个人认为用额外的逻辑来弥补 flow 的错误更不合适。$FlowFixMe 是很烦,但是至少不会引起困惑。

《Making Yourself Indispensable》笔记

当然之前也是非常不屑于成功学的书籍的,不过最近对这类书也有了新的认知,现在个人觉得是一本挺实用的一本书。成功学的书大同小异,读的时候你会觉得道理我都懂,读完之后觉得并没有什么用。

这本书是一本实用型书籍。书中最开始描述了一个理想的场景,你对工作充满激情,老板认可你的价值,同事觉得你很靠谱,并且能够兼顾家庭等等。但是实际生活并非如此,你与不可或缺相去甚远,每天你最不想做的事情就是上班。

作者首先定义不可或缺,让我们树立一个意识,这无关乎智商,能力,教育,每个人都能做到。作者根据自己的观察,给出了一个包括 10 个行为的测评。之后给出几乎每天都会做的 6 个选择,这些选择决定你是否不可或缺。这 6 个选择:

  • Purpose Driven or Goal Driven
  • Paly Big or Play Small
  • Adaptable or Rigid
  • We Centered or Me Centered
  • Priority Focused or Activity Focused
  • Value Others or Disregard Others

六个选择

Purpose Driven or Goal Driven

这是最重要的一个,平时可能只关注老大分配下来的任务,是否思考过你的最高目标。书中的一个例子:他永远不会忘记的一个水管工在修浴室管子时顺便帮检查其它的水龙头。

Play Big or Play Small

这个个人感觉是上一个的延伸,更像是一个人的格局。更多的从团队,从公司视角去思考你能做些什么。

Adaptable or Rigid

每个人都有自己的主张,见解。尤其是最终的决策与你的建议完全不同时,你是否依然能够支持甚至推动下去。

We Centered or Me Centered

Priority Focused or Activity Focused

避免瞎忙

Value Others or Disregard Others

每个人都希望能够得到别人的认可,反过来你也需要认可他人的价值。在一些会给同事一个公开的赞,甚至买一个小礼物(公司报销)即使只是举手之劳。这个在国内并没见到过,关系熟络的反而觉得例外,往往只会在取得一个比较大的成果时才会意思一下。但是个人觉得这也恰恰是我们需要重视的,让别人感受到尊重。

之后紧接着练习,会让你描述你的最高目的,你可以采取哪些行动(Play Big, Being Adaptable, We Center…)。回头再看这些选择都对应了:

you are not indispensable unless you use your gifts and principles in service to other people’s success, improvement, or survival.

这本书介绍了 Road Map 循序渐进地让你不可或缺。良性循环和恶性循环。
在开始 Road Map 之前

  1. State Your Intentions and Set Your Ultimate Goals
    Intention represents the desired purpose, goals, and outcomes that are the basis of your plans and actions.
  2. Picture What Success Looks Like to You
    It usually includes four sections: Customers, Team members, Managers, Self-development
  3. Test Your picture of success
    Apply the above choices

Keep Your Intention and Picture of Success Alive
Spend time to review it regulary

简单来说就是,定义你的目标,越清楚越好,之后想下怎么样做(可以采取哪些行动),越具体越好,同时思考你可以利用哪些资源帮助你。

RoadMap

1. Recognize Your Current Reality 认清你的位置

需要诚实,客观中立,勇敢 测评 找一个导师(几个建议)

2. The power of taking ownership *

3. Gaining Strength through forgiveness

4. Self examination to foster solutions

5. Master learner - Your default response

6. Take action to be successful

Celebrating SUCCESS

总之,书上内容还是非常实用的,即便还未完全照做,但是依然觉得里面的建议十分中肯。

谈谈测试与代码质量

平常开发中,你花多少时间写测试?覆盖率有多少?除了单元测试,其它的整合测试以及 UI 测试有实践么?

以我个人经历来说,在国内工作时几乎不写任何测试,仅限于倒腾过测试。即使阿里这样的大公司,业务部门也几乎不写任何测试,基础研发部门或许很有节操,具体情况不得而知不好瞎猜。为什么不写测试,这跟整体的氛围有关,真有人在意你的代码质量吗?没有!大家在意的是业务结果。原来的负责人升职加薪之后项目交给后面的人维护,如果新需求不多,代码还过得去维护着就行。需求实在太多,维护不下去了,那只能重写了(自动化测试都没有,谈不上重构)。

国内开发节奏太快,着急于抢占市场,不断试错,计划赶不上变化,这周加的功能下周都可能就要废掉。这种情况下,写测试完全得不偿失,自然也就不会花时间在写测试上了。那如何保证代码质量呢?一般在上线截止日期前,集中时间手动测试,或许有些公司将这些任务外包给其它公司来做,毕竟大多数的开发可不屑于干这么枯燥无聊的活。

现在就职的公司在测试上做的可谓非常专业。我们的 QA 团队会支持各个业务团队,QA 是质量辅助而非质量保证。这儿有个文章介绍质量保证与质量辅助。QA 的职责更多的是监督,指导我们来完成测试任务,而非自己测试。他们会收集各种数据,建立指标来评估代码质量。另外,也会帮助新团队或新项目建立自动化测试,指导新人完成测试工作。

再说说我的发布模式,我们的发布周期是每日发布,也就是说当你的代码合并到 master 时必须保证它是正确的。因为第二天固定时间就会部署到线上,部署之后自动化测试通过就认为部署成功。除了单元测试,我们还需要用 UI 测试覆盖到所有的关键路径,也即冒烟测试。冒烟测试只会测试整体流程,允许存在 bug 但不是严重的,不影响正常的流程即可。

一个潜在的 bug 发现的越早所需的修复成本越低。单元测试并不能保证万无一失,模块与模块之间功能是否匹配还需要整合测试来保证。现在的问题是我们为什么而测试,于是,在开发前我们列出所有的需求点来,以保证我们会用适当的测试来覆盖这些需求点。

最后,在后端和前端之间,我们加入了合约测试以保证后端的 API 变动不会影响到前端代码。

现在的趋势是,开发将承担运维和测试的工作,而运维和测试只做些支撑性的工作。某些大厂强制测试转开发,就我之前见到后端写前端的经验来看,除非是内驱的并且公司给予足够的时间来转,否则只是添乱。口号喊的很好,全栈工程师,简单易上手,但是只要不让我接手维护他们的代码随便他们怎么折腾都行。

说说发布周期,每日发布就必须要求开发对代码有信心任何时候合并进去就要能够部署,避免开发将测试责任推卸。缺点是用户不能很好的利用缓存,用户重新加载新资源却并没有任何新的可用功能。将任务切分很细只会带来更多的工作量,而开发分支上本来就不是直接可交付给用户的。个人来看,除非必要的 bug 修复,完全可以等到 Sprint 结束一起发布。

关于测试,我并不是认为测试写多了,代码质量就会变好。测试只应该是辅助,不应该为测试而改动代码的可读性或使得代码变得复杂。真有一个极端的同事,几乎所有的代码都是依赖注入,一个功能函数的参数是一个接口。比如,fetchUser() 依赖的 request 只是一个接口,你需要一层一层往上查看,才知道这个是如何实现的。
我知道这会让我的代码非常容易测试,但毫无疑问它让代码变得更复杂了。如果说好的架构师懂得如何权衡各种技术做出取舍,好的程序员一样也需要懂得取舍。测试的增加必然会拖累产品迭代的速度,有时我常会想,我现在增加的一个 UI 测试,真的以后这儿会做改动吗?或许那时交互的需求早就变了。我同样好奇这些测试到底帮助我们揪出了多少个潜在的重大 bug,是否值得我们的投入。

关于是否应该面向需求点检查覆盖率,我们也有不同的意见。个人不太认同,因为我们做单元测试很多时候是知道这个模块会被复用,其它人在使用这个模块时,如果需要改动,单元测试可以很好的保证其不被破坏。这个可复用的模块即使已经被整合测试覆盖到,也应该有对应的单元测试。整合测试并不能够帮助我们迅速定位问题,只是确保某一个功能是否完好。

对于测试,总的来说,它带来好处,但是也不是免费的。对可复用的模块,基本的单元测试是必需的,写单元测试也可以帮助你发现代码异味。关键路径的冒烟测试也是有必要的,至少确实会减少人工成本。业务逻辑代码因情况而定,非关键功能且你认为是一次开发即可的,你老板也不会让你投入这么多时间写测试的。如果你没有写过测试,开始尝试用单元测试覆盖你的可复用模块,尝试写些 E2E 测试减少重复劳动吧(E2E 测试远并没有你所想的复杂)。

浅谈编码能力

若说编程能力,涉及的方方面面太多,这儿只谈谈写代码。
你可能也有发现,有些课程优秀的同学代码写的并不优雅,甚至在大公司工作几年的人代码写的也可能不堪入目。或许不难理解,在学校的学习的计算机知识与编码能力没有太大关系。我们说代码写的好,往往说的是整洁,清晰,易于维护扩展。

如果不清楚自己编码的水平,可以尝试一下这个挑战:给你两个小时让你实现一个类似 1024 的游戏。要求不依赖任何库,当然可以使用工具和 IDE。
如果你没有尝试做过类似的事情,不妨现在试一下,回头再读这个文章。

在你做完之后与 Github-2048 上的实现比较一下,看看有哪些收获。

我经历的一些实际项目中,充斥着大量的反模式和代码异味。我们花了很多时间去清理那些技术债务。依据我的经验来看,里面的错误做法非常普遍。
React.js 简单,但是简单并不代表容易。某个框架上手容易,其实也意味着挖坑容易。在真正的将新技术在业务项目中铺开之前,一定要多调研,多参考优秀的实践。

当你用 React.js 堆业务时,思考一下创建的组件是否符合面向对象的基本原则,新手是否能够通过你暴露的属性猜出这个组件的功能。

在你写代码时,哪些原则是你一直遵循的?如果有人指出你的代码中违背了某一原则,你是否能够解释个所以然来。

个人以为提升编程能力的方法有:

  • 推荐阅读《代码整洁之道》《代码大全》《重构》等经典书籍

  • 大量阅读源码

  • Code Review(自己先 Review 一遍)