空格与选项卡:开发人员人体工程学和工具链现实
如何做出保持代码可读性、包容性和自动化友好的风格决策
争论仍然存在
每次入职电话仍然会有这样的时刻:有人问团队是否喜欢空格或制表符,然后房间就安静了。争论不再是意识形态的;而是。我们提供的工具决定了我们的代码的可访问性、我们的差异看起来有多干净以及我们的自动迁移的可预测性。
本指南的目标很简单:为您提供一个可重复的框架,您可以将其粘贴到工程手册中,以便“空格与制表符”问题不再浪费您的冲刺时间。
推动决策的关键标准
- 辅助功能要求 - 屏幕阅读器和等宽字体对于制表位的行为有所不同。
- 差异稳定性 - CI 机器人和审阅者更喜欢确定性格式以避免嘈杂的 PR。
- 语言生态系统默认设置 - Go、Python 和 Rust 工具链都附带了内置的意见。
- 旧版足迹 - 您可能有数万行已经以一种方式格式化。
- 编辑器支持 - 开发人员仍然在同一存储库上的 VS Code、JetBrains 和 Vim 之间切换。
工具链供应商默认的内容
| 语言/生态系统 | 官方格式化程序 | 默认缩进 | 覆盖选项 |
|---|---|---|---|
| JavaScript / TypeScript | 更漂亮 | 2 个空格 | text tabWidthtext useTabs |
| Python | 黑色的 | 4 个空格 | 无(选项卡被拒绝) |
| 去 | 戈夫姆特 | 选项卡 | 通过 text gofmt -tabs=false |
| 锈 | 铁锈 | 4 个空格 | 需要不稳定的配置 |
| C# | 点网格式 | 4 个空格 | text .editorconfig |
如果您遵循生态系统默认设置,则每次格式化程序添加规则时,您都可以获得免费升级。与默认设置作斗争意味着永久保留自定义配置。
辅助功能和屏幕阅读器注意事项
- 选项卡根据用户设置以可变宽度呈现。这对于高级用户来说非常有用,但对于期望均匀间距的屏幕阅读器来说却很混乱。
- 空间为盲文显示和语音合成提供确定性布局,因为每个空间都是一致宣布的。
- 对于混合能力的团队来说,最安全的选择是在数据表中保留缩进和制表符的空间,以便在灵活性很重要的情况下进行对齐。
Diff Hygiene:审稿人如何体验您的选择
考虑一个 TypeScript 文件,其中开发人员添加了两个保护子句。将选项卡配置为 4 个空格后,使用 80 列 Git 控制台的审阅者可能会看到整个差异重新对齐。空格使差异保持本地化。
typescriptif (!user?.profile) { return redirect('/login') } if (!user.isOnboarded) { return redirect('/welcome') }
上面带有空格的代码片段会产生微小的差异,因为每个格式化程序都同意确切的字符数。选项卡通常会根据本地编辑器设置加宽或缩小,从而在不相关的行上产生“虚拟”更改。
2025 年可行的混合模式
许多产品团队采用的实用折衷方案:
- 缩进: 使用格式化程序强制使用的空格(2 或 4)。
- 对齐: 仅允许在 Makefile、Go 代码或数据表中使用制表符,其中对齐在语义上很重要。
- 自动化: 添加 以及格式化程序脚本,这样就没有人手动提交空格。text
.editorconfig
示例 text.editorconfig
.editorconfiginiroot = true [*] indent_style = space indent_size = 2 insert_final_newline = true trim_trailing_whitespace = true [*.go] indent_style = tab indent_size = 4 [Makefile] indent_style = tab [*.md] trim_trailing_whitespace = false
旧存储库的迁移手册
- 选择一个能够理解您的语言的格式化程序(Prettier、rustfmt、clang-format 等)。
- 在主分支上生成基线差异并将其标记为 ,以便将来的指责会话有一个检查点。text
style-migration-base - 在整个存储库中运行格式化程序一次。使用类似 的消息进行提交。text
chore: normalize whitespace - Enable CI enforcement using a lint job. GitHub 操作示例:
yamlname: formatting on: [pull_request] jobs: prettier: runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - run: npm ci - run: npm run lint:format
- 在工程手册中记录决定,这样新员工就不会再次引发争论。
当标签不可协商时
- Go 项目 - 输出选项卡;解决这个问题意味着维护一个分叉的格式化程序。text
gofmt - Makefiles - 语法需要配方行的文字选项卡;空格会引发运行时错误。
- 内核或固件代码库与硬件文档的一致性很重要。
使用
.editorconfig您团队的决策矩阵
| 约束 | 选择空格如果... | 选择选项卡如果... |
|---|---|---|
| 混合语言单一存储库 | 大多数人青睐空间 | 大多数是 Go / Make |
| 屏幕阅读器贡献者 | 无障碍是优先考虑的 | 团队可以保证选项卡友好的工具 |
| CI 格式化 | 格式化程序默认为空格 | 格式化程序输出选项卡 |
| Git历史稳定性 | 你想要一致的责备线 | 制表符宽度差异是可以接受的 |
实施清单
- 以书面形式同意缩进大小(2 与 4)。
- 提交 并格式化脚本。text
.editorconfig - 添加一个因空格漂移而失败的 CI 防护。
- 直接在存储库自述文件中记录异常(Go、Makefile)。
- 运行一次性迁移并标记提交。
TL;DR 适合您的剧本
空间提供可预测性、可访问性和清晰的差异。选项卡在少数生态系统中仍然至关重要。最可持续的策略是遵循格式化程序默认值,对决策进行自动化编码,并且不再依赖单独的编辑器设置。
在您进行下一次回顾之前,请将本文复制到您的内部 wiki 中并明确做出决定。当 lint 作业运行时,火焰之战结束。