任何已有的基本代码库都有其黑暗和丑陋的角落,这是必然的。 并非所有事情都能比我们期望的更完美,更频繁地完成,情况会迫使我们编写我们不感到骄傲的代码。 有时,我们必须实时学习,而没有内部人员熟悉我们核心能力以外的东西。 随着时间的流逝,这将开始在代码的可读性及其维护中显示出来。
您可以采用/监视/放弃一些简单的习惯,这些习惯可能会使您和您的同事的生活更轻松。 本文旨在与任何平台或编程语言无关。
1.复制并粘贴或复制面食
虽然毫无疑问,复制和粘贴可以节省时间并避免输入错误,但它也有可能两者兼而有之,尤其是当您不是作者时,如果未经测试的代码从网络上窃取,则更是如此。
除了移动代码外,还应谨慎使用或复制和粘贴整个代码块,或者至少要保持警惕和谨慎。 如果您要从当前的代码库复制,则希望您在重构时不会重复工作。
如果您从参考文档,论坛,文章,教程,开发博客等中摘录一小段,则键入代码而不是复制代码的好处是双重的:
首先,当您花时间输入时,您要仔细检查它的实际作用。 可能有多余之处,或行不适用于您的情况。 也许作者出于偏执或迷信添加了一些东西(您会感到惊讶)。 您应该能够自信地了解要添加到产品中的内容。 否则,您很可能会植入定时炸弹。
其次,这使您有机会分配有意义的变量名或提供更好的结构或分解。 请记住这一点,让我们继续下一个习惯。
2.长度很重要,但不是您认为的那样
我记得在2000年代初期,我在阅读Linux内核源代码中的代码贡献准则(出于好奇)。 我现在最喜欢的部分听起来对我年轻的大学版本来说非常严格,因为当时Linux上已经有了图形化IDE,但是这些指导原则是为了支持那些 仍在80x24终端中的Emacs或vi中进行编码。
制表符的规则是8,并且代码行不能超过80个字符。 您可能想知道,是否还有空间可以写任何东西? 好吧,是的,如果您必须缩进或嵌套控件结构/块3次以上,则这是代码的味道,您的函数可能太大了。 而且,如果您需要垂直滚动大量内容以阅读其余功能,则可能应该将其分解为更多功能。
这样做的准确性可能听起来很极端,所以我们不要着重于细节,但是如果您提取其背后的原因,那么它在现代软件开发中仍然与今天相关。 在我职业生涯的前半段,我并不总是听从这个建议,而另一半则受到启发。 您可能不是用C进行内核编程的,但是我发现您可以将这些基本思想应用于C ++,Objective-C,C#,Java,JavaScript,Ruby,Swift等,并为此做得更好。
您可以做一些非常简单的事情来帮助您。 例如,使用列,您可以在代码编辑器的设置中显示页边距,并可以指定在哪一列显示。 任何一行代码超出此裕度的确切时刻,将是显而易见的。 对于某些开发人员来说,也许80太少了,但是超过120的任何东西都变得有些笨拙。 如果您同时水平和垂直滚动以阅读代码,则所需的精力会激增。 这是低效的,并且可能导致疲劳。 我敢打赌,没有人喜欢滚动220个字符的代码行。
> Going up to a dozen characters passed the margin probably won't hurt once in a while, especially if the rest of the line is predictable, but at least the margin keeps you mindful of potential readability issues.
对于缩进,我认为如果每次嵌套时都使用最佳判断,则可以找到一种合理的方法来管理块的大小。 可以重复使用吗? 它已经在其他地方使用了吗? 是否可以在逻辑上将其作为明确的工作单元分开? 将其移出会使该部分更容易理解吗?
对于垂直滚动,任何方法(尤其是块)都不应太长,以至于不确定何时结束。 对于文件本身也是如此。 一位同事曾经告诉我,超过400行的文件是打破SOLID的单一职责负责人(SRP)(或解决关注点分离的任何其他模式)的一种气味。 如果您查找它,很多人都会同意这个限制。 我个人没有硬性限制,但是我已经在考虑重构比此更大的内容。
3.自记录名称
我们都看到过本地化,错误,方法和类,这些本来可以更具描述性,有时我们也可能对此感到内gui。 除非您是唯一能够阅读代码的人来定义工作安全性,否则习惯于花更多时间思考不太含糊和更具描述性的内容的习惯对您自己和他人都会有很大帮助。
一位团队负责人曾经告诉我,包含单词" Manager"的类名称是潜在的代码气味。 对于某些人来说,这听起来可能有点保留,但是经过一番思考之后,的确是,我见过的大多数人的目的都是模糊的,并且通常违反了SRP或"依赖倒置"原则。
如果您很难找到适合某个类的名称,那么这是一个思考是否可能完成比单个类更多的工作的机会。
4.空白一致性
在这里,我将不讨论制表符与空格的关系,但是我们大多数人都同意至少在同一文件中或至少在同一行代码中保持一致。 这是很容易检查的东西,如果发现您不注意,那看起来会很尴尬。
如果您曾经见过在代码差异,拉取请求或其他编辑器中单行缩进显示不同的代码,这是因为该代码可能是用不同的编辑器或不同的设置编写的。
我们不能总是假设每个人都会使用相同的编辑器,而在格式设置不严格的开发团队中,我们经常会看到这种情况。 下面,我重新创建了一个情况来说明这一点,与当多个开发人员在一段时期内编辑文件时不经意间创建的情况相比,这实际上是很温和的。
> Intended indentation, looking pretty normal in XCode
> Looking a bit off, and we can see why with whitespace visualization enabled (VS Code)
> Sense of indentation is at risk of becoming completely lost in raw text view, e.g. code reviews
大多数现代编辑器都有显示空白字符的设置,因此您可以看到制表符和相等数量的空格之间的差异。 只需将其打开,您就可以看到压痕何时开始看起来不一致,而将其关闭将使您不知道并且不知不觉地导致脏空格问题。
这还将显示尾随空格,因此您可以防止自己提交行,唯一的变化是在EOL之前添加12个空格或仅由空格组成的空行。 除了在您的代码库中猖these之外,这些提交除了会使您显得有些业余之外,还可以逐渐使您的源代码控制大小膨胀并减少不必要的更改历史记录。
当然,如果您的团队养成在每次提交之前使用代码格式化程序(并共享配置)的习惯,那么这没什么大不了的。 我们从中受益,因为样式变得更加统一,您可以指望它以某种方式看起来。
5.随身携带清洁
通常,无论客户多么迫切,拥有足够客户的公司都不会停止生产功能以花费数周或数月的时间进行重构。 主要是因为您无法将其出售给客户。 不要等待重写(顺便说一句,它可能会失败)。
编写新代码时,很容易清理干净。 在旧的代码库中编写新代码时,您可能必须破坏现有的反模式以使其更具可维护性,但是这样做时应格外谨慎,因为混合使用旧代码和新代码通常会有所取舍。
如果有机会以很少的风险清理旧代码,则应采取措施,但要再次小心; 如果没有覆盖该区域的单元测试,可能不清楚所受影响的是什么。 如果没有测试覆盖,我不建议对旧代码进行大量重构。
如果要在要修改的文件上使用代码格式化程序,强烈建议您在单独的提交中进行修改和格式化。 否则,很难找到是否有人必须检查文件历史记录的更改。
6.句法风格
每个人都有自己的风格,但是每种编程语言都有自己的事实上的标准或既定风格,您不应该习惯于与之抗争。 为了保持一致性,细微差别的任何变化都应该在您的开发团队中达成共识。 现在是时候在第二节和第四节中用我的Swift示例大声疾呼/嘲笑我了。
如果编程是一门艺术,那么真正的杰作将具有一致的结构,看似简单,并且易于阅读和维护。 有人会认为镶嵌是一种有效的艺术形式,但是在编程中,由几十个开发人员编写的代码库可能看起来不像几十个开发人员编写的代码库。
架构
不幸的是,这不是一个简单的习惯,但是正确构建的代码库将鼓励并在一定程度上实施良好的习惯。
使用用户界面进行开发时,使用MVC或MVVM之类的范例将有助于您使业务逻辑远离显示代码和数据模型,反之亦然。
如果您使用的是面向对象的语言,那么没有足够的文字来描述SOLID设计原理如何改变游戏规则。
使用Message Queue以受控的方式处理事件和数据请求 命令查询责任隔离将有助于进一步放松可能相互响应的独立功能的耦合。
当正确使用以上三个概念时,它们是创建干净,可扩展,持久,可单元测试的代码的三重奏,并且是反模式的祸根。 如果您有更好的选择,请告诉我。
执行力
尤其是高级开发人员,不喜欢被告知如何完成工作。 一种不太有力的方法是促进一种工程文化,该文化鼓励良好的习惯并围绕软件设计实践进行开放式交流。
我已经看到在代码审查期间专注于美学和其他缺点是多么无效,但是总体上执行代码审查应该使我们更加有意识,并且审查者有机会提出良好的习惯,或者是可能更好的替代方法。 从长远来看。 在代码审查之前强制执行代码格式化对我来说还可以,但是格式化程序将无法捕获方法和类太大的情况。
缺乏执行力的问题是,肮脏的编码习惯很有可能赢得所有人的支持,即使不是所有人都参与其中。
结论
当您对单个代码库有很多贡献者时,混乱的代码将是不可避免的,但是我可以保证您可以避免很多代码-在一个以上的层次上。
养成一些好习惯而放弃一些坏习惯是保持新代码库整洁或帮助延长老化代码库寿命的轻松之举。 初级和中级程序员更容易养成良好的习惯,这是他们职业生涯中重要的时刻。
如果您对此主题有任何意见,请发表评论,无论好坏。 我一直都在辩论,很想分享想法。