文章摘要
文章讨论了现代软件开发中过度依赖处理边缘情况的库,导致依赖树过于复杂和臃肿的问题。作者以clamp函数为例,指出开发者常常过度设计,处理一些可能从未遇到的情况,增加了不必要的复杂性。作者呼吁简化代码,避免过度工程化,以减少依赖树的冗余。
文章总结
标题:边缘优先库的膨胀问题
主要内容:
近年来,许多库在设计时过度考虑了边缘情况,导致依赖树过于复杂和臃肿。本文通过几个例子探讨了这一问题,并提出了改进建议。
问题:
许多隐藏在深层依赖树中的小型库,往往是为了处理我们可能从未遇到过的输入和边缘情况而过度设计的。例如,一个简单的 clamp 函数,原本只需要处理数字的上下限,但为了应对各种边缘情况(如传入字符串、无效范围等),代码变得复杂且不必要。最终,这些边缘情况的处理甚至被提取为独立的库,如 is-number,进一步增加了依赖树的复杂性。
正确的做法:
库的设计应专注于处理常见的用例,而不是试图解决所有可能的边缘情况。例如,clamp 函数应仅接受数字作为输入,并在必要时进行简单的值验证(如 min <= max)。库应假设传入的数据类型是正确的,而将复杂的验证工作留给应用程序层。
不应做的事情:
我们不应构建以边缘情况优先的库,即那些为了解决我们可能从未遇到或不太可能遇到的边缘情况而设计的库。例如,is-arrayish、is-number、pascalcase 和 is-regexp 等库,虽然在某些特定场景下有用,但在大多数情况下,它们的复杂性和依赖性是多余的。
应做的事情:
库应专注于解决常见用例,并对输入类型做出合理的假设。例如,scule 和 dlv 等库,它们只接受设计中的输入类型,并且没有不必要的依赖。
验证的重要性:
验证是重要的,但应在数据的所有者(如应用程序层)进行,而不是在每个库中重复进行。深层次的依赖树中的验证实际上将负担从数据边界转移到了依赖树的深处,这通常对库的使用者是不可见的。
过度细分的库:
本文还提到了过度细分的库,如 shebang-regex、is-whitespace 和 is-npm 等,它们的功能非常简单,但却被提取为独立的库,导致依赖树过于复杂。
如何改进:
作为库的维护者,应审查依赖项,看看是否有可以替换为原生功能或更小、更高效的替代品。作为用户,应密切关注依赖项,并寻找更好的替代方案。使用工具如 npmgraph 和 Dependabot 可以帮助管理依赖树。
结论:
大多数这些库的存在是为了处理确实存在的边缘情况。然而,我们所有人都在为此付出代价,而不仅仅是那些需要支持这些边缘情况的人。这是错误的。库应实现主要用例,而替代品或插件可以为少数人提供边缘情况的支持。我们应更加关注依赖树中的内容,并推动更简洁、更轻量级的库。
评论总结
评论主要围绕以下几个观点展开:
静态类型与动态类型的对比:
- 一些评论认为静态类型语言(如TypeScript)可以减少不必要的类型检查库的使用。例如,评论1指出“3 of those 4 examples wouldn't exist in a statically-typed language like TypeScript”。
- 评论28提到“If JS’s dynamic types worked like Ruby’s or Python’s then you wouldn’t think to build a library that tells you if something is a regex”。
JavaScript语言设计的缺陷:
- 评论5和15认为JavaScript缺乏良好的标准库和强类型设计,导致需要大量类型检查库。评论5说“This is why every language needs a good standard library, which unfortunately JavaScript never had”。
- 评论17进一步指出,JavaScript的问题在于其“弱类型”设计,而不是缺乏静态类型或标准库。
库的依赖与复杂性:
- 评论6和23讨论了库依赖的复杂性和更新问题。评论6提到“The farther you go down in the dependency tree, the older the packages are”,而评论23认为“Handling a ton of edge cases so I don’t have to do it myself is a good reason to use a library”。
- 评论20批评了过度依赖包管理器的现象,认为“how do I check if a string starts with a shebang”应该通过代码片段解决,而不是引入新的依赖。
函数设计与输入验证:
- 评论7和19讨论了
clamp函数的设计,认为它应该处理更多边缘情况。评论7说“clamp comes down to sorting the three numbers and returning the middle one”,而评论19认为“clamp should actually accept anything comparable”。 - 评论10和22则主张函数应假设输入符合约定,调用者应负责验证输入。评论10提到“the caller handles the not-a-number case, so the callee doesn’t have to”。
- 评论7和19讨论了
库的合理性与历史背景:
- 评论14和25讨论了这些库的历史背景和合理性。评论14指出“The library is-arrayish exists because array-like objects are actually a thing in javascript”,而评论25认为“You don’t need a ‘is it a number’ package in java, because the function cannot be passed a string”。
总结:评论中既有对JavaScript语言设计的批评,也有对库依赖复杂性和函数设计的讨论。静态类型语言被认为可以减少不必要的类型检查库,而JavaScript的弱类型设计被认为是问题的根源。同时,库的依赖更新和函数设计的合理性也是讨论的焦点。