写点什么

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

  • 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:431763
用户头像

发布了 150 篇内容, 共 89.1 次阅读, 收获喜欢 198 次。

关注

评论

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

每日一题:LeetCode-240. 搜索二维矩阵 II

Geek_4z9ami

Go 面试 算法 矩阵 LeetCode

博睿数据参与支持2023年度证券期货业标准研究课题获评“优秀”

博睿数据

Metasequoia 4 for Mac v4.8.6b激活版

iMac小白

SecureFX for Mac(ftp文件传输工具)附注册码 v9.4.3破解激活版

mac

苹果mac Windows软件 SecureFX 文件传输客户端

权威认可,天翼云云原生一体机iStack斩获“2023云原生企业TOP50”第一名

编程猫

【第七在线】媒介投产分析 Colony Brands每一个宣传画册运营产出收益

第七在线

融云观察:给 ChatGPT 加上声音和脸庞,AI 社交的多模态试验

融云 RongCloud

AI 设计 API 社交 ChatGPT

【案例】第七在线商品组合计划赋能安德玛每一个加盟商精准计划

第七在线

热热热!开放原子开发者大会议题征集火爆!

开放原子开源基金会

Java 开源 程序员 开发者 算法

现在大火的低代码是什么?有哪些优势?

高端章鱼哥

低代码开发 应用程序 JNPF

虾皮商品评论接口(Shopee.item_review)|虾皮API接口指南

tbapi

shopee API 虾皮商品评论接口 虾皮商品评价接口 虾皮评论接口 shopee 商品评论接口

「代码舞者」2023开放原子开发者大会——开源大侠秘闻

开放原子开源基金会

开源 开发者 算法

item_get-1688商品详情在跨境电商中的营销策略创新

技术冰糖葫芦

API

【第七在线】国际市场扩张与商品计划:跨越地域的挑战与机会

第七在线

Integrity Plus for Mac:数据完整性校验的得力助手

iMac小白

使用TikTok云手机轻松拓展全球市场

Ogcloud

云计算 TikTok 手机云服务

如何又快又好、又便宜地开发体育赛事直播平台

软件开发-梦幻运营部

Visio Viewer for Mac激活版 查看和编辑Visio文件

iMac小白

【第七在线】服装企业商品部关注的关键问题与解决策略

第七在线

React高手都会用的useMemo有什么用的?

互联网工科生

性能优化 React useMemo

mac右键助手 MouseBoost Pro 3.3.4破解版

iMac小白

MongoDB中的分布式集群架构

EquatorCoco

分布式 索引 db 集群架构

Tower for Mac注册激活版下载(强大的Git客户端)

iMac小白

“基于inBuilder低代码平台开源社区版的应用开发”创新赛获奖队伍公示

inBuilder低代码平台

Navicat Premium for Mac(多协议数据库管理工具) 16.3.4中文破解激活版

mac

数据库管理工具 苹果mac Windows软件 Navicat Premium 16

2024年市场上最好的免费开源工单管理系统六强

爱吃小舅的鱼

开源 工单管理

浅析 ArrayList

不在线第一只蜗牛

Java 开发语言

华为云Astro,让业务专家秒变“技术大拿”

华为云PaaS服务小智

低代码 华为云

海外云手机在跨境外贸中的作用

Ogcloud

云计算 跨境电子商务 跨境电商 电子商务

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