月度归档:2021年06月

《The Selfish Gene》

(豆瓣) Richard Dawkins –《The Selfish Gene》

第一章

“We, and all other animals, are machines created by our genes.”

“Be warned that if you wish, as I do, to build a society in which individuals cooperate generously and unselfishly towards a common good, you can expect little help from biological nature.”

第二章

本章讲述的是 replicators。Replicators 是早期的基因原型,它们因为各种物理化学反应出现,又经过进化和竞争生存下来。它们最初仅仅是一些生物分子,在竞争过程中进化出了「survival machines」去保护自己。

「Now they swarm in huge colonies, safe inside gigantic lumbering robots, sealed off from the outside world, communicating with it by tortuous indirect routes, manipulating it by remote control.」

人类就是基因的「survival machines」。

第三章

本章讨论了基因的「永生」。本章内容先是介绍了很多关于基因的生物学基础知识,我顺便也回忆了高中所学的比如显隐形、有丝分裂、减数分裂、等位基因等等生物知识。

随后道金斯提出了尽管一条染色体无法一直存在,但其中的基因可以通过不断地复制,随着个体的不停繁衍实现一种类似「永生(immortal)」的状态。

但是我们似乎不能说一个基因「活」过,所以又怎样去定义一个基因的「死亡」呢?姑且把这种说法当作道金斯的一种比喻吧。

第四章

本章从基因层面抽象出来讨论了基因载体的「行为」。从神经细胞到神经系统,基因像是一个程序员,编写了一个庞大的「程序」让宏观的个体去处理和判断外部的信息。基因类似「policymakers」大脑类似「executives」。随着大脑不断进化,大脑的认知和决策能力越来越强,甚至可以取代「policymakers」的角色,做出一些「反基因」的决策,比如决定不去生育后代。

本章内容中关于利己行为和利他行为的讨论让我想到波普尔的「宽容悖论」——没有限制的宽容会导致宽容本身的消亡。虽然从基因层面讲我们是「自私的」,但由于我们具备认知和学习的能力,我们拥有了更加优秀的「policymaker」——大脑。如果说「利己」是一种生物本能,那么「利他」则是我们区别于其他生物的重要特点。

但完全无限制的「利己主义」或者「利他主义」都会如「宽容悖论」那样令其本身消亡。因此掌握合适的利己和利他尺度至关重要,也就要求我们需要不断地去认知和学习。或许这就是「学习」这个能力在生物层面的意义。

第五章

看到本章中道金斯用老鹰和鸽子的例子解释竞争关系,感觉这个模型类似一个马尔可夫过程,由此联想到了在一个公司中的相似情景。

假如一家公司有两种员工,一种是努力员工,一种是摸鱼员工。努力员工第二天努力的概率是80%,摸鱼的概率是20%。摸鱼员工第二天努力的概率是40%,摸鱼的概率是60%。那么过程矩阵就是一个二阶矩阵 [0.8, 0.2; 0.4, 0.6]。矩阵自乘的极限最终稳定在:努力员工和摸鱼员工的比例为2:1。

而这个比例是不受偶尔的一些外部干预影响的。比如,今天下午要放假了,那么摸鱼的人可能更多;今天CEO来视察,那么努力的人会更多。如果第二天的状态变化的概率,也就是80%20%40%60%这些参数不变化的话,最终的比例总是会在2:1。

因此,想要让企业中努力的人增多,需要在这些参数上想办法,考虑员工能从「努力」中收获什么,「摸鱼」中失去什么。而不仅仅是偶尔打鸡血,或者强制要求996。

第六章

本章讨论的是利他行为。基因并不是简单的「a single physical bit of DNA」,而是地球上所有包含该基因的个体总和。因此,基因的目的是让它的容器不停地存留和繁殖,从而增长它的总量。而对个体而言,血缘关系越近,两个个体拥有相同基因的概率就会越高。

当动物出现保护亲人的利他行为,这时候发挥作用的并不是「group selection」而是「gene selection」。保护后代的行为类似于一种投资,冒着一些损失资源或者生命的风险,换取基因更长久、大量存活的回报。而利他行为所冒的风险必须要小于考量亲缘关系后的综合回报。

直系亲属(尤其是母亲)更能确定双方的基因相同性,而旁系亲属则相对更加不确定。因此,比起旁系亲属,父母去保护自己的后代更有理由和价值。

「The gene for individual selfishness has the enormous advantage of certainty of individual identity.」

第七章

本章中的一段话到最近的三胎政策。

「…individual parents practise family planning, but in the sense that they optimize their birth rates rather than restrict them for public good. They try to maximize the number of surviving children that they have, and this means having neither too many babies nor too few.」

比起对族群的贡献,更多的人只能以一种反生物本能的卑微方式让自己和家人能过得能稍微轻松一些。生育本是一件很「自然」的事情,却越来越被道德和法律所「规范」,无奈的是这种情况也许会愈演愈烈。

第八章

本章讲述的是「代际之争(battle of the generations)」。一个母亲是否对某个后代有所偏爱呢?从基因层面上讲,一个母亲是没有偏爱的理由。最好的方式是平等投资地投资最大数量后代。而一个母体的「绝经」则是保证其对孙辈投资的一种进化行为。

而子女则可能通过「欺骗」或者「暴力」的竞争方式为自己争取更多的生存资源。比如,一些鸟类幼体会杀掉同辈幼体让自己更有机会存活下去。

作为人类,这种自私性也会带来一些「道德层面」的负面行为。因此,父母必须教导子女帮助他人的利他行为,因为道金斯认为「帮助他人」这并不属于动物的天性。

第九章

本章讲述的是「性别之争」。道金斯从进化的角度上分析了为什么母亲更倾向「一夫一妻」,而父亲更希望「一夫多妻」。母亲因为生育的原因需要更有责任心的父亲,而父亲则希望通过交配繁殖更多的后代。这种差别在进化角度上的根本原因是,卵子比精子的体积更大。

第十章

本章讲述的是「互利和共生」。欺骗(cheat)行为对于个体生存是有利的。而我们如今很多的心理情绪特点,比如嫉妒、内疚、感恩等等都是在自然选择中进化而来,目的是为了更好地去欺骗、识别欺骗的行为、并且不被当做一个骗子。

第十一章

本章是关于「梗(Memes)」的传播。这章内容将基因的概念抽象出来类比于文化传播,梗类比于基因,可以通过在人们头脑中的传播实现进化。

梗是文化传播的单位,也存在着各种竞争关系。当「梗」的规模和结构足够庞大,它也可以达到一种 ESS(Evolutionarily stable set)的状态,比如宗教信仰,而与稳定「梗」相关的衍生「梗」也往往可以存活下去。

第十二章

本章讨论了「好人是否会有好报」的问题。其中讨论了「囚徒困境」,并且指出人们往往会在这种博弈中很难保持合作。个体的最佳策略并非群体的最佳策略,生活中各个方面都会出现类似囚徒困境的场景。对此道金斯提到一种「Tit for Tat」的策略,这种策略是任何一方最开始选择去合作,并且接下来重复对手上一轮的选择,是一种不嫉妒的、宽容的、友善的策略。

文中指出这种「non-envious, forgiving niceness」的行为是在实际中是存在的,比如战争中默认的「互不侵犯条约」,但是需要双方处于「非零和」游戏中。尽管基因是「自私的」,但善为仍是存在的,也是有善报的。

第十三章

本章道金斯解释了他另一部作品《The Extended Phenotype》的主题——「extended phenotype(延伸的表现型)」。

所谓「extended phenotype」就是「the bodily manifestation of a gene, the effect that a gene, in comparison with its alleles, has on the body, via development.」基因对身体产生的影响而呈现出的表现形态。自然筛选基因是因为基因的表现,而基因的表现不仅仅局限于个体生物(比如长手长脚利于攀爬),也会影响外部的环境和其他生物。能够繁衍的基因会被大自然「青睐」,而能够建立一种利于繁衍环境的基因也会获得长存。

回顾全书,「replicator」这个概念贯穿始终。Replicators 不仅仅因为自己的特点和优势得以生存,也因为对于周围和环境的有利影响而被自然所选择。大有一种不仅「独善其身」,也要「兼济天下」的特点。在道金斯看来,生物学家总是习惯性关注个体,但我们需要记住的是「replicators come first」 。

《边城》

(豆瓣)沈从文–《边城》

从前只看到了一段暧昧又伤感的爱情。做了爸爸之后更能体会爷爷那种压抑的责任感。

沈从文先生说这本书是写给「本身已经离开了学校,或始终就无从接近学校,还识些中国文字,置身于文学理论、文学批评以及说谎造谣消息所达不到的那种职务上,在那个社会里生活,而且极关心全个民族在空间与时间下所有的好处与坏处」的人们。

我觉得不然。需要读这本作品的正是像我这种喜欢「高谈阔论,眼高于顶」的人。

内卷、科技、躺平

内卷化(Involution)是一个社会学概念,用来形容社会文化因为重复劳作、发展迟缓。近些年在中文网络中大家变化其含义,用来指代内部竞争的恶性循环。「内卷」爆火的原因无疑是引发了大家,尤其是年轻人,的情感认同和共识。当代青年人和中年人承受着包括工作、买房、结婚、赡养老人、养育子女的重大压力。这些压力不仅仅源于金钱,在心理上甚至是生理上也对人们产生着巨大的影响。

密歇根大学的心理学专家 Angus Campbell 认为,幸福来自对自己生活控制的自由。

Having a strong sense of controlling one’s life is a more dependable predator of positive feeling of wellbeing than any of the objective conditions of live we have considered.

而「内卷」却让越来越多的人失去了对自己时间的自由支配。我们为了孩子能上好的学校需要学区房,为了学区房呃孩子的教育要赚更多的钱,为了高薪需要一份好工作,为了一份好工作需要上一所好大学,为了上好大学需要上重点中学,为了上重点中学需要大量的课外补习,周而复始。在这种逻辑下,很多孩子一出生便进入了这个闭环。然而「教育的本质是培养人,激发人的独立的思维和自由的思想,而不是筛选人。」

内卷的实质是,有竞争,无发展。人们疲于竞争却又看不到尽头,因而产生了倦怠感和无力感,「打工人」、「社畜」这些自嘲的称谓也因此而生。

然而内卷的并不仅仅是「打工人」们,高速发展的时代「科技」也同样避免不了内卷。科学技术的进步大大方便了人们的生活,「AI」、「新能源」、「区块链」、「5G」、「星链」等等能概念让科技正在以空前强大的力量影响着社会和经济。但充满科技感的未来真会让人们的生活更「幸福」吗?

正如所有的「内卷化」一样,科技也只能更加充满竞争、拒绝退步。假如今年的 iPhone 只有挤牙膏式的一些更新,那么无疑会招致用户的大量批评。我们需要承认,「科技不进步」已然成为了一件政治不正确的事情。因此许多科技产品必须越来越「高级」,越来越「好用」,挤牙膏式的进步已经无法满足如今用户挑剔的胃口。结果是,越来越多的需求被「创造」了出来,用户被科技「喂养」得更加挑剔。很多的需求并不是一直存在的,而是被科技公司「创造」出来的。而当我们逐渐习惯了那些被创造出来的需求的时候,我们便再也无法适应离开它们的生活。

于是各个公司需要在这个竞争激烈的市场生存下去,必须变得更大、更强,需要 996,需要24小时 on call。这不是能或者不能的问题,而是关乎一家公司「生死」的问题。

这时,「躺平」出现了。

疲于应付社会期望的年轻人选择了用无欲无求的「躺平」对抗内卷。在百度贴吧一篇《躺平即是正义》的帖子中,名为「好心的旅行家」写道:

两年多没有工作了,都在玩,没觉得哪里不对,压力主要来自身边人互相对比后寻找的定位和长辈的传统观念,它们会无时无刻在你身边出现,你每次看见的新闻热搜也都是明星恋爱、怀孕之类的「生育周边」,就像某些「看不见的生物」在制造一种思维强压给你,人大可不必如此。我可以像第欧根尼只睡在自己的木桶里晒太阳,也可以像赫拉克利特住在山洞里思考「逻各斯」,既然这片土地从没真实存在高举人主体性的思潮,那我可以自己制造给自己,躺平就是我的智者运动,只有躺平,人才是万物的尺度。

普罗泰戈拉说「人是万物的尺度,是存在的事物存在的尺度,也是不存在的事物不存在的尺度」。苏轼的文章中也写道「自其变者而观之,则天地曾不能以一瞬;自其不变者而观之,则物与我皆无尽也」。二者的思想相近,都强调了「人」的重要性,也就是世界的样貌由我们看待世界的方式决定。躺平的一代选择用一种无作为的坚定消极态度对抗内卷,像是中国式「垮掉的一代」。

但如果人人躺平,「拒绝消费,拒绝奋斗,拒绝被割韭菜」,显然不是国家希望的,也不是现实情况所允许的。因此躺平的有关讨论也受到了一定程度的限制,豆瓣的多个「躺平小组」也被陆续删除。但大家对于躺平的共识并没有很大减弱,躺平者用一种「低调」的方式让他们的声音被越来越多的人听见。

因此,转变出现了。

阿里巴巴宣布取消「周报」,腾讯光子游戏工作室尝试「强制不加班」,字节跳动取消「大小周」,政府开始严格规范课外补习机构,减少学生压力。不论成效,我们确实看到了「反内卷」的行动。

但是对于这些做法,并不都是赞同的声音。比如,字节跳动有三分之一的员工反对取消「大小周」,因为这样会导致他们的收入降低。比如,一个员工的年薪50万,取消大小周会减少近10万元的收入。所以,并不只有「躺平的一代」,还有需要钱的「咬牙的一代」,和以努力为乐趣的「内卷的一代」。

能躺平的人是幸福的,因为他们找到了一种暂时卸下身上负担的方式。但是也有很多的人,即使很辛苦、很委屈,也在咬牙坚持下去,只是为了能够多赚一些工资。我在一篇文章中写过「为了高薪而工作」也是一种合理的选择,并不世俗。有人选择「浪漫」,另一些选择了「现实」。二者没有贵贱,只是人们在不同价值观影响下的不同选择罢了。

真正痛苦的是那些内心「浪漫」的高薪打工者,和崇拜金钱「现实」的低薪甚至无业者。能力和欲望总是以一种玩笑般的手法操纵着人们的心理。

所以,无论是「内卷」或是「躺平」,对自己的认知至关重要。我们需要清楚知道自己想要什么,又能做些什么,才能决定自己做什么。每天摸鱼,打游戏,看视频并不是「躺平的胜利」。无休止的加班,放弃对家人的陪伴,也不是被迫内卷的「高薪借口」。

「Everything that rises must converge」,认清我们的内心,想要躺平就稍作休息,想要努力就加把劲,相信世界会在某个时间给我们答案。

《Elon Musk》

Elon Musk

作者:Ashlee Vance

第一章内容作者以Musk的前妻Justine对他的评价结尾:「He does what he wants, and he is relentless about it. It’s Elon’s world, and the rest of us live in it.」

Well defined.

— —

能将自己的兴趣变成职业,继而变成企业和产业无疑是幸福的,也是是幸运的。

用一些关键词总结马斯克早期经历:孤僻,大量阅读,强大的记忆力,自制力,浪漫的理想主义,目标清晰,专注和投入。

— —

早期创业让马斯克有了第一桶金,却有很多人质疑他的性格和能力无法胜任CEO的角色。现在以上帝视角回看,马斯克不总是会被看好却总是能把看似疯狂的想法逐一实现。

可以说马斯克的运气很好,否则我也无法读到属于他自己的个人传记。但不可否认的是,他的身上确实有着惊人的能量。时间在他的身上的速度和节奏总是快上许多,我很难想象一个人能够自发地一天工作23个小时。所以即使没有特斯拉,马斯克一定也会在某个领域大放异彩。

有趣的是马斯克在第一次给自己放假放松的时候险些染病掉。「That’s my lesson for taking a vacation: vacation will kill you.」看来工作狂人不需要假期。

— —

从SpaceX到Tesla Motors,创业的过程总是充满了不断的挑战。然而马斯克看起来更是一个「务虚」的人,比如比起投资能增加研发效率的设施,他更喜欢买看起来华丽的装饰物。也许正是这种「疯狂」使Tesla成为了区别于其他「中庸」公司的存在。

有一些人因为Tesla的成功成为了马斯克的极端支持者。见识到这种「疯狂」「逾矩」后成功的魅力时,我们也要警惕类似的例子全世界鲜有一二。

更普世的所谓「成功」的经验也许是结合我国自古推崇的「谦虚」「务实」再加一些的创业者们的「狂野」。

Naval Ravikant说过如果我们可以掌握build和sell这两样技能,那么我们便会势不可挡。传统文化更多鼓励我们学会build,所以对我们这些更「务实」的人来说,学会如何销售产品、销售自己的能力会是重要的tipping point。

— —

书中提到马斯克禁止在公司使用专有词缩写,避免造成理解上的障碍,尤其是新职员的理解,继而提好沟通和工作效率。

马斯克的时间效率惊人的高,他能够高速运转自己的头脑,在不同的线程间切换,并且有着深入的理解。因此,马斯克也总是按照自己「变态」的标准去要求自己的员工。员工们虽然对这种高压工作苦不堪言,却没有减少丝毫对马斯克的尊敬和崇拜。

值得学习的是在2008年马斯克人生最低谷的那段时间,丑闻、婚变、发射失败、交付期拖延,各种不利消息足以让任何人崩溃。但马斯克并没有因为高压做出仓促愚蠢的决定,他的决策始终是「hyperrational」。

始终保持目标清晰、头脑清醒、从不言败或许就是马斯克挺过困难时期走向「liftoff」之路的关键。

— —

内容已经接近尾声,马斯克可他的事业也进入了腾飞阶段。太空技术、新能源技术都是与大多创业公司相比完全不同的颠覆性技术。这部分内容引发了我对技术的一些思考。

科技或者说技术的进步大大方便了人们的生活,但是真的让人们的生活变得更「好」了吗?在万物内卷的时代,科技也只能越来越进步。假如iPhone只有平淡无奇的一些更新,那么无疑会招致大量用户的批评。这就导致许多科技产品必须越来越「高级」,越来越「好用」,挤牙膏式的进步已经无法满足如今用户挑剔的胃口。因此,越来越多的需求被「创造」了出来。比如,面部识别、自动驾驶、AI。

是的,很多的需求并不是一直存在的,而是被科技公司「创造」出来的。而当我们逐渐习惯了那些被创造出来的需求的时候,我们便再也无法适应曾经没有它们的生活。

我曾想象,如果未来世界都是无人驾驶的电车,漫天的飞船,甚至存在价格不高昂的星际旅行,那真的很酷。但我们会更幸福吗?科技的进步究竟有什么边界?科技的进步会让我们付出什么代价呢?

我不知道答案。正如我隐约知道自己不应该做什么,却又因为各种原因不得不去做。「Everything that rises must converge」,或许世界会在某个时间给我们答案。

— —

Google的CEO Larry Page对马斯克是这样评价的。

"I’ve learned that your intuition about things you don’t know that much about isn’t very good, ”Page said. “The way Elon talks about this is that you always need to start with the first principles of a problem: What are the physics of it? How much time will it take? How much will it cost? How much cheaper can I make it? There’s this level of engineering and physics that you need to make judgments about what’s possible and interesting. Elon is unusual in that he knows that. and he also knows business and organization and leadership and governmental issues."

There’s something we should learn from.

Tobi Lutke 的思维模型

George Mack 在 twitter 上发表了 Shopify 的 CEO Tobi Lutke 的6个思维模型

1 遵循「Crocker」定律

Crocker是Wikipedia的编辑,并且鼓励人们不要为编辑他的页面而道歉。如果他被冒犯的话,那么错的是自己而不是他人。

Tobi 十分重视反馈「feedback」的重要性,并且希望能够获得真实、清晰的反馈。

「如果我被侮辱了,那是因为我的大脑做了一个决定,把被那个人侮辱的想法植入我的记忆和思想中……。
我是在自己的意志下做这样的决定的。这是我自己的选择。我的大脑已经把这个权力交给了对方」

「If I’m insulted it’s because my brain made a decision, to implant in my memory and thoughts the idea of being insulted by that person…
I did that under my own volition. It was my own choice. My brain has assigned the power to the other person.」

2 永远跟随「第一原则」

Tobi 的思维模型

「Global Maximum > Local Maximum

Local Maximum = Optimising a cog in the machine

Global Maximum = Optimising the machine itself」

第一原则:「A first principle is a foundational proposition or assumption that stands alone. We cannot deduce first principles from any other proposition or assumption.」

一个「第一原则」的例子

在港口运输货物的时候,比起一件一件卸货、装货,直接把所有的东西一次性搬到船上效率会高很多。

这就是「SHIPPING CONTAINER」航运集装箱的由来。他的发明者就是一个港口的卡车司机——Malcolm McLean,一位上世纪最被低估的企业家和现代全球贸易的「教父」。

因此 Tobi 总是认为自己现在的所作所为都可能是错误的。

「I think the best company (that exists right now) is a 6/10 on the scale to what is a perfect company」

他认为现在世界上最好的公司只能算是6分,而自己想要建立一家接近6分、目标7分的公司。

我们总是认为当下的事情是合理的、正确的,却不曾想过50年后的人们会如同我们现在嘲笑50年前的人们一样嘲笑现在的我们。

3 从长远角度考虑问题

牺牲短期利益换取长远收益。Tobi 认为每一个决定都应该回答这个问题「你在做的优化是为每一笔单独的交易还是为了LIFETIME交易?」

你在和用户进行有限的游戏还是无限的游戏?

Shopify 并没有向投资人希望的那样,在他们平台店铺的产品上强制印上「Powered By Shopify」,尽管这样做会形成品牌效应的正反馈。

Tobi对此的看法是,他们想要让店铺的产品看起来更好。而这就是Tobi提出的「LTV Thinking」,在足够长的时间轴上,和你的用户玩「正和游戏」而不是「零和游戏」。

4 拥抱迁移学习

Tobi 认为电子游戏是一种很好的学习途径。

在实际的商业世界你可能每年只有一次机会进行豪赌。但在游戏中我们的大脑可以对类似情景进行千百次的训练。

「Factorio」是Tobi最喜欢的游戏。

5 决策

每一次做了错误决定的时候,Tobi都意识到他遗漏的那部分信息完全是自己本可以获得的。

Tobi 重视事后决策的难度,并把决策当做一种工作认真对待。

每次 Tobi 做出决策的时候他都会记录下来,并且附上为什么会做出这个决定的相关信息。

国际象棋大师 Kasparov 习惯用「系统思维」去分析自己下棋时候的错误。比如,走了一步A棋导致输掉比赛。

「结果思维」:以后不再走A这步棋。

「系统思维」:在做这个决定之前,我的思维路线是怎样的?不要再犯类似的错误了。

「结果思维」防止我们再一次犯某个错误,「系统思维」防止我们用类似的思考方式犯更多类似的错误。

6 好奇心驱动的人才堆栈 > MBA

Tobi 没有读过MBA,每天也不会疯狂工作。相反,他喜欢玩游戏(进而写代码),玩滑雪(进而建立了一个在线雪板商店)。

Tobi 认为遵从自己的真正的好奇心是职业生涯更好的基础,而不是盲从现在能够赚钱的事情。这个过程也许比较漫长,无法迅速成功,但可以带来长远来看更好的回报。

《审判》

豆瓣链接

卡夫卡说过:「好书是一把冰斧,破开我们內心冰冻的海洋」,《审判》无疑是这样一本「好书」。它与我们的世界如此的不同以至于打破了我们对于个体和社会的固有认知。

人们使用「Kafkaesque 」这个词来形容卡夫卡式的超现实和怪诞的风格。Frederick Karl 这样形容它:「当你进入一个超现实的世界,你所有的控制模式、计划、你的行为方式,都在你发现自己抵抗着一个与固有认知完全不同的世界而开始变得支离破碎。但你不曾放弃,没有束手就擒,而是用能用到的一切奋力反抗。但毫无疑问,你没有一点机会。这就是 Kafkaesque。」

约瑟夫·K 就是 Kafkaesque。

代码重构

最近由于项目需要准备多现有项目进行二次重构,整理了一些关于重构的知识。

主要参考的是 Martin Fowler 的《重构:改善既有代码设计》和极客时间的王争在《设计模式之美》中关于重构的介绍。

一、重构的原则

什么是重构

  • 重构(名词):对软件内部结构的一种调整,目的是在不改变「软件之可察行为」前提下,提高其可理解性,降低修改成本。
  • 重构(动词):使用一系列重构准则/手法,在不改变「软件之可受观察行为」前提下,调整其结构。

重构是这样一个过程:它在一个目前可运行的程序上进行,企图在「不改变程序行为」的情况下(1)容易理解;(2)所有逻辑都只在唯一地点指定;(3)新的改动不会危及现有行为;(4)尽可能简单表达条件逻辑(conditional logic),使我们能够继续保持高速开发,从而增加程序的价值。

为什么重构

  • 改进软件设计
  • 使软件更易被理解
  • 助你找到bugs
  • 提高编程速度

何时重构

  • 三次法则〔The Rule of Three〕
    • Don Roberts 给了一条准则:
      • 第一次做某件事时只管去做;
      • 第二次做类似的事会产生反感,但无论如何还是做了;
      • 第三次再做类似的事,你就应该重构。
    • Tip: 事不过三,三则重构(Three strikes and you refactor)
  • 添加功能时一并重构
    • 帮助理解
    • 代码的设计无法帮助我轻松添加我所需要的特性
    • 新特性的添加就会更快速、更流畅。
  • 修补错误吋一并重构
  • 复审代码吋一并重构
  • 为什么重构有用
    • 原因
      • 难以阅读的程序,难以修改。
      • 逻辑复杂(duplicated logic)的程序,难以修改。
      • 添加新行为时需要修改既有代码者,难以修改。
      • 带复杂条件逻辑(complex conditional logic)的程序,难以修改。
    • 方法
      • 容易理解
      • 所有逻辑都只在唯一地点指定
      • 新的改动不会危及现有行为
      • 尽可能简单表达条件逻辑

如何发现代码质量问题

常规checklist

  • 目录设置是否合理、模块划分是否清晰、代码结构是否满足“高内聚、松耦合”?
  • 是否遵循经典的设计原则和设计思想(SOLID、DRY、KISS、YAGNI、LOD等)?
  • 设计模式是否使用得当?是否有过度设计?
  • 代码是否容易扩展?如果要添加新功能,是否容易实现?
  • 代码是否可以复用?是否可以复用已有的项目代码或者类库?是否有重复造轮子?
  • 代码是否容易测试?单元测试是否全面覆盖各种正常和异常的情况?
  • 代码是否易读?是否符合编码规范(比如命名和注释是否使用得当、代码风格是否一致)?

业务需求checklist

  • 代码是否实现了预期的业务需求?
  • 逻辑是否正确?是否处理了各种异常情况?
  • 日志打印是否得当?是否方便debug排查问题?
  • 接口是否易用?是否支持幂等事务等
  • 代码是否存在并发问题?是否线程安全?
  • 性能是否有优化空间,比如,SQL、算法是否可以优化?
  • 是否有安全漏洞?比如,输入输出校验是否全面?

幂等:就是用户对于同一操作发起的一次请求或者多次请求的结果是一致的,不会因为多次点击而产生了副作用。

知会经理

不要告诉经理!

重构的难题

  • 数据库(Database)
  • 修改接口(Changing Interfaces)
  • 难以通过重构手法完成的设计改动
  • 何吋不该重构?——有时候既有代码实在太混乱,重构它还不如重新写一个来得简单

重构与设计

  • 「事先设计」(upfront design)可 以助我节省回头工的高昂成本。
  • 哪怕你完全了解系统,也请实际量测它的性能,不要臆测。臆测会让你学到一些东西,但十有八九你是错的。

重构与性能(Performance)

  • 三种「编写快速软件」的方法
    • 「时间预算法」(time budgeting)——性能要求极高的实时系统
    • 「持续关切法」( constant attention)——设法保持系统的高性能
    • 「良好的分解方式」(well-factored manner)
      • 不对性能投以任何关切,直至进入性能优化阶段——那通常是在开发后期
      • 有比较充裕的时间进行性能调整(performance tuning)
      • 在进行性能分析时便有较细的粒度(granularity)

重构这个概念起源何处?

Ward Cunningham 和 Kent Beck 的 Smalltalk

二、单元测试

什么是单元测试?

单元测试是代码层面的测试,由研发自己来编写,用于测试“自己”编写的代码的逻辑的正 确性。单元测试顾名思义是测试一个“单元”,有别于集成测试,这个“单元”一般是类或 函数,而不是模块或者系统。

为什么要写单元测试?

写单元测试的过程本身就是代码 Code Review 和重构的过程,能有效地发现代码中的 bug 和代码设计上的问题。除此之外,单元测试还是对集成测试的有力补充,还能帮助我们快速 熟悉代码,是 TDD 可落地执行的改进方案。

如何编写单元测试?

写单元测试就是针对代码设计各种测试用例,以覆盖各种输入、异常、边界情况,并将其翻 译成代码。我们可以利用一些测试框架来简化单元测试的编写。除此之外,对于单元测试, 我们需要建立以下正确的认知:

单元测试为何难落地执行?

一方面,写单元测试本身比较繁琐,技术挑战不大,很多程序员不愿意去写;另一方面,国 内研发比较偏向“快、糙、猛”,容易因为开发进度紧,导致单元测试的执行虎头蛇尾。最 后,关键问题还是团队没有建立对单元测试正确的认识,觉得可有可无,单靠督促很难执行 得很好。 编写单元测试尽管繁琐,但并不是太耗时; 我们可以稍微放低对单元测试代码质量的要求; 覆盖率作为衡量单元测试质量的唯一标准是不合理的; 单元测试不要依赖被测代码的具体实现逻辑; 单元测试框架无法测试,多半是因为代码的可测试性不好。

三、可测试性

什么是代码的可测试性?

粗略地讲,所谓代码的可测试性,就是针对代码编写单元测试的难易程度。对于一段代码, 如果很难为其编写单元测试,或者单元测试写起来很费劲,需要依靠单元测试框架中很高级 的特性,那往往就意味着代码设计得不够合理,代码的可测试性不好。

编写可测试性代码的最有效手段

依赖注入是编写可测试性代码的最有效手段。通过依赖注入,我们在编写单元测试的时候, 可以通过 mock 的方法解依赖外部服务,这也是我们在编写单元测试的过程中最有技术挑 战的地方。

常见的 Anti-Patterns

常见的测试不友好的代码有下面这 5 种:

  • 代码中包含未决行为逻辑
  • 滥用可变全局变量
  • 滥用静态方法
  • 使用复杂的继承关系
  • 高度耦合的代码

四、大型重构——解耦

“解耦”为何如此重要?

过于复杂的代码往往在可读性、可维护性上都不友好。解耦保证代码松耦合、高内聚,是控 制代码复杂度的有效手段。代码高内聚、松耦合,也就是意味着,代码结构清晰、分层模块 化合理、依赖关系简单、模块或类之间的耦合小,那代码整体的质量就不会差。

代码是否需要“解耦”?

间接的衡量标准有很多,比如,看修改代码是否牵一发而动全身。直接的衡量标准是把模块 与模块、类与类之间的依赖关系画出来,根据依赖关系图的复杂性来判断是否需要解耦重 构。

如何给代码“解耦”?

给代码解耦的方法有:封装与抽象、中间层、模块化,以及一些其他的设计思想与原则,比 如:单一职责原则、基于接口而非实现编程、依赖注入、多用组合少用继承、迪米特法则 等。当然,还有一些设计模式,比如观察者模式。

五、重构的建议

  • 关于命名 

    命名的关键是能准确达意。对于不同作用域的命名,我们可以适当地选择不同的长度。
    作用域小的变量(比如临时变量),可以适当地选择短一些的命名方式。
    除此之外,命名中也可以使用一些耳熟能详的缩写。
    我们可以借助类的信息来简化属性、函数的命名,利用函数的信息来简化函数参数的命 名。 命名要可读、可搜索。不要使用生僻的、不好读的英文单词来命名。
    除此之外,命名要符合项目的统一规范,不要用些反直觉的命名。
    接口有两种命名方式:一种是在接口中带前缀“I”;另一种是在接口的实现类中带后缀“Impl”。
    对于抽象类的命名,也有两种方式,一种是带上前缀“Abstract”,一种是不带前缀。这两种命名方式都可以,关键是要在项目中统一。

  • 关于注释

    注释的目的就是让代码更容易看懂。只要符合这个要求的内容,你就可以将它写到注释里。
    总结一下,注释的内容主要包含这样三个方面:做什么、为什么、怎么做。对于一些复杂的类和接口,我们可能还需要写明“如何用”。
    注释本身有一定的维护成本,所以并非越多越好。
    类和函数一定要写注释,而且要写得尽可能全面、详细,而函数内部的注释要相对少一些,一般都是靠好的命名、提炼函数、解释性变量、总结性注释来提高代码可读性。

  • 函数、类多大才合适?

    函数的代码行数不要超过一屏幕的大小,比如 50 行。
    类的大小限制比较难确定。

  • 一行代码多长最合适?

    最好不要超过 IDE 显示的宽度。当然,限制也不能太小,太小会导致很多稍微长点的语句被折成两行,也会影响到代码的整洁,不利于阅读。

  • 善用空行分割单元块

    对于比较长的函数,为了让逻辑更加清晰,可以使用空行来分割各个代码块。
    在类内部,成员变量与函数之间、静态成员变量与普通成员变量之间、函数之间,甚至成员变量之间,都可以通过添加空行的方式,让不同模块的代码之间的界限更加明确。

  • 四格缩进还是两格缩进?

    王争比较推荐使用两格缩进,这样可以节省空间,特别是在代码嵌套层次比较深的情况下。
    除此之外,值得强调的是,不管是用两格缩进还是四格缩进,一定不要用 tab 键缩进。

  • 大括号是否要另起一行?

    比较推荐将大括号放到跟上一条语句同一行的风格,这样可以节省代码行数。
    但是,将大括号另起一行,也有它的优势,那就是,左右括号可以垂直对齐,哪些代码属于哪一个代码块,更加一目了然。

  • 类中成员的排列顺序

    在 Google Java 编程规范中,依赖类按照字母序从小到大排列。类中先写成员变量后写函数。
    成员变量之间或函数之间,先写静态成员变量或函数,后写普通变量或函数,并且按照作用域大小依次排列。
    代码风格都没有对错和优劣之分,只要能在团队、项目中统一即可,不过,最好能跟业内推荐的风格、开源项目的代码风格相一致。

  • 关于编码技巧

    将复杂的逻辑提炼拆分成函数和类。
    通过拆分成多个函数或将参数封装为对象的方式,来处理参数过多的情况。
    函数中不要使用参数来做代码执行逻辑的控制。
    函数设计要职责单一。

  • 统一编码规范

    项目、团队,甚至公司,一定要制定统一的编码规范,并且通过 Code Review 督促执行,这对提高代码质量有立竿见影的效果。
    移除过深的嵌套层次,方法包括:去掉多余的 if 或 else 语句,使用 continue、break、return 关键字提前退出嵌套,调整执行顺序来减少嵌套,将部分嵌套逻辑抽象成函数。
    用字面常量取代魔法数。

  • 建立一组可靠的测试环境。

    这些测试必须有自我检验(self-checking)能力。

  • 分解并重组长函数

    以微小的步伐修改程序。如果你犯下错误,很容易便可发现它。
    修改变量名
    搬移函数位置
    去除临时变量 Replace Temp with Query

  • 运用多态(Polymorphism)取代相关的条件逻辑

六、错误码

对于函数出错返回数据类型,王争总结了 4 种情况,它们分别是:错误码、NULL 值、空对 象、异常对象。

  1. 返回错误码
    C 语言没有异常这样的语法机制,返回错误码便是最常用的出错处理方式。而 Java、 Python 等比较新的编程语言中,大部分情况下,我们都用异常来处理函数出错的情况,极 少会用到错误码。
  2. 返回 NULL 值
    在多数编程语言中,我们用 NULL 来表示“不存在”这种语义。对于查找函数来说,数据 不存在并非一种异常情况,是一种正常行为,所以返回表示不存在语义的 NULL 值比返回 异常更加合理。
  3. 返回空对象
    返回 NULL 值有各种弊端,对此有一个比较经典的应对策略,那就是应用空对象设计模 式。当函数返回的数据是字符串类型或者集合类型的时候,我们可以用空字符串或空集合替 代 NULL 值,来表示不存在的情况。这样,我们在使用函数的时候,就可以不用做 NULL 值判断。
  4. 抛出异常对象
    尽管前面讲了很多函数出错的返回数据类型,但是,最常用的函数出错处理方式是抛出异 常。异常有两种类型:受检异常和非受检异常。 对于应该用受检异常还是非受检异常,网上的争论有很多,但也并没有一个非常强有力的理 由,说明一个就一定比另一个更好。
    所以,我们只需要根据团队的开发习惯,在同一个项目 中,制定统一的异常处理规范即可。 对于函数抛出的异常,我们有三种处理方法:直接吞掉、直接往上抛出、包裹成新的异常抛出。

《The 4-Hour Workweek》

本书的作者Tim Ferriss 被列为 Fast Company 的 「最具创新精神的商业人物 」之一,同时也是《财富》的「40 under 40」人物之一。他是早期投资者和顾问(Uber、Facebook、Shopify、Duolingo、阿里巴巴和其他50多个公司),是《纽约时报》和《华尔街日报》五本畅销书的作者,包括《The 4-Hour Workweek》和《Tools of Titans》。

Tim 能说六门外语:中文、韩文、日文、德语、西班牙语、意大利语。入学期间开始创业。曾留学并漫游中国,并且在中国获得过散打比赛的冠军。推崇旅居世界各地的数字游民生活。

这本书是 Tim Ferriss 最为著名的一本畅销书,在本书中作者提出了 New Rich 这个概念——一个新时代下的富有而自由的群体,具有「more time and more mobility」。这本书并不是要让人们工作偷懒,而是强调通过提高效率,增加被动收入,外包等方式解放自己的时间,拥有更自由的生活。

人们并不是想成为百万富翁,而是想要获得财富自由之后能够拥有的东西。所以 Tim 提出了这种使没有财富自由的人获得财富自由的人的生活方式的理论。

本书主要从4个方面阐述了 Tim Ferris 的观点:

  • D代表 「Definition 定义」:颠覆人们被误导的常识,引入新的规则和目标。
  • E代表 「Elimination 消除」:这一步主张消除时间管理的概念。
  • A代表「Automation 自动」:着眼于将你的现金流置于自动收益的状态。
  • L代表 「Liberation 自由」:「自由」不一定是要四处旅居,而是指摆脱使你被束缚在一个地方的限制。

一些我赞同的观点:

「Be effective, not efficient.」

Tim 所倡导的生活围绕着 80/20 法则或者帕累托法则(Pareto principle)而建立。大多数人用工作中花费的时间来衡量生产力高低,但这并不是一个好的指标,因为我们花费的很多时间都是「无效时间」。

因此,Tim 建议有效地花费时间:在20%的事情上获得80%的结果,而不是相反。

「Doing something unimportant well does not make it important.」把不重要的事情做好并不会使它变得重要。不要去做很多「不重要的事」,而要专注于能给我们带来极大进步的事情上。这一点工作和生活中都重要。前提是我们要分清哪些是重要的,哪些不是。

「Always validate your business ideas.」

在建立任何产品或服务之前,要确保人们愿意为此花费时间或者金钱。

「What we fear doing most is usually what we most need to do.」在开始行动之前,去向更多的人咨询,比如你想要卖一款键盘,那么多问一些人是否愿意花钱购买。很多想法一旦开始就很难轻易停下来,而想着一个错误的方向开始则会带来很大的损失(时间上和金钱上)。

这个观点不仅仅适用于「bussiness idea」,还有比如创作、工作、一段亲密关系等很多方面。对事情有仔细而全面的研究和准备会减少我们失败的风险。

「Charge a premium to need less clients and make your life easier.」

销售产品是选择长尾效应中的高质量少数量的产品还是数量很大的普通产品?Tim 的建议是高质量的产品。扩大客户规模是一件很费时费力的过程,售后问题也会接踵而来。

Kevin Kelly 提出的「1000 true fans」理论也是相似的道理。一个创作者只需要1000个「铁粉」就可以满足自己的生活所需,全身心投入创作,不需要为生计发愁。

找到自己的1000个忠实的支持者吧。

不赞同的观点:

「But you are the average of the five people you associate with most, so do not underestimate the effects of your pessimistic, unambitious, or disorganized friends. If someone isn’t making you stronger, they’re making you weaker.」

对我而言,这种向上社交的方式带来的成长远低于它所带来的焦虑。我会不停地评价判断周围的人,随着我不断地「stronger」,以前的朋友和关系就需要被狠心断开?我是做不到这样的。

随之而来的还有缺少自我认同。如果周围的人都比你强,你是否会觉得自己始终稍逊一筹。又或者大家都抱有这种去和比自己「强」的人去结交,那么其中最「不强」的人应该如何自处?

这让我想起 Karl Popper 的「The Paradox of Tolerance」。大意是如果每个人都对每一种想法持宽容态度,那么就会出现不宽容的想法。宽容的人将容忍这种不宽容,而不宽容的人也不会容忍宽容的人。最终,不宽容的人将接管并创造一个不宽容的社会。因此,波普尔说,为了维持一个宽容的社会,宽容的人必须对不宽容的人不宽容……因此出现了悖论。

没有尺度的宽容最终会导致宽容的灭绝。因此,宽容需要限制和规范,我们对人际关系也是类似。不加限制地去变「强」会削弱「弱」这个概念,当我们的世界只剩下「强」的时候,「强」也就不复存在了。

「Life is too short to be small.」

「small」是一个很微妙的词,多小算是小呢?多微不足道才算做是微不足道呢?

这里 Tim 预设了一个价值世界,那就是缺乏生产力的生活是「small」,朝九晚五固定在一个地方打工的生活是「small」,默默无闻的生活是「small」,缺乏挑战、一成不变的生活是「small」。

结合最近的「躺平主义」,很多人都已经厌倦了996,厌倦了不停努力和进步,厌倦了没有灵魂的工作,只希望能够躺平休息,用一种无奈的方式对抗这个内卷的社会。

在《躺平即是正义》中作者「好心的旅行家」说道,

「我可以像第欧根尼只睡在自己的木桶里晒太阳,也可以像赫拉克利特住在山洞里思考‘逻各斯’,既然这片土地从没真实存在高举人主体性的思潮,那我可以自己制造给自己,躺平就是我的智者运动,只有躺平,人才是万物的尺度。」

同样是拒绝无聊繁重的工作,「躺平」却更能引发人们的共鸣。大部分人并不希望成就一番伟业,做出惊天动地的壮举,而是仅仅希望有一个温馨舒适的房子,爱自己的伴侣,远离进步焦虑的平淡生活。

所以,这种生活算是「small」吗?Tim Ferriss 明显放大了人们的焦虑,在书中强调要高效、要进步、要把繁重的工作外包、自己享受舒适清闲的好日子。也是很「资本主义」的行为了。

因此,尽管这本书中很多看法和内容我并不十分赞同,却也是一本能够引发我思考的书,因此在这里推荐,希望读者能够辩证地思考里面的观点。关于生活方式,哪一种更适合自己,或许只有我们自己能给出答案。