我听说过这样的表达,要成为一名程序员,您需要变得懒惰。 但是有时编程的懒惰会导致严重的技术债务。 在我关于SRP的文章中,我提到违反此原则会导致复杂性增加甚至增加。 我的一位同事提出了一个有趣的例子,在我的帮助下,我决定展示它的外观。
让我们决定这种过度复杂性是什么。 但是首先,让我们谈谈它的反面,即需求的复杂性。 例如,有一些要求要根据小时工资和工作时间来计算员工的工资。 并且,如果一名员工已经在公司工作了五年以上,则可以获得奖金。 这个“如果”来自需求,这是无法避免的。 一种或另一种形式,它将成为应用程序代码中复杂性的一个组成部分,最有可能以条件运算符“ if”的形式出现。 但是有时候复杂性不是来自需求,而是来自开发人员解决问题的方法。
“ if”运算符,诸如“策略”之类的模式,多态方法并不是可包含这种过多复杂性的编程技术的完整列表。 顺便说一句,我个人一直反对开发人员使用模式,只是因为它们可以,而不是解决特定问题。
这是一个简单的例子。 这可能是虚构的,但事实并非如此。 甚至没有简化,几年前我在一次代码审查中以这种形式遇到了他。 在代码的两个地方,调用了相同的函数,但使用了不同的布尔参数:
相似的设计总是看起来可疑,这个功能并没有让我失望。 传递此参数的唯一目的是在此函数内检查该参数:
doSomething(flag: boolean): void { if(flag) {
此检查可以描述为“如果我是从A地点打电话来的,我们做一件事,否则,我是从B地点打电话来的,我们做另一件事。” 该标志,即“ if”就是整个注释的含义。 复杂性并非来自业务需求。 自然,我建议更改代码如下:
就是这样,没有更多的复杂性了。 这是开发人员不应太懒惰并编写另一个函数签名的地方。
在这里您可以大声疾呼:“但是这只是一个'if'”,或者:“这种侵犯是显而易见的,谁来写这样的代码?” 这是第二个例子。 它表明,发现违规情况要困难得多,而且这种违法行为的代价可能不只是一个“ if”。 与第一个示例一样,该函数在两个地方使用:
该方法的名称如下所示,检查对象的有效性。 但是,它还可以检查对象数组的有效性并不明显。 我调整了变量名以强调这种违反。 该方法如下所示:
checkValidity(parm: MyType | MyType[]): void { if(Array.isArray(parm)) { parm.forEach(p => checkValidity(p)); } else {
来了 一个if变成很多if。 如果数组包含100个对象,则此“如果”将执行101次。 在真实数据上,我们在那里可能有3万个对象,这已经是令人印象深刻的性能损失。
显然,遵循唯一责任的原则,需要重构此方法,以便获得两种方法:
checkItemsValidity(parms: MyType[]): void { parms.forEach(p => checkItemValidity(p)); } checkItemValidity(parm: MyType): void {
相应地,您还需要调整呼叫点。
有趣的是,我在有关SRP的文章中提供的示例导致SLOC的增加,相反,相同的示例导致SLOC的轻微降低,以及预期的代码质量提高。
仅此而已。 仅用几个简单的例子来演示优质代码的最重要原理。