【问题标题】:Write programs that do one thing and do it well编写只做一件事并做好的程序
【发布时间】:2011-03-29 21:53:57
【问题描述】:
我可以通过封装,Dependency Injection,Principle of Least Knowledge,和You Ain't Gonna Need It来掌握“做一件事”的部分;但是我如何理解第二部分“做得好”?
给出的一个例子是完整性的概念,在同一个YAGNI article中给出:
例如,在允许添加项目、删除项目或修改项目的功能中,完整性也可用于推荐“重命名项目”。
但是,我发现这样的推理很容易被滥用到功能蠕变中,从而违反了“做一件事”部分。
那么,什么是检验功能是否属于“做得好”类别(因此,将其包含在函数/类/程序中)或其他“做一件事”类别(因此,排除它)?
第一部分“做一件事”最好通过 UNIX 的 ls 命令作为反例来理解,因为它包含过多的标志来格式化其输出,这些标志应该完全委托给另一个外部程序。但是我没有一个很好的例子来看到第二部分“做好”。
什么是一个很好的例子,如果删除任何进一步的功能会使其“做得不好”?
【问题讨论】:
标签:
solid-principles
single-responsibility-principle
yagni
【解决方案1】:
我认为“做得好”更多的是关于函数实现的质量,而不是关于一组函数的完整性(在您的示例中具有重命名以及创建和删除)。
做好事体现在很多方面,一些思维方式:
响应“特殊”输入的行为。示例,计算一些整数的平均值:
int mean(int[] values) { ... }
如果数组有零个元素,这会做什么?如果项目总计超过 MAX_INT?
性能特征。随着数据量的增加,是否对行为给予了足够的关注?
依赖失败。如果我们的实现依赖于其他模块或基础设施,那么当它们失败时会发生什么。示例:文件系统已满,数据库已关闭?
关于特性蠕变本身,我认为您在这里识别紧张是正确的。您可能会考虑一件事:您不需要实现每个功能,只要很明显无需完全重写即可轻松添加功能。
【解决方案2】:
此建议的全部目的是让您重视质量而不是数量。
一件事的概念是主观的,取决于粒度。如果电子表格应用程序还可以打印,您会说它做的不止一件事,还是那一件事的一部分?
关键是,在您争相添加新功能之前,您应该确保所有功能以及应用程序本身都已完成并且会让客户满意。 p>
【解决方案3】:
我认为您的问题指出了特征蠕变的基本有机性质,并且在理解这种性质后,您将有权思考更大的问题。
把它想象成一个花园:如果你种了一棵东西并且种得很好,比如菊花,那么你就不会仅仅种下种子。事实上,您需要确保土壤得到妥善照料、该地区得到充分保护、季节合适等等。
随着您的菊花(您的一件事)的生长,其他有竞争力的植物也会生长——一些需要被淘汰,而另一些可能实际上补充了原来的一件事。事实上,在某些情况下,这些其他有机体可能对你的一件事的生存至关重要。
就像那些 YAGN 的那些特征一样,需要一点警惕来确定哪些杂草代表特征蠕变,哪些代表重要和互补的功能。
无论如何,做得好仅仅意味着你的菊花是丰盛的、健康的、准时的。 :-)
【解决方案4】:
我想说一个不能添加附件的电子邮件程序就是一个很好的例子。
【解决方案5】:
这听起来像是一个奇怪的例子,但我想说 Dropbox 是一个很好的例子,虽然很复杂。
它通过致力于简化和缺乏您提到的违反“只做一件事”原则的功能,成功击败了一大堆类似的竞争应用程序。该应用程序允许您将文档存储在可以在任何地方访问的文件夹中,这就是它的极限。他们深入研究了核心问题,并以在 90% 以上的情况下都能完美运行的方式解决了问题。
很难给它制定一个硬性规定,但我想说的是,满足大约 90% 的大多数用例并忽略“边缘要求”是遵守这条规则的最佳方式。
我猜 90% 以上的 ls 使用没有参数,或者可能是最流行的两三个。 “做好”的原则应该关注大多数用户的需求,而不是像 ls 的众多选项那样迎合高级用户或边缘情况。
这就是 Dropbox 的成功之处,以及为什么它被广泛认为是优秀应用程序设计的一个例子。