写点什么

怎样写出可读性高的代码?

  • 2021-03-29
  • 本文字数:2672 字

    阅读完需:约 9 分钟

怎样写出可读性高的代码?

清楚你的优先级

代码的写法有很多种:有的运行起来很快,有的只会占用少量内存,有的更容易测试,而有的代码则有很高的可读性。


若要编写思路清晰的代码,第一步就是要将可读性放在第一位。


这也意味着势必要降低其他因素的优先级。如果把所有因素都作为最高优先级,就意味着没有优先级。

培养清晰的意识

想要写出好代码,首先要知道什么才是好代码,想要写出思路清晰的代码,也要了解什么才是思路清晰。多阅读一些质量上乘的代码可以让我们对好代码有个大概的认知。


了解什么才是优秀代码并不能杜绝我们继续写出糟糕的代码,但至少能让我们知道代码的哪里不对劲。

修订

编写代码时,我们最初所想的思路未必清晰。在大多数情况下,只有在第一次完成代码后,我们才能找到更适合的思路。反复阅读已完成的代码才会带来更改的空间。

从解释开始

如果我们还搞不清代码结构,那么可以试着想象一下怎样向他人解释清楚或者把逻辑思路写下来,比如“如果删除账户,那么我们需要跳过 xxx。如果 xxx 的进程还没有结束,那么……”。然后把这套逻辑翻译成代码就很顺了。


写程序时,带入人类沟通方式而不是计算机中的抽象概念要更容易。

注释

代码中的注释可以解释某段代码的用处,或者是程序结构为什么要这么写。


单单是阅读程序并不会告诉我们作者所想就是正确的逻辑。里面可能会有我们不了解的商业规则:美国境外的用户有时会把街道名写到地址栏第一行的最末尾。里面也可能有一些技术小技巧:以某种奇怪的方式构造查询,从而让 Postgres 正确地优化它。诸如此类的代码细节,都是只有了解逻辑背后的背景情况下才能彻底明白为什么要这么写的。


代码不会说话。如果我们决定跳过某些步骤,但又懒得留下注释解释为什么,过两天再回来看这段代码恐怕就真没人知道你当时在想什么了。


部分代码可能读两遍就能想明白个中缘由,但为了保险起见,还是不要给自己的大脑添加不必要的负担。

不要搞混层次

不要搞混函数中的抽象层次。


这段“欢迎”代码层次混乱:


def welcome(self):  results = db.query(    'SELECT EXISTS 1 FROM emails WHERE kind = ? AND user = ?',    'welcome_email', self.user.id,  )  if results[0]:    return  self.send_welcome_email()
复制代码


这段则是相对整齐的:


def welcome(self):  if not self.has_sent_welcome_email():    self.send_welcome_email()
复制代码


函数中混乱的抽象层次会让读者思考代码用途和实现方式时被迫进行思维跳跃。当前抽象层次的代码告诉我们代码在做什么,而下一层次的代码则是关于代码要如何实现的。


在例子里的“welcome”函数中,我们首先在数据库中查询是否有过往邮件记录,如果没有则发送一封欢迎邮件。请注意,第二个版本中的“welcome”函数将查询部分放到了另一个函数中,“welcome”中仅仅关注“做什么”,这就是将函数中的抽象层次保持在了同一层,逻辑也更加清晰。不同函数分散在不同抽象层次,将较低层次的实现细节委托给较低抽象层次的函数。

分解函数

有时,分解大体积函数到子函数会更便于阅读。


对于分步骤执行的函数,将函数中的每个步骤都分解成子函数效果会更好。而对于其他如决策类的函数,不同的决策会引向不同的函数:有的部分负责制定决策,有的则是负责执行决策。分解函数的方法有很多种维度,只有通过不断的练习才能一眼看穿哪种才是正确的。


小体积函数有以下几点好处:


  • 每一部分的逻辑都有自己函数名。知道每一块逻辑负责什么更方便我们找到这些函数应当被放在哪

  • 作用域中变量更少

  • 在运行堆栈轨迹和调试时能更清晰地看出函数的作用

  • 小型函数可以被单独测试


其实,没有任何函数计算机也能运行得好好的,函数的存在只是为了服务于程序员,所以还请多多利用它们。

不要分解函数

不要重复你自己(don't repeat yourself, DRY)的意思经常被过度解读。


如今,抽取魔法数常量,以及针对某类特定决策的逻辑副本,已经算是公认的标准答案。此类重复的代码的确不好。而 DRY 的过度解读是指面对区区两行的重复代码,便如临大敌恨不得除之而后快。完全避免任何的重复代码意味着我们最后将面对一堆毫无意义、令人迷惑的代码,其存在只为了防止程序中的两三行重复代码。再加上由于在逻辑上毫不相干的两段代码被迫捆绑在一起,代码也更加难以修改。


判断一段代码的重复是否可容忍很简单:修改 A 段代码,保留 B 段不变,如果程序报错,那么就把 A 和 B 整理到同一段代码;如果无事发生,那么就放着别管。DRY 并不代表我们需要手动压缩代码库,而是为了避免两段代码要依赖于手动的同步。请记住,重复代码和抽象创造并不是同一件事。

避免使用可配置函数

宁可要十个零参数的小函数,也不要一个带十个参数的函数。


诸位对类似的事一定不陌生:初始干净的函数,只在三个不同的地方被调用。而当我们想要在第四处调用时,我们需要做一点小的调整,添加一个参数。但这样第一个 caller 就多了一个新功能,也需要多添加两个可配置的参数。等到第五个用例,我们还要再为它添加独特的参数,以此类推。但反过来我们就又会发现第二个 caller 跑起来太慢了,所以只好再添加另一个参数来跳过部分繁琐的程序。


不知不觉中,我们那个干净整洁的、只负责一件事的函数现在有了五个配置参数,现在能做的事情甚至可以达到 2 的五次方种!


这种情况下,将这一整个复杂的函数拆分成子函数,每个函数只负责各自的事就会好上很多。


但这样以来,又不可避免会出现重复。当这些重复的部分需要保持同步时,我们可以利用 DRY 的思路,将相同的部分抽取到子函数中。这时,做决策和考虑步骤就会容易很多。


请记住,区区几行重复代码是没问题的!像是在不同 list 上跑 for 循环的代码,这类就是可以接受的重复。


这种方法的好处之一是当其中一个用例被删除时,你可以轻松删除掉对应的函数,而不是在复杂函数的逻辑里掘地三尺试图找到对应的选项。只关注某个特定函数的读者也会更容易理解它们的用处。


(注意,当你能负责所有的 caller 时,这种方法才是正确的。如果你的函数只是公共 API 的一部分,那么请不要考虑使用这种方法。因为你并不清楚所有的用例都是什么,也不知道未来会有什么样的用例)

不要过早地进行优化

竞速赛车跑得比普通轿车要快,这点毋庸置疑。但这也是赛车在牺牲了柔软座椅、低噪音,以及车载空调的条件下。如果我们的程序不需要做竞速赛车,那就不要过早地拆掉空调。逐渐熟悉程序的构造,先从编写易于人理解的代码开始,不要一上来就试图挑战计算机的运行速度。


同理,也不应过早开始泛化。没人会在不需要处理大量物品的时候就买入一辆自卸货车,在没有过多需求的时候,我们也不用提前编写多余功能的代码。


原文链接:


[http://jeremymikkola.com/posts/2021_02_02_how_to_write_readable_code.html](

2021-03-29 13:431909
用户头像

发布了 172 篇内容, 共 118.0 次阅读, 收获喜欢 211 次。

关注

评论

发布
暂无评论
发现更多内容

实时数仓Hologres V2.2发布,Serverless Computing降本20%

阿里云大数据AI技术

大数据 阿里云 实时数仓 hologres

JetBrains WebStorm 2024激活码永久使用 JavaScript开发工具

Rose

项目管理软件ClickUp - 使用技巧分享 | 5款替代软件推荐!

彭宏豪95

效率 项目管理 职场 在线白板 办公软件

科普:嵌入式代码软件在环(SiL)测试的可靠性

DevOps和数字孪生

嵌入式 SiL

电商商品数据采集的智能化:淘宝/天猫商品详情API接口的AI应用

技术冰糖葫芦

API Explorer API 接口 API 策略 pinduoduo API

Databend 开源周报第 148 期

Databend

数字化供应链平台:优化运营、驱动创新的未来之路

天津汇柏科技有限公司

数字化转型 供应链

QLab Pro v5.4.0激活版 mac演出控制软件

Rose

专门为Mac用户设计的强大视频下载工具:iTubeGo YouTube Downloader

Rose

Microsoft Office LTSC 2021 v16.86最新许可证版 office2021mac资源

Rose

【论文速读】|当LLM遇见网络安全:系统性文献综述

云起无垠

网络安全 大语言模型

文献解读-农业系列-第八期|《有害突变在多倍体棉花中积累速度快于二倍体棉花,且在亚基因组间不平衡》

INSVAST

基因数据分析 生信服务

从源码分析 vllm + Ray 的分布式推理流程

阿里技术

深度剖析集团型企业在新质生产力和数字化转型过程中面临的身份管理问题(四)

芯盾时代

iam 统一身份认证 身份和访问管理 统一身份管理平台

A Better Finder Rename(ABFR):Mac平台上的批量重命名工具

Rose

视频如何转换为mp3格式?4K YouTube to MP3 for Mac(在线视频转Mp3软件)中文版

Rose

网络的下一次迭代:AVS 将为 Web2 带去 Web3 的信任机制

TechubNews

NFTScan 正式上线 Sei NFTScan 浏览器和 NFT API 数据服务

NFT Research

NFT NFT\ NFTScan

高清视频下载器4K Video Downloader Plus,适用于macOS和Windows系统

Rose

深度解读数据库引入LLVM技术后如何提升性能

华为云开发者联盟

数据库 华为云 华为云GaussDB 华为云开发者联盟 企业号2024年6月PK榜

一文带你搞清楚Python的多线程和多进程

华为云开发者联盟

Python 华为云 华为云开发者联盟 企业号2024年6月PK榜

突破瓶颈:如何优化 LLMs 的落地成本和延迟

Baihai IDP

程序员 AI LLMs 企业号 6 月 PK 榜 Agents

多种类型的思维导图 Simplemind pro for Mac v2.4.0中文激活版

Rose

怎样写出可读性高的代码?_语言 & 开发_Jeremy Mikkola_InfoQ精选文章