作者|朱雷
规划|蒂娜
2020年,我在公司群里做了一个分享。当时PPT题目是《编程十年的十点感悟》。内网分享资料后,有同事看到,评论说看PPT不够。希望能扩展成文章,我回复说没问题。如今三年过去了,我终于兑现了我的承诺。在当时PPT的最后一页,我用纯白背景加粗的给了一行字:“十年很短,编程很难”。现在,第二个十年已经快过半,这句话的后半部分似乎依然适用于我。
很多年前,我还是学生的时候,偶尔会点开一些招聘“高级工程师”的帖子。在这些岗位中,写了令人眼花缭乱的专业术语,但让我印象最深的是经常出现在第一线的岗位生活要求:“本岗位要求5年以上工作经验”。作为一个整天没上班的菜鸟,这几年在我眼里简直就是夸张。不过,除了望洋兴叹,我有时候也会在心里暗暗期待:“一个有五年工作经验的程序员有多牛逼?”对他们来说写代码就像吃饭一样简单吗?”
时光飞逝,十几年过去了。现在回想起来,我已经成为一名有着14年工作经验的光荣农民工。在软件开发行业摸爬滚打多年后,我发现了很多和我大四时想象的大相径庭的东西,比如:
随着经验增长,编程并不会变简单太多,“像吃饭一样简单”只出现在梦里给许多“大项目”写代码不光没意思,还很危险,远不如在 LeetCode 上做一道算法题有趣只从技术角度思考问题,成不了好程序员,有些东西远比技术更重要
想起来,对编程有很多这样的感受。我整理了其中的八个,写了这篇文章。如果这些想法有一部分能引起你的共鸣,我会很高兴。
1. 写代码很简单,但写好代码很难
编程曾经是一个门槛很高的专业技能。曾几何时,一个普通人学习编程最常见的方式就是通过课本和书籍。但是大部分编程书都很难,晦涩难懂,对初学者很不友好。所以很多人还没尝到编程的乐趣就提前半途而废了。
但是现在学习编程越来越容易了。学习不再像以前,只能死记硬背,而是有了很多新的方式。看教学视频,在Codecademy上一门互动课程,甚至直接在CodeCombat打游戏学习编程,每个人都能找到自己的学习方式。
“妈妈,我真的不是在玩游戏,我是在学编程!看屏幕右边!”
此外,编程语言变得越来越容易使用。经典的C和Ja已经不是大多数初学者的首选。现在流行很多更简单易用的动态类型语言,相关的IDE等工具也越来越完善。这些因素进一步降低了编程的学习门槛。
总之,编程早已褪去了它的神秘,从一门只有少数人才能掌握的神秘技能,变成了一门人人都能学会的普通手艺。
但是更低的学习门槛,更友好的编程语言,并不意味着每个人都能写出好的代码。如果你曾经工作和参与过一些项目,我想问你一个问题:“你日常接触的这些项目的代码质量如何?”好代码多还是坏代码多?”
我不知道你的答案会是什么。先说说我的回答。
好代码还是很少
2010年,我跳槽到一家总部在北京五道口的大型互联网公司。
在加入这家公司之前,我只在一个十个人的小公司呆过,所以我对新公司各方面都有很高的期望,尤其是软件质量。当时我是这样想的:“这是一个‘大’项目,支撑着几千万用户的产品。和之前的那些相比,代码质量肯定有质的飞跃!”
直到在新公司工作了一个星期,我才意识到自己真的错了。所谓的“大”项目的代码质量与我的预期相差甚远。打开IDE,上百行的函数和神秘的数字无处不在,任何一个小需求都很难开发。
后来在更多的公司呆过,接触过更多的软件项目,我总结出一个道理:不管公司有多大,项目有多少,在实际工作中遇到好代码还是小概率事件。
好代码有哪些要素?
总之,什么样的代码才是好代码呢?在这方面,马丁·福勒有一句话经常被大家引用:
“任何傻瓜都能写出计算机能理解的代码。优秀的程序员会写出人类能理解的代码。”
“任何傻瓜都能写出计算机能理解的代码。优秀的程序员写出人类能理解的代码。”
我觉得可以把它作为评价好代码的原点:好代码一定是可读的,易读的,易懂的。写好代码的首要原则是把人类读者放在第一位。
除了可读性之外,还有许多其他方面来评估代码的质量:
贴合编程语言:是否使用了当前编程语言的推荐写法?语言特性和语法糖,使用程度是否恰到好处?易于修改:代码设计是否考虑了未来的需求变更,当变化发生时,代码是否容易随之修改?API 设计合理:API 设计是否合理,易于使用?好的 API 在简单场景下使用方便,在高级场景下又可以随需求扩展。性能够用:代码性能是否满足当前业务需求,同时为未来保留了一定提升空间?避免过度设计:代码是否存在过度设计、过早优化的毛病?…
总之,好的代码不是任何级别的程序员都能得到的。要写出好的代码,需要在多个维度反复权衡,精心设计,最后不断打磨。
这种情况下,想尽快掌握写代码的技巧,有没有捷径?
写好代码的捷径
在很多层面上,我觉得编程和写作很像。两者都使用文字和符号来表达思想,但方式略有不同。
说到写作,我想问一个关于作家的问题:“你听说过不读书的作家吗?”你听过一个作家说他从来不看别人的作品,只看自己的吗?” .我猜答案应该是否定的。
如果你查阅相关资料,你会发现很多职业写手的日常生活就是不断的阅读和写作的循环。他们每天花大量的时间阅读各种单词,然后再写作。
作为“作家”,程序员很少关注阅读。但如果想快速提高编程能力,阅读是必不可少的一部分。除了日常工作中接触到的项目,还要多读那些经典的软件项目,学习API设计、模块架构、代码编写的技巧。
不仅仅是代码和技术文档,还不如定期看一些电脑上的专业书籍,保持看书的习惯。在这方面,我认为杰夫·阿特伍德15年前写的文章& # 34;程序员不& # 39;不看书——但你应该(据说程序员不看书——但你应该)& # 34;时至今日,读书依然过时。
提高编程能力的捷径在于“阅读”
“一个好的程序员应该怎么做?”
2. 编程的精髓是“创造”
在程序员的日常工作中,有很多事情会让人很有成就感,甚至会忍不住感叹“编程真奇妙”。比如修复一个极难定位的Bug,用新的算法让代码性能翻倍等等。但在所有这些东西中,没有什么能和“亲手创造东西”相提并论。
当你在编程时,创造新事物的机会实际上无处不在。因为不仅仅是一个新软件的发布就可以称之为“创造”。编写一个可重用的工具函数,设计一个清晰的数据模型,都可以归入“创造”的范畴。
作为一个程序员,对“创造”保持一份是非常重要的。因为它可以帮助我们:
更高效地学习:学习一门新技术,最高效的方式就是用它开发一个真实项目,在创造的过程中学习,效果最好。有机会邂逅了不起的东西: 许多改变世界的开源软件,最初都是作者纯粹出于兴趣所创造,比如 Linus Torvalds 和 Linux,Guido van Rossum 和 Python。
1989年圣诞节期间,荷兰人吉多·范·罗苏姆敲出了Python语言的前几行。Python原本有望成为ABC语言的继承者,后来却“吞噬”了整个世界。
虽然“创造”有很多好处,程序员也有很多机会去做,但很多人往往缺乏一种“创造者”的意识。据说,一位哲学家问正在砌砖的工人。有的人明明知道自己在建大教堂,有的人却以为自己只是在砌砖。很多程序员只是“见砖不见教堂”。
把自己定位为创作者后,看待事物的方式会发生巨大的变化。比如,通过在API中加入错误提示文本,创作者可以跳出“只是快速完成需求”的思维陷阱,向前一步,问自己一些更重要的问题:“我想为用户创造什么样的产品体验?什么样的错别字能帮我达到这个目的?”
就像任何有用的编程模型一样,“创造者思维”也可以成为你职业生涯中的巨大推动力。所以,现在试着问自己一个问题——“我的下一个创作会是什么?”
3. 打造高效试错的环境至关重要
我曾经参与过一个互联网产品的开发,设计精美,功能丰富,每天都有大量用户在使用。
但就是这样一个从市场角度来看很成功的产品,工程质量却很差。如果你打开它的后端项目,把所有的目录都翻个底朝天,你就找不到任何一行单元测试代码,其他自动化测试流程也无从谈起。但是,业务逻辑非常复杂。最后,项目代码之间有太多意想不到的耦合,以至于在开发新功能时很容易挂起旧功能。
“忙什么呢?”“当我以前修复问题时,尝试修复问题。那个问题在另一个问题之前被我解决了,那个问题就是我……”
所以每次项目发布,开发和产品的同学都要准备好,气氛很紧张。整个发布过程也很刺激,紧急回滚时有发生。一个人在这样的环境下工作,不管技术成长如何,一定会得到很大的心理训练。
编程原本是一项有趣的工作,但为这样的项目编程是不可能的。是什么夺走了编程的乐趣?
理想的编程体验≈“刷题”
LeetCode是一个知名的编程学习网站,提供了很多涵盖各种难点的编程问题,其中大部分都与算法有关。用户可以选择自己感兴趣的题目,直接在浏览器(支持十几种编程语言)上写代码并执行。如果所有的测试用例都通过了,那么解决方案就被认为是成功的。
在LeetCode上做题
在LeetCode里刷题就像玩游戏,挑战性和趣味性同时存在。整个做题过程完美展现了一种理想化的编程体验:
关注点分离:每道题目都是一个独立个体,同一时间内,开发者可以完全沉浸在一道题目中;快速获得精准反馈:开发者每次调整代码后,能通过自动化测试快速获得结果反馈;零成本试错:写出的代码语法有错误、逻辑有问题,没有任何不良后果,心理负担小。
然而在屏幕前,你大概觉得我在胡说八道。
“不然呢?解算法题写小脚本不就是这样的体验吗?有什么特别值得说的?”你大概会继续补充,“你知道我们公司的项目有多复杂吗?巨大的规模,巨大的模块数量,你明白我的意思吗?每天服务××××万人,有几套光数据库,三种消息队列。当然,开发起来有点麻烦!”
的确,世界上的软件千差万别,不可能像LeetCode上刷题一样轻松愉快的开发。但这并不意味着我们不应该尝试改进我们的编程环境,即使只是一点点。
为了通过改善环境来改善编程体验,可用的概念和工具包括:
模块化思想:妥善设计项目中的每一个模块,降低耦合,提升正交性设计原则:微观层面上,应用那些经典的设计原则和模式,比如“SOLID”原则自动化测试:编写规范的单元测试,必要时使用 Mock 技术,用自动化测试覆盖业务关键路径缩短反馈回路:切换编译速度更快的工具,优化单测性能,竭尽全力缩短从“改完代码”到“获得反馈”的等待时间微服务架构:必要时,将大单体拆分为多个职责各异的微服务,分散复杂度……
注重编程环境,刻意营造一个允许高效试错的“代码天堂”,让工作像刷题一样轻松愉快。这是一个有经验的程序员能为他的团队做出的最好贡献之一。
4. 避开代码完美主义陷阱
在代码质量上力求完美是好的,但也要注意不要陷入完美主义的陷阱。因为编程不是艺术创造,不鼓励人们无限追求极致。一个作家可以花数年时间打磨一部传世佳作,但程序员陷在代码里是很成问题的。
世界上没有完美的代码。很多时候,你的代码满足当前需求,留一些空给未来扩展就够了。有几次,我看到应聘者在简历上给自己贴上“代码强迫症”的标签。隔着屏幕,虽然我能感受到TA对代码质量的重视,但在我心里,我其实更期待TA已经把完美主义陷阱远远抛在了身后。
5. 技术很重要,但“人”也许更重要
在软件开发领域,“单一责任原则”(全称是Single responsibility principle,以下简称SRP)是一个非常著名的设计原则。它的定义很简单,可以用一句话来概括:“每个软件模块应该只有一个被修改的理由”。
单一责任原则:你能做不代表你应该做。
掌握SRP原理,关键是要搞清楚“被修改的原因”是什么。显然,程序是没有生命的,它不能也不需要改变自己。任何修改程序的理由都来自于与之相关的人,人是导致修改的“罪魁祸首”。
举个简单的例子。看看下面两个类,哪个违反了SRP原则?
一个字典数据类,支持两类操作:存数据、取数据;一个员工资料类,支持两类操作:更新个人信息、渲染一张用户资料卡片图。
在大多数人看来,第一个例子没问题,但第二个例子明显违背了SRP原则。要得出这个结论,似乎不需要什么严格的分析和证明,只要用一点直觉就可以了。但如果你做一些认真的分析,第二个例子的可疑之处在于,你可以很容易地找到两种不同的修改理由:
管理员认为资料中的“个人电话”字段不能有非法号码,需增加简单的校验逻辑;某员工认为资料卡片图上的“名字”部分太小,希望加大字体。
“是人们要求变革。你不希望把许多不同的人出于不同的原因关心的代码混在一起,让那些人或你自己感到困惑。”——“单一责任原则”
“人们要求改变软件。你永远不要把不同人出于不同原因关心的代码搞混,这只会把他们和你自己搞混。”-“单一责任原则”
理解SRP原则的关键在于理解人和他们在软件开发中的角色。
再举个例子。微服务架构是近年来热门的技术话题。但是很多人在讨论的时候,往往只关注技术本身,而忽略了微服务架构与人的关系。
微服务架构风格区别于其他事物的关键在于,大单体拆分成独立的微服务后,不同模块之间的界限可以变得更加清晰。相对于几百人的团队维护一个大单位,很多小机构维护自己独立的微服务,显然运营效率更高。
没有一个具体的组织规模(也就是“人”)作为前提,空谈论微服务的各种技术优势纯属本末倒置。
技术当然很重要。作为技术人员,宏伟的架构图和独特的代码细节自然会吸引我们的注意力。但是,请不要对软件开发中的另一个重要因素“人”视而不见。如果有必要,换一个看事情的角度(从“技术”到“人”),对你大有裨益。
6. 求知若渴是好事,但也要注意方法
现在大家都在说“终身学习”,程序员是一个特别需要终身学习的职业。因为计算机技术的迭代更新非常快,一个三年前流行的框架或者编程语言,一个月前很可能就过时了。
一分钟后会发生什么?网飞观看时间增加7万小时;Snapchat上观看的视频有300万;谷歌增加了240万次搜索;发明了一个新的JS框架(这个不是真的)。
为了在工作中表现出色,程序员需要学习很多东西,涵盖各个层面。以我熟悉的后端领域为例。一名合格的后端工程师至少需要掌握以下内容:
一种或多种后端编程语言/关系数据库如MySQL/常用存储组件如Redis/设计模式/用户体验/软件工程/编译原理/操作系统/网络基础/分布式系统/…
虽然要学的东西很多,但据我观察,大部分程序员其实都是热爱学习的(至少不是排外),所以心态不是问题。但有时候,光有“求知欲”的心态是不够的。学习的时候,需要特别注意“性价比”。
关注学习性价比
下图是学习效果和敬业度的关系。
学习效率和参与度之间的关系图在水平轴上示出了学习参与度,在垂直轴上示出了学习效率。
从图中可以看出,在学习的初始阶段,投入少的时候,获得的成果增加很快。但是,当效果超过一定阈值,然后你想继续提高,所需的学习投入就会成倍增加。
正因如此,我建议大家在学习任何新东西的时候,首先要在脑子里想清楚一个问题:“上图我应该停在哪里?”而不是努力学习。
知识的海洋是无边无际的,有些东西需要我们长年累月的不断学习和提高。还有一些东西,像蜻蜓学点皮毛就绰绰有余了。准确判断和分配自己有限的学习精力,甚至比努力学习更重要。
挑选合适的学习资料
有了学习目标,接下来就是找合适的学习资料。对此,我想分享一下自己的失败经历。
有段时间突然对产品交互设计产生了兴趣,觉得自己应该在这方面有所提高。于是,我精心挑选了一本该领域非常经典的专业书籍:《关于脸4:交互设计的本质》,买回家,自信自己的交互设计能力可以快速提升。
但是事与愿违,当我捧着那本经典的书的时候,我发现我连第一章都无法顺利读完——老话说的没错:“隔行如隔山。”
从这次失败中,我总结了一点经验。就是在学习新东西的时候,我们最好选择那些可读性更强,更适合“外行”的学习资料,而不是“大眼瞪小眼”,只知道自己是冲着最经典最权威的资料去的。
回顾之前的经历,我觉得以下几本书非常适合外行人学习使用,性价比很高:
《写给大家看的设计书》:设计相关《点石成金》:Web 用户体验相关《鸟哥的Linux私房菜》:Linux 系统相关
也许每个人的内心都想成为一个博学的人,什么都懂,什么都懂。但是可利用的时间和精力总是有限的,我们不可能也不需要成为所有领域的专家。
7. 越早开始写单元测试越好
我很喜欢单元测试,我觉得写单个测试对我的编程生涯影响很大。夸张一点说,如果我以“开始写单元测试”来把我的职业生涯分成两部分,后一部分远比前一部分精彩。
写一个单独的测试有很多好处,比如它可以驱动你改进代码的设计,它可以作为代码的文档,等等。此外,完善的单元测试是构建上面提到的“高效的出错环境”的关键。
我写过几篇关于单元测试的文章,比如游戏《蓝山》教授的单元测试和编程原理的五点建议。所以在这里,我不打算重复了。就说:如果你到目前为止还没有尝试过写单元测试,或者从来没有关注过,我建议你明天就开始写。
通常,我不测试我的代码,但是如果我测试,我会在生产环境中测试。
8. 程序员最大的敌人是什么?
在大多数程序员的段子里,产品经理往往是以反派的身份出现的。他们谈的项目需求总是在变,某一天冒出一个新的想法,让程序员苦不堪言。
客户每天都在不断地修改需求,所以我们决定在下一个发布之前“冻结”这些需求。
在这几段的对比下,不断修改需求的产品经理似乎真的成了程序员最大的敌人。似乎只要产品不乱改需求,大家的工作环境很快就会变成乌托邦。
虽然偶尔吐槽一两句产品经理很有意思,但我还是想很认真的说一句:产品经理不是敌人。
因为从某种角度来说,软件生来就是要被修改的(或者猜猜软件为什么叫“软”?)。这样看来,开发软件和盖房子是完全不同的。因为没有人会在建完一栋楼之后说“我们把它拆了重建吧!”同样的建筑,但是用的钢材和水泥比以前少了30%!”
所以,产品经理和不稳定的需求不是程序员的敌人。而且,能否写出易于修改、适应变化的代码,是区别普通程序员和优秀程序员的重要标准之一。
那么,程序员最大的敌人是什么?
复杂度是最大的敌人
如代码2所说,软件开发的核心问题是管理复杂性。失控的复杂性是程序员最大的敌人。
让我们来看看导致项目越来越复杂的因素:
不断增加的新功能: 更多的功能等于更多的代码,更多的代码通常意味着更高的复杂度对高可用的需求: 为了实现高可用,消息队列等额外的技术组件和代码被引入对高性能的需求: 为了提升性能,缓存和相关模块代码被引入,部分模块被拆分后,换成高性能语言重写一再被推迟的重构:因项目排期过于紧张,迫在眉睫的重构被一再推迟,技术债越积越多忽视自动化测试: 没人写单元测试,也没人关心测试…
有一天,当项目的复杂程度增长到一定程度,就会在空中出现一声巨响。“哎!”一个所有人都不愿意也不敢改变的“大坑”以空出现在每个人的IDE里。
猜猜是谁挖的这个洞?
那些投入时间降低复杂性的团队更有可能在他们负责的软件项目中取得成功。
减缓复杂度增长的过程
尽管复杂性不可避免地会继续增加,但是有许多实践可以减缓这个过程。如果每个人都能做到以下几点,复杂度可能会长期控制在一个合理的范围内:
精通当前编程语言与工具,写整洁的代码使用合适的设计模式和编程模式对重复代码零容忍,抽象库和框架适当运用整洁架构、领域驱动设计思想编写详尽的文档和注释编写规范有效的单元测试分离那些变动的与不变的…
要求看似很多,但总结起来,核心其实就是一句话:写出更好的代码。
关于作者:
朱雷(@piglei),程序员,爱好编程、阅读和电子游戏,著有《Python工匠:案例、技能和工程实践》一书。
本文转载自:
https://www.infoq.cn/article/e084f4hdSIP0chOiYojK
免责声明:本站所有文章内容,图片,视频等均是来源于用户投稿和互联网及文摘转载整编而成,不代表本站观点,不承担相关法律责任。其著作权各归其原作者或其出版社所有。如发现本站有涉嫌抄袭侵权/违法违规的内容,侵犯到您的权益,请在线联系站长,一经查实,本站将立刻删除。