硬编码文字是否可以接受?

时间:2008-12-31 00:24:00

标签: language-agnostic hard-coding

我目前正在处理的代码库中充斥着硬编码值。

我将所有硬编码值视为代码气味,并尝试尽可能消除它们......但是有些情况我不确定。

以下是我能想到的两个例子,让我想知道最佳做法是什么:

1. MyTextBox.Text = someCondition ? "Yes" : "No"
2. double myPercentage = myValue / 100;

在第一种情况下,最好的办法是创建一个允许我在配置文件中执行MyHelper.Yes和MyHelper.No或者类似的东西的类(虽然它不太可能改变,谁知道如果可能存在其用法区分大小写的情况)。

在第二种情况下,除非数学定律改变,否则找不到百分比的百分比不可能改变......但我仍然想知道是否有更好的方法。

有人能建议一种适当的方法来处理这种硬编码吗?任何人都可以想到硬编码是可接受的做法吗?

21 个答案:

答案 0 :(得分:17)

  

任何人都可以想到任何可以接受硬编码的地方吗?

  • 小型应用
  • 单人项目
  • 扔掉
  • 短期生活项目

简而言之,任何其他人都不会维护。

Gee我刚刚意识到维护者编码器在过去伤害了我多少:)

答案 1 :(得分:16)

当然,硬编码有时是可以接受的。以下教条很少像使用你的大脑那样有用。

(举个例子,也许回到goto战争很有意思。你知道有多少程序员会发誓所有神圣的东西都是邪恶的?为什么Steve McConnell会把十几页用于在Code Complete中测量了对主题的讨论?)

当然,有很多来之不易的经验告诉我们,小型一次性应用程序经常会变成生产代码,但这并不是狂热的理由。敏捷专家告诉我们,我们应该do the simplest thing that could possibly work并在需要时进行重构。

这并不是说“最简单的东西”不应该是可读代码。这可能是非常有意义的,即使是在一次丢失的尖峰中写道:

const MAX_CACHE_RECORDS = 50
foo = GetNewCache(MAX_CACHE_RECORDS)

无论在三次迭代时间内,有人可能会要求缓存记录的数量是可配置的,并且您最终可能会重构该常量。

请记住,如果你去了极端的事情,比如

const ONE_HUNDRED = 100
const ONE_HUNDRED_AND_ONE = 101

我们都会来到The Daily WTF并嘲笑你。 : - )

想想!就是这样。

答案 2 :(得分:15)

真正的问题不是硬编码,而是重复。如果您采用"The Pragmatic Programmer"中的优秀建议,只需不要重复自己(DRY)。

根据DRY的原则,任何时候都可以硬编码。但是,一旦再次使用该特定值,重构,因此该值仅被硬编码一次。

答案 3 :(得分:7)

它永远不会好,你只是证明了它......

double myPercentage = myValue / 100;

这不是百分比。你想写的是:

double myPercentage = (myValue / 100) * 100;

或更正确:

double myPercentage = (myValue / myMaxValue) * 100;

但是这个硬编码100与你的思想搞混了......所以去找Colen建议的getPercentage方法:)

double getpercentage(double myValue, double maxValue)
{
   return (myValue / maxValue) * 100;
}

正如ctacke建议的那样,在第一种情况下,如果您需要本地化这些文字,您将处于一个痛苦的世界。添加更多变量和/或函数永远不会太麻烦

答案 4 :(得分:6)

如果你需要本地化,第一种情况会杀了你。将它移动到应用程序范围内的静态或常量将至少使本地化更容易。

答案 5 :(得分:6)

案例1:什么时候应该硬编码:当你没有理由认为它会改变时。也就是说,你应该从不硬编码内联。花点时间制作静态变量或全局变量或者你的语言给你的东西。在有问题的课程中执行这些操作,如果您注意到代码的两个类或区域共享相同的值(同样意味着它不仅仅是巧合),请将它们指向同一个位置。

案例2:对于案例2,你是对的:“百分比”的定律不会改变(这里是合理的),所以你可以硬编码内联。

案例3:第三种情况是您认为事情可能发生变化,但您不想/有时间去加载ResourceBundles或XML等等。在这种情况下,你可以使用任何集中机制 - 讨厌的Singleton类是一个好的 - 然后继续使用它直到你真正需要处理问题。

第三种情况很棘手:如果没有真正做到这一点,将应用程序国际化是非常困难的...所以你会想要硬编码的东西,只希望当i18n家伙敲门时,你的代码不是最糟糕的代码:)

编辑:让我提一下,我刚刚完成了一个重构项目,其中先前的开发人员将MySql连接字符串放在代码中的100多个位置(PHP)。有时它们是大写的,有时它们是小写的,等等,所以它们很难搜索和替换(尽管Netbeans和PDT确实有很多帮助)。他/她这样做是有原因的(一个名为POG的项目基本上会强迫这种愚蠢行为),但是没有什么似乎不像好的代码那样在一百万个地方重复同样的事情。

答案 6 :(得分:4)

第二个例子的更好方法是定义内联函数:

double getpercentage(double myValue)
{
   return(myValue / 100);
}

...

double myPercentage = getpercentage(myValue);

这样,你正在做的事情就更明显了。

答案 7 :(得分:3)

我不认为你的第二个真的是硬编码的例子。这就像有一个Halve()方法,它接受一个值来分隔;没有意义。

除此之外,示例1,如果您想更改应用程序的语言,您不希望更改类,因此它绝对应该在配置中。

应该避免硬编码,就像Dracula避开太阳一样。最终会回来咬你的屁股。

答案 8 :(得分:3)

硬编码文字应该出现在测试值的单元测试中,除非在单个测试类中重复使用一个局部常量有用的值。

单元测试是对期望值的描述,没有任何抽象或重定向。 想象一下你自己在阅读测试 - 你希望信息完全在你面前。

我使用常量测试值的唯一一次是当许多测试重复一个值(本身有点可疑)时,值可能会发生变化。

我确实使用常量来比较测试文件的名称。

答案 9 :(得分:3)

“硬编码”是错误的担心。关键不在于特殊值是在代码中还是在配置文件中,重点是:

  • 如果价值可能会发生变化,那需要做多少工作以及找到多少难度?将它放在一个地方并在其他地方引用那个地方并不是很多工作,因此是一种安全的方式。
  • 维护程序员肯定会明白为什么它的价值是什么?如果有任何疑问,请使用一个解释其含义的命名常量。

这两个目标都可以在不需要配置文件的情况下实现;事实上,如果可能,我会避免这些。 “把东西放在配置文件意味着它更容易改变”是一个神话,除非

  • 您实际上希望支持客户自行更改价值
  • 没有可能放在配置文件中的值会导致错误(缓冲区溢出,任何人?)
  • 您的构建和部署过程糟透了

答案 10 :(得分:2)

不正常(硬编码文字可以接受)

另一种看待这种情况的方法是如何使用良好的命名约定 对于用于代替硬编码文字的常量提供额外的 程序中的文档。

即使该号码仅使用一次,仍然难以识别 甚至可能很难找到未来的变化。

恕我直言,让程序更容易阅读应该是第二天性 经验丰富的软件专业。原始数字很少传达 有意义。

使用一个名为constant的常量所需的额外时间将成为 代码可读性(易于回忆),对未来有用 重新挖掘(代码重用)。

答案 11 :(得分:2)

没有

今天什么是简单的扔掉应用程序将明天推动整个企业。总是使用最佳实践,否则你会后悔。

答案 12 :(得分:2)

条件的文本应该在资源文件中;这就是它的用途。

答案 13 :(得分:1)

只要您不进行重构,单元测试,同行代码审查,这是可以的。并且,您不希望重复客户。谁在乎?

答案 14 :(得分:1)

代码总是在发展。当你最初写东西时,硬编码是最简单的方法。稍后当需要到达以改变价值时,可以改善它。在某些情况下,需求永远不会到来。

需求可以多种形式出现:

  1. 该值在很多地方使用,需要程序员更改。在这种情况下,显然需要一个常数。

  2. 用户需要能够更改值。

  3. 我认为没有必要避免硬编码。我确实认为有必要在有明确需要的时候改变一切。

    完全独立的问题是当然代码需要是可读的,这意味着可能需要对硬编码值进行注释。

答案 15 :(得分:1)

请记住,您将忘记任何非明显的硬编码值的含义。

因此,请务必在每次提醒之后加上简短的评论。

Delphi示例:

长度:=长度* 0.3048; {0.3048将英尺转换为米}

答案 16 :(得分:1)

我倾向于根据项目的范围和规模来看待它。

我是个独立开发的一些简单项目?当然,我很难编写很多东西。我写的工具,我将永远使用?当然,如果它完成了工作。

但是,在开展更大规模的团队项目时?我同意,他们是嫌疑人,通常是懒惰的产物。标记它们以供审查,看看是否可以发现可以抽象出来的模式。

在您的示例中,文本框应该是可本地化的,那么为什么不是一个处理该文本的类?

答案 17 :(得分:0)

我曾经有一位老板拒绝不对某些东西进行硬编码,因为在他看来,这让他完全控制了软件与软件相关的项目。问题是,当硬件死了运行软件时服务器被重命名......这意味着他必须找到他的代码。这需要一段时间。我只是找到了一个十六进制编辑器,并在其周围进行攻击而不是等待。

答案 18 :(得分:0)

应永远禁止硬编码。在你非常简单的例子中,我认为在任何类型的项目中都没有使用它们。

在我看来,硬编码是指您认为变量/值/定义等永远不会改变并根据该信念创建所有代码。

这种硬编码的例子是24小时内自学C的书,每个人都应该避免。

答案 19 :(得分:0)

我通常会为字符串和数字添加一组辅助方法。

例如,当我有'yes'和'no'之类的字符串时,我有一个名为__的函数,所以我调用__('yes');通过返回第一个参数开始在项目中,但是当我需要做更复杂的事情(例如internationaizaton)时,它已经存在并且param可以用作密钥。

另一个例子是在线商店的增值税(英国税的形式),最近它从17.5%变为15%。通过以下方式对增值税进行硬编码的任何人:

$vat = $price * 0.175;

然后必须通过所有引用并将其更改为0.15,相反,超级有用的方法是使用VAT的函数或变量。

在我看来,可以更改的任何内容都应该以可变的方式编写。如果我发现自己在同一天做同样的事情超过5次,那么它就变成了函数或配置变量。

答案 20 :(得分:0)

对于第一个值,它确实取决于。如果您没有预期任何广泛采用您的应用程序和国际化永远不会成为一个问题,我认为这是非常好的。但是,如果您正在编写某种类型的开源软件或者有更多受众的东西,请考虑一下它可能有一天需要翻译。在这种情况下,您可能最好使用字符串资源。