本系列共 5 篇,通译自:97-things-every-x-should-know
License:由 CC BY-SA 3.0 获得许可;
欢迎点赞、收藏、评论~ O(∩_∩)O
- 本瓜并未逐字逐句翻译,而是取其精要、理解抽象,结合自身进行撰文表达,与各位看官分享。认知好的编程概念,走向优秀~
技术负债
咱们程序员在接到需求初期,是没办法对整个需求作完全正确评估的!(本瓜以为,由产品需求到技术落地是有着天然的鸿沟的)所以,多数情况下,我们都会在代码迭代过程中面对之前未预想到的问题。
这种情况下,往往就会面临 “快速实现” 和 “正确实现” 的抉择!
快速实现 很具有诱惑性,它可以快速响应产品或客户的要求!但它极有可能造成代码杂乱(由于初期设计不足)。
你可能会安慰自己:“没事,先实现它,后面有空再来优化吧~”
苍天知道这个“有空”是什么时候?!功能要一版接着一版的发,时间也一天接着一天的流逝,你的承诺 —— “有空优化” 最终会演变成为一种 技术负债!
当技术负债越来越多、越来越久,我们的代码也将不可避免的走向一条不归路 —— 代码 💩 山!
所以,承诺了要优化的代码,就得尽快了!技术负债是会产生利息的!
函数式编程
近来,函数式编程在主流编程社区越来越火!
掌握【函数式编程范式】可以大大提高您的代码质量。深入理解并应用它,您的设计将表现出更高程度的 referential transparency(如纯函数)。
函数几乎不出现副作用,这是非常重要的!命令式代码最大的缺陷之一就是变量的赋值和引用混乱,你想要将它完全拎清楚,要付出极大的代价。
函数式编程设计通常会将责任分配给更多、更小的函数!这些函数之间的参数传递十分明确,而不会出现随意引用外部可变变量。这样更便于调试、也降低了可变变量引用赋值混乱的缺陷;
我们期待函数式编程有更多展现!有人断言,函数式编程和面向对象编程互相映射,犹如太极中的阴、阳。
观察用户
我们都倾向于假设其他人的想法和我们一样,但事实并不如此!心理学家称之为:错误共识效应。
这个现象解释了用户和程序员之间的距离。用户不会考虑计算机工作原理、计算时间、技术模型......
了解用户的最好方式就是 观察用户。花一个小时观察用户所想比花一天时间猜测用户所想更具有效果!
前文也提过:从业务需求到技术落地之间是有天然鸿沟的,想要填平这道沟,程序员得学着去观察需求!观察得同时,不断问自己:他/她为什么要这么做?这比花大量时间猜测更符合解决问题的方法论!
自动化编码标准
每个项目都有项目规范、编码标准,我们期望通过它们来约束、规范开发者的编码行为。但是最终交付的时候,往往又是一团糟。为什么?
原因有很多,可能是有人没听清、也可能是不完全明白、也可能是不同意、也可能是同意但由于很难实践最终选择放弃......所以,如果不能将编码标准自动化,那么这种约束将很难进行!
实际上,我们有大量工具可用于生成代码质量报告,以及记录和维护编码标准。在可能的情况下,它还会自动化格式代码并强制校验。
我们要确保代码格式化是项目构建的一部分,每次编译代码时,都会运行它;使用静态代码分析工具扫描代码,找到冗余或错误代码;学习配置一些自动化扫描工具,测试代码、检查代码;
这些行为应该是不断更新、补充完善的,随着项目的迭代而改进。
编程简单即美
所有开发者都应该记住:
Beauty of style and harmony and grace and good rhythm depends on simplicity. — Plato (简单即美)
什么是漂亮的代码?这可能是一个非常主观的问题。学人文艺术的人对美的看法,与学科学技术的人不一样。但是 简单 是大多数论点的基础。
我们的代码需要实现:
- 可读;
- 可维护;
- 快速开发;
- 保持简单;
你可以通过阅读源码来发现其中奥妙~无论应用程序或系统有多复杂,但各部分都应保持简单!它们有着集中的方法、单一的职责。
干净、简单、可测试的代码可以保障系统随着时间推移也有很强的可维护性,从而也可以保持较快的开发速度。再次声明:简单即美!
重构要则
几乎每个程序员都要重构现有代码,在你重构之前,建议你阅读以下几点:
- 重构第一步就是 评估 现有代码和编写的测试,这能帮助你理解现有代码的优缺点,然后保留优点,避免缺点。如果重构后的代码比原有代码更加糟糕,那这一步一定没有做充分;
- 重构 不代表 重写所有!无论之前的代码有多丑陋,你完全扔掉它,这绝不是一个明智之举。因为你扔掉是几个月(或几年)通过测试,久经沙场的代码。其中可能存在你还不知道的方法或 bug 修复逻辑。全新代码可能出现一样的神秘错误,这会消耗大量时间和精力!
- 不断 小规模 的重构比一次大规模的重构要好!这也可以称之为渐进式重构代码。大规模重构如果遇到棘手问题可能会让人倍感压力,甚至崩溃,这一点不开玩笑。
- 每次重构迭代后,都要确保 测试通过。这是十分重要的!如果现有测试场景不足以覆盖您所做的更改,请添加新测试。不要在还没考虑清楚时丢弃到旧代码中的测试用例。
- 你 不喜欢 旧代码的风格或结构不能成为你重构代码的正当理由!个人喜好总是会变的,个人喜好也不一定会被他人喜好。
- 采用 新技术 也不是重构的充分理由!除非成本效益分析表明新语言或框架会在功能、可维护性或生产力方面带来显著改进,否则最好保持原样。
- 记住:重构 并不能 总是保证新代码会更好!
小心复用
系统的两个截然不同的部分以相同的方式执行某些逻辑,你可能会想到写一个公共库,然后进行复用。老师都是这么教的!代码复用、组件复用、公共库复用 balabala ......
但实际上,这两个部分往往还会变化出不同的业务,这样复用就变成耦合了。依赖项增加,使得系统的脉络纠缠在一起。
实战也表明:技术的使用应该基于背景,否则产生的将不是价值,而是额外的成本。
不管是用别人的库,还是你把库分享给别人,都得小心些。
童子军规则
童子军有这样一条军规:“始终让露营地比你发现它时更干净”!英国童军总会总领袖 Robert Stephenson Smyth Baden-Powell 这样说的初衷是:试着让这个世界比你发现的更好一点。
我们在代码开发过程中也应当遵循这个规则!如果大家都遵循这个简单的规则,代码最终沦为屎山的命运将被总结。
在编程中留下一团糟的代码,无异于露营中留下一堆垃圾,这是大家都不能接受的!这更像是一个普遍的社会规则。
优先自我检查
排查问题时,我们会怀疑编译器、解释器、操作系统、应用服务器、数据库、内存管理器是否出了问题,但事实证明它们出错非常非常少见。
假设这些工具被广泛使用,并且已发展足够成熟,你没理由去怀疑:是因为它们的错误导致了你这次错误。
定位问题时,请优先自我检查!
福尔摩斯说过:排除所有可能,剩下的,无论多么不可能,它就是真相!
善其事 利其器
工欲善其事必先利其器,是亘古未变的道理。
开发时选择好的工具非常重要!这里主要指组件、第三方库、框架等等。
它们能带来很多便利:
- 基础的代码可有工具构建;
- 使用组件、框架出错的情况比自己写更小;
- 高质量的库是由高质量的开发在维护的,专业的事交给专业的人去做;
- 可以考虑购买一些工具来提升你的开发效率;
你需要注意的事:
- 弄清工具接口说明,它的模型、协议等是否和你的项目匹配?
- 减少工具的配置,如果它配置非常复杂,可能导致难以维护和扩展!
- 注意许可条款,使用版权问题;
- 注意收费问题,有些工具是局部1范围内免费、局部范围内又收费;
明确类型定义
曾几何时,我们只有非常基本的数据结构:位、字节和字符。后来发展形成了堆栈、队列、散列、链表等。“计算机科学”花费大量精力将现实世界映射到我们的具有限制性数据结构中。
请准确清晰地定义代码的类型。明确表示出来,让下一个人也知道。
同时,明确类型定义利于你以后的代码封装。
编程即设计
设想一下:一觉醒来,建筑行业发生了惊天巨变,生产材料可以凭空产生,并可以由机器人完成建设。
这样一来,设计成本大于施工成本。一家能快速完成设计的公司将在市场上占据优势。
如果建筑工程除了问题,我们只需重新再设计、或者进行修补,因为生产材料没什么成本。建筑质量开始变得糟糕起来,由一次次不完整的设计引起。
这种对建筑行业的漫谈,却实实在在发生在软件行业。我们能快速开发一个项目,不行马上就丢弃。然后再快速开发一个......
设计是一个创造性的工作而非机械性的工作。
编程是设计,开发成本不大,设计成本是更重要的。
规范代码格式
有研究表明:开发人员花了相当一部分时间在寻找“在哪里进行修改”这个问题的答案。
所以,我们需要重视规范代码格式。这样利于我们快速扫描代码,定位问题位置。
代码布局应该是紧凑的、风格一致的、清晰可见的。
有非编程专业的人说:代码有时看起来像诗歌。
真正规范的代码正是这样!既是是一个非专业的人也能感受它的美~
自主 CodeReview
我们应该一致保持 CodeReview 的习惯,它能提高代码质量,降低错误率。
可能我们在 CodeReview 时有过不好的回忆(菜鸟在初始都被吊着打过),许多开发往往不喜欢它。有些公司会有专门的人来做 CodeReview 审查,开发者必须遵守审查者的规则。这样多数偏于严格和正式。其实,这样的方式反而南辕北辙。审查者需要花费时间去了解很多代码细节,这会是一个巨大的瓶颈。
CodeReview 如果能自发,大家共同建立和维护编码指南,会更有效果!寻找错误不是目的,寻找好的编码方法才是目的。因此,做 CodeReview 时,大家最好都是温和的。约定每周或每月来一起建设。
让 CodeReview 变得有趣是关键!如此不仅能优化代码,还能团结团队,共同进步。
给出编码理由
我们应该仔细考虑每个块级代码的正确性,并给出能够说服自己为什么要这样写的理由。
对于条件判断、循环、类的使用、函数的使用等都能给出至少简单的逻辑上的理由。
比如:
- 避免使用 goto 语句,因为它们会导致与远端的耦合;
- 避免使用可修改的全局变量,因为它会导致各部分产生依赖;
- 每个变量都应该有尽可能小的作用域,因为这样不影响外界变量;
- 如果您需要使用嵌套,请将其封装为函数,因为这样代码会更清晰;
- 函数的入参最好不超过 4 个,这样可以减少变量引用赋值找寻时间;
- ......
我们需要养成这样的好习惯 —— 不断推理出“代码为什么这样写的理由”!
这会让你受益无穷!
不断注释
代码注释是非常重要的一块!
作者曾因为在学校的编程测验中代码没写注释而被评低分。
注释本身没有恶意,它们与基本的分支判断或循环结构一样,都是编程所必备。
本瓜之前写过一篇《花五分钟把代码注释也规范一哈子?》,里面有具体介绍注释的相关细则,感兴趣的同学可前往阅读。
当我们阅读别人的代码,往往是先看注释。所以,养成不断维护注释的习惯,能让你的代码走的更远~
有效注释
什么是有效的注释呢?
注释能够表达代码以外的东西,解释代码不能解释的。
还有一种书说法是:代码即注释,优先考虑将你想说的用代码表达出来。
- 注释应当简短、清晰;
- 告诉大家你“为什么”写这个注释,而不是告诉大家这段代码 “是什么” ! “是什么”应该交给代码本身去解释;
- 保持你的注释持久维护,记得及时更新和与代码匹配;
持续学习
随着编程这份工作越来越普及,有一天你也许不会再被需要。你的工作将被取代。你会怎么办呢?
持续学习可能是帮助你的答案之一,这里有一些建议:
- 阅读书籍、杂志、博客、维基百科、和好的学习网站;
- 如果你真的想沉浸在一项技术中,那就动手写一些代码;
- 向身边厉害的人学习,你能从他们那学到更多;
- 订阅一些好的网络博客;
- 深入了解你使用的框架和库,你会发现它们的过人之处;
- 认真的修复问题,记录它们、分享它们;
- 跟别人谈论技术、或者教别人技术,这会帮你你的理解;
- 加入学习兴趣小组;
- 学习 The Pragmatic Programmers,扩展技术栈;
- 提高学习效率,讲究学习方法论;
- 回到学校;
- ......
编程技术更新很快,别掉队!
方便不是标准
我们可能为了方便临时做一些 API 设计,这样导致的问题很多;
作者举了个例子:
- 他不希望其他类必须进行两个单独的调用来完成这件事。
- 如果和这个方法几乎一样,我为什么要制作另一种方法?为什么不写一个判断开关来实现?
- ......
这样考虑的确目的明确,但是会降低 API 的可读性;
API 设计应该有更好的一种策略(比如:用多样化的此词汇进行表达),而非是以“方便”来作为标准。
记住:没有一个英文单词长这样,所以也请别设计出这样的 API,即使它看起来“更方便”~
MakeUpYourRoomBeQuietAndDoYourHomeWork
提早部署
我们通常会在项目尾期进行部署操作,但是部署却是需求方第一时间想看到的事情。
如果把部署放在后面,会出现要去适配代码中对环境的假设等等情况,整个过程将更加复杂化。
提早部署,提高可见,提早可用,完成比完美更重要。
这也是团队生产力的重要体现。
OK,以上便是系列第 1 篇分享(共5篇),关注专栏,系列持续追踪~
我是掘进安东尼,输出暴露输入,技术洞见生活,下次再会~