Skip to content

🔰 左耳听风专栏学习笔记

🕒 Published at:

左耳听风专栏学习笔记

这是我在充电平台学习《左耳听风》专栏的笔记,仅是部分。

开篇词 | 洞悉技术的本质,享受科技的乐趣

分享文章,不仅仅是为了宣传,更多是为了与他人讨论,激发更深入的深入思考。学习别人的知识,如果有真正的思考,那么可能有三个阶段:

在第1个阶段,我们读了以后,有了自己的想法,大胆分享出来,然后遭到了批判,别人可能说我们目光狭隘,狂妄无知。

在第2个阶段,我们预感到可能会有人批评我们,而刻意在用词上柔和了一点点,这在一定程序上是一种「懦弱」的表现。

在第3个阶段,我们明知可能会招来非议,却仍然大胆地表达自己的想法。这是勇,是儒家三宝里的「勇者无惧」。

如果有思考,肯定就是要表达出来的;如果没有思考,那就另当别论了。反过来思考一下,有些东西线上是不适合讲的,所以有时候真正的交流还在线下,这也是为什么有时候明明可以在线交流,却一定还要举办线下活动的原因了。

| 程序员如何用技术变现(上)

这篇文章我最大的心得是,优秀人才都普遍具有三个特征,稍后我们看具体是哪三个特征。

我感觉这个专栏作者的经历真是非常富有传奇色彩。1997年,5个Web页面1万块钱,一个页面就是2000块钱。现在基本上一个页面也是2000块钱,只不过要带上「动态」二字。

作者因为不会网页设计和开发,放弃了这1万块钱的外快,后来他开始自学网页开发,并且自学以后还在网上分享,分享他设计网页的一些技巧,例如「抽屉菜单如何设计」等。这个菜单设计,在当时就属于有一些难度的高级技巧了。

因为在网上做了这些分享,而被电脑报的编辑看到,从而成为电脑报的特约撰稿人,从此专栏作者开始赚稿费了。

后来机缘巧合发现了一个牛x的性能优化工具,叫Purify。因为觉得好,开始读Purify的英文文档,进行全面细致的深入研究,并且还在网上分享研究心得。由此被一家需要使用Purify的公司看到,开始进入企业内训领域。一天税后收入5000块钱。这是20年前的企业内训价格了,在今天来看的话,至少两万起了。

再后来因为继续钻研高精尖技术,继续坚持分享,开始被公司邀请进入内部解决疑难杂症问题。两天时间,报价1万块钱,人家给了10万。感觉作者当时很客气,他是按企业内训价格给报的价,但是人家是按节约的成本给付的报酬。一个技术难点被憋住了,公司投入好几个人进去,花了几天甚至几周时间,企业的沉没成本已经很大了。10万块钱,可能只是被节约下来的一小部分。

作者后来又有一次深入公司解决疑难杂症的机会,两天时间,700行代码,企业给了20万。这个也是应当给的,可能这一次节约的沉没成本更多了吧。

从作者的这些经历看下来,会不会有人觉得他的的运气好?

我觉得在这个快速发展的时代,每个人其实都是有机会的,我觉得不是作者的运气好,是他具有一般人不具备的品质。接下来容我归纳一下这些品质,不妨你也对比一下,看自己有没有。

勤奋好学

第1点,就是勤奋好学,并且是主动学习,这一点基本上就把80%的人给比下去了。很多人学习都是被动的,甚至很有可能他从事的那个职业,也不是他自己喜欢的,只是为了拿一份薪资而已,所以根本也谈不上主动热爱。

善于思考与总结

第2点,就是作者很善于思考和总结,并且还善于把总结出来的理论,继续应用在实践当中。在作者上面这几件事情里面,其实前后都是有因果联系的。如果没有电脑报约稿,可能就没有后来的Purify分享,没有Purify分享,可能就没有后来的企业内训,没有继续高精尖问题的钻研,可能就没有后来解决疑难杂症问题的机会。这里面是有内在联系的,善于思考,善于总结,善于在实践中调整,这一点基本上把90%的人都比下去了。

举一个例子,作者刚开始时还研究如何实现抽屉式菜单,但是后来他就不研究这个了,为啥呢,因为研究的人多了,研究明白了,没意思了,太简单了,这个已经不属于高精尖技术了,后来他就注重研究那些有难度的、有挑战性的技术。这个也不一定就是出于等着某一天有公司请他去做企业内训,或者解决某些疑难杂症问题这个目的去学习的。

江湖上有很多武功,你要选哪一种呢?比如说独孤九剑和辟邪剑谱,比如说降龙十八掌和葵花宝典。武功是有正有邪的,所以在这个里面,我们看到,作者修练的都是正派功夫。那么所谓邪门歪道的武功是什么呀?比如说破解用户名、密码,研究一些黑客技术等。这些东西不要去研究,这些东西研究了也无处分享,不分享别人怎么知道你会。

我曾经因为工作需要,研究过验证码的破解,首次破解成功率达到95%以上,二次成功率几乎100%。我还分享过如何破解,后来有一天被一个北美的哥们看到了,他联系我。我把帖子删掉了。

三、富有分享精神

第3点,就是作者不惮于将自己的研究成果无私地分享出去,非常富有分享精神。很多人是不会分享,还有一些人是不愿意分享,从这点来看,作者又把99的人比下去了。

以上就是我读了以后,我认为一个优秀人才一般都具备的三个基本品质。所以,我觉得也不用羡慕别人运气好,要先看自己是否具备这些品质,是否付出了长年累月的努力。

前天在知乎上有一个人和我评论互动。他说他27岁了,比较迷茫,问现在学编程还来得及吗,学了以后能做一名程序员吗?

我就鼓励他大步前进,如果对编程感兴趣,现在入行就是最好的时机。然后他又觉得,如果现在开始学很多基础知识,像计算机基础,网络基础,数据结构,算法,数据库等等,等学完了基本到30岁了,到时候还有公司要吗?

这时候我就给他一个建议,我说你可以先学会一门实用的技术,让自己有被企业利用的价值,先找一份工作,然后你在工作当中再充电,再夯实基础。

然后他又犹豫说,那到35岁是不是又要被公司给淘汰了?

我接着跟他讲,技术学到了是任何人都「淘汰」不了的,不要觉得技术只有卖给公司才有价值。当然了,这跟学什么技术也有关系,所以我现在主张程序员入门,可以先从应用型技术学起,从能独立赚钱的技术学起,比如说微信小程序。微信小程序已经覆盖了4亿人,市场是非常大的。

| 程序员如何用技术变现(下)

这一篇文章听下来感觉实操性并不强。总的来说,怎么样才可以用技术变现呢?就是首先要先让自己变得值钱。那怎么样才能变得值钱呢?就是要做到别人做不了的事情。

做到别人做不到的事情,感觉这个挺难的。但其实如果我们划定一个范围的话,这件事情好像也没有那么难。我们不需要做到第一名。

就像开餐馆一样,这个世界上有很多餐馆,各大菜系都有。每个餐馆的价格、服务、以及做菜的水平都是参差不齐的。但是那些做得差的餐馆,他们依然也活了下来。有的是靠低价,比如农村大集市里的山东拉面哥;有的是靠地段,比如说北京东单的簋街;有的是靠服务,比如说海底捞。他们活下来的方式都不一样。

那与程序员这个手艺人行业对比一下,我觉得道理也是一样的。我们没有必要非要在某一方面做到顶级。只要我们能给周围的人,给一部分人提供价值,我们就能挣到钱了。

有时候信息是不对称的,要么他们不知道,要么就是他们着急要。就像一个饥饿的人,他就想马上吃一碗面,而我们恰好就开了一家还凑合的面馆。

技术变现这件事情,我之前还听过别人的演讲。大致总结一下,有一个核心的点很重要,就是我们要努力提高我们收入里面的被动收入,而减少一次性收入。

举个例子,比如说像软件外包,这个事情就很不划算,因为你投入一份时间,你就赚一份钱。相对来讲,你做一个模板小程序,然后你给很多人用,重复销售,那这个相对就高级了一些。

还有企业培训也是,你设计了一套课程,你可以重复给很多企业讲。但如果只是与一个企业的业务紧密结合进行培训,那基本上这个就是为他们量身定制的,不可能再二次销售了。这种情况下相应的内训价格就要高一些,至少要比一般的报价高两到三倍吧。

| Equifax信息泄露始末

这是2017年发生在美国的一次非常著名的征信公司信息泄露事件,波及多个国家的1.43亿用户,影响非常恶劣。事故的直接原因是运维人员没有及时更新补丁,没有及时修复一个旧版的Apache Struts漏铜,致使黑客有机可乘。

Apache Struts是著名的开源软件,所以你看,不一定是开源软件就一定更加安全。前几天还听到一个报告,说是大概50%(具体数字记不清了,大概比这个还要高一些)以上的开源软件都存在安全问题。

软件安全问题不容忽视,这里确实应该提高认识。

| 从Equifax信息泄露看数据安全

这篇文章听下来我的体会是:给敏感信息加一个保险箱,给箱子上一把锁,并且钥匙还要定期更换。

箱子的钥匙,也就是密钥,由一个部门或子公司保管,箱子则由另一个部门和子公司保管。

需要从箱子里面取东西的时候,由箱子自身向外提供一个小水龙头,同时还要进行流量监控,发现流量大了立马停止输出并拉响警报。另外,提供数据的时候,还要先对口令,也就是密钥。这个密钥要定期更换,并且密钥不能体现出某种社会工程学上易于猜透的公式特征。

箱子给数据使用者返回的信息要进行脱敏,打马赛克,例如银行卡只返回后4位数字,前面都是星号。

在登录入口多加一些防范,例如限制登陆IP,强制使用安全证书,强制使用复杂的密码,强制定期更换密码。强制使用复杂的密码和定期更换密码,这个规则可能会让员工反感。可以使用带自动生物验证的电脑,将这一步骤简化。让人觉得简单,就容易让安全措施落实。

再总结一下核心要点:在内部建立子系统,对内部也要加以防范。对内提供的数据接口,对内部调用也要加以限制和监测

安全漏洞不是一劳永逸的,它是随着软件的发展而不断进化和生长的,它非常具有服务特性。可以说安全服务是一个消耗品,就像家里的卫生纸一样。我觉得在这个方面,以后国内市场的需求会越来越大的,甚至我觉得都可以专门有这样的一项to B的生意。至少专门有这样的一个专栏课,肯是是很有价值的。

我查了一下,在充电平台上确实有一个这样的安全专栏,叫做《安全攻防技能30讲》,我已入手,也把这个课程推荐给你:

image-20210329095748724

| 何为技术领导力?& 06 | 如何才能拥有技术领导力?

先看第05篇

一看到领导二字,貌似这和组织关系有关系了,其实不是的,这里讲的技术领导力,是指工程师主动发现问题,并推动问题解决的能力

当然,我这么解释有点偏面,这是对人而言,对一个企业,甚至一个城市、一个国家,也可以谈论其技术领导力。在这里,起决定性作用的是工程师,并且这里的工程师,可不是一般的工程师,它应该被描述为「国家的希望」,甚至「人类的福祉」。我们看一下这里的工程师,他需要做哪些事情:

  1. 发现问题。发现生产生活中存在的矛盾或痛点。
  2. 提出问题。只是发现问题还不可以,因为有的人虽然发现了,但是他觉得这件事与他无关,事不关己则高高挂起,这不是真正的有领导力的工程师。
  3. 分析问题。不仅是分析问题,还要调查并给出一个或几个解决方案。
  4. 解决问题。有了方案以后,方案并不一定可以落地,资源永远都是紧缺的,不然的话它可能就不是一个真正的问题了。这个时候,需要工程师主动、有韧性地、坚持不懈地推动方案落地,直到问题完美解决。

所以你看,这里的工程师哪里是招聘网站上提到的工程师啊,他是一身身兼数职,既是产品经理,又是项目经理,可能还是一个QA,当然最本质的,他是一位可以写代码、可以让技术方案落地的程序员。在这里,工程师不等于程序员,工程师大于程序员。

昨天我还刚看到一篇文章,说清末名臣左宗棠发现新疆「伯克」制度日益腐败,民族分化问题日益严重,于是他五次向朝廷上书,要求新疆建省,立乌鲁木齐为省都。这件事情肯定是有阻挠的,在当时那个腐败的年代,在一个摇摇欲坠的朝廷里面,他肯定知道做件事的难度。但是为了做成这件事,左大人是坚持不懈啊,不断寻找有利时机,前后五次上奏,最终在他去世前一年,终于把这件事办成了。如果没有当年左大人办的这件事,恐怕今年新疆的棉花不会收成这么好。

我们对比一下左大人和工程师,按这篇文章作者的标准,一位有领导力的工程师就是一个会写代码、懂技术的左大人。所以你看,这里的工程师规格是非常高的。

那么进一步思考一下,这样的工程师他主要做什么事情呢?

我们知道创新的事情有两类:

  • 一类是从0到1的事,这件事之前从来没有人做过,突然有一个人做了,这就是从0到1的事,例如瓦特发明蒸汽机、莱特兄弟发明飞机、爱因斯坦发现相对论、牛顿发明微积分等等,这些都是从0到1的事情。
  • 另一类是从1到1万的事,这一类里面的事已经有人做了,大家都看到这件事的价值了,但是还有不少问题和可优化的空间,现在需要将它不断完善,不断地进行深入改造,使它更加易用、成本更低、效果更高。在这方面例子也有很多,例如汽车、飞机、高铁、电子计算机等等都是这方面的例子。

这两类事情按说工程师都可以做,但第二类需要的工程师更多。文中所言的工程师,主要也是做第二类事情。

接下来看06篇有关的内容

作为一名技术领域的工程师,那么如何提升个人的技术领导力呢?除了高标准要求自己,坚持终生学习,坚持做正确的事以外,很重要的一条,就是打好技术基础。在这方面作者还给出了一些具体的建议,一共是八条:

  1. 学习基础的编程语言,例如C,推荐阅读《C语言程序设计(第二版)》

    image-20210329103855231
  2. 学习普遍的编程范式,例如面向对象编程、函数式编程、经典的23个设计模式,这些都是编程前辈总结的思想精华。推荐阅读《设计模式-可复用面向对象软件的基础》

  3. 学习算法和数据结构

  4. 学习计算机原理,推荐阅读《深入理解计算机系统》

    image-20210329103935750
  5. 学习操作系统原理

  6. 学习网络通信原理

  7. 学习数据库原理

  8. 学习分布式架构原理

学完这些,基本上二三年时光都过去了。但是并不是学完就结束了,学习它们只是一个开始,这些内容需要用一生的时间去不断锤炼。

在学习资料的获取上,作者提到,一定要从源头学起,用好英文。学习者采用的学习方式,与学习者的水平也是紧密相关的,概括一下大致有三个层次:

  1. 第一个层次,只使用中文搜索引擎,只阅读中文书籍或文档。达到这个层次说实话已经很不错了,因为大多数程序员是不读书的,连这个都达不到。
  2. 第二个层次,使用谷歌搜索英文资料,阅读外文书籍和原始的英文技术文档。
  3. 第三个层次,翻遍这世界上的角落,都找不到问题的答案了,跑到官方Git仓库上看issue列表,和原作者直接交流。甚至原作者都没有答案,你在这个技术上跑到了世界的最前尚,你动手写代码,解决了这个问题,然后再把解决方案分享给其它人。
image-20210329213943242

以上就是我读了这两篇内容之后的感受,做一名工程师不容易,做一名有技术领导力的工程师更不容易。学好上面这些基础内容,或许才真的可以达到「代码改变世界」的境界。

| 推荐阅读:每个程序员都该知道的知识

这篇干货文章没有语音,只有文字。在这篇文章里面,作者推荐了一本电子书,叫《C++软件性能优化》,176页,全英文,我不知道有多少人会看。

另外,还有一个关于Github开源代码bug 的研究报告 。这个报告很有意思,总结一下有这样几个点值得注意:

第1点。Bug产生率与软件所在的领域无关,但却和编程语言是相关的。语言设计的不好,就容易出Bug。函数式编程语言的Bug,比一般过程式编程语言要少。对于这个结果,我的第一感觉是,并不一定函数式编程语言它更具优势,可能是它被用的少。但其实不是这样的,更有可能的一种解释是,函数式编程它是一种线性思维,它不是发散的,它没有提供给程序员更多犯错的可能。

第2点。静态编译的语言,比动态编译的语言Bug要少;强类型的语言,比弱类型语言Bug要少。

什么是静态编译的语言?像C、C ++,Golang,这都是静态编译的语言。反过来像PHP,JS,Ruby,这些都是解析执行的,属于动态语音。

什么是强类型?像Golang、C、C++,这些都是强类型。JS 中一个变量可以随意地改变类型,它是弱类型。

这个规律很好理解,弱类型语言是动态编译的,确实比较容易出Bug。反过来,如果是静态编译、强类型,有很多Bug在编译过程中就被开发者干掉了,因为不干掉的话就编译不过去嘛。

这两个弱点JS都具备,正因为如此,微软搞了一个TypeScript,简称TS 。但是很奇怪,通过这个报告我们可以看到,TS的Bug比JS还要高。按理说TS因为时间不长,比较新,语法更先进,它的Bug应该更少,但其实不是。

所以还是那句话,语言它只是一个工具,语言本身它没有什么绝对的好坏,关键还是使用工具的人。TS它其实只是在JS表面上放了一些语法糖,做了一些人为的限制,来规避一些可能容易发生的错误,但本质上它编译以后还是JS。

第3点。在这个报告里面,我们可以看到像一些传统的语言,C和C++的Bug 率是很高的,而Go语言相对是比较低的。鉴于Go语言它也是互联网时代的C语言,它在分布式系统中很有优势,所以它仍然是目前被建议学习的首款后端语言。

在评论区有读者提了一个很好的一个问题,这个问题很有辩证性,他是这样问的:

对于初学者,学习是应该从上到下学习,还是从下到上学习?

从上到下学习,就是说先从应用型技术学起,先做项目,在做项目的过程当中再去深入学习。这个是我一直主张的PBL学习思想。从下向上学习,它是指我们先把计算机的一些基础知识,网络基础,算法,数据结构,数据库,分布式技术等等这些底层的东西,先学好,打好根基,完了再去学应用层技术。

这是一个好问题,但其实对于不同的人来讲,它可能没有标准答案。我的建议,还是要从上向下学。你先学一门技术,甚至靠这门技术先找到一个工作,然后你在工作当中,再去注意夯实基础。我反对先完全从基础学习,特别对那些不是计算机专业的初学者来讲,因为当你离开学校以后,可能社会不会给你这个学习时间的。

| Go语言,Docker和新技术

如何提前判断一个技术能否引领未来的潮流呢?主要看4点:

  • 第1点,它解决了生产生活中的什么问题?
  • 第2点,它有没有一个大型商业公司在背后推动。
  • 第3点,它上手是否足够简单?
  • 第4点,它的开发是否足够方便?效率是否足够高?社区是否足够完善?文档是否足够丰富?

目前来看,Docker 和Golang 都是符合这个标准的新技术,现在学习还为时不晚。还有Paas也值得了解。有些读者可能不知道Paas的含义,它是Platform as a service的缩写,平台及服务,像谷歌的Google App Engine就是最早的Paas服务之一。

| 答疑解惑:渴望、热情和选择

公司总是加班,没有时间学习怎么办?我也想分享,如何才能长时间数年如一日的坚持?对于年轻人来讲,如何规划自己的人生道路。

这篇内容,作者主要回答了上面这三个问题。这三个问题是每个程序员都会遇到和思考的。我读了以后,深有体会,下面我说一下自己的感触。

对于公司总是加班,没有时间学习,这个要想想老祖先孟子说过的一句话:行有不得,反求诸己。作者的回答就很好,你有时间刷短视频,有时间打游戏,但是没有时间学习,为啥?因为学习是一个痛苦的事,是一个反人性的事,而打游戏是一件让你快乐的事情。

在学习这件事情上,要求我们主动鞭策自己,主动找碎片时间,常年坚持,积少成多,知识来源于点滴积累。另外还有一点,如果你真的到了一个经常加班以至于学不到新东西的程度,索性不如辞职。这个公司它已经不能让你成长了,无论是公司内成长,还是自修式成长,都不能让你成长了,那么你就选择果断地离开。离开也是一种成长,这条建议特别适合20~30岁的年轻人。

再看第2个问题,如何常年如一日坚持写作。人类会说话有100万年的历史,但是有文字会写作,只有1万年的历史。写作这个事情,确实是有难度的,它可能并不适合所有人,有的人天生就能写,但是有的人就不行。有的人一旦坐下来写作,他的大脑就短路了,脑子一片空白。但是这样的人,一般他善于交谈,一旦他和别人开始聊天,他的思维就连贯了,他的各种想法开始层出不穷。所以我觉得,写作这个事情也不必强求,如果你不擅长写,你可以尝试其他方式,比如说录短视频。运营一个视频号目前也是机会,找到适合自己的方式就好。

另外还有写书,这件事情有的人觉得写书在中国因为版税低,收入很低,远远不如做其他的事,像企业内训、软件外包来钱快。我想说的是,像企业内训和软件外包,这些事它就像沙滩上的城堡,海浪一来,随着岁月的冲刷,到年老的时候什么都没有了。

但是你写的书,当你年老的时候还能陪伴着你,这是一种岁月的回忆。另外,写书的收获不在于书内,而在于书外。还有就是,目前咱们国家正在处在科技腾飞的起飞阶段,这个时候需要有人做知识的布道者,做知识市场的开拓人,这既是荣誉也是机会。

再说最后一个问题,如何规划自己的人生。在这个问题上我觉得作者给的建议,都十分有用,20 ~ 30岁就是要拼命让自己成长,尝试各种可能性,说的更直白一点,不要长期在一个岗位上做重复的事情,一旦你感觉自己没有成长了,马上换岗。当然我不是鼓励跳槽,除了跳槽以外,你还可以选择内部创业或转岗,如果公司内部不给你机会,那你就到外面去寻找机会。30 ~ 40岁,正是干事业的时候,如果此时你的激情还没有完全被社会磨灭的话,你可以选择创业,选择一个适合自己的方向,去做一件自己真正喜欢的事情。

现代人的平均寿命已经提高了,原来我们讲一个人最年富力强的青春年华是在20 ~ 40岁,现在我觉得可以延长到50岁。30 ~ 50岁,一个人都随时可以开始创业,为社会创造价值。如果你觉得晚了,可以想一想褚橙。

至于具体从事什么样的职业,这个问题,我觉得很多时候,其实主要是看两点:一个是自己的性格,一个是运气。本质上我们做的很多选择其实都源于自己的性格。但我觉得这里有两点,可以分享一下:

第1点,无论在任何情况下,哪怕你在一个竞争多么激烈的城市,一个内卷多么严重的公司,你始终都要坚持做一个不伤害他人的人,任何时候都不要做亏心事。这是第1点,因为不值得。可以不行善,但也不要作恶。

第2点,要坚持自己的初心,有时候要有一点点情怀。有的人可能会说,那如果照你这样说的做的话,我可能就没有饭吃了。这个社会还不至于,整个社会的风气在慢慢变化,尤其在大都市。有时候这样做,反而可以找到志同道合的人,反而有一些不一样的机会。

| 如何成为一个大家愿意追随的Leader?

分享一个小故事吧,大概10年之前,有一年公司颁发最佳员工奖。当时大领导找到我,说你和你的属下都应该得奖,但是今年总公司只给了一个名额。我说如果只有一个名额,那么就把这个名额让给我的好兄弟吧。而我甚至从来没有把这件事情告诉过获奖人,我觉得这是他应该得的,也是我当时作为一名Leader应该做的。但是这并不是说,我就是一位合格的Leader,我还有许多需要学习的地方。

这篇文章讲如何做一名大家都愿意追随的 Leader,注意,这里的定语是大家都愿意追随,但是这样的Leader并不是谁想追随就能追随的,因为太稀少了。100个人里面没有一位,1000人里面也没有一位,1万人里面才可能出一位。

文章里有大量的篇幅对比了Boss和 Leader的区别。简言之, Leader是用自己的技术领导力,用个人魅力去带领团队,做事情的时候总是说「跟我上」,有肉吃和大家一起分享。甚至为了兄弟多得一些利益,愿意把自己的让出来。而Boss主要是用行政命令和制度,用组织关系,以机械的方式驱赶团队,「给我上」。一旦项目进展不顺利了,就要有人背锅,领导是永远没有错的。

两者在对待离职员工这件事情上会有本质的区别。 Boss的态度是,不准走,走就扣你工资,走就通过行内朋友打压你,让你找不到工作。而Leader则是帮助你,主动推荐公司给你,衷心祝你有更好的发展。即使你错了,也要帮助你提升认知。

一个由Leader带领的团队,是以项目为单位进行组织的。而Boss带领的团队,一般都是以工种进行划分的。如果你所在的公司有明确的前端后端分工,有专门的产品经理、QA,那么恭喜你,你的领导可能只是一个Boss,他不太可能是你可以真心追随的Leader。

尽管真正的 Leader这么少,但让人值得高兴的是,并不是只有在组织关系上的 Leader,你才可以追随。事实上你在社区里发现的,你都可以追随。你可以读他的书,学他的课,可以和他一起维护他开创的开源项目。追随的方式有很多种。

==(好,以上是前10篇的笔记,大约8800字)==

| 程序中的错误处理:错误返回码和异常捕捉 & 12 | 异步编程以及我的最佳实践⭐️

这两篇关于错误如何处理的文章,干货特别特别多。它是帮助我们正确处理错误的终极方法论。包括各种常见语言,常遇错误,都谈到了。

软件不可能没有错误,当出现错误的时候,我们应该思考两个问题:

第一,这个错误是在哪里产生的? 第二,这个错误最终要由谁来买单?由谁来消化?

我们依次看一下软件中三类常见的错误。

image-20210331140422862

第1类,关统底层基础设施产生的错误,比如远程服务器通讯失败,内存耗尽,网络资源无法拉取等等这些错误。它们最终要由运维人员来买单,所以对这些错误的处理,我们要 Catch,同时监控,然后发短信或语音警报。

第2类,中间件模块代码中的错误。这类错误有可能是调用底层代码产生的,也有可能是接受了来自上面业务层不合理的输入触发的。这些错误最终是要由开发者来消化,所以这些错误我们要Catch,并且要暴露出来。哪里出错了,具体错误信息是什么,然后都要报告给开发者。这些错误都要在开发阶段解决,所以越早暴露越好。

业务错误,一般公司要靠测试用例和QA把他们全部覆盖住。同时还需要程序员写上足够的Unit Test代码,自动化测试跑一跑,保证代码的健壮性。模块代码要有Swagger 文档,上层消费代码调用的地方需要考虑到所有错误,在文档中要有体现。

第3类,发生在业务代码处。有可能是调用底层代码或者是模块代码产生的,也有可能是来源于用户错误的输入。对于前者,要把它们全部Catch 住,并在开发阶段消化掉;对于后者,要把信息通过界面反馈给用户,建议用户做出适当合理的调整。

对程序错误的处理,从处理与不处理来讲,又可以分为两种:

  • 一种情况,是把错误抓住,再向上抛出去,本身不处理。这种情况一般发生在中间件模块层,当应用代码调用出错的时候。还有就是发生在业务代码层,由用户输入不当导致的错误,这种错误还给用户,让用户自己来消化。

  • 另外一种情况,是抓住错误以后自己消化掉,并且做相关的错误日志记录。这种错误一般属于运维错误,不是开发阶段能够解决的,一般在开发阶段也暴露不出来。

当涉及到异步代码的时候,JS里面的异步转同步编程是最理想的一种方式。结合async / await语法可以让代码非常简洁。但是在这里,我不喜欢使用try-catch,至少不在明面上使用。我们至少可以在一层代码里面,例如在中间件模块层或者是业务代码层,专门有一个地方统一封装一下try-catch ,这样其他地方就不需要再写类似的catch代码了。

举一个最常见的场景,在业务层请求后端接口,这个地方,我们可以直接将try-catch和相关的 then 捕捉,都封装到一个requst 方法里面,并且这个方法还包含 n 次网络错误重试。这样我们在调用接口的时候,只需要使用await同步调用这个request方法就可以了。举一个代码伪例看一下:

js
let res = await http.request(url,data)// 内含网络不佳、服务器打盹等情况下自动3次重试机制
if (res && res.errMsg === ‘ok‘) {
  ...
}else {
  ...
}
let res = await http.request(url,data)// 内含网络不佳、服务器打盹等情况下自动3次重试机制
if (res && res.errMsg === ‘ok‘) {
  ...
}else {
  ...
}

| 魔数 0x5f3759df

这篇内容虽然是选读,但非常值得一读。之所以作为选读,我觉得不是因为不重要,而是因为它确实有点难。普通文章可以2倍速快过,这篇文章可能对于大多数读者,即使全神贯注,第一遍也只是能了解个大概,很难明其细理。

既然这么难,为什么还值得阅读呢?因为它充分体现了程序员的一种孜孜不倦的探索精神。文章里说的这个魔数,它很神奇,是杜甫诗中那种「造化钟神秀」的神奇。这个魔数就像人类是如何进化出来的一样,它是理性+直觉的智慧结晶,是一代一代程序员大神接力完成的一个小壮举。

接下来我们就一起感受一下这个魔数吧。原作者已经很讲的很好,但有些读者仍然觉得没有看懂,我结合自己的学习体会,努力让内容再变得更加容易理解一些。

这个魔数是在下面代码第9行用到的:

c
float Q_rsqrt( float number ) {
    long i;
    float x2, y;
    const float threehalfs = 1.5F;

    x2 = number * 0.5F;
    y  = number;
    i  = * ( long * ) &y; // evil floating point bit level hacking
    i  = 0x5f3759df - ( i >> 1 );  // what the fuck? 
    y  = * ( float * ) &i;
    y  = y * ( threehalfs - ( x2 * y * y ) );  // 1st iteration 
    // 2nd iteration, this can be removed
    // y  = y * ( threehalfs - ( x2 * y * y ) ); 

    return y;
}
float Q_rsqrt( float number ) {
    long i;
    float x2, y;
    const float threehalfs = 1.5F;

    x2 = number * 0.5F;
    y  = number;
    i  = * ( long * ) &y; // evil floating point bit level hacking
    i  = 0x5f3759df - ( i >> 1 );  // what the fuck? 
    y  = * ( float * ) &i;
    y  = y * ( threehalfs - ( x2 * y * y ) );  // 1st iteration 
    // 2nd iteration, this can be removed
    // y  = y * ( threehalfs - ( x2 * y * y ) ); 

    return y;
}

我们先不要先这个代码,即使是程序员,第一眼也很难直接看懂。首先,我们想一个问题,就是计算机是如何表示小数的?

整数很好表示,十进制转二进制就可以了。例如10,不断除以2,将余数从左向右排列,例如10转成二进制是1010:

image-20210402180105134

但是小数怎么表示呢?要知道计算机里只有0和1,没有小数。我们举个例子,例如0.2这个小数,如何用二进制表达?

二进制分式十进制
0.011*2^-2^0.25
0.0102*2^-3^0.25
0.00113*2^-4^0.1875
0.001106*2^-5^0.1875
0.00110113*2^-6^0.203125
0.0011001151*2^-8^0.19921875

(表格转绘于知乎答案

在这张图里,中间那一列,星号前的数字,是小数点后面的十进制值,星号后面是2的n次幂,小数点后面有几位,n就等于几。我们看到,第5行数字还大于0.2,第6行数字就少于0.2了,并且第5行只是比第5行二进制在尾部少了一个0.00000001。

我们发现,有些数字计算机无法精准表达,只能近似。明白了这一点,对于我们理解一个老生常谈的问题「浮点数0.1+0.2为什么不等于0.3」很有帮助。

有的读者可能会想,既然整数能用二进制表示,小数应该也能用二进制表示,为什么不能直接将小数用二进制表达成一个「整数部分+小数部分」这样的形式呢?

image-20210403094450055

答案肯定是可以的。在上个世纪80年代,在小数形式没有被IEEE754浮点标准统一之前,确实存在很多表示小数的形式,其中之一就是定点数。如上图所示,78.375这个小数主要就由两部分组成,绿色区域是1001110,是十进制的78,红色区域是0.01100000000000000000000(20个零),是十进制的0.375。这就是定点数的表示方法。

定点数的表示方法结构清晰、简单。

与定点数相对的是浮点数,目前应用最广泛使用的浮点数标准是IEEE754。一般教科书上32位浮点数的公式是这样的:

image-20210403173457541

其中E是指数区的数字,M代表的是尾数区的一个比值大小。

image-20210403172105901

(图片转自https://fabiensanglard.net

这个公式是怎么来的呢?为什么定点数这么清晰,但是最后复杂的浮点数却统一了天下呢?接下来我们看一下这个浮点数公式是怎么推导出来的,以及它有什么优点。

基于前面对定点数的了解,想一想0.2那个数字,我们不难想象,在二进制中,对于任何一个小数,都存在一个n,使其介于 2^n^ 与2^n+1^之间。

image-20210402183917560

其中n可以是正数,例如2^1^(2) < 3.14 <2^2^(4);也可以是负数,例如2^-3^(0.125) < 0.2 <2^-2^(0.25)。这也很好理解,假设2^n^有10个二进制位,那么2^n+1^刚好就有11位,在它俩之间,由于后面子位的变化,肯定还能容纳一些数字,于是它俩就构成了一个两端是整数的闭区间[2^n^ ,2^n+1^]。

那么,我们能不能这样,对于任何一个小数,我们能不能先确定它所在的闭区间的下限,以其作为起始值,然后再加上一个不大于2^n+1^-2^n^ 的偏移量,这样不就可以表示一个小数了吗?

image-20210403174446637

(图片转自https://fabiensanglard.net

这是一个使用窗口和偏移量解释浮点数的例子。我们以3.14举例,它的闭区间是[2^1^ ,2^2^],闭区间下限是2^1^,即2,二进制表达是10。由有在IEEE754浮点数标准中,E区为了同时可以表示正负指数,故意作了偏移,E-127等于指数,指数是1,所以E等于128,二进制是10000000(七个零)。

image-20210403175516227

(图片转自https://fabiensanglard.net

那么尾部区数字应该是多少呢?

尾数区等于(3.14 - 2)/(4 − 2)*2^23^,等于4781507,二进制表示就是10010001111010111000011。相当于把尾数区分成2^23^个段,然后将3.14在闭区间[2^1^ ,2^2^]所在的位置,映射到这个尾数区域中来。

最终如上图所示,这正是3.14使用IEEE754标准表示的二进制形式。

现在我们尝试做一件事情,从这个示例中,归纳出浮点数的公式。为了表示方便,我们先将表示正负的符号位略去:

X = 闭区间窗口左边界 + 窗口偏移量 = 2^n^ + M / 2^23^ * (2^n+1^-2^n^)

其中M是偏移量。因为二进制比较特殊,2^n+1^-2^n^其实就于2^n^ * 2 - 2^n^,等于2^n^。所以:

X = 2^n^ + M / 2^23^ * 2^n^

组合一下,并且将n由E-7替换掉,再加上符号位,就变成了:

X = (-1)^S^ * (1+M/2^23^) * 2^n^

对于上述公式,忽略一些常数,可以简化为:

X = (1+m)∗2^e^

对于整数,不需要偏移量,32位的整数公式可以这样写:

X = E∗2^23^ + M

那么接下来我们看一下,浮点数有什么优点呢?

浮点数虽然复杂,但是相同的二进制位数,它比定点数表示的范围更大,精度更高,因为它应用的范围最终也最广。当然了开始的时候程序员可能也没有想这么远,定点数可能是浮点数产生的土壤,正是因为看到了定点数的不足,然后才在此基础上才发明了浮点数。

解释了这么多,刚刚在解释魔数上走完了第一步。接下来就是关于平方根倒数据公式的推导,首先看一下正宗的平方根倒数公式:

image-20210403204229490

平方根基本都理解。什么叫倒数?标准定义是,一个数与其乘积为1的数。也就是将一个数作为分母,1作为分子,这样形成的数就是原数的倒数。表现在指数上,就是在指数的绝对值上加上负数。平方根表现在指数上,是2的倒数。同理,如果是立方根,就是3的倒数。

接下来,我们将公式两边取以2为底的对数,于是公式变成了这样:

image-20210403204842047

什么是对数?

一般人对幂运算比较清楚,但是对对数可能不了解。像2^n^这是幂运算,所谓对数是求幂的逆运算。如果有a^x^ =N,那么数x就是以a为底,N的对数。

取对数一般用数学符号log表示,以2为底取y的对数,就是log~2~(y)。对x^-1/2^以2为底取对数,就是log~2~(x^-1/2^)。

参照对数的基本运算规则,我们看一下:

image-20210403210122126

log~2~(x^-1/2^)也等于-1/2 * log~2~(x),应用的是第4条规则。

接下来就要用到前面提到的浮点数公式了,因为x是小数,我们将简化的浮点公式(X = (1+m)∗2^e^)带入上面的公式,于是得到:

log~2~( (1+m~y~)∗2^ey^) = - 1/2 * log~2~( (1+m~x~)∗2^ex^)

再运用一下上面提到的第2条和第6条对数运算规则,于是就变成了:

log~2~(1+m~y~) + e~y~ = -1/2 * (log~2~ (1+m~x~) + e~x~)

到这里,在逻辑上数学公式能做的事基本做完了,接下来要到发挥想象力的时候了。由于m~y~和m~x~都是M与2^23^的比值,它是一个在区间(0,1)之间的值。这样一来,我们可以将对数曲线函数,得以近似转换为一个直线函数:

image-20210403211241641

这一步是关键,因为我们本来要计算的就是近似值,就是为了牺牲一定的准确度,而换取高效率。不得不佩服第一次想到这个办法的程序员,他一定相当的聪明,不仅长于逻辑推理,还富有想象力。

再往下就没有什么需要多加解释的啦,原文中就写的很明白,基本上就是代入前面已经推导好的浮点公式和整数公式,最后终于将平方根倒数公式推导成为了:

image-20210403211716119

其中I~x~是一个整数,R是一个常量。

接下来,又到了程序员秀工程智商的地方了,这个R是啥?R就是这篇文章标题中提到的魔数。那这个魔数是怎么算出来的呢?

可能就是基于大量历史数据,归纳出来的一个估值。正常情况下,我们可以用平方根倒数公式,用正常的、效率低的方式,算出应该的得数,然后将得数代入上面的这个精简的公式,将I~y~替掉,算出R的值。

由于我们前面将对数曲线函数,转换成为了直线函数,这中间是有误差的,所以就多次代入,暴力求解,最终得到一个使测试数据误差最小的R常量。然后再把这个常量用到程序代码中。

优化这个常量R,是一个从1到1万的活,是一个工程的话。前面我们提到的曲线转直线,以及将浮点公式带入,是一个从0到1的创举。

故事讲到这里,刚进行到了第二步,接下来还有进一步的工程优化。

由于前面我们在计算过程中取了近似值,误差肯定是有的。接下来又有一位聪明的工程师想出了使用牛顿迭代法,近一步将误差缩小。我们看看他是怎么做的。

image-20210403213122916

所谓牛顿迭代法,是在曲线上不断做切线,取切线与坐标轴的交点,例如x~1~,再于曲线上x=x~1~的点继续做切线,不断向方程解逼近的一种近似求解的方法。这种方法非常像创业,在创业中只要能找到像牛顿迭代法这样的抓手,一步一步逼近,效率就会越来越高,成功也会越来越近。

牛顿迭代法依据其定义,还有一个通用公式:

image-20210403213639456

在这里f’(x~n~)是f(x~n~)的导函数,这又是一个概念。

什么导函数?导函数是怎么来的?网上有人做了一个简单的推导:

image-20210403213728962

(图片转自知乎

所以,对于f(y)=y^-2^−x这个函数,因为x此时相当于是常数,直接被略去了,所以它的导函数,按上面推导出来的公式,是f‘(y)=-2 * y^-2-1^。那进一步变换一下,就成了f’(y)=-2y^-3^。

然后将函数,与导函数,代入上面牛顿迭代法的通用公式,于是就得到了:

image-20210403215700412

这一步没有别的目的,就是用牛顿迭代法,使我们前面近似求出的平方根倒数更加精准一点。原文中有明确讲解的,我都不再讲了。强烈建议感兴趣的读者阅读一下原文。

好了,这个关于魔数的故事讲完了。我不知道你是什么感觉,我的感觉是这样的,它非常像我们人类的进化。今天我们看自身,我们觉得人类与猿猴已经相去甚远,但是在我们进化的过程当中,也有可能充斥着一些魔数。这些魔法它们怎么产生的?无非就是在资源不充足、算力不够的情况下,个别富有想象力的天才猿猴突发奇想,走出了一条不同寻常之路。之后又有人在他从0到1的基础之上,继续迭代完善,以至于后来人类都看不到来时路的模样了。

| 推荐阅读:机器学习101

这篇文章推荐了大量的关于机器学习和深度学习的课程以及资料,好多都是免费的。全部学完这些内容,基本上整个夏天都要过去了。

我个人比较倾向于学一些实用型的技术,就是怎么样在工程层面,加一些已经可以直接应用的人工智能功能,到应用中去。我感觉关于TensorFlow的那9节课就不错,每节只有10分钟。

| 时间管理:同扭曲时间的事儿抗争 & 16 | 如何利用好自己的时间?

这两篇文章是关于如何管理时间的,这是每个人都应该学习的内容。

在学习时间管理之前,首先要了解一下,人作为一种智慧动物,与时间有关的规律有哪些;其次,要懂得管理自己的周遭环境和人际关系;最后,要学会管理自己的目标和行为。

1,认识规律

有一本书叫《蜥蜴脑法则》,这本书提到在我们每个人体内,在理智的大脑之下,都有一个原始的蜥蜴脑存在。这个蜥蜴脑总想贪图享乐,好逸恶劳。当我们工作了一段时间以后,它会说,“休息一下吧“。一个自律的过程,就是不断与这个蜥蜴脑作斗争的过程。可以说,自律如逆水行舟,不进则退。

还有充足的睡眠,与富有营养的食物,这些都为自律提供了良好的物质基础。据有关研究发现,当人处于饥饿状态的时候,血液中的血糖过低,这时候自控力会大大降低。所以如果要保持良好的自律习惯,保持良好的作息,按时吃饭,不暴饮暴食也很重要。

在时间管理领域还有一个「二十英里法则」。有这样一个故事,美国西海岸圣地亚哥距离某地目录有3000英里,有一个心理学家发现,能够坚持徒步到达目的地的人,不是走的最快的,也不是因环境变化而聪明应对的,相反只有那些不管什么天气,每天只走20英里的人,才能最终到达目的地。这个典故告诉我们,时间是我们的朋友,只有坚持不懈的人,才能获得时间上的复利。

人很容易受环境影响。在一个干净的餐厅,例如KFC,如果服务员不停地打扫,这种情况下就餐的人也不好意思随地丢垃圾,甚至还会主动将餐盘收走。再举一个例子,在图书馆,大家都安静看书,你也不会好意思大声喧哗。如果环境能给人及时反馈,或者人能预知到这种反馈,这时候人的言行就会受到环境的约束。我们可以利用这一点,达到养成某些习惯的目的。

还有一个承诺一致原则。如果我们在某个场合公开说了什么话,就倾向于兑现这个承诺。

以上,就是在人的身上,与时间管理有关的规律,这些规律都是客观的。利用好这些规律,才能把时间管理这件事做好。

接下来我们看环境。

2,管理环境

环境分为现实的物质环境,和虚拟的人际关系。

为了让每天的工作都卓有成效。我们可以设个闹钟,定点起床,专门准备一间书房或一个角落。工作的地方远离沙发、床铺和电视,摆上闹钟,纸、笔等学习和工作用具,这样的环境利于帮助我们进入工作状态。

如果你在某个公开场合,立了一个Flag,让大家看到了。有许多同行人,那么同行人可以监督你或鼓励你。例如最近充电平台上架的学习排行榜功能,就是在学习活动中融入了游戏元素。

这两篇文章里面,提到了外企和国企的氛围差异。在15年前就是这个样子,不要企望短期内这个风气可以改变。在国内企业,厂子里确实有一些人是不好好工作的,是混水摸鱼的,正是这些人的行为,形成了普遍的一种领导对员工的认知,以为只要不管理,只要监管松一些,下属就会偷懒。

事实上,还有一些有理想有追求的人,即使公司放假了,要求员工休息,他都在奔跑。如果没有智慧的领导,以一种大众的偏见,用一刀切的制度,管理所有下属,那么势必会打扰甚至伤害这些积极工作的人。有时候他们还会觉得,如果制度不能一视同仁,会让人不服。为了让庸人服气,不惜伤害真正用心的人。不能因人而管理,是没有智慧或懒惰的体现。

这种职场状态是普通的,抱怨是没有用的,唯一有效的应对方式就是了解,然后变被动为主动,主动管理自己和领导、和周围同事及下属的关系。

一个有效的办法,就是让自己的工作时间表透明,多争取一些信任。

在这两篇文章中,作者给出了三个说「不」的话术,这三个话术我觉得每个职场人在上班前都应该知道。当被要求加班,或压缩工时的时候,可以这样说:我可以加班加点按时完成任务,但是不能保证质量,如果有了bug,概不负责,并且上线后我需要1个月的时间消化不良代码。一听有bug,对方多半都不同意,这时候还可以说:我可以保质保量地完成,但是做不了这么多需求,有些需求必须砍掉。一听砍需求,对方可能也不会同意,这时候就可以说:我还可以保质保量地完成所有需求,但是时间必须延长二周。

你看,「诡」吧,我读到这里的时候,我都觉得做程序员太难了。当然了,上面这个话术是理想情况,有时候你应用了这个话术,也并必能得到自己想要的。起决定性作用的,往往还是文化。

接下来再说一下开会、会谈和通电话。这三者本质上是一样的。如果我们没有目的,这三个活动都可能失控,会浪费我们不少时间。

关于开会,作者说的已经非常好了。开会之前就要准备好议题,12345,还有每个议题的方案,123。开会是为了同步和确认,同步所有人的认知,立个Flag;确认所有人的责任,和关键的时间节点。大多数人开会没有效率,都是因为本来应该在会下完成的议题断定和方案筛选,都拿到了会上进行。有些产品经理将开会当成工作,但开会不是程序员的工作,所以没有几个程序员是喜欢开会的。

会谈和通电话是一样的,你想和对方聊什么,想交换什么单见,最好像购物一样列一个清单。当清单完成的时候,就可以中止这项活动了。

3,管理自己

如果说认识规律,和管理环境都是容易的,那么接下来对自己的管理却不那么容易了。管理自己主要是管理自己的目标,包括任务的优先级,还有管理好时间投资的方向。

一个人无论多么聪明,有两项能力不一定拥有:一是认清人生目标,二是断定路径价值。这两项对一个人的影响非常大,也和时间管理有关系,甚至需要半生甚至一生去学习。

我们相信每个人来到这个世界上,都有他独特的价值,大多数人普普通通,不是因为资质平平,只是因为选择太多;相反有些残疾人,资质弱于常人的人,反而取得了常人没有取得的成就,这是因为很多时候他们没有选择。他们不需要学习如何认清目标,以及如何选择路径,因为命运往往只抛给了他们一根稻草。

一个人觉得自己无所不能的时候,其实是什么也做不成的,只能做成一些小事,做不能大事;只有当一个人认识到他这也不能做,那也不能做的时候,他才有可能认清自己的人生目标。目标选定以后,接下来就是路径价值的判断。

通向罗马的路有千万条,但是当你的位置和罗马的位置确定以后,只有一条路是最近的。如何判定是哪条路呢?很多人都没有这个能力,特别是当做某件事没有经验时,我们很难判断接下来应该怎么做。当遇到困难的时候,我们应该坚持,在一个地方深耕呢?还是要学会变通,不要在一颗树上吊死呢?因人而异,而时而异,没有标准答案。这项路径价值判断的能力,只能独自练习。

在有了这两项能力以后,剩下的事情就好办了。制定一个需要经年累月才能完成的大目标,制度年度计划,季计划,月计划,为每周制定计划。每天早上起来刷牙的时候,可以想一下今天要做什么;每天晚上刷牙的时候,可以想一想今天做了什么,有什么事做的好,有什么事做得不好。这是目标管理。

在目标管理领域有一套SMART方法,是被广为接受的一个目标制定方法。

  1. S代表明确。如果一个目标,连机器都能判定是否完成,那么它一定是明确的。
  2. M代表工作量可衡量。如果连机器都能自动判定工作量完成了多少,那么M的标准就达到了。
  3. A代表目标有没有可能达到。在判断一个目标有没有可能实现时,不能凭主观臆断,一般从三个方面判断:1)这件事别人有没有完成过;2)这件事以前咱们有没有人完成过,这是指经验;3)如果前两项判断都不成立,那么从逻辑上分析,这件事有没有可能完成。
  4. R代表相关性。就是完成这件事,对完成大目标有什么增益价值。
  5. T代表时限性。做任何计划都要有一个最终时间点。

使用SMART方法,将大目标拆分为一个一个可执行的小目标后,接下来就是做事情的方法。最经济的方法,是把每一个事情都当成一项工程来做。所谓工程,每个节点都追求时间可控。

举个例子,一个婴儿的孕育需要十个月的时间,在这十个月里,无论营养是否充足,时间一到,都会分娩。这就是工程管理的艺术,在每个时间点,确定要做某个特定的事情,在单位时间段内,争取把任务完成得最好;如果没有100%完成,也不要影响下一个时间段工程的开始。这就是工程思维。要管理自己的时间,必须有这个思维。

有了以上能力和管理方法,剩下的就是关于时间的算术题了。

例如,花时间学基础知识,啃原始文档。建立全面的目标技术知识结构,在遇到问题的时候,知道要向哪里寻找答案。这是投资一次,避免多次浪费的时间投资。

例如,做一些软件自动化配置,或使用自动化工具。机器能干的活,就不要让人干。

例如,花钱节省时间。在信息的获取上,直接购买专栏,而不是到处搜索零散的内容。直接购买付费软件,而不是忍受盗版。付费软件可以自动更新,与时俱进使用最新功能,还没有广告。还有,花钱购买更高配置的电脑,让工作更高效。有时候付费就是节约。

这一点我做的就很不好,我凡事都想节约,在更新设备这件事上,我一直都是能用则用。拿我在充电平台录课这件事来说,由于我自己的电脑是8年前的旧款,不是高清屏,分辨率不够,所以每次录制都是借用充电公司的电脑,但如此一来,每次都要来回拷贝文件。如果我舍得花这一万块钱,就不用忍受179次的浪费了。

再如,关于目标的优先级,先完成优先级高的事情。那么哪些事情优先级高呢?这个主要看SMART中R,看与总目标的相关性。应该把精力最好的时段,留给最重要的任务;而一些非紧要任务,非困难任务,可以采用双工模式

所谓双工模式是这样的,在工作的时候,主要在电脑上,用双手和眼睛工作,这时候耳朵是空闲的,所以一般情况下可以选择听书。听樊登读书,或听充电平台。这个时候听书是一种需要,而不是一种任务了。时间长了,如果工作的时候不听,还会觉得不习惯;而工作开始的时候,同时启动听书,也更容易进入工作状态。这种模式开始我也不习惯,但久了就离不开了。它可以让我们在一份时间内完成两份事情,这相当于我们每天比别人多出一倍的工作和学习时间。

除了双工模式,还有一种写作技巧,我觉得也很好,就是双写作模式。用手机和电脑同时打开一份共享文档(我一般使用石墨文档),在手机上用讯飞语音输入,在电脑上用五笔修改一些错字,以及处理一些表格、图片等信息。这种方式可以极大提高写作效率。使用这种方式的时候,一定要记得开启手机免锁屏,以及设置输入法最大时间的免跳转。

后来我发现PC版本的讯飞还有一种跨屏语音输入的能力,可以将手机用作PC语音识别的话筒,效率也不错;还有,现在PC版本的语音识别本身准确率也很高,可以直接在电脑上作语音输入。

// 下面这首诗识别率就很高
床前明月光,疑是地上霜。
举头望明月,低头思故乡。
// 下面这首诗识别率就很高
床前明月光,疑是地上霜。
举头望明月,低头思故乡。

遗憾的是,讯飞一直不支持五笔输入,我使用讯飞语音识别的时候,还必须在它和一个五笔输入法之间做频繁切换,这一点很不爽。工具是不断变化的,相信以后会有更好的工具。

以上就是我学习这篇文章以后所有的感悟了,很多内容都是想到了,但是不一定能做到。关于时间管理,确实是一项值得我们不断修炼的技能。

==(第二段到这里结束)==

| 故障处理最佳实践:应对故障 & 18 | 故障处理最佳实践:故障改进⭐️

《黄帝内经》中说:“上工治未病,不治已病”。这句话用在运维实践中也很实用,就是我们要努力去避免线上故障的发生,而不是在故障发生以后手忙脚乱地处理。

自动化的运维工具

我们需要根据用户功能,创建一张全站点的资源地图。在这张地图中,每个节点都必须有一个相对完善的运维工具,这个工具可以帮助我们检测这个节点有没有问题,帮助我们定位问题,以及有问题了怎么处理。是降低处理,还是回滚代码,还是紧急更新,都需要在这个运维工具中有自动化的支持。

有了这个工具还不够,我们还需要适当的采用一些灰度更新,和平时期的故障演练,来避免线上真实故障的发生。这就是内经里讲的治未病。此外,我们还要思考,我们的系统架构是否合理?团队的工程能力是否到位?以及在故障发生后,如何复盘(Ask 5 Whys),如何对待故障责任人。

对于一个经常发生线上故障的公司来讲,有三样东西是非常有价值的:

  • 第一,一套全自动运维工具,并且支持分布式;

  • 第二,一个合理而富有弹性扩展能力的分布式系统架构;

  • 第三,一个让团队不断学习,工程能力不断提升的技术管理规范。

如何处理故障责任人

在文章中,作者提到了关于如何处理故障责任人。有的公司主张采用罚的方式,罚钱或降级。这是惩罚措施,其实只适用于非创造性岗位;对于研发岗位其实是不适合的。惩罚会在文化层面上起副作用,它会让大家以后做事情畏手畏脚,不敢放手尝试。多做不如少做,少做不如不做。原理上讲所有创新都是有风险的,创新产生故障的机率都很大。你要鼓励创新,就要容忍犯错。

我想从另外一个层面说一下这个问题。其实每一个有追求的程序员,他都希望自己写的代码很漂亮,架构很合理,软件很稳定,这是他的技术追求,是人性中向上的一面。所以我的想法是,对于线上故障,我们应该更多的去挖掘人性中积极向上的一面,而不应该去处理导致故障的直接负责人。说实话发生一次线上故障,给直接责任人定责很容易,但故障背后可能是一个工程问题,是一个团队管理问题,甚至是一个公司文化问题。这时候你怎么好意思只处理直接负责人呢,对吧。

最好的方式还是惩前毖后,治病防病。分享一个在公司中亲身经历的见闻,有一次团队组织大家学习一个技术,而这个技术让某个后端兄弟主讲。这个兄弟新来不久,为啥让他分享呢?后来才知道,由于他对这项技术使用不当,导致了线上一次故障,所以公司安排他主动学习并做会议分享。

| 答疑解惑:我们应该能够识别的表象和本质

这篇文章是教我们如何进行深度思考的,如何透过表象看清问题的本质。

首先第一点,如何看待兴趣?一般常识告诉我们,兴趣是最好的老师。但是兴趣这个东西,如果说长期坚持,不能给我们带来正反馈和成就感的话,那么我们可能很难坚持下去,这个时候兴趣可能就会变成一种压力了,那这种现象其实在家长给孩子报兴趣这件事情上就可以很好的体现出来。

关于这一点,我其实有那么一点不是很一样的看法。我自己有一个很小的兴趣爱好,已经陆续坚持十几年了,就是吹管弦乐,我喜欢吹笛子、箫这些乐器。但是我在音乐上天赋真的又非常差,我都难认准确识别音高,每次练习,我都是练得完全没有兴趣,然后就不练了。过了一段时间,工作累了,又拿起来吹一下。我从这件事里得到的正反馈和成就感非常少,但是也从来没有放弃过,我一直视其为我的灵魂爱好。

在上一篇里面,我们聊到了认定人生目标,还有判定路径价值。这两点能力其实对每个人来讲,都非常难。有的人可能一生都找不到一个明确的目标,就是觉得好像对什么东西都感兴趣,又好像对什么东西都不感兴趣一样,很难找到某一个兴趣点持续坚持下去,很难找到一个能够持续收获成就感的目标。我觉得这也是很正常的,因为大多数人就是做不到。

另外还有一点,就是关于学习,我们一向以为在工作中学习得更快。其实这个问题的本质,在于我们在工作中,有实际要解决的问题,有更为紧迫的时间,当然还可能有高手可以切磋。在实践中学习,在任何时候效率都是最高的,无论是在什么样的一个场景中,是在工作中,还是在开源软件的开发中,还是在一个PBL教学实例中。

现在开源社区发展的很好,加入开源软件的贡献者队伍,同样可以学到很多东西。门槛更低,要求更少,很多开源大神也非常nice。这两年开源软件发展得很不错,有些国外的孵化器投资国内一些云原生公司的要求之一,就是看软件是否完全开源。

文章中还提到了什么技术是未来的趋势。有一种观点说,看未来社会中的痛点在哪里,痛点在哪里趋势就在哪里。还有一种观点说,看大企业和国家把资源投向哪里。很多时候这两者是重合的,那些大企业他们也特别注重解决未来的社会痛点,这是企业赖以长久生存的基础嘛。比如说人工智能,像谷歌、Facebook这些大厂都在大力度投入。咱们国家更是将人工智能的世界领先,列为了2035年的科技目标之一。

说到人工智能,现在的人工智能一直都是弱人工智能,有多少人工,才有多少智能。未来如果这一块有所冲突了,可以将类似于人类意识的某种东西,通过量子纠缠或其它形式,注入到计算机的CPU当中,那个时候上面的很多行业都会发生翻天覆地的变化。这个基础技术的创新,就是在一个很大的范围上,在科技杠杆的支点上,发挥了巨大了的作用。这样的技术就是牛x的技术,但是对于我们大多数程序员来讲,是触碰不到的。我们能触碰到的,反而是视频号、小程序这样的技术机会。这些技术虽然含金量不高,但却影响了几亿人,甚至以后还会影响十亿人。

不知道你读了是什么感觉,总结一下就是四个字:深度思考,从动力因、目标因、质料因和形式因各种因果关系中,找出动力因,这是因果关系里面的主要方面。

| Git协同工作流,你该怎么选?

什么叫工作流?Git工作流什么意思?这来源于英文翻译,英文叫Git workflow,翻译成中文就是Git工作流。从workflow这个单词的字面来理解,它是一个让工作流畅、不发生阻滞的一个规范。再说得直白一点,就是git仓库的使用规范,告诉我们在开发中应该如何使用git仓库。

git工作流

如何使用git仓库,看git操作文档不就可以了吗?我们看一张图,看完这张图就明白了。

image-20210405104051925

(图片转自专栏原文)

这个图里的规范,被称为GitFlow,最早是由一个老外文森特·德里森(Vincent·Driessen)在2010年发明的。它是一个方法论,它将一个git仓库强制分为两个主要分支,一个是master或main线上分支,另一个是developer研发分支。

当线上有bug时,新增一个hotfix分支,bug解决后同时将这个临时分支的代码,同步至两个主要分支内。这一点也很好理解,如果只同步到了线上分支,或忘记往开发分支同步了,那么下次版本上线老bug又出现了。工程管理问题就出现了。

常规的开发,分小组(或个人)进行,每组一个feature分支,本地开发完了,往developer分支合并,在测试环境测试。测试环境没有问题,将所有待发布的功能点对齐,创建一个临时release分支,部署到预发环境。预发环境测试没有问题,再推到线上。

image-20210405105706216

现在明白了吧,因为在研发过程中,我们需要不同的软件环境,每个环境要对应不同的仓库代码,而我们的开发又不能停止,还需要实现CI/CD,也就是持续集成(Continuous Integration)与持续发布(Continuous Delivery),这个时候Git协作工作流规范就应运而生了。

那有人可能会问,为什么要搞多个环境呢?这不是为了控制版本更新的风险吗,线上有百万用户正在使用产品呢,发版如果有问题,影响了用户怎么办?事实上在中国确实到今天都有许多公司小团队,是不使用Git工作流的,版本更新都是直接从程序员的开发机怼到线上去,这时候什么测试用例覆盖率、上预发、回归测试都是浮云。

用过一段时间的GitFlow你会发现它有可能,虽然很严谨,但是有点麻烦,不适合小步快跑。于是后来就有了改进版的Github Flow,

image-20210405111230244

(图片转自阮一峰博客

在这个规范中,两个主分支变成了一个,只有一个Master或main分支。当线上有bug或开发新功能时,从主分支拉出一个补丁分支,开发完成后,向主分支发起PR,也就是Pull Request。处理PR的过程,就是一个讨论、决策和优化的过程,最后没有问题,就把补丁合并到主分支上,同时临时的补丁分支被删除。

虽然这个协作规范简化了,但是在企业团队中它也有问题,它影响团队的持续交付。企业要求发版不能影响开发,不能因为有一个小组要发版,其它小组都要被阻塞。于是更一步改进的Gitlab Flow。

image-20210405112055833

(图片转自阮一峰博客

这个规范在Github Flowr基础上,增加了两个分支,一个是pre-pro分支,用预发测试,另一个是pro分支,用于线上生产。Gitlab规范是前面两种规范在企业开发中妥协的结果。事实上仍然有人使用GitFlow规范,因为它足够严谨;Github Flow也有许多人使用,Github 开源网站本身用的就是这个协议。

Gitlab Flow规范除了企业版本,还有一个开源版本:

image-20210405112509117

(图片转自阮一峰博客

这个版本适合开源软件的研发,它将每个稳定的发行版都固定为一个分支。

git使用技巧

在使用Gitlab Flow或Github Flow时,有一些git技巧是必须要掌握的。

image-20210405114023413
bash
git clone git@gitee.com:rxyk/git-test.git --depth=1
git clone git@gitee.com:rxyk/git-test.git --depth=1

git clone将远程仓库代码拉取本地。depth参数用于控制拉取层次,在拉取一些历史悠久的老仓库时很有用。

bash
git add .
git stash
// output: Saved working directory and index state WIP on master: 040d83b Initial commit
git add .
git stash
// output: Saved working directory and index state WIP on master: 040d83b Initial commit

当我们在本地写代码的时候,如果线上有个问题必须马上处理一下,而本地的代码还没有写完,还不能提交,这时候应该怎么办呢?git stash指令可以帮助我们将本地的修改,暂时藏匿至一个看不见的区域。

bash
git checkout -b hotfix-0404
...
git add . // 添加所有新增或修改文件
git commit -m '...' // 指定提交消息,描述本次修改
git push origin hotfix-0404 // 推送
git pull origin master --rebase // 
// output: CONFLICT (add/add): Merge conflict in c.txt
git checkout -b hotfix-0404
...
git add . // 添加所有新增或修改文件
git commit -m '...' // 指定提交消息,描述本次修改
git push origin hotfix-0404 // 推送
git pull origin master --rebase // 
// output: CONFLICT (add/add): Merge conflict in c.txt

在处理线上问题时,我们需要先迁出一个临时分支,例如叫hotfix-0404。

在合并代码之前,最好先在临时分支里使用rebase指令,尝试合一下主干代码。在合并代码时,如果别人提交过代码,这时候是可能出现冲突的:

image-20210405122628337

我们需要手动编辑冲突,将所有冲突fix掉,然后继续执行指令:

bash
git add c.txt // 还可能有其它文件
git rebase --continue // 最后修改提交消息
git push origin hotfix-0404 // 推送
git add c.txt // 还可能有其它文件
git rebase --continue // 最后修改提交消息
git push origin hotfix-0404 // 推送

rebase操作也可以用于在小组内同步代码。时不时同步一下代码,可以避免代码积攒太多不好处理。如果你对项目做了不小的重构修改,最好也及时通知其它组员更新。

分支代码处理完以后,接下来到主分支,开始合并分支代码:

bash
git checkout master
git pull origin master --rebase
git merge hotfix-0404 --no-ff
git checkout master
git pull origin master --rebase
git merge hotfix-0404 --no-ff

在合并分支的时候,仍然有可能出现冲突。这时候也需要手动编辑所有冲突,完成后再执行:

bash
git add c.txt // or others
git merge --continue // 
git push origin master
git add c.txt // or others
git merge --continue // 
git push origin master

在这个地方,使用merge指令的时候使用了一个参数--no-ff。如下图所示,使用这个参数的好处,在于主分支提交历史更加清爽,这有利于线上代码的回滚。

image-20210405135942552

经过这一番折腾,线上bug终于解决了。接下来我们可以继续编写我们本地暂存的代码了:

bash
git stash pop
git stash pop

使用stash指令将代码取出来继续编辑。有时候我们一不小心写错了分支,也可以使用stash指令将新增的代码暂存起来,然后新增一个分支,再将暂时的代码恢复在新分支上,这样也是可以的。

以上就是我关于这篇文章所有的学习心得了。git操作是一个程序员的基础技能,git指令可以干很多事情,指令用得好,胜过IDE工具。

(暂时就这些)