在嵌入式软件开发中实施SCRUM

 

(本文在去年程序员上发表过,现在应该可以贴上来了吧^_^)

 

摘要:介绍如何解决在嵌入式软件开发中实施 Scrum 遇到的挑战,如何很好的进行团队组织以及针对 Scrum 的实践活动进行了哪些改进。

关键词:  敏捷、 SCRUM XP 、嵌入式

 

 

Scrum,  软件开发模型是敏捷开发的一种,在最近的一两年内逐渐流行起来。 Scrum  开发流程通常以  30  ( 或者更短的一段时间 ) 为一个阶段,由客户提供新产品的需求规格开始,开发团队与客户于每一个阶段开始时挑选该完成的规格部分,开发团队必须尽力于  30  天后交付成果,团队每天用  15  分钟开会检查每个成员的进度与计划,了解所遭遇的困难并设法排除。在本文不介绍 SCRUM 是什么,如何进行推广实施,也不谈为什么要实施 SCRUM

本文主要从以下几个方面来谈在嵌入式开发中实施 SCRUM 的经验:

l          嵌入式开发对 SCRUM 的挑战

l          公司现有状况对 SCRUM 的挑战

l          实施 SCRUM 中的一些改进措施

1        嵌入式开发对 SCRUM 的挑战

嵌入式软件开发和 web 应用开发有很大的区别:

l          一般都有自己的操作系统,该操作系统一般不同于现在的通用操作系统(比如说 Windows/Linux 等),这就造成需要开发时必须在该操作系统上直接开发

l          和硬件结合非常紧密,必须等硬件回来,并且硬件测试完毕后才能开始调试,前面的时间只能写代码,不能验证代码的正确性。如果硬件延后了,那么将同时导致软件也延后,计划也变得不可控了。

l          当出现问题后,必须利用硬件环境才能定位问题和解决问题

l          当代码到了一定规模后,每个小改动就会发现从编译到上硬件调试都需要花很长时间,在我们的开发中,花费 20min 以上都是常有的事情

由于有这样的特殊性,在嵌入式开发中,一个特性的完成一般都需要分为几个阶段:代码编写 à 代码调试(硬件回来后) à 集成测试(各个功能模块测试完毕后) à 系统测试。而在 SCRUM 开发中,一般要求一个特性在一个较短时间( sprint )做完,并在每个 sprint 后输出产物。当然实施 SCRUM 时也可以将前面几个阶段放到不同的 sprint 中去,但那样会导致检测每个特性在每个 sprint 结束后如何定义做完的问题,而我们希望将问题简单化。

为了解决这些挑战,在实施 SCRUM 时,做了如下的改进。当然有些活动在实施 SCRUM 之前就已经执行了。

1.1     操作系统封装

首先解决不同操作系统的问题。为了能够在开发中做到开发与操作系统的无关性,设计了操作系统封装层,如下所示:

1   操作系统封装示意

所有功能模块的代码,均是架构在操作系统封装层之上。采用这种方式后,在开始写代码时,开发人员就可以在自己熟悉的平台上进行开发和调试,进行相应的单元测试和集成测试,以及持续集成等技术实践活动,这样可显著提高在每个阶段后的代码质量,并且在每个 sprint 结束时,可很好的定义和检查每个任务是否做好。

1.2     硬件仿真

嵌入式开发中还有一个与其他领域相比差别很大的地方就是和硬件结合非常紧密。很多功能模块都必须和硬件进行交互,从特定硬件寄存器中读取状态,向特定硬件寄存器写入数据,响应中断等。因为有了这些操作,如果硬件开发还没有完成,硬件环境缺少,或者脱离硬件开发时(比如说在 windows 下),都会因为硬件不存在,出现读写不正常,导致不能调试下去的情况。

为了解决该问题,当不在真实硬件上运行时,所有与硬件相关的交互,全部转入到一个硬件仿真模块中,由该模块负责进行硬件信息的仿真。

进一步,分析系统功能发现,大部分的代码可以不合硬件进行交互,所以设计了一个分层结构,上层代码只与相连的层次进行交互,而与其它层次进行隔离,这样可以更好的做好硬件仿真模块。

如下所示:

硬件仿真模块示意

利用该硬件仿真,就可以做到在开发人员熟悉的开发环境上,进行绝大部份功能模块的开发、测试;同时当硬件回来后,只要开发人员对硬件所提供的功能进行仔细测试,基本上就可以确保大部分功能运行正常。硬件延迟对软件的影响被降低到一定层度了,将软件开发变到一个比较可控的状态。

通过图 2 ,开发人员在开发 Level 2 以上层次时,就可以在现有的代码上进行 TDD 开发,持续构建也能很好的进行下去;而对 Level 1 层次就可以使用 Mock 对象。同时,当遇到问题时可以利用开发人员熟悉的开发环境进行调试跟踪,定位出问题时发生在逻辑代码中还是硬件中,很好的定位问题;也就是说,大部分的问题定位都可以在开发人员所熟悉的开发环境上进行定位,而不一定是要到硬件上进行调试。

针对这种模式,可能会有朋友会说,采用多个层次损失了一定的实时性,而嵌入式开发中一个重要指标就是实时性。但大家可分析一下,将软件划分了层次,只是导致在调用时多了一些操作,相对现在的硬件发展,其基本上可以忽略不计,而起带来的可维护性以及稳定性却是不可估量的。

在每个 sprint 结束时, Scrum Team  就可以向 PO 及项目相关人对每个特性进行直观的演示,而 PO 和项目相关人就可以很好的了解到项目的进度,同时项目的质量很可以比较好的控制。

1.3     脚本的使用

当代码达到一定规模后,每个改动对代码进行编译链接时间就非常长。笔者所遇到的几个项目,出现过即使增量编译也会花费 15min 以上的时间的情况。同时,由于需要将目标代码上传到硬件才能进行调试,整个过程花费时间较长。当然,对于代码的编译可以使用分布式编译系统,但是由于操作系统不同,不一定有相应的分布式编译系统,或者该系统并不适合。我们也曾经试用过许多分布式编译系统,但都不适合我们。大家可以看到,这个时间是严重影响开发人员的开发效率。特别是在项目紧张的情况,其更不能容忍该情况频繁发生。

我们通过如下几种方式减少该情况的发生:

l          利用操作系统封装和硬件仿真功能,尽量让开发人员的每个改动在自己熟悉的开发环境上进行定位调试。当然,也必须给开发人员提供相应的开发工具支持,比如说在该环境上的分布式编译系统、界面友好的 IDE 等。

l          持续系统的构建:使用比较好的服务器,缩短编译时间,让开发人员尽量用服务器构建好的版本。

l          TDD 的引入:由于 TDD 还需要转变大家的开发意识,该实践活动只在较少 team 中采用

l          脚本嵌入:这是在本章节需要重点讲到的。

在系统中,加入对脚本的支持,同时根据系统需求、可扩展性、可维护性和脚本的功能,进行设计,充分发挥脚本的功能。将运行中可变的部分采用脚本来控制,这样每次发现不符合预期时,只需要修改脚本,就可以重新测试,而不需要改动代码(同时还需要重新编译和下载)。大家可考虑一下,修改脚本,可能几十秒中就搞定了,而代码改动却需要花费二三十分钟,这个功能的加入是非常值得的。

这里举个例子,比如在调试时,发现某个芯片对写入顺序以及写入的数据有非常严格的要求,而这需要进行不停测试才能找到合适的数据以及合适的顺序。如果需要用硬代码来实现,那大部分的时间都花费在编译和下载上,可能一天的时间都被这样浪费了,更有可能花了几天的时间在这上面。如果将这段逻辑代码采用脚本来控制,由于根本不需要编译和下载,每次改动只耗费了极少的时间,说不定在一两个小时内就搞定了。

再发散一下,如果在硬件仿真中加入脚本控制,利用脚本来模拟芯片动作,基本上就可以在开发人员熟悉的开发环境下,实现整个系统的模拟运行,这不就是一个完整的设备模拟器么。

嵌入脚本好有一个好处就是可以给现场运行环境打补丁。笔者曾经遇到一个现场紧急问题,在一次针对现场的大规模升级后,发现有些设备运行不正常,最后检查发现,是由于代码中没有对一个变量进行初始化,在赋值过程中,少了一个判断逻辑。而恰好某些设备就运行到这个逻辑分支。如果有了脚本支持,那么只需要上载一个脚本,就可以让设备继续正常运行,而不需要重新升级版本了。

2        团队建设

公司原有开发模式是比较传统的开发模式,其基本开发流程为:市场提需求 à 产品部评估需求 à 需求分析工程师写出需求 à 研发进行开发 à 测试部测试 à 版本发布。而研发这边由一位研发产品经理领导硬件组和软件组进行开发。在部门中开始实施 SCRUM 时,为了不对现有流程做较大改动,决定只在软件部内进行,研发产品经理任 PO 职责。

软件部内的现状有:

l          有些产品线人数较多,已经远远超过了 SCRUM team 建议的人数。这种情况在很多介绍 SCRUM 的资料中,建议采用 SCRUM of SCRUM 模式,这方式也在我们公司运行不错,故不在后面提起。

l          有很多同事是跨产品线工作的,并且工作在几个产品线上的情况比较普遍。如果按照产品划分 team ,则这些同事在该产品线上都只能投入一定的精力,而不是全部精力投入的。

l          目前软件部内 team 划分,存在着按照相同功能的同事划分为一个组的情况。如图 2 所示, level 2 的开发组成一个团队, level3 组成另外一个团队。在进行产品开发时,各个 team 将各自部分的功能完成,然后再进行集成测试。

2.1     跨功能团队组建

在进行团队建设时,将原来 team 组织形式拆分,然后按照跨功能的人员组合成一个 team ,尽量保证一个 team 内的成员组成能够在不寻求其他成员帮忙的情况下完成该 team 的任务,如下:

跨功能团队组合

在这种组织下,要求每个团队在 sprint 结束后,其输出必须是一个完整的功能,也就是说,其演示的功能是需要从 levle1 贯穿到 level4 ,整个是一个连贯的过程。在划分 team 时,尽量保证每个 team 之间的功能不重合,或者相关性较小。那么当几个 team 的成果集成在一起时,其相对来说容易和稳定很多。

2.2     跨产品开发

在开始实施 SCRUM 时,遇到一个很大的问题,就是 Team 的一些成员和其它产品是共用的,可能在一个 10 天的 sprint 周期内,这些成员只能在本 Team 工作 5 天,甚至更少,并且这不是个别现象。

在最初的运作中采用的方式为:针对这些成员,在启动之初就设定其能够在本 sprint 内工作几天,并按照这几天来估计任务。当该成员在某天与本 Team 一起工作时,如果发生了其它事情,全部作为 unplaning 的任务。在运作一段时间后,发现其很少能够按照计划运行。同时开发人员发现自己就很多事情,还不知道该立即做哪件事情,已经被多头领导了。

考虑了一段时间后,决定采用如下方式进行组织,目前反馈效果不错。

跨产品开发

尽量将跨产品开发的人员组织为一个团队,并有一位 Scrum Master 。在每个 sprint 启动之前,由各个产品的 PO Scrum Master 根据当前需要制定出一个综合的 sprint Backlog Team 就针对该 Sprint Backlog 进行计划和执行。

采用这种方式,让各个产品的 PO Scrum Master 之间的沟通增加了很多,在制定 Sprint Backlog 时,有可能还会牵涉到上层领导。但是这种运作方式下,开发人员被外来事情打断的机率就大大降低了,让开发人员可以按计划做事情,开发效率大大提高,同时避免了以前的多头领导。

2.3     其它经验

在团队活动中,还有一些经验可以说一说。

1)   工作氛围

嵌入式开发中,开发人员与硬件有较多交互,故工作时间大都在实验室。实施 Scrum 以后,要求该 Team 所有成员必须在一起,一般在实验室找一个环境,任务板也贴在 Team 附近。因为和硬件人员关系也比较大,也要求与该 Team 相关的硬件人员也必须和团队在一起,但硬件人员不纳入到 Scrum Team 的管理中。

2)   后勤保障工作

为了让 Scrum Team 专注于工作,部门内部特别为各个 Scrum Team 提供了一些便利服务:

l          提供任务板模板:即大白纸,将任务板的各个栏目都在大白纸上打印出来

l          提供燃尽图模板:即网格纸, Scrum master 将该网格纸拿去后就可以开始画燃尽图,而不需要自己用笔和尺子。

l          提供贴纸:大家可以将任务写在贴纸上,然后就可以直接贴到任务板上。从目前来看,贴纸效果不错,基本上能够在任务板保持一个 sprint 以上而不掉下来。

3)   专人负责录入和统计工作

到目前为止,我们都还没有打算在 Scrum team 中使用电子系统,而是直接用纸件方式(任务板是大白纸,所有信息写在贴纸上 J ),因为这样效果直观。但这样带来的一个问题是统计工作不好做,并且没有资料可以给后面留下来。故我们专门安排了人员在每个 sprint 结束后,将这些该 team 的信息录入到我们开发的 Scrum 系统中去。

3        SCRUM 改进

3.1     Backlog 制定

由于人员的限制和不同硬件限制,也可能没有明确的客户对象,很多时候 PO 并不能制定出完整的 Product Backlog 以及相应的 Sprint Backlog

在实施过程中做了如下规定, PO Backlog 的负责人,其必须负责在 sprint 启动会议前提交出正确的 Backlog PO 需要组织产品经理、系统工程师、 ScrumMaster 或者合适的开发人员制定出相应的 Backlog ,最后需要三方同意即可(产品经理、系统工程师、 PO )。

为什么需要三方同意,这是为了防止研发和市场的认识差异,防止出现在特性做出来后,项目相关人不同意这种做法等情况发生。

3.2     Daily Meeting

在最初运行阶段, Scrum Team Daily Meeting 会议严格按照 Scrum 方式进行,每个人员回答三个问题:做了什么,要做什么,有什么问题。在试运行一段以后,发现大家的参与度非常低,经常是 Scrum master 和发言者进行交流,其他人基本上都游离在外。

我们做了如下尝试:

l          强制规定每个人在每次会议上问三个问题

l          成员在领取任务时,大致说一下做的思路;在任务完成时,说一下如何做的。

l          发言人的议题如果有较多人感兴趣,则当场讨论,如果只有较少人感兴趣,则会后单独讨论

l          在该会议上现场指定某人给大家进行专题讲座,当然时间要短

l          整个过程所有成员都是站着开会。

当然,上面这些尝试,是在不同小组实施的。经过这些尝试后,各个团队逐渐找到一种比较适合自己的方法,目前基本上都比较活跃。

大家会问, 15min 的时间够做上面的事情么。我老实的回答大家,时间不够,大多数团队的时间都超过半个小时,比较激烈时会到 1 个小时(当然是少数情况)。

此时大家又会问了, Scrum 强烈要求该会议控制在 15min ,这不是和 Scrum 的精神违背么。这个问题我们也考虑过,但最后大家一致同意仍然继续下去。为什么?

第一,               由于之前一个 team 内部相对来说交流较少,每个人都自己做自己的事情,只有在发生问题或者需要集成时才和别的同事进行交流。更有甚者,如果两个人所做的事情不相干,基本上在工作上就很少交流了。虽然平时也会组织专题讨论,但效果甚微,因为听者并不一定关心该问题。采用在 Daily meeting 上多发言,多讲解后,让大家逐渐了解其他人做的特性,并逐渐深入进去。利用晨会这种短时间,但频率高的方式,让大家互相了解,采用这种潜移默化的方式让大家的知识背景趋同。如果用一种辩证的眼光看,那就是团队在用多的这段时间在还以前欠下的债,本来这些沟通,这些交流在以前就应该进行的。我相信,经过这种方式运行几个 sprint 后,整个 team 的知识背景将会融合在一起,从那时开始, Daily meeting 的时间可能就会逐渐变短。

第二,               由于仍然是站着开会,大家会自觉不自觉的注意会议的进度。

第三,               部门在实施 Scrum 的过程中,严格遵循一个原则就是,不能为了 Scrum Scrum 。以前做的好的方面,仍然继续,不能因为 Scrum 而改变;如果大家觉得对的方面,可以继续,不用照搬。实际上这也是敏捷的精髓。

3.3     持续构建

持续构建这方面网上的资料很多,心得也很多,在这儿只讲一下在嵌入式设备上的一些心得。

1)   Test case 分级

l          单元测试:由于有 OS 封装,进行单元测试完全没有问题

l          与硬件无关测试用例:这些测试用例可以不与硬件进行交互

l          单设备运行:这些测试用例只需要一个设备就可以了

l          组网测试:需要多个设备配合测试

l          耗时测试:需要消耗时间长

2)   充分利用模拟器

编译服务器运行的结果,如果每次都要上载到设备上进行测试的话,将会造成设备需求较多,时间较长,开发人员不可能会忍受。按照前面介绍的,由于对操作系统进行了封装,以及有了硬件仿真模块,那么可以完全做到在一个通用操作系统(比如说 Windows/Linux )上进行模拟仿真。此时可以将单元测试和与硬件无关测试用例在模拟器上运行测试。如果设计的比较好,还可以用多个模拟网元进行组网测试。

3)   充分利用空闲时间

嵌入式开发的一个重要特点就是对硬件的依赖。一般来说,硬件并不一定满足当前需要,特别是在开发初期,硬件一般是远远低于开发需求的;同时,某些 test case 还需要多个设备进行组网测试。很难专门做到预留一些设备做自动化测试。实施过程中,充分做到人可休息,但设备不能休息的原则。比如说在中午时分,运行可在单个设备上运行的测试用例;在晚上,就可以进行组网测试;在周末就可以进行耗时测试等。

4)   仪表操作封装

特别是在通讯领域,很多测试用例都需要与仪表进行交互,为了提高效率,节约时间,部门专门成立小组,对仪表的各种操作进行脚本封装,充分利用自动化的优势。

3.4     demo 会议

demo 会议上如何进行演示,在最初也困扰了我们。在试运行一段时间后,决定在 demo 会议上只做自动测试的演示,针对本 sprint 已经完成的任务,需要做到相应的自动测试脚本运行 ok 即可。

 

4        总结

笔者从 02 年开始接触敏捷开发,并试图在团队内部推行,但都遇到一定的阻力,基本上没有实施下去。其原因有两方面,一方面是很多观点很难使其他人转变过来,二来是没有找到一种比较可行的推行方法。在接触到 SCRUM 以后,采用里面简单易行的实践活动,已经成功在部门内部实施起来。

在不断推行过程中,对敏捷的理解越来越深刻。 SCRUM 的所有组织形式实际上只有一个目的(抛开产品目标和公司目标 J ),就是让团队能够自省,不断的总结自己,发现自己的不足,然后不断完善自己,找出适合团队的方法,让团队能够高效运行。当团队能够高效运行时,也就能产生高质量高效率的产品,也就让公司能够获得更好的效益。

在实施 Scrum 以后,就有很多小组开始琢磨如何让任务做得更好,完成得更高效。当他们提出这些问题时,我就给大家讲解敏捷中的 TDD 开发、结对编程、持续构建、自动化测试等技术实践活动,其非常容易被开发人员所接受,而以前很难推行这些技术实践活动。

敏捷开发实际上抓住了最本质的一点,人才是最重要的。其它流程工具都只是辅助工具,如果执行的人不能很好的认清自己,做好这些,好的流程,好的工具都是白搭。

最后,给想开始实施敏捷的读者提个建议,切记在推行敏捷的过程中,为了敏捷而敏捷。所有的组织形式,活动实践都是敏捷的“形”,我们应该体会为什么要这么做,最重要的就是抓住敏捷的“神”。

 

5        参考书籍:

l          敏捷软件开发:原则、模式与实践 作者: Robert C. Martin  译者:邓辉

l          硝烟中的 Scrum XP— 作者: Henrik Kniberg  译者:李剑

l          Scrum-Checklists- 中文手册 作者: SPRiNT iT GmbH  译者: InfoQ

 

 

 

 

你可能感兴趣的:(SCRUM)