敏捷开发中的持续集成
在过去⼗年或更长的时间中,软件开发团队⼀直受益于敏捷开发⽅法。他们采⽤这些迭代和增量开发实践,通过协作式开发推动解决⽅案的发展。传统的、⾮敏捷的软件创建⽅法通常依赖于⼀个更严格管制的开发流。瀑布流程就是这⽅⾯的⼀个⽰例,其中需求、设计、开发和测试的每个活动都是连续执⾏的。
虽然瀑布式开发多年来⼀直是⼤型的复杂系统开发的标准,但它有⼏个明显的缺陷。⾸先,即使需求会随时间⽽变化是众所周知的,但开发⼈员仍会努⼒在设计前完成⽂档,在编写代码前完成设计,其中有⼤量⼯作被浪费。另⼀个缺陷是,将测试和集成⼀直延迟到项⽬结束时才执⾏,问题往往发现得太晚,如果要解决问题,则有可能导致错过最后期限。这两个因素结合起来,在以较慢速度发展的世界中,也许可以容忍。但是,随着创建创新系统的压⼒的增加,这种⽅法的满⾜组织需求的能⼒在下降。
虽然敏捷实践是由开发 IT 系统的团队推⼴的,但它们同样适⽤于产品开发,其中的产品包括硬件、电⼦和软件。嵌⼊式软件开发与 IT 应⽤程序开发的主要区别在于部署⽬标资源(如处理器性能和内存)的有限可⽤性。嵌⼊式软件往往要在这些约束条件中执⾏复杂的实时操作。想像⼀下计算机控制的系统,例如汽车⾥的安全⽓囊。您需要他们⽴即部署,但需要的是可靠的部署。敏捷⽅法最初专为不受管制的⾏业中的在同⼀地点⼯作的较⼩型项⽬团队⽽设计。我们花了很多年对它们进⾏扩展,使敏捷⽅法可以容纳更⼤、更复杂的开发项⽬。
当应⽤为基于架构的⽅法的⼀部分时,持续集成(CI)和测试驱动的开发(TDD)扩展了基本敏捷实践,使之⾜以同时提供⾼品质和项⽬灵活性。本⽂将探讨在嵌⼊式软件开发的上下⽂中如何采⽤敏捷⽅法、CI、TDD。本⽂还说明了这个组合的好处。
如何将持续集成和测试驱动的开发融⼊敏捷实践中
现在,⼤多数⼈可能都已经听说过敏捷⽅法。它们带给软件开发的概念改变了团队组织的⼯作⽅式、适应不断变化的需求的⽅式以及发布软件的⽅式。持续集成(CI)是为敏捷开发⽽创建的,所以敏捷⽅法是任何 CI 讨论的背景。它将开发组织为功能性⽤户故事(user story)。这些故事按优先级分成较⼩的⼯作组,也称为冲刺(sprint)。
这⾥的思路是不要提前尝试解决每⼀个问题,相反,专注于您已经知道的东西。因此,团队设计、构建和测试他们对预期功能所知道的内容。这将在完整产品需求的⼀个⼦集的基础上创建⼀个⼯作产品。然后,团队继续到下⼀个最⾼优先级的需求集,并重复上述过程。当然,这是⼀个⾼度简化的视图,这个过程中有许多变化,但核⼼是:以增量⽅式构建您的产品,并尝试在过程中做⼀些改进。
根据 ThoughtWorks 的 Martin Fowler 的观点,持续集成(continuous integration)是⼀种软件开发实践,要求团队成员经常集成他们的⼯作。每个⼈⾄少每天集成⼀次,这导致每天有多个集成。集成是通过⾃动化的构建进⾏验证的,这些构建运⾏回归测试,以尽快检测集成错误。团队发现,这种⽅法
会导致集成问题⼤幅减少,更快地实现有凝聚⼒的软件开发。
这导致 CI 流程的成功执⾏的最终细节。如果持续集成的思路是为了快速发现问题,从⽽向每个开发⼈员提供⼯作反馈,则必须以某种⽅式快速评估其⼯作。测试驱动的开发填补了这项空⽩。利⽤ TDD,您可以构建测试,然后等代码通过测试后再开发功能。随着每⼀个新代码的添加,可以将它的测试添加到在构建集成⼯作时运⾏的测试套件中。这将确保新增内容不会破坏之前出现的运作中的⼯作,并且事实上 “破坏了构建” 的代码的开发⼈员可以迅速获得通知。在图 1 中显⽰了持续集成和测试驱动的开发的典型组合。
图 1. 使⽤持续集成和测试驱动开发的敏捷实践
24 ⼩时流程的⼯作流图
受益于持续集成的项⽬类型
少于 50 ⼈,处理不太复杂的项⽬的团队绝对是敏捷开发和 CI 的试验场。但因为产品已变得 “更智能”,其复杂性也会明显增加。
进⼊传统产品的嵌⼊式软件的数量是惊⼈的。如今,⼀辆新汽车已较少以其马⼒作为卖点,⽽是以其嵌⼊式软件技术(例如,⾃动泊车、先进的安全警告、燃油效率、信息娱乐系统)作为卖点。为创建
⼀辆新汽车⽽编写的代码⾏数多于为 F16 战⽃机所编写的代码⾏数。
产品复杂性的增加,同时加速了新产品的上市时间。嵌⼊式软件的普及,结合更严格的最后期限,这些将敏捷实践和 CI 带到了嵌⼊式开发⼈员的⾯前。
使⽤敏捷⽅法实现嵌⼊式系统开发
敏捷⽅法让软件和系统团队能够快速响应变化。敏捷⽅法减少了与传统的软件⼯程相关联的时间进度风险,在传统⽅法中,组件的集成被视为后期阶段的⼯作。后期阶段的集成会引起对设计规范的误解,在发现问题时,对于要解决该问题同时⼜要满⾜其最后期限的团队⽽⾔,已经为时已晚。
然⽽,系统团队要⽣成的不仅仅是软件组件,他们对敏捷⽅法的某些⽅⾯持怀疑态度。他们说,删除过多的早期规划,最后就会获得糟糕的软件和硬件集成。如果没有早期的、经常的检查点来根据架构蓝图验证进度,团队可能⽆法⽣成可在更⼴泛的系统中正常运作的组件。此外,对于正在寻求设计的可重⽤性和可扩展⾄较⼤型项⽬需求的复杂系统的开发⼈员来说,敏捷⽅法看起来可能存在局限性。
这些担⼼是可以理解的,因为建模和架构不是敏捷技术的特点。但系统开发的 CI ⽅法对纯敏捷⽅法提供了多项改进。CI 帮助系统开发团队变得敏捷,并且能够响应快速的业务变化,在同⼀时间确保正在开发的实际硬件和软件都在不断同步。CI 使得团队成员能够在⾃⼰的领域组中有效地⼯作,集中精⼒
于他们最擅长的任务。在每天结束时,他们知道,他们对项⽬的贡献被集成,并且各组件可以⼀起⼯作。如果有哪个组件⽆法集成,该组件很快就会被发现。
让我们来考虑复杂系统开发和交付的⼀些必不可少的组成部分,并探讨 CI 如何有助于迎接挑战。
架构
当您正在构建复杂系统时,如果没有蓝图,就⽆法不断添加新的特性。如果没有蓝图,那么在利⽤额外的迭代时,就会遭遇更多返⼯的情况。不管您将它称为蓝图、模型还是架构,它都提供⼀个开始迭代过程的坚实基础。
架构在最多 50 名团队成员的较⼩型项⽬中很有帮助,但是,如果超出了这个规模,就必须做⼀些前期⼯作,以了解组件化、重⽤和可变性。此前期分析使您可以拆分团队,但仍发布协调的产品。在让硬件和软件开发⼈员⼀起⼯作也是这样,就像对包括嵌⼊式软件的复杂系统⼀样。
仿真
通过在仿真模型中捕获架构,团队可以看到系统如何响应不同的输⼊。这种形式的早期测试可以验证系统是否如预期般执⾏,从⽽满⾜要求。这也使得设计⼈员能够可视化设计的任何意想不到的后果。在检查代码⽂本时,很难看出这些意想不到的后果。当查看系统模型时,它们会变得明显得多,在查
看⼯作中的系统模型时,它们甚⾄变得更加明显。
在这种⽅式中,建模和仿真让测试和集成可以在设计⼯作开始时就⽴刻开始执⾏,从⽽消除了在嵌⼊式硬件尚未可⽤时可能遇到的延迟。它可以节省对那些不可⾏的早期架构原型所进⾏没有必要的⼤量投资。即使您的确有可⽤的硬件,持续集成也要求不断地构建。
越早需要看到结果,构建环境就会变得越昂贵。由于 CI 的主要⽬的是尽可能快地提供结果,仿真使您能够在⽆需⽀付超⾼硬件成本的情况下进⾏测试。它还提供了⼀个更简单的⽅法来沟通组件的功能,这对于敏捷开发中常见的结对编程和 “代码审查” ⾮常有价值。
构建⾃动化
持续集成要求构建⾃动化,也就是说,提供让软件⾃动编译和链接到可执⾏⽂件的能⼒。速度⾮常重要,因为⼤型构建可能需要很长时间。如果没有快速、可靠的构建,就会缺乏解决集成问题所需的洞察⼒。在运⾏集成构建时,会识别由两位或多位开发⼈员所做的更改之间的冲突,以便解决该冲突。所以,如果发现问题,要解决前⼀个构建的冲突的开发⼈员可以通过硬件仿真来测试更改后的代码,不会耽误其他开发⼈员的⼯作。但是,要实现这种效率,则必须不断进⾏集成构建,在上⼀个构建完成时就⽴刻开始新的构建。这与其他流程所使⽤的每天⼀次或每周⼀次的构建⾮常不同。
当然,这种⽅法要求构建⾃动化,因为要将⼀天中反复多次开始构建的任务指定给⼀个⼈是不切实际的。此外,构建应快速执⾏,这往往要求构建是多线程的。多线程的构建可以使⽤软件的不同组件,利⽤在某个其他组件上运⾏的构建并⾏地执⾏这些组件,从⽽加快汇总的构建时间。它的确需要更多硬件和更复杂的脚本。脚本变得越复杂,构建管理⼯具就会变得越有价值。
⼯作管理
主要的敏捷概念是将⼯作拆分成为易于管理的⼩块的价值。这也是 CI 的基本前提:及早地、经常地改正错误。这样就可以避免它们稍后在项⽬中发展成为更⼤、更难解决的问题。
该技术提供的好处之⼀是能够提供在项⽬时间表中多个⽇期进⾏构建和测试的更⼩的功能性发布。通过验证来⾃团队的架构、需求和时间表估算,每个交付都降低了项⽬风险。在敏捷⽅法中,尚未完成的⼯作被称为积压(backlog)⼯作。如果您开始将⼯作分配给⼩交付增量(被称为冲刺),分配给某个冲刺的⼯作被称为冲刺积压(sprint backlog)。分配给未来冲刺的剩余⼯作被称为项⽬积压(project backlog)。⽬标是将在冲刺定义的时间内可以实现的尽可能多的⼯作项分组到冲刺中。
此流程⾼度依赖于指标的收集,使团队可以更准确地预测任务所需的时间量,并推算出可以放⼊某个冲刺交付的任务量。然⽽,与这些指标等价的是,数据收集即使对于⼩团队也⾮常繁琐。当您将这些⼩团队组合在⼀起来产⽣更加复杂的产品时,任务会相当庞⼤,且⽆法⼿⼯完成。
市场上有很多产品可以帮助组织完成其⼯作,跟踪⼯作的完成状况,并⽣成与⼯作完成了多少、完成的速度、完成的质量等有关联的指标。如果遵循了 CI 实践,则必须将所确定的集成错误迅速添加到⼯作积压中,并作为⾼优先级移动到列表的顶部。在这⽅⾯,在市场上最好的产品提供了新⼯作项和构建管理系统之间某种程度的集成,因此,在每个构建后识别的错误就可以迅速得到修复,并与现有⼯作项集成,优先升级,并路由到正确的团队。
质量管理
质量管理是确保所有产品要求均已经过测试的开发⽣命周期实践。该⼯作需要得到组织和理解,使正确的测试可以在需求变更时得到更新。质量管理有助于项⽬经理回答以下问题:
如果我的产品必须在下周发布,哪些部分将会产⽣最⼤风险?
我们是否可以在没有低层要求的情况下发布产品?
这是否是⼀个⾼品质的发布?持续集成的概念
在⾯对加快交付周期的市场压⼒时,快速回答这些问题可以帮助业务充满信⼼地将产品发布到市场。管理⼈员可以更好地了解要添加哪些资源、在何处调整产品特性,以及何时重新建⽴交付⽇期,从⽽获得最⼤优势。
利⽤测试驱动的开发,测试的概念对于开发⼯作更加重要。在 TDD 中,需要根据需求编写测试,然后开发代码,直到它通过测试。这将确保没有创建额外的功能,即开发团队称为 “镀⾦”的东西。即使额外的功能或特性似乎是⼀个好主意,但在不要求驱动决策时,额外的⼯作可能会提⾼成本,并增加交付时间。最终产品可能并没有实际提⾼客户满意度。
⾃动测试
在创建多个构建后,团队需要重新测试之前的版本中的可⾏功能。这个重新测试的流程以前被称为 “好代码(good code)”,现在称之为回归测试(regression testing)。它确保没有因为刚刚完成的变更⽽将错误引⼊或重新引⼊之前测试过的代码。利⽤ CI,可以将⾃动的回归测试编写为脚本,在每个构建结束时运⾏。这使得开发⼈员能够得到有关在在新构建中发现的错误的即时反馈。这⼀步是为了通知开发⼈员,他们所⽣产的新代码在按要求(或没有按要求)⼯作。如果没有回归测试,开发⼈员只知道构建已完成。由于⽆论如何都必须创建测试,所以TDD 并没有添加额外的⼯作。它只是将⼯作的顺序颠倒了,⾸先创建测试,然后编写代码。
即使没有任何⾃动化测试,传统的瀑布式开发项⽬也是有可能⽣存的。可以描述和构建项⽬,然后让⼀⼤堆⼈不断对其进⾏测试。但只要您开始定期发布,这⼀流程就会出现问题。⼿动测试⼀个在⼀天中被多次构建的系统是不可⾏的。
协作
IBM® Rational® 软件组织长期以来⼀直主张协作是成功的系统开发和交付的⼀个关键因素。但在软件和硬件团队都参与的 CI 中,协作不仅包括从⼀个团队到另⼀个团队的有效构件移交,还包括对要求、特性和最后期限之间的权衡的全⾯协调的理解。
良好的架构可以⽀持这种协作,部分原因是⼈们可以更好地了解他们正在构建的各个组件之间的依赖关系。利⽤项⽬组合管理,您可以了解特性、重⽤和资源分配。但在合作开发的硬件和软件项⽬中,管理要求并制定有关何时可以更改这些要求以及何时不得更改它们的明智决策也很重要。
这些项⽬通常涉及决策的多个层次中的多个利益相关者。良好的协作有助于满⾜更⼤⽐例的利益相关者。它可以确保创建了正确的产品,并且可以快速识别来⾃更⼴泛的⽬标的偏差。这将产⽣可以更好地满⾜客户需求的产品。
结束语
从技术⾓度来看,CI 可以帮助团队更⾼效地⼯作。这些团队可能是跨职能的,创建配合⼯作的硬件和软件。他们在地理上可能是分散的,因为不断的集成⼯作将会确保您没有偏离设计。⼈们可以在⼤型团队中⼯作,因为复杂系统的不同组件将以更可靠的⽅式⼀起⼯作。CI 解决了许多⾮传统的敏捷团队
在没有 CI 时可能都经历过的早期陷阱。CI 与测试驱动的开发相结合使更多⼈可以利⽤敏捷,因为它可以让敏捷⽅法更⾼效地⼯作。
从业务的⾓度来看,CI 可以提供更好的业务成果,让团队可以拥有⾃⼰的蛋糕并吃掉它。也就是说,通过在问题的早期并且在问题还是⼩问题时发现它们,⽽不是等到这些问题变成⼤问题且更难解决时才发现它们,团队可以将产品更快地推向市场。他们还可以在产品开发过程中更好地响应所引⼊的需求。敏捷开发将为客户创建更好的产品,这才是敏捷性的真正承诺。

版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。