敏捷(Agile)——“说三道四”

概述

关于敏捷开发,Wiki给出如下解释:

Agile software development describes a set of principles for software development under which requirements and solutions evolve through the collaborative effort of self-organizing cross-functional teams.

  可以这么理解:一种以人为本、团队合作、快速响应变化和可工作的软件作为宗旨的开发方法。亦可理解为在一个高度协作的环境中,不断地使用反馈进行自我调整和完善,持续交付用户想要的软件的过程。敏捷开发提倡通过多种工程实践来提高交付质量,如自动化测试、持续集成、重构、结对编程、代码的集体所有权等,比传统的设计-开发-测试-修改流程有更高的成效。

  前辈们“筚路蓝缕”无私付出造就了敏捷开发,使软件界不能承受之”重“变得轻盈,让我们能够站在巨人的肩膀上展望软件界。现在我们就开始敏捷之旅吧。

  在介绍敏捷之前,先回顾一下传统的开发流程。

瀑布式开发流程

  瀑布式开发流程(Winston Royce 1970)是最早得到广泛承认的开发流程。这是一个线性的模式,只有完成了前一个步骤才能开始下一个步骤。比如说,在开始设计之前,必须先完成需求分析。如果发现了问题,就得返回上一个阶段并进行适当的修改。

waterfall-model

  这种流程存在的不足之处:首先,即使需求会随时间而变化是众所周知的,但开发人员仍会努力在设计前完成文档,在编写代码前完成设计,其中有大量工作被浪费。其次,将测试和集成延迟到项目开发结束时才执行,这就导致问题往往发现得太晚,如果要解决问题,则有可能导致错过最后的交付期限。该流程既无法控制业务需求的变更,又抑制了反馈的周期阀值,伴之而来的是不可避免的延期和失败。

对比瀑布式开发

  瀑布模型是最典型的预见性的开发方法,严格遵循预先计划的需求、分析、设计、编码、测试的步骤顺序进行实施。步骤成果作为衡量进度的标准,例如需求规格,设计文档,测试计划等。

  瀑布式开发流程的严格分级导致的自由度降低,项目早期即作出承诺导致对后期需求的变化难以调整,适应变化代价高昂。瀑布式方法在需求不明确并且在项目进行过程中可能变化的情况下基本是不可行的。而敏捷开发的一个核心理念便是:"Fix time, Flex Scope"——固定时间,弹性范围。这就使团队具有更高的灵活性去适应未来需求的变化。

60920267e95299539a96824736a63581_b

  敏捷方法在几周或者几个月的时间内完成相对较小的功能,强调的是能将尽早、尽量小的交付可用的功能,并在整个项目周期中持续优化。

迭代式开发流程

  是一种有别于传统的瀑布式开发的软件开发过程,它弥补了传统开发方式中的一些不足,具有更高的生产率和成功率。其开发流程明显比瀑布式开发流程更为灵活,其特征如下:

  • 在进行开发之前就进行了风险评估。
  • 更早的获取用户反馈。
  • 对各个目标里程碑提供了短期的焦点。
  • 对过程的测量是通过对实现的评定来进行的。
  • 可以对局部实现进行部署。

Iteration

迭代式开发的优点:

  • 降低项目风险。
  • 更早的得到用户反馈。
  • 持续的测试和集成。
  • 使用变更。
  • 复用性增加。

  在迭代式开发流程中,整个开发工作被组织成一系列短小的、固定长度的小项目,被称为一系列的迭代。每一次迭代都包括了需求分析、设计、实现与测试。实施这种开发流程,开发工作可以在需求被完整地确定之前启动,在一次迭代中完成系统的一部分功能或业务逻辑的开发工作。再通过客户的反馈来细化需求,并开始新一周期的迭代。快速迭代是为了使产品更加接近消费者的需求,使消费者的体验变得更加完美。世界上没有能一劳永逸的产品,更没有所谓的正确产品,在互联网的时代,服务和产品都是一个有机的生命体,需要不断地发展变化。成功的产品就像一场蝶变,在蜕变中越显完美。

对比迭代式开发流程

  迭代式开发流程是传统的“阶段一门限”工程实践之一,而敏捷方法是一系列工程实践的综合体,两者属于一种包含与被包含关系。相比迭代式开发两者都强调在较短的开发周期提交软件,敏捷方法的周期可能更短,并且更加强调队伍中的高度协作,这也是敏捷的核心理念之一“以人文本”。

敏捷实践

Scrum

  像所有的敏捷过程一样Scrum是一种迭代式和增量式的软件开发方法。在Scrum项目中,测试人员需要知道测试也和符合用户需求有关。程序员需要知道在编写代码前并不一定需要有经过深思熟虑的设计。作为最受青睐的敏捷技术Scrum,我们有必要熟知它的机理,下面一步步介绍吧。

Scrum角色分配:

scrum rules

  1. Scrum Master (Scrum推动者): 是Scrum教练和团队带头人,确保团队合理的运作Scrum,并帮助团队扫除实施过程中遇到的障碍。
  2. Owner (产品负责人):确定产品的方向和愿景,定义产品发布的内容、优先级及交付时间,为产品投资回报率负责。
  3. Developer (开发者们):由开发者组成,人数5-9人,团队拥有交付可用软件需要的各种技能。

  在每一次冲刺(Sprint)或迭代当中,开发团队创建可用的软件的一个增量。每一次迭代所需要实现的功能来自产品需求。开发团队决定在下一次迭代中他们能够承诺完成多少需求项。

Scrum的四个会议

  • Sprint计划会(Sprint Planing)
  • 每日站会(Daily Scrum)
  • Sprint评审会(Sprint Review)
  • Sprint回顾会(Sprint Retrospective)

以下逐一拆解

Sprint计划会:

  1. 进行需求讲解。
  2. 挑选PBI(product backlog item),也就是由客户选出重要的PBI。
  3. 拆解PBI到SBI(sprint backlog item)。
  4. 讨论每个SBI的工时。
  5. team挑选本次Sprint任务。

每日站会:

询问自己三个问题

  • 从昨天Daily Scrum到这一刻,我完成了什么工作?
  • 从这一刻到明天的Daily Scrum,我计划完成什么工作?
  • 是否有什么困难阻碍了我的进展?

Sprint评审会:

在 Sprint 结束后,大家一起评审本次 Sprint 的产出。每个人都可以自由发表看法,协助产品负责人对未来工作做出最终决定。并根据实际情况,适度调整产品待办事项列表。

Sprint回顾会:

在一次Sprint结束后,回顾一下团队在流程和沟通等方面的成效。大家一起讨论,哪些完成得好,哪些有待改进?

Scrum实施流程

Step1. 拟定 Vision
首先,我们需要有一个Vision ,就是我们所做的产品或者所做项目的需求。这个需要所有Team Members,包括Product Owner 一起确定,然后大家朝着同样的目标前进。

Step2. 维护Backlog
它可以理解成我们从产品当中,从各个角度收集的需求。 Product Owner 要做的事情就是维护Product Backlog,将Backlog 一条一条的按照优先级排好顺序。Product Owner 是唯一有权利维护这个列表的人,并且可以给任务打标签来标示优先级。

Step3. 拆分Sprint
在开发周期中,将 Backlog 里面的项目添加到Sprint 中去,成为Sprint Backlog。每一个Sprint 开始的时候,需要进行一个Sprint Plan。

Step4. 运行Sprint Plan
Sprint Plan 就是整个团队在一起通过Backlog 从优先级最高的这个item 开始分配,大家将Backlog 拆分成单个Task,团队的成员领取Task,并负责完成Task。

Step5. 维护Daily Scrum
在 Daily Scrum 中,每个成员只需三件事情:我今天做了什么,明天要做什么,遇到什么困难。Daily Scrum 一般来说会控制在15分钟之内,而且所有的成员必须要站着开会。

Step6. Sprint Review
当Scrum 结束后都有有个产出物,这个产出物在Scrum 里面,可以是一个可以运行的软件,也可以是一个可展示的功能,我们要做的就是对它进行客观的点评。

Step7. Retrospective
最后一步就是Retrospective。所有团队成员一起参加讨论,这个Sprint我们哪些做的不错,哪些有待改善。

工具的作用

TeambitionWorktileTrello这三个工具对 Backlog 的管理和会议活动管理都非常方便,能更好地实现团队协作、需求到研发的信息关联与共享。个人比较喜欢Trello

以下是一些Scrum的通用实践:

  • 客户成为开发团队中的一部分。
  • 和所有其他形式的敏捷软件过程一样,Scrum有频繁的包含可以工作的功能的中间可交付成果。这使得客户可以更早的得到可以工作的软件,同时使得项目可以变更项目需求以适应不断变化的需求。
  • 开发团队经常评估风险并制定缓解计划。在每一个阶段根据承诺进行风险缓解,监测和管理。
  • 计划和模块开发要保持透明,让每一个人知道谁负责什么,以及什么时候完成。
  • 参与者要经常开会以跟踪项目进展 – 平衡的(发布,客户,员工,过程)仪表板更新 – 利益所有者更新。你必须拥有预警机制,例如在可能延期交付时提出警告。
  • 不要隐藏问题。认识到或说出任何没有预见到的问题并不会受到惩罚。
  • 在工作场所和工作时间内必须全身心投入。– 完成更多的工作并不意味着需要工作更长时间。

在这里我们需要明确一个问题,敏捷实际上就是一种理念,然后基于这个理念提供了一些方法和实践,在我眼里它意味着持续改进。

敏捷开发技术体系及原则

测试驱动开发(TDD)

  测试驱动开发始于20世纪90年代。测试驱动开发的目的是取得快速反馈并使用“illustrate the main line”方法来构建程序。一种软件开发过程中的应用方法,由极限编程中倡导,以其倡导先写测试程序,然后编码实现其功能得名。测试驱动开发是戴两顶帽子思考的开发方式:先戴上实现功能的帽子,在测试的辅助下,快速实现其功能;再戴上重构的帽子,在测试的保护下,通过去除冗余的代码,提高代码质量。测试驱动着整个开发过程:首先,驱动代码的设计和功能的实现;其后,驱动代码的再设计和重构。

TDD

测试驱动开发可以有效的避免过度设计带来的浪费,让开发者在开发中拥有更全面的视角。

重构(Refactor)

按照《重构》书中的定义

第一个定义是名词形式:

重构(名词):对软件内部结构的一种调整,目的是在不改变软件可观察行为的前提下,提高其可理解性,降低其修改成本。

“重构”的另一个用法是动词形式:

重构(动词):使用一系列重构手法,在不改变软件可观察行为的前提下,调整其结构。

以下内容出均自《重构》第2.2节

重构改进软件设计

  如果没有重构,程序的设计会逐渐腐败变质。当人们只为短期目的,或是在完全理解整体设计之前,就贸然修改代码,程序将逐渐失去自己的结构,程序员愈来愈难通过阅读源码而理解原本设计。重构很像是在整理代码,你所做的就是让所有东西回到应该的位置上。代码结构的流失是累积性的。愈难看出代码所代表的设计意涵,就愈难保护其中设计,于是该设计就腐败得愈快。经常性的重构可以帮助代码维持自己该有的形态

重构使软件更容易理解

  所谓程序设计,很大程度上就是与计算机交谈:你编写代码告诉计算机做什么事,它的响应则是精确按照你的指示行动。你得及时填补“想要它做什么”和“告诉它做什么”之间的缝隙。这种编程模式的核心就是“准确说出我所要的”。除了计算机外,你的源码还有其他读者:几个月之后可能会有 另一位程序员 尝试读懂你的代码并做一些修改。我们很容易忘记这第二位读者,但他才是最重要的。计算机是否多花了几个小时来编译,又有什么关系呢?如果一个程序员花费一周时间来修改某段代码,那才关系重大—如果他理解你的代码,这个修改原本只需一小时。

重构帮助找到bug

  对代码的理解,可以帮助我找到bug。我承认我不太擅长调试。有些人只要盯着一大段代码就可以找出里面的bug,我可不行。但我发现,如果对代码进行重构,我就可以深入理解代码的作为,并恰到好处地把新的理解反馈回去。搞清楚程序结构的同时,我也清楚了自己所做的一些假设,于是想不把bug揪出来都难。

重构提高编程速度

  我强烈相信:良好的设计是快速开发的根本──事实上,拥有良好设计才可能做到快速开发。如果没有良好设计,或许某一段时间内你的进展迅速,但恶劣的设计很快就让你的速度慢下来。你会把时间花在调试上面,无法添加新功能。修改时间愈来愈长,因为你必须花愈来愈多的时间去理解系统、寻找重复代码。随着你给最初程序打上一个又一个的补丁,新特性需要更多代码才能实现。真是个恶性循环。

一些常用的重构方法

  • 封装成员变量(Encapsulate Field)—将仅限于本类使用的变量重写成私有(private)成员变量,并提供访问方法(accessor method)。这种重构方式可以将与外部调用者无关的变量隐藏起来,减少代码的耦合性,并减少意外出错的概率。
  • 提取方法(Extract Method)—意思是将大段代码中的一部分提取后,构成一个新方法。这种重构可以使整段程序的结构变得更清晰,从而增加可读性。这也对函数通用。
  • 一般化类型(Generalize Type)—将多个类/函数共用的类型抽象出可以公用的基类,然后利用多态性追加每个类/函数需要的特殊函数。这种重构可以让结构更加清晰,同时可以增加代码的可维护性。
  • 函数归父(Pull Up)—或译函数上移,指的是方法从子类移动到父类。
  • 函数归子(Push Down)—或译函数下移,指的是方法从父类移动到子类。
  • 方法更名(Rename Method)—将方法名称以更好的表达它的用途。

......

  重构在敏捷开发过程中重构是一个常用的和必要的实践,它让我们反思过去所为,扫除敏捷开发道路上的障碍。

持续集成

  大师Martin Fowler对持续集成是这样定义的:持续集成是一种软件开发实践,即团队开发成员经常集成他们的工作,通常每个成员每天至少集成一次,也就意味着每天可能会发生多次集成。每次集成都通过自动化的构建(包括编译,发布,自动化测试来验证,从而尽快地发现集成错误。

  持续集成通常借助于一个工具或者脚本来实现,这些工具或脚本会注意到有代码检入版本控制系统。可以采用Cruise Control工具,它可以根据需要运行尽可能多的测试,并且可以自动发送通知给破坏构建的开发人员或者整个团队。

结对编程

  结对编程是指两个开发人员一起写代码。结对编程的想法来源自:如果偶尔的代码检查会带来好处,那么持续进行代码检查会更好。通过结对编程产出代码,会创造出集体所有权的感觉。其次如果有另外一个开发人员坐在你旁边的时候,更容易让代码比你在检出修改前更干净。

敏捷的原则

关于敏捷开发以下原则我们必须知晓:

  • 对我们而言,最重要的是通过尽早和不断交付有价值的软件满足客户需要。
  • 我们欢迎需求的变化,即使在开发后期。敏捷过程能够驾驭变化,保持客户的竞争优势。
  • 经常交付可以工作的软件,从几星期到几个月,时间尺度越短越好。
  • 业务人员和开发者应该在整个项目过程中始终朝夕在一起工作。
  • 围绕斗志高昂的人进行软件开发,给开发者提供适宜的环境,满足他们的需要,并相信他们能够完成任务。
  • 在开发小组中最有效率也最有效果的信息传达方式是面对面的交谈。
  • 可以工作的软件是进度的主要度量标准。
  • 敏捷过程提倡可持续开发。出资人、开发人员和用户应该总是维持不变的节奏。
  • 对卓越技术与良好设计的不断追求将有助于提高敏捷性。
  • 简单——尽可能减少工作量的艺术至关重要。
  • 最好的架构、需求和设计都源自自我组织的团队。
  • 每隔一定时间,团队都要总结如何更有效率,然后相应地调整自己的行为。

敏捷团队工具

所谓“工欲善其器,必先利其器”,优秀的工具有助于及早交付有价值的软件使客户满意。

  • 站会:主要目的是给团队讨论每日的承诺和Sprint目标的进度的机会,每个团队成员在会议中都必须回答以下三个问题:
    1. 过去24小时做了什么?
    2. 接下来的24小时机会要做什么?
    3. 有没有什么问题阻碍了进度?
  • 看板:被用来共享项目的状态并将之可视化
  • 演示:适合于小团队的协作和优化反馈方式

  • 用户故事:用户故事是从用户的角度来描述用户渴望得到的功能。一个好的用户故事包括三个要素:

    1. 角色:谁要使用这个功能。
    2. 活动:需要完成什么样的功能。
    3. 商业价值:为什么需要这个功能,这个功能带来什么样的价值。
  • 持续集成:随时高质量交付的基础,有利于应对变化剧烈的市场

  可以用它们来帮助规划,跟踪,分析和整合工作, 这些工具在敏捷开发中扮演着不可或缺的角色。

敏捷度量指标

  Ron Jeffries建议使用可工作的经过测试的特征数量(Running Tested Features,简写为RTF,下同):

  1. 所需的软件被分解为给定名称的特征(需求、故事等),它们组成了需要交付的整个系统。
  2. 对于每个给定名称的特征,至少有一个或者多个自动化验收测试,(当它们都通过了),反映了特征已经全部完成。
  3. RTF指标表示了项目在各个时刻有多少特征通过了各自的全部验收测试。

Scrum教练Peter Hundermark建议可工作的自动化测试数量(Running Automated Tests)也是度量指标。

敏捷方法的适用性

  在敏捷方法其独特之处以外,它和其它的方法也有很多共同之处,比如迭代开发,关注互动沟通,减少沟通过程中无谓的资源消耗。通常可以在以下方面衡量敏捷方法的适用性:从产品角度看,敏捷方法适用于需求萌动并且快速改变的情况,如系统有比较高的关键性、可靠性、安全性方面的要求,则可能不完全适合;从组织结构的角度看,组织结构的文化、人员、沟通则决定了敏捷方法是否适用。跟这些相关联的关键成功因素有:

  • 组织文化必须支持谈判
  • 人员彼此信任
  • 人少但是精干
  • 开发人员所作决定得到认可
  • 环境设施满足成员间快速沟通之需要

  另外的问题是项目初期的大量假定或者快速收集需求可能导致项目走入误区,特别是客户对其自身需要毫无概念的情况下。与之类似,人之天性很容易造成某个人成为主导并将项目目标和设计引入错误方向的境况。开发者经常能把不恰当的方案授予客户,并且直到最后发现问题前都能获得客户认同。虽然理论上快速交互的过程可以限制这些错误的发生,但前提是要有效的“负反馈”,否则错误会迅速膨胀,并在最终提交时造成极大返工。

写在最后的话

  敏捷方法有时候被误认为是无计划性和纪律性的方法,实际上更确切的说法是敏捷方法强调适应性而非预见性。 敏捷开发不是一套一成不变的标准化流程,而更多的是一种自适应,自我优化的流程理念,不一样的团队有不一样的流程,所以实施前一定要根据自己团队当前状态做调整。记住这一点:敏捷就是永远只做对产品和项目有用的事情 。

附一

敏捷开发宣言

我们正通过亲身实践和帮助他人实践,揭示了一些更好的软件开发方法。通过这项工作,我们认为:

  • 个体和互动胜于流程和工具
  • 工作的软件胜于详尽的文档
  • 客户合作胜于合同谈判
  • 响应变化胜于遵循计划

虽然右项也有价值,但我们认为左项具有更大的价值。

PS:图片来源于网络,如有侵权请私信删除。

参考书籍:

《敏捷软件开发实践》

《Scrum敏捷软件开发》

《敏捷软件开发实践:估算与计划》

《重构:改善既有代码的设计》

admin

发表评论

电子邮件地址不会被公开。 必填项已用*标注