开发中的硬编码:是什么、风险以及如何避免

作者: IT Sectr 发布日期: 2026-07-31 阅读时间: 7 分钟

“硬编码”是行话术语,意味着将值直接固定在程序代码中,而不是将其提取到设置或配置中。硬编码是开发中最著名的反模式之一,因为它降低了代码的灵活性和可重用性。根据Refactoring Guru,硬编码使测试、维护和应用程序适应不同环境变得困难。有意识地使用常量代替硬编码是成熟架构的标志。

要点

  • 硬编码 – 将特定值直接写入源代码中
  • 硬编码因失去灵活性和维护困难而被视为反模式
  • 例外:数学常量、数组大小、默认值
  • 替代方案:配置文件、环境变量、资源
  • 重构硬编码可提高代码的可测试性和可扩展性

“硬编码”是什么意思

硬编码 – 将特定值嵌入程序代码中,以至于更改它需要编辑源代码并重新编译应用程序。“硬编码”这个比喻准确地反映了本质:值被牢牢固定,只能费力地将其从代码中分离出来。

硬编码的例子——写在函数体中的服务器URL字符串。如果服务器迁移到另一个地址,开发人员需要在代码中找到该字符串,更改它,重新构建应用程序并发布新版本。在具有正确架构的应用程序中,这样的URL会被提取到配置文件、环境变量或配置服务中。

“硬编码”一词带有更多情感色彩:它强调值是牢固嵌入且无法快速替换的。在中文环境中,这两种表达方式都作为完全同义词使用,带有负面含义。有时硬编码被戏称为“从常量中提取到单独常量的常量”。

为什么硬编码被视为反模式

硬编码是一种反模式,因为它违反了代码的可维护性、可测试性和可扩展性原则。在值被“硬编码”的代码中,任何环境、设计或逻辑的更改都需要在源代码中手动查找和替换。这增加了错误的风险并减慢了开发速度。

让我们以典型的移动应用程序为例来考察硬编码的具体后果。如果所有按钮的间距是由代码中的数字而不是通过资源来指定的——设计更改将需要查找所有出现的地方并替换。如果端点URL被硬编码——在环境(开发、测试、生产)之间切换而不重新编译是不可能的。

后果描述严重程度
维护困难更改需要搜索整个代码
复制错误并非所有出现的地方都被找到和替换
无法测试无法替换测试数据
本地化问题代码中的文本无法翻译
代码审查复杂化审查者必须记住所有上下文

糟糕的硬编码示例

使用魔法数字和硬编码字符串的函数是硬编码的经典例子。一个月后,作者将不记得18、0.07和2.5是什么意思。一年后——团队中没有人敢于更改这些数字,担心破坏逻辑。将值提取到命名常量使代码成为自文档化的。

kotlin
// 坏:魔法数字和字符串
fun calculatePrice(base: Double): Double {
    val tax = base * 0.07
    val tip = base * 0.15
    val discount = if (base > 100) 10 else 0
    return base + tax + tip - discount
}

对测试的影响

硬编码的数据库URL将不允许在本地内存中数据库上运行测试。开发人员将不得不启动完整的服务器或在测试前修改代码。将配置从代码中提取出来解决了这个问题:测试使用测试参数,生产使用真实参数,而代码保持不变。

何时硬编码是合理的:规则例外

硬编码是一种反模式,但存在合理的例外,即硬编码的值不仅允许,而且更可取。界限沿着可变性轴划分:如果值在应用程序的生命周期中从未或几乎从未更改过,则可以硬编码。如果至少有可能更改——请提取到配置中。

数学和物理常量——圆周率、重力加速度、每秒毫秒数——对硬编码来说是安全的。它们由自然或标准定义,不会改变。由规范定义的常量数组大小也可以硬编码,但需附带关于数字来源的注释。

合理的硬编码示例

每秒毫秒数是由时间标准定义的稳定常量。将其提取到配置中没有意义,因为它永远不会改变。然而,即使是这样的常量也最好用可理解的名称声明,这样代码就不会包含“魔法数字”:将1000写成MILLISECONDS_IN_SECOND

kotlin
// 合理的硬编码:稳定常量
private const val MILLIS_IN_SECOND = 1000
private const val LOGIN_TIMEOUT_SECONDS = 30

fun formatDuration(ms: Long): String {
    val seconds = ms / MILLIS_IN_SECOND
    return "${seconds} sec."
}

硬编码的替代方案:配置、环境变量、依赖注入

有几种经过验证的方法可以避免硬编码,每种方法适用于特定类型的值。替代方案的选择取决于值变化的频率以及谁在更改它:开发人员、运维人员还是最终用户。

配置文件

对于服务器URL、API密钥和功能标志,使用JSON、YAML或TOML格式的配置文件。在Android上是带有buildConfigField或res/values/config.xml的build.gradle。在iOS上是Info.plist或xcconfig。配置与应用程序一起构建,但对于不同的构建方案可能不同。

环境变量

对于机密信息(令牌、密码)和环境参数,使用环境变量。它们不会进入代码仓库,并且在开发、测试和生产服务器上可能不同。在移动开发中,环境变量通常通过Xcode构建方案或Gradle中的构建风味来模拟。

应用程序资源

字符串、颜色、尺寸、图像应提取到资源文件中:Android中的strings.xml、iOS中的Localizable.strings、Flutter中的ARB文件。这简化了本地化、适应不同屏幕和深色模式。更改资源中的字符串不需要重写代码。

xml
<!-- Android: res/values/strings.xml -->
<resources>
    <string name="app_name">MyApp</string>
    <string name="api_base_url">https://api.example.com</string>
</resources>

依赖注入

对于服务和提供者,使用依赖注入,在Android上通过Dagger、Hilt或Koin,在iOS上通过Swinject。依赖注入框架允许动态替换实现——用于测试、不同环境、不同用户。这是最高级别的抽象,其中值的“硬编码”被外部注入所取代。

如何重构硬编码的代码

重构硬编码是将硬编码值提取到配置或资源的过程。如果方法得当,这是最安全的重构操作之一。下面描述的序列适用于任何语言和平台。

第1步:找到所有魔法数字和字符串

可以通过集成开发环境(在项目中搜索)或脚本进行搜索。搜索字符串、URL、数字字面量、尺寸、超时。特别注意重复值:如果同一个数字出现在五个地方,那么它就是提取到常量的候选对象。使用grep或集成开发环境/ Xcode的内置搜索。

第2步:替换为命名常量

为每个找到的值创建具有有意义名称的常量。按模块或类对常量进行分组。名称应解释值的含义,而不是如何使用:API_TIMEOUT,而不是TIMEOUT_30。替换后,代码中不应有任何数字没有解释。

swift
// 之前:魔法数字0.4
let cardHeight = screenHeight * 0.4

// 之后:命名常量
private let cardHeightRatio: CGFloat = 0.4
let cardHeight = screenHeight * cardHeightRatio

第3步:提取到配置或资源

如果值可能在构建或环境之间变化——将其提取到配置文件或应用程序资源中。对于字符串,使用本地化文件。对于URL——构建配置或xcconfig。对于尺寸——资源文件(Android中的dimens.xml)。检查应用程序在提取后是否正确编译和运行。

第4步:编写测试

重构后,编写一个测试来检查配置是否正确加载以及值是否符合预期。如果将来有人更改配置,测试将指出不一致。配置测试是防止回归的快速可靠方法。

第5步:删除重复项

提取到配置后,检查所有使用旧值的地方是否引用单一来源。删除注释掉的代码和不再使用的旧常量。用描述哪些值以及被提取到何处的消息提交完成重构。

常见问题

编程中的“硬编码”是什么意思?

硬编码 – 将值直接写入源代码,而不是将其提取到配置或资源中。这使得代码不太灵活且更难以维护。

为什么硬编码被认为是糟糕的做法?

硬编码使更改应用程序行为变得困难,妨碍测试,产生重复并增加复制错误的风险。更改硬编码的值需要重新构建和重新发布应用程序。

何时允许硬编码?

允许用于数学常量、在应用程序生命周期中不变的稳定值以及临时原型。在生产中,即使是常量也最好提取到命名变量中。

如何替换现有代码中的硬编码?

通过搜索找到所有魔法数字,用命名常量替换它们或提取到配置文件中。编写一个测试来检查配置的加载。删除重复项并用描述更改的提交提交。

常量和硬编码有什么区别?

常量 – 代码中的命名值,可在单个位置更改。硬编码 – 分布在代码各处的未命名值。良好实践:始终使用具有有意义名称的命名常量。

总结

  • 硬编码 – 将值写入代码,无法快速替换
  • 硬编码 – 使维护、测试和可扩展性恶化的反模式
  • 魔法数字和未命名字符串 – 硬编码最常见的形式
  • 例外:数学常量和稳定的默认值
  • 替代方案:配置文件、资源、环境变量、依赖注入容器
  • 重构硬编码从查找重复项并将其替换为命名常量开始
  • 重构后编写用于配置加载的测试

我们将开发一款交钥匙移动应用程序

IT Sectr自2017年以来为初创企业和企业打造iOS和Android应用程序。我们将为您提供咨询并提出最佳解决方案。

讨论项目

另请阅读