硬编码通常被认为是一种反模式。将这些随时间变化的值硬编码到源代码中,每次值实际变化时都需要重新编译。虽然这句话也是正确的,但我觉得硬编码应该是开发应用程序时的默认选择。硬编码VS配置文件当您处理项目或功能时,总会有一些神奇的数字或字符串可能在未来发生变化。第一个冲动是使这些更改可配置,以便您将来可以轻松修改它们。在大多数情况下,此决定会使后续维护复杂化。我们在这里面临的是一个经典的困境“简单vs敏捷”。随着应用程序的增长,修改它的一些参数变得更加容易,因为它们被提取到配置文件中,但同时整体维护负担也增加了。在极端情况下,您最终可能会拥有数十个甚至数百个可配置参数,从而使维护应用程序变得异常痛苦。这种情况称为配置地狱。与许多其他软件设计决策一样,我们需要求助于YAGNI原则。所有这些参数真的需要立即配置吗?还是我们只是提前计划?如果是后者,我们最好在需求变得明显之前砍掉配置文件,以保持它的小。如果没有证明必要性,硬编码应该是默认选择。通过硬编码,我并不是说您应该将神奇的数字和字符串添加到您的项目源代码中。它们仍然需要被收集并作为常量放在一个地方。但是,这意味着您应该从配置文件中删除它们。日志记录示例让我们举一些例子,看看我们如何在实践中应用上面提到的原则。我最喜欢的日志库是NLog。它具有相当丰富的功能集,每个功能都可以轻松配置。以下是典型NLog安装的配置文件:虽然设置本身很合理,但我还是想建议一个一个问题:真的有必要把所有这些设置都放在配置文件中吗?我们要修改它们吗?在大多数情况下,答案是否定的。即使你怀疑,根据YAGNI原则,那也意味着“不”。幸运的是,NLog允许我们使用它的配置API在代码中进行配置。因此,我们可以轻松地将这些设置移动到源代码中,而不是依赖配置文件。让我们仔细看看这个例子,看看我们可以去掉哪些设置。首先,在目标部分,您可以看到我们对真实目标使用异步包装器。我们真的希望它是可配置的吗?不,此设置很少需要修改。好的,其他目标呢?它设置了许多有用的属性,例如日志布局、文件名、最大日志文件大小等。我们真的需要这种“无需重新配置的改变”机会吗?很可能,不需要。规则部分呢?这部分不像目标部分那么明显。修改最低日志级别(minlevel)以触发规则的可能性似乎是可以理解的,因为出于调试原因,我们可能希望即时修改它。然而,问题是实际上我们从来没有这样做过。因此,我们***也删除了此设置。好吧,最后我们还剩下什么?只剩下一个设置,它是日志文件本身的路径:现在,所有其他设置都放在源代码中:stringlayout=“Date:${longdate}\r\n”+“Level:${level}\r\n”+“Message:${message}\r\n";varconfig=newLoggingConfiguration();vartarget=newFileTarget{FileName=fileName,Layout=layout/*其他参数*/};varasyncWrapper=newAsyncTargetWrapper(target){QueueLimit=5000,OverflowAction=AsyncTargetWrapperAction.OverflowBlock};varrule=newLoggingRule(“*”,LogLevel.Error,asyncWrapper);config.AddTarget(“asyncWrapper”,asyncWrapper);config.LoggingRules.Add(rule);LogManager.Configuration=config;你可以看,我们删除了整个nlog部分,并将保留的设置移到了appSettings部分。现在它成为我们配置文件的普通成员。唯一真正需要具有不同值的设置取决于environmentitisbeingusedin.我们在这里所做的是减少表面配置,从而使解决方案更易于维护,但代价是灵活性降低。我坚信这是一个很好的妥协。随后,我们可能会发现自己经常修改硬编码设置。这发出了一个信号,我们找到了将其移动到配置文件中的正当理由。但是现在,让硬编码成为您的默认选择。总结我经常将这条规则应用到所有可能被移动到配置文件中的设置,这有助于保持它们的小和可维护性。另外,我注意到即使偶尔需要修改一些配置,在大多数情况下直接在源代码中修改就足够了。[更新]我应该指出本文的内容仅适用于内部软件。第三方存储库开发是另一回事。另外,我真的很感谢这篇文章收到的所有反馈,我没想到它会引起如此多的讨论。但是,不要混淆本文的主要思想——“让硬编码成为你的默认选择”——与“让硬编码成为你唯一的选择”。如果您真的需要从您的代码中提取一些价值并使其可配置,您一定会这样做。我唯一向您推荐的是问问自己是否真的有必要进行这种提取。