@jianhua.cheng

什么是优秀的程序员

February 13, 2019

我们看过的技术文章太多,每天都在追逐着各种干货文章充实自己,且无论你在自己认为的优秀的评判标准中是否达到了优秀,相信你也有过疑惑:我算是一个优秀的程序员吗?怎样才算一个优秀的程序员?所以我们可以暂先不谈那些让我们趋之若鹜的技术“干货”,来重新审视我们内心的疑惑并思考它。我的看法难免会有我自身经历和环境下的局限性,希望读者以自身的见解以及秉着批判的角度来看。

过年前的 2018 年终总结给了我一个很好的自我反省的契机,同时意外的读错了一本他人推荐的书《程序员的自我修养——陈逸鹤》,原本推荐的应该是《程序员的自我修养 : 链接、装载与库》。不过同样有所收获,算是对自我审视所得内容的验证。以下引用的片段如无意外声明,基本引用自《程序员的自我修养——陈逸鹤》

下面就几个方面来谈谈在我目前的认知中一个好的程序员应该是什么样的。

职业生涯

要有自己的主张

我经常听到一些程序员抱怨自己的职业生涯毫无起色,或者在工作了几年之后就担忧自己遇到了瓶颈。其实,造成这些的原因往往是他们已经习惯了听命于人,而缺少自己的观点和主张,久而久之便成了那个在他人眼中可有可无的平庸之人。你不妨也学一学我的那位美国同事,选择合适的时机去表现自己,建立个人权威,这能让其他人看到你的不同之处,并为你在公司或团队内部构建起良好的影响力。当然,这一切的前提是你通过不断努力积累了自己的实力,并在恰当的时候去展现它。

尤其是从学生时代过来不久的我们,很容易会习惯于接受任务然后去完成任务。还有一些人即使脱离了学生时代已久却仍旧有着这最有可能被认为是“学生思维”的思维方式。要想获得成长,我们就不能永远只被推着走,站在原地抱怨没有好的机会来成长也于事无补。举个例子,身为一个前端工程师,大家基本都有过开发后台系统的经验,这种工作在大家看来往往是枯燥无趣的,没有什么好的成长。时间长了会让人觉得自己成了“码农”。我承认有些工作内容是更有趣的,也更具成长性的(但是这样的工作也不会让不“主动”的人来完成)。但是开发后台系统真的不能获得好的成长吗?

答案是否。例如,后台系统一般就是 PC 端的 Web 应用,而现在多使用 SPA 的方式进行开发。我就以熟悉的 React 为例,在使用 React 开发一个复杂的中后台 SPA 时我们多会使用一些状态管理的库,因为其中会涉及到数据在多个页面间的共享以及在一个页面中会对数据有较多的操作和处理。这其中会有 domain state 如何设计比较好的问题:

  • 哪些状态需要放在状态管理工具提供的 store
  • 放在 store 中的数据应该如何以什么样的结构存储比较好
  • 共享的数据放在 store 中是否会导致占用内存过多
  • 选用什么状态管理库,比较主流的是reduxdva 我也归于 redux 系) 和 mobx
  • ……

能够考虑的问题很多,明确 domain state 的定义就很重要,不少人应该不一定清楚这个词是什么意思。对于数据在客户端的存储也有一些“优化”的方案,例如 normalizr。你需要明白这种方案产生的原因,能够解决什么样的问题,是否会引入新的问题,要如何权衡。其中“全局共享的状态是否会导致内存占用过多”这个问题就有人做过详细的研究。如果想要真正理解 mobxredux 的运作机制,免不得阅读他们的源代码。其中 mobx 的实现方式以及运作方式更加复杂,想要理解会有些难度。状态管理这个坑有点大,就不过于展开了。我想说明的是实现业务需求之外还有很多问题可以思考和改进,并不想我们所认为的没有机会成长,即使业务需求不需要,你仍然能够在闲暇时间慢慢研究。我经历过这个过程,所以我是不信服没有机会成长的。即使是业务需求,有些需求也不全然合理,我们要学会甄别,有些问题和改进只有从工程师的角度才能了解和获得解决。

有时候环境没有提供成长的条件,我们要么改变环境(换个工作),要么自己创造条件(自己找问题)。但是无论是否改变环境,成长永远需要自己来主动。

对待薪酬的态度

你的薪酬其实取决于很多因素,技术能力、经验资历、工作量等,但最本质的却是,你对公司是否重要,换句话说你是否容易被取代。公司很容易找到一个和你差不多的应届毕业生,而那些对公司产品非常熟悉,并且起到关键作用的老员工,要想替代他们,公司所需要付出的代价及需要承担的风险就会高得多。

如果对薪酬有不满意之处,根据上述描述以及结合自身的期望来权衡下自己的不满意是否是合理的,是否能够有办法解决。有可能是你确实能够找到一份更好的工作,也有可能是你发现当下确实符合你的能力,暂时并无更好的选择。无论是哪个决定,都需要仔细考虑,不能仅凭借自己的感觉来下定论。

专注和深入本质

经常有年轻程序员朋友向我诉说他们所遇到的一些困惑,比如,觉得自己在工作中用到的技术太旧了,询问是否应该转向其他技术甚至转行;或是对公司里做的项目不感兴趣,觉得没有前途,是否应该跳槽,等等。我当然会鼓励他们去学习更多不同的东西,但同时我也会提醒他们,技术深度及完整项目经验的重要性,如果你总是在跟随那些新出现的技术和框架,那你很难在某一项技术上达到理想的深度;同样,在一个公司里,如果你总是在更换项目,那你也很难提升自己的价值。参与10个项目,不如完整参与一个项目。持续做一件事是要你把每一件事做透、做好,而不是蜻蜓点水,浅尝辄止。

无论选用什么框架和工具,reactvuemobxreduxwebpackparcel……换来换去,他们的实现思路可能不同,但是解决的问题是差不多的,落到细节处终归是相似的。如果只是图新鲜,一个换一个的用,那么终究只是熟读或背下了每个工具的接口文档。工具常有更新,大版本的升级更是可能接口以及内部实现原理均发生变化,此时你的经验就变得一文不值了,你的价值随着一次升级就锁了水。虽然我没法做到阅读每一个库的代码以及熟悉他们的实现原理,但是有些部分的原理是大致了解过的,且我知道最重要的是学习他们设计一个库的思路,如何根据问题想出解决方案。我知道要向着这个方向走,我不需要了解每一个,我只需要挑一个我经常使用的,能够大致理解,且也有自信给我一定的时间我也能弄清楚它的所有细节。这也是大家应该具备或学习的思想。

协作能够拓展影响力

如果你真的希望做出一些具有影响力的东西,那么光靠个人是很难实现的。你需要和团队中不同角色的人进行合作,有时候你需要说服别人,有时候你则会被别人说服。在这期间,你可能会因为被否定,而受到挫折,这种感受容易让程序员们产生挫败感,但这却是你成长的机会。不要总是单打独斗,要学会在团队中协作,并尽可能让优秀的人围绕在你身边,这将扩展你的能力范围,让你变得更加强大。

有些优秀的程序员能够凭一人之力优秀地完成工作或是个人作品,能力是值得肯定的。但是一个人的能力终究有限,有些事情一个人能做好,可能也只是在你个人(不经过他人协助)所能影响的范围中做到了最好。有些人可能会反对了,例如 HomebrewVue 起初都是一个人完成的,且影响到了世界各地的许多开发者。但是在我看来这还是不同的。这样的工具影响力如此大是因为它影响的是整个开发者社区,影响的人很多,但是它终究影响的只是开发者或者 Web 开发者,且作者的产出是开发工具。但是公司的项目不同,一个项目中有多种不同的角色,每种角色人数不会很多,都是为了产出一个产品(对用户来说可能就是个手机应用),且各项目之间相互比较独立。

如果要解决某个业务问题,其中你可能为了这个业务实现了一个十分强大的开发者工具或者工具包,那么你尽你所能你能影响的仅是和你参与开发同一个项目的同事,你不会影响到产品经理,也大概率不会影响到不同工种的开发者。你对业务的产品开发产生了正面的影响,这是肯定的,但是也许影响没那么大。一个产品由各工种完成其各自的部分,每个人即使都做到了最好,这些部分合在一起却未必足够好。如果没有协作,各个部分粘连的部分可能会有问题,一方的实现对另一方不够友好,增大了其实现的难度,甚至可能影响了设计的合理性。

unit-test

这些问题都需要沟通,需要协调。没有人逼着你去做这些事情,你不做的话你依然可能完成你的工作,但是就是“不够好而已”。有些协作是锦上添花,但是在平时的开发工作中,有些协作是不可或缺的,例如前端工程师和设计师、前端工程是和产品经理等等。不过协作的程度总有区别,开发者应该重视协作,争取做到更好,更大的影响力的收益的不仅是公司从中受益,更是对你自身能力的肯定,且通常伴随着更多的成长机会和激励。

自我营销

大多数刚走出校门的年轻程序员们绝不会把“自我营销”作为一项自己需要具备的技能来关注和学习。他们往往一头扎进自己所热爱的某一个技术领域里,不断追求着更高的技术水平。

自我营销往往能够有效地放大你所做的努力,并且在你成功的道路上起到催化剂的作用。尽早地获得成功对于我们这一代程序员来说异常关键,因为这个世界上有许多与你一样努力的人,但有些人在最佳的时间点获得了成功,而另一些人虽然也通过努力达到了相同的能力,但错过了那个正确的时间点,从而走上了一条完全不同的道路。

在一开始的时候我一直没有把这些放在心上,我一直崇尚的是埋头学习技术,投入时间和精力一定能带来很大的成长。但是随着工作的进行,有些意外的收获让我意识到自我营销其实在我的成长中实际上起到了很大的促进作用。如果你身边的人技术都很优秀,要如何让你自己凸显而出呢?除了技术上的精进之外,自我营销也很重要。在工作中的自我营销其实就是即使你厉害,也要让他人知道你有多厉害。再高的水平,如果体现出来那么也等于没有,所以当读者如果会有“怀才不遇”的心理时请务必警惕是不是自己表现得不够好,而不是责怪同事、上级或者公司。

会写文档

很多程序员可能会有很大的热情来写代码,但是如果让他写文档的话就像是在为难,写出来的文档质量也比较差。其中的原因无非:文档是写给别人看的,对自己来说没有意义,浪费时间;文档写起来很麻烦,还不如写代码。

实际上,文档确实是写给别人看的,但也是写给自己看的。无论你当时对代码有多么了解,时间一长,做的事情多了,复杂的逻辑难免会遗忘。即使是代码注释也不一定能足够有效地帮助你理解代码,注释是块状的,是局部的,但是文档脱离于代码,是能够用于梳理设计方案以及代码逻辑的。一个项目协作的人多的时候,后来者同样需要快速地理解你的代码,优秀的文档能够帮助他们快速上手。需要写文档的地方很多:会议记录、方案评审、项目文档等等。优秀的文档能够帮助与你协作的人,他们从中受益,也建立了对你的信任和认可。

文档写起来比较烦中的一个可能性很大的实质原因是写作能力不强,一件事情自己能够理解和能够写出来让他人理解的难度是不一样的。我们的经验和知识在我们脑中是散乱分布的,文字是有前后顺序的,当写成文字时我们需要斟酌用词,切中关键的问题,建立条理清晰的结构。这些都是很难的,需要持续的锻炼和学习。

分享你的观点

在很多人看来,程序员是不需要“会讲话”的,只需要埋头写代码即可。埋头写代码是我们的本职工作之一,沟通对于我们来说同样重要,沉默的你要做到 90 分才能让人认为你是 80 分。这句话未必准确,我想说的是你做出了多少分的努力,那就展示出来,沉默地“默默贡献”无益于任何人。沟通交流就是展示的一种方式,有大致以下几种途径:

  • 公司团队内的技术分享
  • 与你的团队成员分享你看过的好文章、好点子,或者分享你自己的有趣想法
  • 和同事交流探讨一些你遇到的问题
  • ……

尝试多讲,通过创造机会多讲,你能更加好地掌握使用语言的能力,这些都是为了你能更好地、流利地表达自己的想法。

认真负责地对待工作

有的人会抱着只要完成了任务就行的心态,对很多事情都偏消极地对待。诚然公司不是你家开的,你也不是创始人、领导或者其他你认为能从公司的发展中受益的那些人,但是认真负责地对待工作同样使你自己受益。我们不一定能从我们认真负责工作的事情中收获直接的金钱,但是你能收获更多的认可和信任。当有挑战的任务或晋升来临时,在技术实力相差不大的情况下没人会愿意选择更消极对待的那个人吧?从中

持续学习

国外有一个词,叫作PKSS(PK Saturday and Sunday),也就是说在周六和周日进行比拼。爱因斯坦也曾说过:人的差别在于业余时间。特别是在当今这个竞争社会,持续学习对每一个职场人都显得尤为重要。每晚抽出两个小时,周六周日抽出4~6个小时来阅读、学习、思考或参加有意义的演讲、讨论,你会发现,坚持数月之后,你便会超过周围的人。

走出学校之后,我更加认可“终生学习”的观点。这不是句口号也不是为了让谁满意,而是为了完善和丰富我们自身,一切都是为了更好地生活。在平时的工作压力下学习时间是有限的,不得不说利用好周末的时间,腾出部分时间来持续学习是更快地成长的绝佳方法。

值得注意的是,虽然同样是利用周六周日的时间来学习,但千万别认为加班等价于学习。加班是为了完成一个既定的工作,对我们而言也就是写代码,大多数时候不需要探索新的技术知识,也无法让我们学习技术之外的知识。

个人发展

完成即是价值

在得到一个新的灵感时并打算实现时,我会有些“完美主义”,我会慢慢思考方案以及不断推翻原有的设计找到更“优良”的设计,但是时间一长,方案想得越来越多,细节考虑得越来越多,到了最后简直不敢下手了。这样的“完美主义”往往也是拖延症的代名词,要不得。从灵感到实现这一个过程,切不可贪图“完美”,有时候甚至考虑过度,将简单问题复杂化,超出了其问题本身应有的边界。MVP(Minimum Viable Product)是我们解决问题时应当放在心中的警钟。优化的空间总是很大,但是产品没有做出来,又何从优化,现实不允许这样的“完美”。

这不仅仅针对于公司内的工作,如果是自身的一些想法,无论是否和编程相关。我们都能用 MVP 提醒我们自己不要过度追求“完美”而停留在迈起第一步前。完成才是价值,后续总有时间来改进它。

信息检索

今天几乎每个程序员都知道不要重复发明轮子的道理,但问题往往是他们无法找到那个需要的轮子,或者他们无法很好地使用它们。

这反映了信息检索能力的缺失,信息检索能力不够有很多原因:

  • 掌握的搜索工具或者搜索方式优先,例如查资料只知道百度,或者即使用 Google 但是不知道如何更精确的搜索;或者局限于中文资料,其实英文资料更多
  • 不能提炼出所需要查找信息的关键词,关键词找得对事半功倍
  • 不够有耐心花时间,这是我认为的主要原因,因为只要有耐心不断尝试,前面的几点都能慢慢积累和训练出来

我们可能每天都在解决没遇到过的问题,信息检索能力强意味着我们能更好地解决问题,更快地获得所需要的知识。

热情

有很多因素会使一名程序员走向平庸,而最最直接的便是失去对编程的热情和兴趣。当一名程序员不再能够感受编程所能带来的乐趣时,编程对他来说,只是一项不得不去完成的工作,而他也将失去继续学习的动力,无法再与优秀沾边了。

兴趣在大多数时候看来就是当你做好了一件事情时得来的成就感会带来喜悦和自信,从而在喜悦和自信的驱使下,你会更加愿意做这件事情。所以兴趣的开始都需要一份些许迷茫的坚持。乐趣是能够培养的,不完全是所谓“天生”的。乐趣来自于成就感带来的喜悦情绪,更多的学习和训练能带来成长,能让你更易于完成编程任务,从而收获成就感带来的喜悦。为了维持这份有趣的成就感,我们需要不断地找到一些有意思的事情来做,可以实现一些自己的小创意以及不断地完成一些小的挑战。反过来这些也会帮助你有热情地享受编程、享受成长,这都是相辅相成的。

不仅是经验,更是判断力

同样的,在编程领域,专家与普通人的区别也在于是否能够更好地解决问题,而解决问题的关键又在于程序员身上的敏锐觉察力。我们平时的学习、实践并不仅仅是为了积累所谓的经验,更重要的是培养自己独特的觉察力。

以招聘为例,我们当然会希望招到更加有经验的人。但是大家也不要对经验有所误会,这个经验不仅仅是你熟练或者精通编程语言和框架的使用,实际上是解决问题的经验。框架不停在变化,甚至编程语言及其生态都在不停变化,许多经验最终都会变得过时。这个经验应该是你积攒出当面对新的问题时,如何思考分析问题找到解决问题的关键?如何将借鉴已有的解决方案“因地制宜”地来解决面对的问题?如何获取尚不具备的知识来解决问题?是否足够有效地执行解决方案?等等诸如此类的问题。常有人戏说“一年经验当三年使”,一方面是没有进行新的学习,另一方面就是因为习得的经验流于表面,没有收获到解决问题的经验,而只是如何写某段代码的经验。

所以在工作和学习中我们要注意把握问题的本质,凡是多想几步,反思和总结总是必要的。所谓的判断力在我看来也就是编程经验带来的对编程相关领域系统和全面的认识,将所学知识应用并将其串联后,我们能够做到举一反三。这就是所谓的觉察力。我们不仅是为了收获当下解决某个问题的经验,也是为了收获到下次遇到新问题时如何判断问题并解决的能力

技术只是人生的一部分

我常会和身边的年轻程序员说,那些正在做的工作以及所钻研的技术可能都不是你们存在的真正意义,只有生活才是。而我们的修养也绝不在于掌握了哪些链接库,或理解一些Windows底层的编译原理,反而应该多在生活中做学问,培养些兴趣爱好,懂得去欣赏、体验与实践“美”(那些美好的事物)。之所以我会这样说,是因为看到了太多程序员在年轻时还能用技术去填满自己的生活,然而随着年龄的增长,在遇到一些不可避免的现实之后,就渐渐迷失了前进的方向,这时候才发现自己脑袋里除了一些已经快要过时的技术外便空空如也,便会感觉迷茫、无助,也只得浑浑噩噩、迷迷糊糊地去度过一生,这样岂不可惜?

这对于许多“有上进心”的同学来说可能是个问题。我们或是焦虑、渴望成长,或是真的热爱技术享受编程,但是无论是哪一条,过犹不及。生活是一张很大的画纸,我们何难用一种色彩来画出一幅漂亮的好画。技术不是全部,即使再渴望技术的成长也不能忘记这一点。换句话说,事情都有轻重缓急,如果技术当下对你很重要,技术可以占据暂时的绝大部分,但是绝不能是我们人生的全部,其他的人和事都需要认真对待。

建立个人品牌

好的个人品牌的在早期就能够让他人建立对你的信任以及认可你。对个人来说,无论是求职、工作外的第二份收入都有很大的促进作用。说到这个,我非常想提到一位我很钦佩的国外开发者 Kent C. Dodds。我了解到的他大概有以下这些成就:

  • 在 PayPal 有一份很好的远程工作机会,工作范围大致是偏基础架构性质的工具开发
  • 每周都会定期为订阅用户发出一封订阅邮件:大致是一篇文章,内容涉及到职业生涯、技术、工具类内容,以及最近一周内的精选 twitter、网站、文章等链接
  • 在 egghead.io、frontendmasters.com 等视频课程网站上录制教小学视频
  • 在 youtube 上发布 Dev Tips With Kent 系列视频分享技术经验
  • 参加了许多线下和线上的演讲
  • 开放 AMA,接受读者的各种问题并给予回答
  • 积极参与开源项目,有许多著名的个人开源项目以及参与了许多开源项目,更是在测试方面有很深厚的经验
  • 在 twitter 中也积极回答问题、分享知识以及和他人沟通
  • ……

现在他离开了 PayPal 的工作,作为一个自由职业者,凭借着以上的这些优质的内容和成就积攒了许多关注者全心关注于教学相关的工作。我相信这即是他喜欢的工作也是能有比较丰厚回报的工作。

我不是很想清晰地(也很难)定义出个人品牌是什么以及有哪些作用。但是冒昧地以 Kent 为例,从他的这一部分职业生涯来看,他显示是有着自己的个人品牌,所做的很多事情,例如开源、博客、教学视频等等也促进了个人影响力的构建,反过来也促进了他职业生涯中的选择。他有了选择的空间,并且所做的事情的效果在应影响力下似乎也被放大了。

个人在技术上的精进很重要,但是个人品牌就像是个放大器,其作用好比就是我做到了 1,但是收获的是 2、5、10 或许更多。如果有兴趣的读者可以关注下 Kent C. Dodds,我们未必能够按照他们的轨迹走,但也许你会从这些“大牛”的经历中有所感悟和收获。

博客是思考的一种方式

每个程序员都可以写出优秀的技术博客,即使现在它还不是那么受到关注,但写作本身依然是一件非常有意义的事情,它将使你变得更加勤于思考,思维也将变得更加成熟与完善。同时,你也会为自己用心写出的每一篇文章感到骄傲,并从中获得信心。

因为书写需要将脑中的知识或想法转换成清晰且利于理解的文字,这需要我们思考或提炼,在这个过程中我们会纠正和完善平时不会注意到的细节。这既是对思维的锻炼也是对自己的一次认真审视。

《暗时间》中的一个类似观点也令我影响深刻,大致意思是:人脑的思考深度是有限的,只将思考过程放在脑中,难以进行更加复杂和需要更多上下文的思考。当书写时,思考过程记录在纸上,我们能够释放大脑的思考空间,从而腾出空间来进行更加复杂和深入的思考。

博客能够作为建立个人品牌的一种方式,但希望我们更多地将其作为自己回顾和总结的方式。写博客很容易成为一件想做却懒得做的事情,但是我越发感受到我需要一个机会来总结和反思,在过年的时候脱离了工作环境,也不学多少东西,只是静下来思考却让我收获了许多。我剖析了自己的确定啊

编程思维

既然要提到编程思维,那么我们就从结果的角度来认识下编程是什么。编程即编写程序,而程序是用来解决问题的,在我看来,一般无非两种问题:

  • 人力不能解决的问题。对精度和计算有较高的要求,无法人力为之。
  • 人力能够达到,但是效率不够高。即让能够做到的事情变得更加容易和快速的完成。

而编程思维也就是我们在编写这两种程序解决相应问题时的思维过程和心理活动。简而言之,能帮助到我们解决这两种问题的思维方式和过程就是编程思维。

解决人力所不能解决的问题

其中解决不能解决的问题很好理解,例如你有一张照片,你希望对照片做些个性化的处理,你找不到满意的软件,但是你能够通过相关知识编写自己的图像处理程序来处理你的图片。毕竟除了软件,人力可没法一个像素一个像素地修改图片并产生期望的效果。

举个例子,有位设计师

喜欢和擅长”偷懒“。

我们身为一个程序员,按照公司的需求来解决了许多的问题,提高了很多的效率,我们应该培养出一种意识:能够意识到一些事情是重复性的,即使再简单的事情重复得多了也会耗费相当的精力和时间;当面对一个频繁出现的重复问题的时候,会主动思考是否通过自动化的方式(程序)来解决它。所以”勤快“的人可能不会意识到重复的劳动是烦人的。其实这就是编程思维的一部分,我们能够以自动化的方式解决我们的问题,节省时间和精力。


Jianhua Cheng

Written by Jianhua Cheng who lives and works in Shanghai. Try to build something more attractive and interesting. You can follow him on Twitter, Github