我要投稿
在多年的编程实践中,我总结出了一套三条原则,帮助我编写更加模块化、易读和可修改的代码。这些原则不仅适用于编写新代码,也在重构复杂代码时发挥了重要作用。随着时间的推移,我意识到许多关于代码质量的启发式方法,实际上都是这些原则的特例。现在,我将它们集中在一起,称之为“分离三角”。
编写代码时,应避免混合高层次和低层次的概念。相反,顶层方法应完全由其他方法组成,这些方法本身执行具体的工作。这些方法通常是私有的。这种编写代码的方式通常会导致“冰山文件”,其中 90%的代码位于私有部分,只有少量代码位于公共部分。
这种风格使得读者在阅读高层次方法时,可以专注于方法的“做什么”而不是“如何做”,从而使代码更易读。在编写系统/功能/验收测试时,这种风格特别有用。
例如,在 Elm 中编写视图代码时,我大量使用这种风格。理想情况下,读者不需要关心渲染层的具体实现(HTML?Canvas?),而是关注 UI 元素的存在(例如,加载屏幕、主要内容、摘要等)。以下是一个用于渲染调查的代码示例:
survey
[ surveySection "Toppings"
[ yesNoQuestion "Pineaple on Pizza?" PoP "pop"
, yesNoQuestion "Anchovies?" Anchovies "ancho"
]
, surveySection "Crust"
[ pickOne
[ ("Thin Crust", Thin)
, ("Thick Crust", Thick)
, ("Chicago Style", Chicago)
]
]
]
这个想法有时被称为 SLAP(单一抽象层次原则)。
作为程序员,我们经常喜欢编写试图遵循代码中单条路径的代码。为此,我们尝试让分支要么快速终止,要么重新合并到主路径中。这导致了重复检查、深度嵌套的 if/else 以及不必要的复杂条件代码。
相反,将条件推到决策树顶部意味着必须在程序的边界处处理代码的不确定性和边缘情况。这导致了更自信的代码。对于剩余的条件,早期分支迫使我们承认程序中存在多条主路径。决策树顶部的扁平条件更易于阅读、理解和调试。
考虑以下来自“嘈杂动物 Kata”的复杂条件代码:
# BEFORE
def make_noise(loud: true)
if is_bird && !loud
make_bird_noise(false)
end
if loud
if is_mammal
2.times { puts mammal_noise }
end
make_bird_noise(true) if is_bird
elsif is_mammal
puts mammal_noise
end
end
应用这一原则后,代码变得更加清晰:
# AFTER
def make_noise(loud: true)
if is_bird && loud
make_bird_noise(true)
elsif is_bird && !loud
make_bird_noise(false)
elsif is_mammal && loud
2.times { puts mammal_noise }
elsif is_mammal && !loud
puts mammal_noise
end
end
这种重构消除了方法中的许多偶然复杂性,使得逻辑更加清晰。当我重构复杂多步表单代码时,这一原则特别有用。
这一原则指出,分支代码不能有实现细节。如果一个方法包含条件,每个分支只能调用另一个方法。这一指南和 Sandi Metz 的“每方法最多 5 行规则”通过最小化你可以在if/else
表达式中放入的内容,自然导致类似的结果。
这一原则通过在算法的自然关节处拆分算法,强调组合性和复用性。我发现自己一直在应用这一规则的专门变体,例如将昂贵的计算和这些计算的备忘录分离到不同的方法中,或者在使用 Elm 中的Maybe
时,将检查存在与否的代码与计算值的代码分离。
考虑以下恶臭代码:
# SMELLY
def save(for_real:)
if for_real
File.open("#{@title.downcase}.txt", "w") do |file|
file.puts @title
file.puts @body
end
else
$stdout.puts "PREVIEW"
$stdout.puts @title
$stdout.puts @body.slice(0, 240)
end
end
应用该原则后,代码变得更加清晰:
# BETTER
def save(for_real:)
if for_real
save_to_file
else
output_preview
end
end
现在,如果有人确定要保存到文件,他们可以直接调用save_to_file
,而不需要硬编码布尔值save(for_real: true)
。这种风格在计划拥有子类时特别有用,尤其是使用模板方法模式时。
你可能在阅读一些示例时会对自己说“这感觉像是一个更适合其他原则的例子”。这是因为所有原则都收敛到同一种类型的代码。它们是硬币的三个面,或者说……三角形?
我称这个三元组为“分离三角”,因为它为你提供了一套启发式方法,用于发现分离代码的接缝。综合起来,这些想法帮助您编写更易读、更易更改、更易扩展和更易混搭的代码。
如果你喜欢这篇文章,你可能还会喜欢:
通过这些原则,你可以编写出更加模块化、易读和可修改的代码,从而提高代码质量和开发效率。
亚星管理平台菁思福科技秉承"专业团队、品质服务" 的经营理念,诚信务实的服务了近万家客户,成为众多世界500强、集团和上市公司的长期合作伙伴!
亚星管理平台菁思福科技成立于2001年,擅长网站建设、网站与各类业务系统深度整合,致力于提供完善的企业互联网解决方案。亚星管理平台菁思福科技提供PC端网站建设(品牌展示型、官方门户型、营销商务型、电子商务型、信息门户型、DIY体验、720全景展厅及3D虚拟仿真)、移动端应用(手机站、APP开发)、微信定制开发(微信亚星官网、微信商城、企业微信)、微信小程序定制开发等一系列互联网应用服务。