<返回更多

开发者应知道的方法论:JavaScript中的DILOS原则

2020-11-11    
加入收藏

本文最初发布于 hackernnon 网站,经原作者授权由 InfoQ 中文站翻译并分享。

SOLID 原则是开发人员创建灵活、可理解和可维护代码的基础。但你要正确遵循这些原则就可能明显减慢开发速度,并且大多数人没那么操心代码质量,因此我发明了一套更好用的原则。

DILOS 原则是我们构建可怕代码的坚实支柱。

我个人已经用上了 DILOS 原则,成功创建出大堆混乱难懂和臃肿的代码,这篇文章我就来具体介绍一下:

DILOS 的含义:

依赖倒置反转原则

高级模块必须依赖低级模块。依赖实体而不是抽象。

把某些东西抽象出来,就是要隐藏这些东西内部的实现细节,有时是原型,有时是函数。因此当你调用这个函数时不必完全了解其机制。如果你非得先搞懂大型代码库中的所有函数,那就别想着写代码了。可能需要几个月的时间才能看完那些东西。

但现在我们要把这条原则倒过来:不要抽象任何东西。也就是尽量少用小块函数,把所有东西都塞到一个单体函数里。如果别人想调用你的函数,让他看懂你的每一行代码再说吧。

下面是整洁代码的一个示例:

function hitAPI(url, httpMethods){
  // Implementation example
}
hitAPI("https://www.kealanparr.com/retrieveData", "GET");
hitAPI("https://www.kealanparr.com/retrieveInitialData", "GET");

你看,你用不着操心 hitAPI 在做什么,我们只传递了一个 URL 和一个 HTTP 请求,然后就搞定了。现在这段代码是高度可重用和可维护的。这个函数可以在一个地方处理所有 URL。我们已经尽可能让高级函数(我们放在 base 原型中的函数,可以和下层的许多东西共享)不依赖于任何低级函数。

那么如果我们反转这个依赖倒置(Dependency-Inversion)原则呢?

function hitDifferentAPI(type, httpMethods){ 
  if (this instanceof initialLoad) { 
    // Implementation example
  } else if (this instanceof navBar) {   
    // Implementation example 
  } else {  
    // Implementation example 
  }
}

现在我们让高级 api 请求依赖于许多较低级别的类型。完成任务后,它不再是完全通用的了,并且会依赖其继承链中较低的类型。

接口捆绑原则

强迫客户端依赖它们不用的 [代码]。

其他语言里的接口用于定义不同对象拥有的方法和属性。

不要向不需要的对象添加代码?不要将太多无关的功能捆绑在一起?嗯,胡扯嘛这是。

我们一定要把松散耦合的代码都绑在一个地方。关键在于一定要依赖你用不着的东西。

我们稍后将在“多重职责原则”中进一步解释,但请记住这条原则,在所有地方疯狂用它。还记得花半天时间查找几百个文件搜索 bug 的经历吗?那种事情不会再有了。搞一个名为 main.js 的 JS 文件,然后把所有代码都塞进去。

让你的站点预加载所有内容,不要搞什么 JS 脚本按需加载,这样初始加载速度就会慢如蜗牛啦。

写代码的时候把宇宙毁灭时的需求都想好,然后提前写好对应的逻辑,反正你迟早用得上嘛。

如果有人需要你代码里的一根香蕉,那就塞给他一头拿着香蕉的大猩猩。客户端要啥就给它附送一堆垃圾,它们肯定会感谢你的。

写的函数越少越好。把什么东西封装在一个放在其他地方的新函数里,并抽象化它的逻辑?可别这么干。怎么让人犯迷糊怎么来,需要代码的时候复制粘贴过来就行。

理想情况下,我们的代码流只有 1 个对象。在非常大的代码库中,我们可能有 2 个对象。通常将其称为“上帝对象”反模式,其中我们要到处用单独的一个对象,因为所有事情都得它来做。稍后我们将详细讨论。

里氏分离原则

软件各部分的子级和父级不可以互换。

你竟然会在代码中使用继承吗?这绝对要注意。你应该复制粘贴而不是继承代码。Copy-Paste 反模式就是这个意思,你不应该把代码的通用功能抽象为模块化的可重用功能,而应当在所有需要的地方都复制代码。这会增加技术债(将来你迟早要回来修复的),而且每更改一段代码,都需要多次搜索才能找到它在代码库中出现在了哪些位置。

DRY 原则表示 Don't Repeat Yourself,而 WET 原则恰恰相反,指的是我们 Write Everything Twice。必要时应该写更多次数。抵制继承,随意复制粘贴。

但是,如果你确实需要利用里氏分离原则,请确保在与继承链中较高子级(父级)交换对象时,继承链中较低子级的对象原型不能正常工作。

为什么?

因为如果我们不遵循里氏分离原则,我们就会构建准确而健壮的继承链。将逻辑抽象为封装好的 base 原型 / 对象。我们还会对原型链中的不同方法按逻辑分组,它们的特定覆盖会让代码路径更加可预期和可发现。

如果你正确地遵循了这一原则,那么父级能用的时候子级也没法用,继承就会毫无意义。如果你的程序尝试引用的函数并不存在于自己的子级中,因此崩溃掉——你就会完全避免继承会给你带来的任何好处——这正是我们遵循这一原则的目的。

开闭原则

对象应对修改开放,对扩展封闭。

好的代码通常会扩展对象的代码,以限制修改 base 原型。这样,完成扩展的对象就可以处理自己的状态以及需要执行的新功能(仅处理子项需要做的少量更改即可)。

上面这段话是胡说八道,我们真正应该做的是:

如果在处理每个场景时都分支,那么上面这两步带来的负担就更重了。所以最后你会看到诸如这样的代码:

function makeSound(animal) {
  if (animal == "dog") { 
    return "bark"; 
  } else if (animal == "duck") { 
    return "quack"; 
  } else if (animal == "cat") {  
    return "meow"; 
  } else if (animal == "crow") { 
    return "caw";  
  } else if (animal == "sheep") {  
    return "baa";  
  } else if (animal == "cow") {  
    return "moo";   
  } else if (animal == "pig") {  
    return "oink";   
  } else if (animal == "horse") {  
    return "neigh";   
  } else if (animal == "chicken") {  
    return "cluck";  
  } else if (animal == "owl") {
    return "twit-twoo";    } else {  
      /// It has to be a human at this point
      return "hi";  
    }
}

现在,如果你需要更改某些内容,只需添加另一个 if 检查即可。这和下文列出的多职责原则有关,但核心在于将所有内容都包含在 base 函数 / 原型中。

这样你就会进入“脆弱基类”反模式。在这种模式下,更改 base 函数 / 原型时,你最后会在调用此函数的其他触点上出现错误。

例如,假设 human 不该再掉进 else 里,而你添加了新的 animal,名为 wolf,你就会引入错误(除非你更新了期望 human 被记录的位置)。

多职责原则

确保你的函数 / 对象有多重职责。

优秀的编程人员常常会将他们的代码分成多个不同的对象或模块。但我可搞不清楚这种事情,我记不住它们都负责什么事情。

下面是一个例子:

const godObject = { 
  handleClicks: function(){},
  getUserName: function(){}, 
  handleLogin: function(){}, 
  logTransactionId: function(){},  
  initialSiteLoad: function(){} };

godObject 负责网站的许多功能。付款、登录、网站负载、记录交易 ID 以及网站上的所有点击功能都包括在其中。太棒了,这样如果你遇到了错误,就会知道它只能出现在这里。确保代码库中的每个地方都需要访问 godObject。让它做一切工作。

我们在代码中真正想要的是高耦合(确保系统的各个部分相互依赖)和低内聚(将许多随机的数据和片段放在一起)。

这种反模式有时被称为“瑞士军刀”,因为就算你要的只是一把剪子,但它也可以是指甲锉、锯子、镊子、开瓶器,也可以是软木钉。

我不断强调的是,要把所有东西放在一起,然后绑定、打包、捆在一起。

总 结

我希望大家看完这篇文章后,就知道软件究竟应该怎么写才能尽可能增加调试需求、尽可能把人搞糊涂,并且搞出来最多的技术债。

延伸阅读:

https://hackernoon.com/introducing-dilos-principles-for-JAVAscript-code-jp1d3w1b

声明:本站部分内容来自互联网,如有版权侵犯或其他问题请与我们联系,我们将立即删除或处理。
▍相关推荐
更多资讯 >>>