”过程”在敏捷开发中的位置

本文是《敏捷热点问题的多角度杂议》(首次刊发在程序员杂志2011年9月刊)的一部分,为方便讨论,在这里独立成文。

敏捷软件开发宣言的第一个价值观指出“个体和互动 高于流程和工具”。“流程”对应的英文是“Process”,在有些地方也译为“过程”,下文中“流程”和“过程”为同义词。由于敏捷宣言和原则总共篇幅不长,并没有完全说明其中问题,导致了如下有趣又矛盾的现象:

1,部分敏捷的执行者抱怨以Scrum为代表的敏捷流程比较生硬,让员工都是那一副副苦逼的脸,一些团队依然察觉到许多刻板、教条之处,比如站会,Sprint的干扰,一旦听到ScrumMaster或团队试图“照着书本做Scrum”,就会为自己敲响警钟。

2,部分刚刚了解敏捷的人,尤其是团队以上的管理者,认为“敏捷不怎么讲过程规范,引入敏捷意味着冒较大的风险,为稳妥计,暂时先不搞敏捷了吧”。

敏捷软件开发宣言是在软件工程基础上提出来的,出发点所比对的是以瀑布型生命周期为核心的传统软件工程。Martin Flower把传统软件工程方法称为重型方法,敏捷为轻型方法。可以合理的推断敏捷宣言的意思是在传统软件工程已经得到了过程和工具的情况下,个体和互动更重要,并不是没有过程和工具,这点在Martin Flower的《新方法学》一文中也得到了表述。如果不站在软件工程基础上来采纳敏捷,那么很容易沦为软件作坊,其实这是违背敏捷的。

敏捷中给予软件开发团队最直接、最易操作的指导恰恰是在流程上,比如XP中的持续集成、TDD、重构等共12个实践,Scrum中的4种会议,FDD的5个流程等等。分析这些流程,与及传统软件工程的流程,可以发现:敏捷把其中没价值的部分大大弱化了,有些甚至是取消了,比如中间文档里程碑评审、状态报告、需求矩阵等等;而对其中有价值的部分,敏捷却是大大加强了,有些甚至鼓励追求极限,比如迭代开发、结对编程、代码规范、TDD等,而且有些敏捷流派还强调纪律。

常常看到有些敏捷的材料中来比对经验主义的流程和已定义流程,说明在软件开发中,当过程过于复杂时,经验主义方式是适合的选择。但这里面存在混淆:已定义流程存在三种解释:

1.第1种是在Cockburn的《敏捷软件开发》第2版中,“理论的或者已定义的过程是一个理解得足够好可以自动化的过程(这个定义与CMMI对‘已定义的’一词的定义完全不同)。经验主义的过程需要人的检查和干预”;

2.第2种是在CMMI中,“已定义过程”的解释是“根据组织裁剪指南从组织标准过程集中裁剪得到的已管理过程,有得到维护的过程描述,为组织过程资产提供过程相关的经验”;

3.第3种是字面意思,形成描述的过程是已定义流程。

显然,与经验主义流程比对的已定义流程采用的是第1种解释。在这种解释下,软件开发中的已定义过程是很少的,典型的有持续集成、每日集成、静态代码检查等,绝大多数过程需要人的检查和干预,无论是传统的需求分析、OOAD等,还是敏捷推荐的TDD、结对编程等等。所以经验主义的过程并不是不要描述,需要而且必须要一定形式的描述。停留在个别团队成员头脑里的经验主义的流程是无法讨论传播的,而只要说出来,哪怕没有写下来,这个流程就已经得到了描述。“只可意会、不可言传”的东西是佛学考虑的问题,不是软件开发考虑的问题。不了解上下文的朋友会很自然的采用第3种解释,那么极可能会误以为敏捷不需要过程描述。

因此这里真正的问题在于流程描述的颗粒度不同。口头表达的流程往往是颗粒度最大的,也是最不稳定的,而传统软件工程中包括进入-任务步骤-确认-退出(ETVX范式)再加上详尽文档模板+评审+度量等的流程提供了很细的颗粒度,被MartinFlower等称为“繁琐滞重”。细粒度的过程有更好的指导性,但显得繁琐呆板,粗粒度的过程往往是抓住关键,但对细节往往指导不够。按照刚刚好(Just enough)的原则,敏捷类流程描述倾向于刚刚好的粗颗粒度,整体上要讲究平衡。

得到描述的流程能够处理大多数情况,一般的颗粒度粗的流程适用性更宽些,但无论如何是不可能把所有未来流程执行时碰到的情况都说明,所以就存在如何遵循流程的问题。显然的在道理上,碰到新情况不能死硬的遵循流程,碰到老情况也不能肆意的破坏流程。虽然恪守约束,避免整个流程体系走向混乱是很好的,但过于教条以至于无视实际情况同样不利于项目和团队。 根据精益的理念,笔者主张:“过程中发现浪费并积极消除重于遵守既定教条”。流程的严格程度要根据团队和团队碰到的实际情况来处理,不要忘记敏捷宣言的第1条价值观:“个体和互动高于 流程和工具”。

在流程方面还有一个问题,就是流程的定义和执行不完全是项目团队级的事情,就算是最尊重团队决策、已经采纳敏捷的组织也会倡导团队之间的经验分享,而有些组织就会直接要求团队采纳其它团队获得的流程,这些流程在不同组织有不同说法,比如有效实践、最佳实践、规范、规程、经验分享、知识共享等等。这里笔者提议“组织整体协同并重于团队自身提高”。

把流程发挥最大作用,必须处理好如图三所示的三对平衡:

图一 过程的三组平衡

说明:图一 只是为形象的说明存在三组平衡,高低位置并不代表哪个更重要,寻找合适平衡点是关键。

从Scrum看,Scrum本身给出的过程略偏向于细颗粒度,比如站会、燃尽图等,而围绕着Scrum的不少培训材料和文章对计划会、反思、评审会等给了很多指导,感觉更加偏向于细颗粒度。在Scrum的咨询、培训和文章中,一般要求遵循Scrum给定的过程,对裁剪Scrum中的元素要慎重,尽量不要裁剪。KenSchwaber对此的描述是,“对Scrum规则的修改,只有在ScrumMaster确信团队足够深入的掌握了Scrum的运行原理,有足够的技能和思维来修改规则时才可以进行”。Sprint计划会上制定的计划通常被假定为某种承诺,作为承诺往往意味着务必要完成。在2011年7月发布的最新scrum指南中,澄清那不是承诺,而是可以完成工作的预测,而且这个预测会在Sprint过程中因为更多信息而改变。笔者认为这个澄清非常好。承诺并不能准确预测未来发展,但却要求(甚至于是压迫)开发人员必须在限定时间内完成某些任务。澄清为预测后,相对容易改变,执行起来不再那么生硬。

从CMMI看,CMMI本身对各个过程域给出了目标、实践和子实践,看起来颗粒度上偏向于细,而且CMMI覆盖的过程范围比几个常见敏捷软件开发流派覆盖的范围要大,所以整体上显得也细。对待裁剪,CMMI在满足目标的情况下是允许并鼓励的,CMMI全部目标的累计字数与敏捷宣言+原则的字数在同一个数量级上,偏向于粗粒度的敏捷类过程描述也是能够符合CMMI要求的。

XP给出了12个实践,比较强调纪律,而水晶方法系列探索了用最少纪律约束而仍能成功的方法,从而在产出效率与易于运作上达到一种平衡。

1. 结束语

敏捷宣言和原则及主要的敏捷流派指出了优化的方向。根据实际情况进行适配,把握恰当的平衡,同时保持对优化方向的追求,保持在"ing"---进行中,持续发现不足并提升,这就满足了敏捷软件开发宣言和原则。平衡、适配是本文强调的关键词。

参考文献:

1,MartinFowler,新方法学, http://www.uml.org.cn/SoftWareProcess/rjgc.12052003.htm

2,Vikas Hazrati, Scrum到底有多教条?,http://www.infoq.com/cn/news/2011/08/rigid-scrum

3,Pete Deemer,经理2.0:Scrum中经理的角色,

http://www.infoq.com/cn/articles/scrum-management-deemer

4,JeffSutherland,Ken Schwaber,Scrum Update:&2011,

http://www.scrum.org/storage/Scrum%20Update%202011.pdf

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。

相关推荐


迭代器模式(Iterator)迭代器模式(Iterator)[Cursor]意图:提供一种方法顺序访问一个聚合对象中的每个元素,而又不想暴露该对象的内部表示。应用:STL标准库迭代器实现、Java集合类型迭代器等模式结构:心得:迭代器模式的目的是在不获知集合对象内部细节的同时能对集合元素进行遍历操作
高性能IO模型浅析服务器端编程经常需要构造高性能的IO模型,常见的IO模型有四种:(1)同步阻塞IO(BlockingIO):即传统的IO模型。(2)同步非阻塞IO(Non-blockingIO):默认创建的socket都是阻塞的,非阻塞IO要求socket被设置为NONBLOCK。注意这里所说的N
策略模式(Strategy)策略模式(Strategy)[Policy]意图:定义一系列算法,把他们封装起来,并且使他们可以相互替换,使算法可以独立于使用它的客户而变化。应用:排序的比较方法、封装针对类的不同的算法、消除条件判断、寄存器分配算法等。模式结构:心得:对对象(Context)的处理操作可
访问者模式(Visitor)访问者模式(Visitor)意图:表示一个作用于某对象结构中的各元素的操作,它使你在不改变各元素的类的前提下定义作用于这些元素的新操作。应用:作用于编译器语法树的语义分析算法。模式结构:心得:访问者模式是要解决对对象添加新的操作和功能时候,如何尽可能不修改对象的类的一种方
命令模式(Command)命令模式(Command)[Action/Transaction]意图:将一个请求封装为一个对象,从而可用不同的请求对客户参数化。对请求排队或记录请求日志,以及支持可撤消的操作。应用:用户操作日志、撤销恢复操作。模式结构:心得:命令对象的抽象接口(Command)提供的两个
生成器模式(Builder)生成器模式(Builder)意图:将一个对象的构建和它的表示分离,使得同样的构建过程可以创建不同的表示。 应用:编译器词法分析器指导生成抽象语法树、构造迷宫等。模式结构:心得:和工厂模式不同的是,Builder模式需要详细的指导产品的生产。指导者(Director)使用C
设计模式学习心得《设计模式:可复用面向对象软件的基础》一书以更贴近读者思维的角度描述了GOF的23个设计模式。按照书中介绍的每个设计模式的内容,结合网上搜集的资料,我将对设计模式的学习心得总结出来。网络上关于设计模式的资料和文章汗牛充栋,有些文章对设计模式介绍生动形象。但是我相信“一千个读者,一千个
工厂方法模式(Factory Method)工厂方法模式(Factory Method)[Virtual Constructor]意图:定义一个用于创建对象的接口,让子类决定实例化哪一个类,使一个类的实力化延迟到子类。应用:多文档应用管理不同类型的文档。模式结构:心得:面对同一继承体系(Produc
单例模式(Singleton)单例模式(Singleton)意图:保证一个类只有一个实例,并提供一个访问它的全局访问点。应用:Session或者控件的唯一示例等。模式结构:心得:单例模式应该是设计模式中最简单的结构了,它的目的很简单,就是保证自身的实例只有一份。实现这种目的的方式有很多,在Java中
装饰者模式(Decorator)装饰者模式(Decorator)[Wrapper]意图:动态的给一个对象添加一些额外的职责,就增加功能来说,比生成子类更为灵活。应用:给GUI组件添加功能等。模式结构:心得:装饰器(Decorator)和被装饰的对象(ConcreteComponent)拥有统一的接口
抽象工厂模式(Abstract Factory)抽象工厂模式(Abstract Factory)[Kit]意图:提供一个创建一系列相关或相互依赖对象的接口,而无须指定他们具体的类。应用:用户界面工具包。模式结构:心得:工厂方法把生产产品的方式封装起来了,但是一个工厂只能生产一类对象,当一个工厂需要生
桥接模式(Bridge)桥接模式(Bridge)[Handle/Body]意图:将抽象部分与它的实现部分分离,使他们都可以独立的变化。应用:不同系统平台的Windows界面。模式结构:心得:用户所见类体系结构(Window派生)提供了一系列用户的高层操作的接口,但是这些接口的实现是基于具体的底层实现
适配器模式(Adapter)适配器模式(Adapter)[Wrapper]意图:将类的一个接口转换成用户希望的另一个接口,使得原本由于接口不兼容而不能一起工作的类可以一起工作。应用:将图形类接口适配到用户界面组件类中。模式结构:心得:适配器模式一般应用在具有相似接口可复用的条件下。目标接口(Targ
组合模式(Composition)组合模式(Composition)意图:将对象组合成树形结构以表示“部分-整体”的层次结构,使得用户对单个对象和组合对象的使用具有一致性。应用:组合图形、文件目录、GUI容器等。模式结构:心得: 用户(Client)通过抽象类(Component)提供的公用接口统一
原型模式(Prototype)原型模式(Prototype)意图:用原型实例制定创建对象的种类,并且通过拷贝这些原型创建新的对象。应用:Java/C#中的Clonable和IClonable接口等。模式结构:心得:原型模式本质上就是对象的拷贝,使用对象拷贝代替对象创建的原因有很多。比如对象的初始化构
什么是设计模式一套被反复使用、多数人知晓的、经过分类编目的、代码 设计经验 的总结;使用设计模式是为了 可重用 代码、让代码 更容易 被他人理解、保证代码 可靠性;设计模式使代码编制  真正工程化;设计模式使软件工程的 基石脉络, 如同大厦的结构一样;并不直接用来完成代码的编写,而是 描述 在各种不同情况下,要怎么解决问题的一种方案;能使不稳定依赖于相对稳定、具体依赖于相对抽象,避免引
单一职责原则定义(Single Responsibility Principle,SRP)一个对象应该只包含 单一的职责,并且该职责被完整地封装在一个类中。Every  Object should have  a single responsibility, and that responsibility should be entirely encapsulated by t
动态代理和CGLib代理分不清吗,看看这篇文章,写的非常好,强烈推荐。原文截图*************************************************************************************************************************原文文本************
适配器模式将一个类的接口转换成客户期望的另一个接口,使得原本接口不兼容的类可以相互合作。
策略模式定义了一系列算法族,并封装在类中,它们之间可以互相替换,此模式让算法的变化独立于使用算法的客户。