我的是这样的:
硬编码才是王道!我所有的问题都消失了。只需一一编码即可。问题又回来了,会扼杀你的一天。
我绝对讨厌它,但事实是“商务人士”倾向于喜欢它,因为获得他们想要的东西需要更少的时间。作为一名特别是在企业环境中工作的软件开发人员,大多数人会说:“是的,何必麻烦,只需硬编码即可”。你对硬编码的态度是什么?
我的是这样的:
硬编码才是王道!我所有的问题都消失了。只需一一编码即可。问题又回来了,会扼杀你的一天。
我绝对讨厌它,但事实是“商务人士”倾向于喜欢它,因为获得他们想要的东西需要更少的时间。作为一名特别是在企业环境中工作的软件开发人员,大多数人会说:“是的,何必麻烦,只需硬编码即可”。你对硬编码的态度是什么?
硬编码是应该尽可能避免的事情。
如果您在代码上硬编码某些内容,它将在很大程度上完全“破坏”代码的可移植性。即使使用独立于平台的语言,您也无法说“编译一次,随处运行”。由于这不是一个好的软件工程实践,我认为避免硬编码更好。
但我知道在某些情况下我们需要它,特别是在调试代码时。我建议的方法是:先用硬代码开发代码,使其稳定并消除硬代码然后......
由于安全问题等原因,在某些情况下我们需要硬编码:)。您可能不允许使用注册表、配置文件等任何东西,因为它们会增加攻击面。但我认为这是一种罕见的情况。
IT 中不存在灵丹妙药。
如果有人告诉您做愚蠢的事情,请保存电子邮件线程并保存您的工作
只要出于正确的原因,硬编码就没有错!
“做对了”意味着将所有的硬编码集中在一两个模块中。
对于 C 来说,在 code.h 中定义所有值,对于 Java,有一个 codes.java 类,该类充满了公共常量。
硬编码有几个“正确的理由”。
还有几个原因可以避免过于复杂的配置文件。如果你有足够的参数和选项,你最终只会用一种不太好的语言进行编程。
从概念上讲,我不喜欢太多的硬编码。
但在实践中,我倾向于硬编码一些值。硬编码的主要原因是:
我认为有一些“硬编码最佳实践”永远不会过度设计:
这使得以后可以将硬编码值移动到其他位置。
作为一个在我早期有过硬编码经验的人(不要告诉任何人),我可以自信地告诉你,它会再次困扰你。我制作的这个应用程序(我现在不谈)必须完全重写,因为它有很多硬编码的内容。那是1998年的伙伴。
除非您将来不想支持该客户,否则不要这样做。您现在节省的时间将用于以后修复。
在嵌入式和关键软件中,硬编码有两个主要优点:
这意味着更少的 CPU 负载,即更少的功耗,更少或没有动态内存分配,更少的算法复杂性,即更容易调试,...
通常,硬编码数据被放在一个单独的头文件中以提高可维护性。
此外,从数据库自动生成该头文件提供了灵活性。
我认为对默认值进行硬编码是解决可能需要配置的所有内容的方法:
在我们的 GUI 代码(客户端-服务器)中,我们使用三步查找:我们向偏好实例询问具有默认值的偏好。但是这个传递的默认值会被配置文件覆盖(如果存在)。
这样我们以后有两个选择。如果客户想要不同的东西,我们可以在配置文件中进行更改。我们还可以配置我们的设置对话框以使其用户可配置。
如此有效地,我们有硬代码,可以被配置覆盖,可以被用户偏好覆盖。
唯一的问题是记录所有首选项键...
通常花费在维护代码上的时间和金钱比最初编写代码要多。代码总花费的 80% 通常用于维护期间。因此,任何使维护变得更加困难的事情最终都会比第一次做对的成本更高。硬编码绝对是使维护变得更加困难的一件事,因此是一个坏主意。
硬编码是要走的路!
但正如 Anthony 提到的,我将可配置的值放在他们自己的类中。通过这种方式,它们可以在编译时进行配置,但不会增加外部 xml/txt 文件进行配置所带来的复杂性。
我只在绝对必要的情况下使用 xml/txt 文件进行配置。否则,您只是过度设计,这可能与硬编码一样糟糕,甚至更糟糕。更不用说人们在配置文件中放入了很多你不希望客户端更改的东西。
如果您需要为不同的客户端进行不同的配置,没问题,将硬编码的值放在他们自己的程序集/dll中,并为每个客户端部署不同的配置程序集。
正如Ayende所说,对所有内容进行硬编码是实现变革的关键。
我通常尝试将值放入配置文件而不是硬编码。如果一个值必须是硬编码的,我会用硬编码的值创建一个常量,并且代码中的任何地方都引用同一个常量。如果值需要更改,可以在一个地方完成。
对于应用程序范围的常量,我通常创建一个类并在其中创建常量。
涉及的几个因素很难做出涵盖所有情况的断言。
如果这是一个有几个周期的长项目,那么如果你开始硬编码,它们很可能很快就会再次弹出。因此,在这些情况下,最好使用适当的解决方案进行修复。
但是,如果您有一个周期短的项目,或者有预定义的时间表,并且无论如何您都必须交付产品,那么大多数客户都会对产品的工作感到满意,他们不会关心内部结构。但在这些情况下,我更喜欢硬编码解决方案,但让路径开放,以便将来很容易做出正确的解决方案。
无论如何,硬编码是不好的,但是我正确地记录它可以使下一个人的生活更轻松,并且可能不会诅咒你,至少不会太多;)。
但根据我的经验,我开始避免从头开始硬编码,只有在别无选择时才使用它们,并且总是记录这些情况,以便以后有时间时可以正确修复它。
得到他们想要的东西需要更少的时间。
这几乎就像是在说:“我喜欢编写不带注释的代码,因为得到我想要的东西需要更少的时间。”
当然,这并不是说硬编码总是一件非常糟糕的事情。(我的意思是,在配置文件中存储诸如 π、e 或普朗克常数之类的数学常数有点愚蠢。此外,硬编码查找表以查找正弦/余弦值可能会比从文件中加载要高效得多。)但是纯粹为了方便而对数据进行硬编码并不是一个聪明的主意。它不灵活,并且使以后修改数据比必须的要麻烦得多。
此外,硬编码会使本地化变得极其困难,即使在许多情况下并非不可能。如果它是某个公司的内部应用程序,那么我想这在某种程度上并不重要,但这并不能使它成为一个好的软件开发实践。
如果我需要 achar *
指向 12 个字符,我可以安全地写malloc(12)
,因为sizeof(char)
它总是 1。如果我需要 aint *
指向 12 个整数,我写malloc(12 * sizeof(int))
.
硬编码一些绝对 不会改变的东西。对于其他所有事情,它需要额外的两秒钟,所以为什么不继续做呢?
如果硬编码正确完成,它可能是一个奖励。例如,如果您对数组大小进行硬编码而不是进行动态分配,则可以很容易地进行调试,因为您确切地知道数组在内存中的位置。这是假设您实际上想知道这些事情。
我总是创建一个常量,但尽可能接近/明智地使用它的“唯一”用途。
如果我在单元的其他地方需要它,它会被移动到单元的顶部。
如果在另一个单元中需要它,则常量将移动到设置单元。
如果有人希望它可以更改,它会被移动到设置单元(如果还没有),并从配置文件等中设置。
归根结底,您给事物起的名字就是它的文档,至少这意味着您不会将您的 73 与其他人的 73 混淆。如果您明白我的意思。
关于 C/C++ 中的硬编码字符串;我通常将它们#define 作为避免硬编码的最简单方法(尽管在某种意义上仍然是硬编码)。原因是定义的标识符拼写错误将被编译器捕获,而引号之间的任何内容都不会。
我对配置的态度?它经常做得很差而且太随意 - 随着用户试图了解 100 多个可配置值,TCO 会增加。仅在证明有必要时才添加可配置性(软编码)。
必要时... 应以与用户输入相同的不信任来对待可配置值,并在输入错误时提供清晰的错误消息。大多数组件应该与配置基础设施隔离 - 就像您将大多数组件与任何数据访问基础设施隔离一样。一旦与配置基础设施隔离,您就可以并且应该测试组件如何处理来自配置系统的各种“输入”。最重要的是,该程序应该可以在最少的配置下正常工作。
但是,这种类型的反模式非常常见:
File.Open(configuration["widgetsFileStorage"] + "/" + widgetImage)
或者这个(你会不会将用户输入直接放入一个 href 中?我不会。不知何故,很多人过于信任配置值)。
LinkWriter.href=configuration["supportUrl"]
什么时候配置?正如你证明你需要。良好的关注点分离将使以后可以轻松地使值可配置。我会放弃将文件定位到文件定位器中的责任。
File.Open(new WidgetFileLocater().GetUncPath(widgetImage))
在我的文件定位器后面的某个地方,我可能会或可能不会引用配置文件、数据库。我可能会开始硬编码到应用程序目录中的“图像”目录。当我们有一个灵活性用例(有人想把它放在 SAN 上?)而不是之前,配置就会出现。无论如何,无论是否配置,大多数应用程序都不应该。我可能会在文件定位器上使用一些依赖注入来验证它是否正确处理了来自配置文件的糟糕输入。
另外:配置几乎总是松散类型,未编译,因此比代码危险得多。开发人员很少尊重这种风险(但系统管理员非常尊重这种风险)。我已经讨论过使用像 python / ironpython / boo 这样的脚本语言来满足配置需求。我将获得在编译后更改内容的能力,其语法和类型检查比 xml 或文本更自由。
警告:我的态度假设一个迭代的发布周期。如果你有一个 2-10 年的发布周期,比如 Microsoft,你会倾向于倾向于配置更多的值。