20 个故事,每个故事有 5 种代码气味,每个故事都是 100 种代码气味,对吧? 以前的代码气味 第一部分 第二部分 第三部分 第四部分 第五部分 第六部分 第七部分 第八部分 第九部分 第十部分 第十一部分 第十二部分 第十三部分 第十四部分 第十五部分 第十六部分 第十七部分 第十八部分 第十九部分 让我们继续... 代码气味 96 - 我的对象 你不拥有对象。 TL;DR:不要使用 作为名称前缀。 my 问题 缺乏背景 双射错误 解决方案 删除 前缀。 我的 更改为建议名称的角色。 语境 一些旧教程使用“我的”这个词作为一个懒惰的名字。这是模糊的,并导致上下文错误。 示例代码 错误的 MainWindow myWindow = Application.Current.MainWindow as MainWindow; 正确的 MainWindow salesWindow = Application.Current.MainWindow as MainWindow; /* Since window is instanciated, we are currently working with a specialized window playing a special role */ 检测 自动 [x] 我们可以告诉我们的 linter 和静态检查器搜索这个前缀并警告我们。 标签 命名 结论 避免使用 .对象根据使用上下文而变化。 我的 更多信息 究竟是什么名字——第二部分康复 学分 照片由 在 上拍摄 Michał Bożek Unsplash 想想我修改代码的经历,我发现我花在阅读现有代码上的时间比我写新代码的时间要多得多。因此,如果我想让我的代码便宜,我应该让它易于阅读。 肯特贝克 软件工程名言 Code Smell 97 - 没有同理心的错误信息 我们应该特别注意用户(和我们自己)的错误描述。 TL;DR:使用有意义的描述并建议纠正措施。 问题 最小意外原则 解决方案 使用声明性错误消息 显示明确的退出操作 语境 程序员很少是 UX 专家。 我们也低估了我们可以站在柜台两边的事实。 示例代码 错误的 alert("Cancel the appointment?", "Yes", "No"); // No consequences // Options not clear 正确的 alert("Cancel the appointment? \n" + "You will lose all the history", "Cancel Appointment", "Keep Editing"); // Consequences are clear // Choice options have context 检测 手册 [x] 我们需要阅读代码审查中的所有异常消息。 标签 例外 用户体验 结论 在引发异常或显示消息时,我们需要考虑最终用户。 学分 照片由 上的 拍摄 Unsplash 视觉效果 虽然程序员从不犯错误是一个众所周知的事实,但通过在程序的关键点检查错误来取悦用户仍然是一个好主意。 罗伯特·D·施耐德 Code Smell 98 - 拼写错误 拼写和可读性对人类来说非常重要,而对机器来说并不重要。 TL;DR:照顾好你的名字。 问题 可读性 更难在代码中搜索术语。 解决方案 拼写检查您的代码。 使用带有拼写检查的 IDE 语境 我们中的许多人不会说英语作为我们的第一语言。 我们需要特别注意我们的文本和名称。 😀 这篇文章的标题中有一个错字作为上下文的证明,也是一个点击诱饵 示例代码 错误的 comboFeededBySupplyer = supplyer.providers(); 正确的 comboFedBySupplier = supplier.providers(); 检测 标签 可读性 命名 代码样式 结论 密切注意你的名字。 几个月后,您可能会成为阅读代码的人。 关系 代码气味 48 - 没有标准的代码 更多信息 名字到底是什么——第一部分探索 究竟是什么名字——第二部分康复 学分 在 上的照片 布雷特乔丹 Unsplash 每一个写得好的大程序里面都有一个写得好的小程序。 汽车霍尔 代码气味 99 - 第一秒 我们看到多少次惰性参数名称? TL;DR:根据角色而不是偶然位置命名你的论点 问题 可读性 意图透露姓名 解决方案 使用有意义的名称 语境 在编写方法时,我们通常不会停下来寻找像样的名字。 我们也从不重构显而易见的东西。 示例代码 错误的 class Calculator: def subtract(self, first, second): return first - second class CalculatorTest def test_multiply(): assert equals(first, second) 正确的 class Calculator: def subtract(self, minuend, subtrahend): return minuend - subtrahend class CalculatorTest def test_multiply(): assert equals(expectedValue, realValue) 检测 手册 [x] 我们可以警告诸如“第一”和“第二”之类的禁止词作为参数名称。 标签 可读性 结论 始终遵循规则建议参数。 根据角色命名您的合作者。 关系 Code Smell 65 - 以类型命名的变量 更多信息 究竟是什么名字——第二部分康复 学分 照片由 在 上拍摄 Priscilla Du Preez Unsplash 最终的源代码是真正的软件设计。 杰克·里维斯 代码气味 100 - GoTo GOTO 在 50 年前被认为是有害的 TL;DR:永远不要使用 GoTo。 问题 可读性 难以遵循的代码 解决方案 用结构化代码替换 GOTO 使用例外 语境 我开始用 Basic 编程。 GOTO 在那里被严重滥用。 我必须在康复模式下从头开始学习结构化编程。 示例代码 错误的 for x < 0 { if x > -1e-09 { goto small } z = z / x x = x + 1 } for x < 2 { if x < 1e-09 { goto small } z = z / x x = x + 1 } if x == 2 { return z } x = x - 2 p = (((((x*_gamP[0]+_gamP[1])*x+_gamP[2])*x+_gamP[3])*x+_gamP[4])*x+_gamP[5])*x + _gamP[6] q = ((((((x*_gamQ[0]+_gamQ[1])*x+_gamQ[2])*x+_gamQ[3])*x+_gamQ[4])*x+_gamQ[5])*x+_gamQ[6])*x + _gamQ[7] return z * p / q small: if x == 0 { return Inf(1) } return z / ((1 + Euler*x) * x) } 正确的 for x < 0 { if x > -1e-09 { return small(x, z) } z = z / x x = x + 1 } for x < 2 { if x < 1e-09 { return small(x, z) } z = z / x x = x + 1 } if x == 2 { return z } x = x - 2 p = (((((x*_gamP[0]+_gamP[1])*x+_gamP[2])*x+_gamP[3])*x+_gamP[4])*x+_gamP[5])*x + _gamP[6] q = ((((((x*_gamQ[0]+_gamQ[1])*x+_gamQ[2])*x+_gamQ[3])*x+_gamQ[4])*x+_gamQ[5])*x+_gamQ[6])*x + _gamQ[7] return z * p / q small(x, z) { if x == 0 { return Inf(1) } return z / ((1 + Euler*x) * x) } } 检测 自动 [x] 在支持 的语言中,我们的 linter 可以警告我们不要使用它。 GOTO 标签 可读性 结论 我们在几十年前就承认了 GOTO 问题。 这个问题仍然存在于 GoLang、PHP、Perl 等 中。 现代语言 大多数程序员幸运地避免了 GOTO 语句。下一个目标是考虑有害的 。 null 使用 礼貌 XKCD 关系 代码气味 12 - 空 更多信息 Goto 语句被认为是有害的 维基百科 学分 詹斯·约翰森 ( 在 上拍摄的照片 Jens Johnsson) Unsplash 向之前接触过 BASIC 的学生教授好的编程实际上是不可能的:作为潜在的程序员,他们在精神上被残缺不全,没有再生的希望。 埃兹格·迪克斯特拉 软件工程名言 这就是现在的全部内容,我们已经达到了 100 个里程碑。 下一篇文章将解释另外 5 种代码异味!