是什么阻碍 IT 项目执行
Source: Dev.to
Cover Image

我已经在此发布了详细内容。
我有超过 18 年的系统构建经验。这是我从失败的项目中学到的经验。问题不在于代码质量,而在于失败前 6–12 个月所做的决策。
失败分为七类
1. 执行模型不匹配
错误
现实:客户合同要求 固定范围。
结果:永久性的范围蔓延、客户愤怒,约 18 个月后又回到瀑布模式。
案例 – 一家制造业软件公司在使用固定价合同的同时采用 Scrum。由于范围不断变化,功能无法在冲刺内交付。当他们尝试限制范围时,客户回应:“这不在原始协议里”。他们用了两年才意识到 Scrum 与固定范围的业务模型不匹配。
更好的做法
| 业务模型 | 推荐的交付模型 |
|---|---|
| 固定范围合同 | 瀑布或混合(计划驱动 + 迭代交付) |
| 基于结果的(SaaS,平台) | 敏捷 |
| 项目中期范围变更 | 滚动波 + 按时计费 |
| AI 产品 | 实验驱动(快速测试 + 学习) |
框架很重要。业务模型决定框架。
2. 估算表演
错误
选择故事点、功能点、T‑恤尺码或 AI 估算让所有人都感觉很有信心。六个月后速度下降 40 %,团队陷入集成地狱。
为何所有方法都会失效 – 它们把三个不同维度混为一谈:
- 工作量 – 需要多少工程师工时?
- 复杂度 – 有多少未知数?
- 执行风险 – 可能会出什么问题?
示例 – 微服务迁移
| 服务范围 | 原始估算 | 实际工作量 |
|---|---|---|
| 1‑5 | 每个 13 sp | 3 个月完成 |
| 6‑10 | 每个 13 sp | 6 个月(集成复杂度) |
| 11‑25 | 每个 13 sp | 每个 3‑4 个月(级联 API 依赖) |
工作量保持一致;复杂度却爆炸式增长。
更好的做法 – 将每个维度 单独估算,并根据复杂度/风险添加预留。
- **工作量**:120 工程师工时
- **复杂度**:低(5 个未知)/ 中(15 个未知)/ 高(40+ 个未知)
- **风险**:技术、集成、供应商、人才
- **预留**:+30‑50 % 缓冲(取决于复杂度/风险)
承诺 工作量,而不是时间表。
3. 测试信心
错误
团队指标:代码覆盖率 80 % + 左移测试 + AI 生成的测试。
生产指标:事故率与两年前相同。
为何指标会骗人
- 代码覆盖率只告诉你 “代码是否运行过?”,而不是 “它是否工作?”
- 左移测试关注的是 happy path;生产环境会出现 99 % 的边缘情况。
- AI 生成的测试继承了人写测试的同样盲点(错误的数据、错误的规模)。
案例 – 零售公司自动化覆盖率 85 %。黑色星期五:
- 测试在干净数据和稳定流量下运行。
- 实际流量激增 100 倍,缓存失效,连接池耗尽。
- 生产宕机 6 小时 → 500 万美元 损失收入。
更好的做法 – 把问题从 “它工作吗?” 改为 “它什么时候会崩?” —— 即 混沌工程 与 故障注入。
# 而不是这个简单的 happy‑path 测试:
def test_user_creation():
user = create_user("john@example.com", "password123")
assert user.id is not None
# 这样做:
def test_user_creation_under_load():
# 1 000 请求/秒时会崩吗?
load_test(create_user, requests=1000)
def test_user_creation_with_slow_db():
# 如果数据库很慢会怎样?
slow_db_connection()
user = create_user("john@example.com", "password123")
assert user.id is not None # 或者会超时?
def test_user_creation_concurrent_writes():
# 如果重复的邮箱同时提交会怎样?
concurrent(lambda: create_user("john@example.com", "pass"))
assert no_duplicates()
采用这种风格的团队 事故减少约 70 %。
4. AI 生成的代码债务
错误
| 时间线 | 观察 |
|---|
| Month 1 | “我们在使用 Copilot!速度提升 +30 %!” | | Month 6 | 代码审查变得不可能,缺陷翻倍,重构噩梦。 | | Month 9 | 代码库清理耗时 2 个月 → 生产力变为负数。 |
为什么会发生 – AI 编写的代码在理想路径上可以运行,但往往缺少错误处理、类型检查,并会引入隐藏缺陷。
示例生成代码
def process_orders(orders):
results = []
for order in orders:
price = order['price'] * order['quantity']
if price > 1000:
price = price * 0.9 # 10% discount
results.append({'order_id': order['id'], 'total': price})
return results
立即可用,但存在以下问题:
- 没有错误处理(例如键缺失)。
- 没有类型检查。
- 折扣逻辑在其他地方重复 → 技术债务(现在有 47 处包含折扣代码)。
更好的做法
| 使用 AI 的场景 | 避免使用 AI 的场景 |
|---|---|
| 低风险代码(工具、样板、测试) | 决策类代码(架构、核心算法) |
| 明确定义的问题(实现规格,而非设计) | 新颖问题(无已知解决方案) |
| 重复模式(CRUD 接口、错误处理器) | 关键路径(安全、支付处理、数据完整性) |
衡量指标
- 代码质量指标(圈复杂度、测试覆盖率)
- 缺陷密度(每 1 000 行代码的缺陷数)
- 维护成本(每季度的重构工时)
5. 可观测性剧场
错误
团队收集了 10 000 条指标,却实际上只使用 3 条;其余的都闲置在仪表盘中。
工程师为何忽视可观测性
- 仪表盘信息过载,难以找到关键信号。
更好的做法 – 保持仪表盘 精简 且 可操作:
- 定义明确的 SLO / SLI。
- 挑选 5‑7 个关键指标,直接反映系统健康(例如错误率、p95 延迟、CPU 使用率、请求量、队列深度)。
- 将相关指标归类,在同一视图中展示。
- 仅在重要阈值上设置告警;避免告警疲劳。
当工程师能够快速回答 “系统健康吗?” 时,就能更快采取行动。
工程师工作流示例
tail -f /var/log/app.log | grep "slow"
- 在 2 分钟内定位问题
- 仪表盘显示 “所有系统正常”
- 日志显示:“数据库查询耗时 45 秒”
为决策而设计可观测性,而不仅是收集数据。
提问:CTO 需要了解哪些信息才能做出决策?
答案——5 个关键问题:
- 这是一次宕机吗?(是/否)
- 受影响的用户数量是多少?(数字)
- 哪部分出现故障?(服务名称、错误类型)
- 影响范围有多大?(是否有连锁故障)
- 我们能回滚吗?(是否可以撤销最近的部署)
构建能够回答这五个问题的仪表盘,其他内容可酌情添加。
案例研究:媒体公司 – 告警疲劳
- 构建了“最先进”的可观测性系统。
- 告警疲劳导致采纳率下降。
- 45 分钟的宕机期间,告警触发但无人关注。
- 成本: $2 M。
组织转型的惯性
错误之处
你已经现代化了技术栈:
- 微服务? ✓
- DevOps? ✓
- 云计算? ✓
但仍保留 1995 年的组织结构:
- 审批流程: 12 个月
- 招聘: 每人 3 个月
- 团队结构: 按职能划分的孤岛
结果: DevOps 可以在 5 分钟内完成部署,却必须等待 12 个月才能获得审批。
真实案例:某电信公司
- 已经实现了 DevOps + 微服务,聘请了“高大上”的架构师,搭建了漂亮的基础设施。
- 但:
- 功能需求仍需通过传统计费系统的审批流程。
- 计费系统以“模块”形式出售(缺乏灵活性)。
- 客户合同为 12 个月固定范围。
敏捷开发团队与固定范围的需求产生冲突。
结果(3 年后):
- 5,000 万美元 已投入,上市时间没有任何改善,领导层更换了三次。
更好的做法
先转变组织——技术随后跟进,而不是相反。
需要思考:
- 我们的决策速度能有多快?(1 周?1 个月?1 季度?)
- 团队拥有多少自主权?(完全自主?还是受审批约束?)
- 激励机制是否对齐?(快速交付?成本控制?规避风险?)
- 能否在团队之间调动人员?(重组成本?保留风险?)
旧有的组织惯性比新技术的力量更强。仅靠微服务无法摆脱破碎的激励机制。
Source: …
供应商锁定优化为创新
错误之处
选择“领先供应商、行业标准、优秀案例”。
供应商的优化目标:
- 锁定(专有 API、定制语言、高切换成本)
- 路线图由最高付费客户驱动(通常不是你)
供应商被收购 → 产品线被终止。
结果: 被迫承担 500 万美元以上的切换成本,或被迫重写。
真实案例:金融科技公司
- 为“核心平台”选择了供应商。
- 供应商宣传语:
- “为金融科技打造”
- “企业级”
- “零停机部署”
3 年后:
- 供应商被收购 → 新所有者终止产品线。
- 迁移需要完全重写。
- 成本: 800 万美元,18 个月,三名离职。
更佳做法
假设供应商会让你失望。
- 使用 开放标准(SQL、REST、标准框架)。
- 自行掌控关键数据流(绝不让供应商拥有你的数据)。
- 保持 低切换成本(避免专有 API)。
- 规划退出(迁移成本会是多少?)。
- 分散风险(在可能的情况下使用多个供应商)。
实际可行的决策框架
| 步骤 | 要做的事 | 关注点 |
|---|---|---|
| 1. 为决策命名 | 供应商、执行模型、技术栈、扩展、迁移策略等。 | 明确范围 |
| 2. 建模主要后果 (6–18 个月) | • 工程工作量 • 运维负担 • 学习曲线 • 成本走势 | 短期影响 |
| 3. 建模次要后果 (18–36 个月) | • 迁移成本(撤销难度) • 供应商风险(被收购、停运) • 人才风险(招聘/保留) • 组织风险(文化变更) | 近期风险 |
| 4. 建模第三层后果 (3+ 年) | • 锁定(是否永远受限) • 扩展限制(瓶颈) • 过时风险(5 年后是否陈旧) • 机会成本(我们不能做什么) | 长期展望 |
| 5. 透明决策 | 在约束条件下选择 最佳权衡,而不是绝对的“最佳”。记录决策依据。 | 未来问责 |
六个月后,你需要记得当初为何做出这个决定。
测试你自己的判断
我构建了一个简单的模拟器,能在 2 分钟 内带你了解这个框架。
- 试一试:
- 无需登录。无需注册。只需自行测试。
