敏捷开发与项目管理敏捷实践敏捷战事

开发团队的自我救赎

2019-02-03  本文已影响59人  edwardzhq

前言

前段时间受邀到厦门线下分享,后来也在众学院上在线分享这个主题。自我回顾,在有限的时间内,确实很难把整个主题全部详细分享。Eric建议我把它再次整理成文章,方便更多的伙伴借鉴。

曾经我们非常差,现在的我们做的并没有多牛X,只是比以前要好一些,并在持续改进。

注: 文中图片均收集自网络,非常贴切表达我们的情况,如有侵权,请联系我删除图片。

追求技术卓越 - 开发团队的自我救赎

为什么会分享这个主题?

因为经历了太多相似的 失败
工作这么多年,成功的经历较少,失败的经历众多。IT产品/项目大多数的失败,背后都有类同的共性,大体可以归为两大类问题: 产品规划问题技术实践问题
这里先聚焦在 技术实践问题

产品/项目的共性

  • 工期紧
  • 任务重
  • 难度大
  • 人手少

通常便带来这些场景

  • 明确需求,验收标准
    时间紧,边做边整吧。

  • TDD、单元测试
    做不到,不现实。

  • CI/CD
    不可能。单元测试时CI的前提,没有单元测试,对于编译类语言(如 java),顶多称为每日构建;假如是解释型语言(javascript, php, python, ruby), 连每日构建都算不上。

  • 质量保证
    人肉。 由于没有单元测试,所有的测试都只能人肉完成。质量与成本与进度便是一组矛盾。

  • 架构设计
    来不及了,啥也别说,赶紧开车吧

如果你的项目情况有上面三点以上相似的问题,那么下面的场景,你应当会感到亲切与熟悉 😉

项目开始

项目开始

对于这类项目,没有有效的工作边界(明确的完工标准),缺乏制动化质量保证,也无从说起有效的持续集成、持续发布,我们称为 裸奔型项目

项目进展

裸奔的进度

正因为 裸奔, 抛弃了许多技术实践的工作,因此,我们在初期阶段便获得了 “飞一般的” 的开发进度。某个户外APP项目,我们3个月 9-9-6 干出等同于 正常情况(有单元测试,有CI/CD ...) 6个月的功能数量。 与此同时,我们累积的大量的技术债务。

进度泥潭

我们的进度开始被大量的缺陷拖住,每天在改BUG,每天在加班制作更多的BUG。到后来,修改代码都变得小心翼翼的。

生怕改一行代码,怼垮一片功能。

牵一发、动全身

解决了一个问题,发现还有更多的问题在背后。

一个问题的背后是更多问题

所有的环境全靠手工部署,各种对接问题,项目交付演示状况频发。

阶段交付演示

测试环境一切OK了,好不容易熬到上线

上线既炸裂

三个月赶完上线的APP,后期花了六个月的时间修修补补。

团队的状态

运维全靠人肉,每次假期,都得先求不崩。我自己有一次休长假,都得随身带着笔记本处理突发状况。

放假之前

新的项目开始

新的轮回开始~


.

我们在努力思考,如何才能改变这种状况?问题出在哪里?

是我们不够努力?

是软件管理过程不够好?

用敏捷,不一定就能成功;用传统方式,不一定就会失败;

当 "我" 用PMI的项目管理方式,失败了,并不能说明PMI的项目管理方式不行,更多说明的是 "我" 的能力需要提升。


我们反思现状,导致我们(公司与团队)陷入这种泥潭的多种原因。

根源之一便是

公司愿景目标(营收期望) 与 团队的实际能力(现实)的矛盾

期望与现实的差距 = 压力与焦虑
差距越大,焦虑与压力变越大。但是,焦虑与压力本身,并不能改变现状和解决问题。

正向的认知,应当是


如何提升团队产出价值?

image.png

用我们想开一辆车从 A地 出发去 B地,来类比项目的情况。
想尽快(更少的日历时间)到达目的地,有几种常见的方式:

  1. 每天多开几个小时 ----- 加班.
  2. 替换更高效的变速箱,提升对发动机动力的转换效率,减少损耗,达到动力不变的情况下,有效提升速度 ----- 改进工作过程.
  3. 替换发动机,更大的动能输出,提升速度 ----- 提升团队能力.


调整认知

基于前面的思考,我们尝试调整认知:


改变的动力

调整了认知后,支持我们寻找改变的动力


达成一致的认知

通过讨论沟通,我们达成需要遵守的一致认知


解决方案

如何才能把前面刷新的认知,变成现实?如何把握好经济实用技术追求之间的平衡?

如果过于侧重经济性(eg. 低水平开发人员),追求进度,我们往往得到满足于当前需求的脆弱而苟且的架构与代码,扩展与维护的代价随着时间指数增长。

如果过于侧重技术追求(eg. 高水平开发人员),首先高水平人员相对稀缺,其次成本通常也比较高昂。好处是扩展与维护的代价是线性的。

我不断学习探索各种技术,主要的目的也就是既想经济适用的同时技术上也不苟。

所以通过 合适的语言、合适的过程、合适的工具 可以帮助我们做好这些平衡。

JAVA PHP 是当前占有量最大的,市场职位数量与劳动力数量也是最大的。许多公司选择JAVA PHP,一个重要的考虑就是,市场有大量的人员补充,走了谁都不怕,两条腿的码农到处都是。大多数人员选择这两种语言,是因为好找工作。

基数大了,十几K的代码搬运工程师的比例也就大了,感受如何,合作过的就知道。

优秀的JAVA开发人员不少,但其成本并非大部分初创公司、小型公司所能承担。一名熟练TDD的JAVA开发人员,成本不低于30K+。

JAVA语言,把一个初级开发人员培养到能TDD的水平,需要的时间相对比较长。

我们没有考虑JAVA的另一个主要原因就是 穷 没钱
不缺钱的公司,尽量考虑JAVA吧。


认知改变了,方案有了,那就执行吧,由于一开始团队就很弱鸡,整个成长过程,分了几个阶段:

能力提升第一阶段

整个阶段大约用了一个多两个月的时间, 扭转了不少不良习惯,提升了团队的开发能力。所有人从在Windows上开发,全部切换到Ubuntu上开发,迫使开发人员自己写的功能,是如何在服务器上运行和部署、以及如何排错问题。切换的第一周,开发人员各自不适用和痛苦,一周后,习惯了就好 😜 。

关于开发人员的操作系统,有兴趣可以浏览另一篇文章 为什么我推荐程序员的标配是Mac (i7 16G 双显)


能力提升第二阶段

这个阶段,是最困难的一个阶段。我们要解决一个大多数公司都共同的问题: 要TDD,团队得有TDD的能力。鸡生蛋问题。

我们的现状是开发人员只是听过单元测试,没有实际写过一个单元测试,更无从TDD了。但是我们现在做不到,并不代表未来也做不到。

image.png

现在做不到TDD,就先做到DDT,先写业务代码,在编写对应的单元测试代码;确保每一个API,都有充足的测试用例。

在这个痛苦的过程中,让团队体会到 "可工作代码" 与 "可以测试代码" 是两个完全不同层次的差别。团队每编写多一个测试用例,都需要对代码进行必要的重构与解耦,知识与经验的积累就多一分。

让团队成功坚持下去的一个关键因素是,贯穿整个过程,必须有人(我)为团队提供了全方位的培训、指导、搭建框架与示例、以及一对一结对工作。直到团队成员拥有独立完成的能力。

团队成员的成长也非常明显:
从一开始,提的问题是 “这个功能我该怎么做?怎么写这个测试用例?”;

到后来,提的问题是 “这个功能我可不可以这样做?这个测试用例这样写对不对?”

再后来,提的问题是 “这个功能我有A B两种做法,哪种好一点?”

再往后,问题变成 “这个功能我有 A B两种做法,分别的优缺点是XXX,是否有正确,该选哪一个?”

最后, “这个功能有A B两种做法,分别的优缺点是XXXX,我觉得 A 更适合我们....”

这个阶段大约经历了半年左右,技术是通过不断的实践积累而成,没有一步登天的事情。

.


能力提升第三阶段

提升目标

成果

我们拥抱XP的理念,“如果一个方法是有效的,那就努力把它推向极致”。
单元测试让我们体验到质量提升的同时,保证工作的成本却在下降,且效率在提升。因此,团队便编写更多的测试代码,使得人工测试的工作尽可能的减到最少,编写测试代码也成了团队基本工作一部分。

先写实现再写测试已经没有什么挑战和难度了,开始持续引导开发人员,能否尝试先写测试用例,再写实现?经过一两个sprint的尝试,开发人员适应了先写测试在写实现的方式。

注: TDD有一个小陷阱,是多数开始尝试TDD的团队都会遇到的,也是导致许多TDD持续不下去的重要原因。在我的内部分享<<TDD的正确姿势探索>>专门讲了这个问题,后期有时间再分享出来。有兴趣可以加我微信探讨 😉

除了功能质量之外,代码的风格、一致性、最佳实践方面也是我们想要解决的问题,通过引入代码风格检查工具 rubocop, 确保代码严格遵守规范,依照最佳实践.

这两种实践,令到团队在编写更简洁的代码和更优的交付质量的同时,获得更高的重构意愿: 开发人员表示,他们看到以前写的代码不够好的时候,他们很放心的就直接重构了,因为已经有充足的测试用例在一两分钟内确保重构是工作的。Rubocop又会帮助发现代码的臭味写法指导开发人员提升代码能力,以及可能的代码风险.

另外,部署工作由手工脚本化部署 (手动执行capistrano), 转为通过由gitlab pipeline自动执行,除了生产环境外,代码一旦合并,就会自动部署到相应的环境,节约了需要等到人工部署的等待时间。


能力提升第四阶段

提升目标

成果

当团队做到TDD时,测试用例都是针对后端服务,API与业务逻辑的质量得以保证。然而,前端部分(ReactNative App)还是依靠人手测试,繁琐低效且耗时,难以做到每次发布都进行全回归测试。几个Sprint前端部分都存在这样那样的质量问题,而且随着功能的增加,出现的问题越多。

实际上,前端部分的质量问题,已经困扰我们多个项目很长一段时间了,一直寻找解决的办法,这次正好碰到一个契机,详见 敏捷实践 (1) - 我们是如何自动化App验收标准 ,我们解决了这个难题,前端部分也引入了自动化测试 ,做到了前后端测试的全自动化。每次交付,业务流程方便基本没有缺陷。

而且,另一个重大的收获,就是验收标准(Acceptance Criteria)测试自动化,形成Scrum中 用户故事 -> 验收标准 -> 测试自动化 的闭环,整个团队充分理解了验收标准的真正作用与价值,也是团队Scrum实践取得成效的重要基石。(有些团队Scrum实践的更多是流程,最后也就容易留于形式,收效远低于预期)

在部署方面,我们通过自动化脚本部署,简化了每次部署的工作。但是我们还有一些问题需要改进:

  1. 开发人员的环境与部署环境的差异,可能导致一些环境依赖问题。
  2. 每增加一台服务器,都需要4~6小时左右的初次准备时间。
  3. 每增加一套环境,都需要花费更多的时间和脚本修改。
  4. 弹性弱。

因此,对系统架构进行一些调整,让它能以docker的方式运行,解决环境一致性问题,准备一个新服务器的时间,也仅需不到一个小时左右便可。


能力提升第五阶段

提升目标

成果

这个阶段,主要解决docker化后剩余的问题: 仍是基于单个服务器部署。
继续调整系统架构与配置,支持以 Docker Swarm方式部署与运行,达到:

  1. 所有环境部署与运行方式都保持一致
  2. DEV & QA 等只需运行一个实例
  3. Prod 运行多个实例
  4. 实例位置透明
  5. 环境部署运行方式一致
  6. 自动弹性负载

待解决问题:

  1. DEV & QA的实例(Nginx MySQL/PostgreSQL App)被随机分配到某一个节点,导致查看日志前,需要先了解实例是运行在哪个节点上,造成很大不便。
  2. 生产运行多个实例,访问在实例之间自动均衡,日志查找困难。

做了这些,我们在哪?

image.png

团队的状态

对于开发团队来说,需求、开发、测试不再是割裂的充满苦与泪的工作,而是可适应可挑战的,也让大家避免了恶性加班的泥潭,工作之外还有丰富多彩的生活。

image.png

夜晚能安然入睡,不会苦逼的被半夜叫起来重启系统解决问题 😜.

image.png

总结

我们取得的成果

我们依然有很多不足与挑战

上一篇下一篇

猜你喜欢

热点阅读