可读代码编写炸鸡十 - 保持单纯
大家好,我是多选参数的大炮。
难以置信,我用了一个月的时间重新捡起了这个炸鸡。很惭愧,我很长的时间没有阅读相关的东西了。但是感谢当时的我留下了宝贵的思维导图,保留了我当时的思路。
这篇炸鸡也是属于可读代码编写的第三层的内容,说实话我也有些生疏了,所以重新看一遍第三层的概览:
所以上一篇是 针对已经出现不好代码 的一种处理方法,本篇炸鸡会先尝试说一下另一种处理方法 —— 一次只做一件事。
当然我们也可以翻译成让代码 保持单纯。因为一次只做一件事的执著与质朴,已经被许多人放弃去了,但放弃的人不愿承认一两分,只好恼羞说着 这是傻子 之类的惹人哂笑的话。
难理解的「三心二意」
就不说写代码这么宽泛的,就单单说实现一个接口,很容易因为 校验,判断 等需求,增加了许多非直接服务于目标的代码。这个上一篇炸鸡便提到了,这叫做不相干的子问题,需要抽取。(可以看一下,给我加点业绩也是极好的。)
但是抽取子问题会遇到一种情况,如果这些不相干的子问题 被打散了散落在一个接口 中呢?这就好像一段代码同时在做很多件事情,你以为你在玩并发,阅读者却以为你在玩他。其实这件事情,在上一篇炸鸡中也有提到解决方法,就是让相关的代码逻辑与相关变量,尽量放在一块。
在《编写可读代码艺术》第十一章中提供的一张图就能很形象地描述这类情况。
截图自《编写可读代码艺术》第十一章
这就是可视化的三心二意呵,很明显,这样对可读性是有很大的伤害。而且这样的三心二意一定伴随着多变的数据流动,光这样的跟踪,就足够占据阅读者的精力了,谈何快速理解代码。
保持单纯与执着
虽然前文提到,上篇炸鸡提到的方法基本都与本篇炸鸡的思想沾边重叠了。因为 上一篇讲的是直接服务于代码目标和非直接服务于代码目标中间的冲突与调和,那么其实这两段代码交织在一块,就是一种同时想做多件事情的三心二意。
但是毕竟上篇的侧重点是子问题的抽取,而本篇炸鸡侧重一整段代码中分散的逻辑。毕竟提高代码的可读性的方法,本质上都是类似的。
那么就让代码保持单纯与执着,一次尽量只做一件事。我们有这样一段代码(我承认看起来有点蠢,但为了说明例子而为之):
function sendMail2Aid(aid, content)
local db = getDb('u_xxx')
db.send2aid = aid
local mailParam = {}
local info = getAidInfo(aid)
mailParam.content = content
mailParam.target = aid
if db.remainSendCount <= 0 then return end
mailParam.tag = info.tag
db.lastTime = os.time()
sendMail2Aid(aid, mailParam)
db.remainSendCount = db.remainSendCount - 1
end
乍一看非常工整,审美上是说得过去的。但是读下去这段代码,发现逻辑上很跳脱。这一段代码主要是 sendMail2Aid
,发送一封邮件给一个 aid
。
但是分析下来,这段代码做了起码两件事,但却是交替进行的。先是读取数据,要对 db
做一些数据变动操作。
local db = getDb('u_xxx')
db.send2aid = aid
但是马上就变成邮件参数的构造了:
local mailParam = {}
但马上又请求了 aid
相关的数据,你以为打算开始做一些校验判断了,但是又开始构造邮件参数数据了:
mailParam.content = content
mailParam.target = aid
就这样左右横跳,辗转反侧,阅读者会被这样的三心二意所累。所以我们将他们整合一下,让一段代码只做一件事:
function sendMail2Aid(aid, content)
-- 获取数据,并且做一些校验
local db = getDb('u_xxx')
local info = getAidInfo(aid)
if db.remainSendCount <= 0 then return end
-- 发送邮件
local mailParam = {}
mailParam.content = content
mailParam.target = aid
mailParam.tag = info.tag
sendMail2Aid(aid, mailParam)
-- 相关记录
db.send2aid = aid
db.lastTime = os.time()
db.remainSendCount = db.remainSendCount - 1
end
所以,完全可以先理清自己的代码要做什么,列成一个个任务:校验
,发邮件
,相关记录
。然后将他们各自归于一件事,一件事一件事做下去。
如果这件事体量太大,那我就抽函数嘛。
function sendMail2Aid(aid, content)
-- 获取数据,并且做一些校验
if not _check(aid) then return end
-- 发送邮件
_sendMail(aid, content)
-- 相关记录
_afterSendMail(aid)
end
小结
其实本篇炸鸡主要就强调了代码段中,尽量不要 「三心二意」,要保持「单纯与执着」。本篇炸鸡的内容其实不是很大,因为这个系列到了快结篇的时候了,你会发现很多的建议与方法,都是有本质上的相通点。
可读代码炸鸡的系列从第一层到现在的第三层,可读性提升的方法从小范围到大范围,提供了许多方法与建议。但是他们是各自有侧重点的,当你知道的越多,你就需要更多的实践,因为项目代码是 复杂 的,不可能是几个例子就能穷举。只有更多的实践,你才能权衡该怎么去写代码。
talk is cheap, show me the code
.
- 在美国国会图书馆标题表的SKOS上运行Apache Spark GraphX算法
- 【精选】破解波动性突破实盘系统
- 从程序员的角度看神经网络的激活功能
- 在线矩阵微积分工具,可以生成 Python/Latex 代码哦!
- 机器学习应用区块链系列(一)——如何开发一套自己的智能合约系统
- 使用Botkit和Rasa NLU构建智能聊天机器人
- 【量化投资】缠论面面观(附Python源码)
- 独家 | 教你用Q学习算法训练神经网络玩游戏(附源码)
- 使用重采样评估Python中机器学习算法的性能
- Autofac正式发布2.1版
- DataDirectory是什么?
- android的消息通知栏
- qq安全原理
- activity的启动模式和栈管理
- JavaScript 教程
- JavaScript 编辑工具
- JavaScript 与HTML
- JavaScript 与Java
- JavaScript 数据结构
- JavaScript 基本数据类型
- JavaScript 特殊数据类型
- JavaScript 运算符
- JavaScript typeof 运算符
- JavaScript 表达式
- JavaScript 类型转换
- JavaScript 基本语法
- JavaScript 注释
- Javascript 基本处理流程
- Javascript 选择结构
- Javascript if 语句
- Javascript if 语句的嵌套
- Javascript switch 语句
- Javascript 循环结构
- Javascript 循环结构实例
- Javascript 跳转语句
- Javascript 控制语句总结
- Javascript 函数介绍
- Javascript 函数的定义
- Javascript 函数调用
- Javascript 几种特殊的函数
- JavaScript 内置函数简介
- Javascript eval() 函数
- Javascript isFinite() 函数
- Javascript isNaN() 函数
- parseInt() 与 parseFloat()
- escape() 与 unescape()
- Javascript 字符串介绍
- Javascript length属性
- javascript 字符串函数
- Javascript 日期对象简介
- Javascript 日期对象用途
- Date 对象属性和方法
- Javascript 数组是什么
- Javascript 创建数组
- Javascript 数组赋值与取值
- Javascript 数组属性和方法
- [折腾]小型HTTP web服务Caddy及配置PHP
- graftcp一种把指定程序的 TCP 流量重定向到代理的方法
- Flutter应用集成极光推送的实现示例
- android调用C语言实现内存的读取与修改的方法示例
- Android中网络框架简单封装的实例方法
- Auto Remove Torrents:自动删种程序部署
- OpenVZ平台Alpine Linux一键安装脚本
- 使用holder.js生成美观的网页占位图
- Android studio 3.5.2安装图文教程详解
- Android面试必备的JVM虚拟机制详解,看完之后简历上多一个技能!
- 如何在PHP中JSON在线解析
- Linux下如何克隆磁盘/分区命令dd入门
- Android自定义跑马灯文字效果
- Android实现图片自动切换功能(实例代码详解)
- Android Studio 3.6 正式版终于发布了,快来围观