更有效率地生产更好的应用
想象一个产品,比如一辆汽车,它是如何出现,又是如何成为我们在街上见到的那样,而它又结束在何处呢?
首先,任何产品都不是凭空出现的,它们都是凝结了人类的智慧和劳动,被人们生产出来的,那么,这些产品最开始都是出现在人类的大脑中。
蜘蛛的活动与织工的活动相似,蜜蜂建筑蜂房的本领使人间的许多建筑师感到惭愧。但是,最蹩脚的建筑师从一开始就比最灵巧的蜜蜂高明的地方,是他在建筑蜂房以前,已经在自己的头脑中把它建成了。
一开始,我们要思考——这些即将被我们制造出来的汽车,它们满足了哪些人的哪些需要?它们应该是什么形状,它们应该具备哪些功能?对此,我们进行了一些想象和假设,有了一个模糊的蓝图。
接着,我们对生产过程进行规划和分工,我们设计出产品的原型,建设生产线,估计各种零件制造和组装的工时和损耗等,我们规划这些过程并安排相应的任务,追踪进度和问题。
随后,生产线被打造出来,零件被车铣、打磨,组装成型,成为完整的汽车。
我们将这些运输到世界各地,最终交付到了客户手中。
但这还没有结束——如果我们想要业务持续地进行下去并增长地话。
我们要为客户维修故障车辆,我们要聆听客户的抱怨以及他们新的、更深层的需要,我们总结这批汽车的优点和缺陷,我们继续进行新的市场调查和技术研究,然后打造更快,更舒适,更安全的新的汽车。
应用的生命周期
类似的,应用的生命周期通常有着如下几个阶段:
- 计划。在这个阶段,我们收集用户需求,对应用的功能和形态进行假设和描绘,设计产品原型。拆解开发任务,评估任务的开发成本和难度,规划任务的优先级和排期,追踪任务的进度和开发过程中出现的缺陷。
- 开发。这个阶段中,我们进行应用的编码和测试等工作,最终生成可部署的制品。
- 交付。应用开发完成后,我们要将其部署到生产环境,配置相应的基础设施,如服务器和数据库等,直到用户能够使用到它。
- 运维。应用交付后,我们需要对其进行观察和维护,如果它出现了故障,我们需要进行响应处理。
而对于绝大多数现代应用来说,无论是web服务还是客户端应用,它们都是需要持续进行迭代和改进的,一个版本上线后,我们总是会不断地收集或者开发到更多的用户需求,我们会不断地识别到其中隐藏着的商业空间和发展潜力,我们会不断地尝试对其调整,以响应市场的变化,也会不断地进行改进,以图拓宽用户群体和商业渠道,或是为了应对来自竞争对手的压力。
而应用的每一次改进和调整,也都有着上面讲的四个阶段,形成一个迭代周期,这样,应用的生产成为了一个多周期的、持续性的活动。
在这样的活动中,在不断的改进和调整中,产品的价值不断增长,业务更加成功,而这正是我们所追求的。
恶性循环和黑天鹅
然而真的有这么乐观吗?来看看现实中的情况吧:
- 工期评估是否足够准确?计划是否总是被意外打乱?
- 新功能需要多久时间才能够完全上线?在这期间出现过多少次返工?
- 我们多久可以进行一次部署?部署总是可以顺利进行吗?
- 线上产品出现过多少次在开发阶段没有测试出来的缺陷?
- 线上产品出现过多少次服务中断?我们花费了多少时间来定位问题?又花了多少时间使其恢复正常?
- 花费大量人力和时间投入打造的新功能,是否被客户所接受?是否具备与成本相符合的价值?
- 变更是否很可能会导致失败?是否经常会破坏已有的功能?团队是否已经开始恐惧对产品进行变更?
- 团队能花费多少力气在新功能的开发交付上?又有多少力气用在了不停地修复不断产生的问题?
- 如果我们扩充团队,团队的生产力能随之有效增长吗?
思考清楚这些问题后,再看:
- 我们能够对变化莫测的市场及时做出有效的响应吗?
- 竞争对手们呢?
软件开发中存在着一个常见地恶性循环:
- 新功能的开发总是会难以避免地在代码和基础设施中引入混乱,如果不及时进行干预,这些混乱会使得软件和基础设施变得越来越复杂和脆弱。
- 复杂和脆弱的代码及基础设施,导致了更高的开发难度,更高的返工率,以及线上产品更高的故障率,也使得我们的任务和成本预估变得更加不准确。
- 我们花费了更多的资源用来调查和修复问题,而新功能的开发又会需要更高的资源投入,为了满足工期要求,我们不得不暂时(我们是这么说服自己的)地去快而脏地处理故障和进行新的开发,从而引入了更多的混乱。
所有事情都变得更加困难——所有人都越来越忙,工作所消耗的时间越来越多,沟通变得更加缓慢,工作积压得越来越多。我们的工作耦合得更加紧密,即使是很小的行动也会导致较大的事故,我们更加害怕和拒绝做出变更。工作需要更多的沟通、协调和审批;团队必须等待更长的时间,等待相关的工作完成;我们的工作质量持续恶化。车轮开始嘎嘎作响地缓慢移动,要想使之继续转动,就需要付出更多的努力。
最终,黑天鹅出现了:
也许是一个政策的变更,也许是一次疫情的发生,或者是一个新生的更有活力的竞争对手的崛起,总之,灾难似乎是在慢慢地逼近,又仿佛在一瞬间降临,一个产品迎来了自己的终点。 也许企业会开发出新的应用,会去追求新的商机,团队也会有新的项目,或者有新的东家,但是这个应用的一切都死亡了。
这个产品结束了,我们失败了。
改变状况的三个关键
如何避免这样的结局呢?这其中有三个关键点:
1. 缩短交付周期:
更短的交付周期意味着能够更快更及时更有效地获得来自客户的反馈,这有助于我们发掘客户的真实需要并去实现这些需求。 而更短的交付周期里,我们的交付计划能够做到更为准确,每次交付过程中的风险也会相对较小,出现的问题也更容易处理。 最终,更短的交付周期使得我们能够更迅捷、更频繁、更准确地向客户交付更多的价值。
从:
到:
2. 建立快速、高效、持续的反馈机制:
在应用交付的每个阶段里,我们建立快速、高效、持续的反馈机制,缩短问题检测周期,一方面,这可以帮助我们更及时准确地发现问题,从而以更低的成本实现更及时快速的修复,另一方面,也帮助我们打造安全可靠且高质量的应用。
3. 持续学习和持续改善
通过持续地,制度性地学习和改善,提高团队技能水平,将局部的经验快速转化为全局的改进,帮助整个组织尝试和实践新技术,通过科学的方式改进流程和开发产品,从成功和失败中积累经验教训,持续不断地进行改善,从而提高产品质量和生产力。
一些实践、方法和工具
具体来说,会有多种实践方法和工具来帮助我们做到这些:
1. 持续集成
频繁持续地将个人的代码变更集成到主干分支,能够避免解决冲突成本过高,bug难以修复,开发者之间代码互相影响或重复相同工作等。 持续集成流水线中的自动化测试能够帮助我们在更早的阶段发现和解决问题,并避免问题在将来被重复引入。 自动化代码质量检查能够持续地帮助我们改善代码质量,减少代码中的混乱和隐患。
2. 持续交付
通过高效、可靠、自动化的发布流水线,减少应用交付流程中的人工和停滞环节,降低过程中的阻力和风险,从而使应用可以更频繁、轻松地进行发布。
3. 建立应用可观测性
为应用建立可观测性,提供完善的日志收集、链路追踪和监控能力,使开发者能够更好的理解应用内部的行为,从而减少应用故障的发现和定位所需要的时间,提高线上可用性。 完善的监控也提供了基于线上应用的反馈回路,能够在故障恶化或产生严重影响之前提前发现,也能够通过对用量指标的收集为应用的后续增强和改善提供信息。
4. 技术债务管理
通过持续性地、组织性地、制度性的对技术债务进行管理,降低应用代码中存在的风险,减少新功能开发时可能导致的额外成本。
5. 代码评审
通过代码评审,增强业务知识和技术知识在团队成员之间传播,增强团队成员的生产力,减少bug出现的风险,提高代码质量,获得可能的更优解决方案等。
6. 基础设施即代码
通过以代码形式管理幂等、不可变的基础设施,解决应用发布过程中因环境偏移(如随时间发展各个环境中的配置逐渐变得不同)而导致的各种问题,降低应用交付过程中的阻碍和风险。 同时,基础设施即代码也提高了管理基础设施的可靠性和效率等。
7. 待续
引用:
1. The DevOps Handbook
2. What is DevOps?
3. State Of DevOps 2021