“易于维护的主要特征是局部性:局部性是源代码的一种特性,它使程序员仅通过查看一小部分就能理解该源代码。” – Richard Gabriel
行为局部性是指:
代码单元的行为应尽可能通过仅查看该代码单元本身就能显而易见
LoB 原则是 Richard Gabriel 上述引述的一种简洁规范性表述。在尽可能且兼顾其他关注点的情况下,开发人员应努力使代码元素的行为在检查时显而易见。
考虑 HTML 中 AJAX 请求的两种不同实现,第一种在 htmx 中:
<button hx-get="/clicked">点击我</button>
第二种在 jQuery 中:
$("#d1").on("click", function(){
$.ajax({
/* AJAX 选项... */
});
});
<button id="d1">点击我</button>
在前者中,button
元素的行为在检查时显而易见,符合 LoB 原则。
在后者中,button
元素的行为分散在多个文件中。没有对整个代码库的完全了解,很难确切知道按钮的作用。这种"远距离的诡异行为"是维护问题的根源,并阻碍开发人员理解代码库。
htmx 示例展示了良好的行为局部性,而 jQuery 示例的行为局部性较差。
对行为局部性的常见反对意见是,它是在代码单元内内联实现细节,使代码单元抽象程度降低且更脆弱。然而,区分内联行为的实现和内联行为的调用(或声明)非常重要。
考虑大多数编程语言中的函数:函数声明与其在调用点的使用是有区别的。一个好的函数抽象了其实现细节,但也以明显的方式调用,没有任何远距离的诡异行为。
增加元素行为的明显性在其他条件不变的情况下是好事,但这需要最终开发人员(尤其是框架开发人员)使 LoB 尽可能简单且概念清晰。
LoB 常与其他软件开发原则冲突。两个重要的原则是:
软件开发人员通常努力避免代码或数据冗余。这被称为"保持 DRY",即不要自我重复。与其他软件设计原则一样,这本身是件好事。例如,htmx 允许你将许多属性放在 DOM 的父元素上,避免在子元素上重复这些属性。这是为了 DRY 而违反 LoB,开发人员需要明智地做出这种权衡。
请注意,行为离其影响的代码单元越远,对 LoB 的违反就越严重。如果它在代码单元几行之内,这就不那么严重;如果在一页之外,则严重性较低;如果完全在单独的文件中,则更为严重。
没有硬性规定,而是开发人员必须做出的主观权衡。
关注点分离是将计算机程序分成不同部分的设计原则,每个部分解决一个独立的关注点。一个典型例子是将 HTML、CSS 和 Javascript 分开。同样,孤立来看这可能是件好事。内联样式最近变得更加普遍,但在这方面仍有支持 SoC 的有力论据。
注意,SoC 与 LoB 冲突。通过调整 CSS 文件,元素的外观和(在某种程度上)行为可能发生巨大变化,而这种巨大变化的来源并不明显。工具可以在一定程度上提供帮助,但这里仍然存在"远距离的诡异行为"。
再次强调,这不是全盘否定 SoC,只是说明在考虑如何组织代码时必须做出主观权衡。最近内联样式变得更加普遍,这表明 SoC 在开发人员中获得的支持正在减弱。
LoB 是一种主观的软件设计原则,它有助于使代码库更人性化且更易于维护。它必须与其他设计原则权衡,并考虑代码单元所在系统的限制,但在可行范围内,遵循这一原则将提高软件的维护性、质量和可持续性。