专业学位研究生软件工程能力培养探索
2022-03-25吴毅坚张天戈
吴毅坚,彭 鑫,张天戈
(复旦大学计算机科学技术学院,上海 200438)
0 引言
自2002 年我国开展软件工程专业硕士培养以来,各培养单位已为软件和互联网等相关行业输送了大量优秀的软件开发人才[1]。当前,软件和互联网企业对于产品创新、快速交付及质量可信的要求越来越高。与此同时,敏捷开发、持续集成(Continuous Integration)、持续交付(Continuous Delivery)与开发运维一体化(DevOps)等软件工程实践日益成熟,并在企业中得到了广泛应用。因此,企业的软件开发方式以及对从业人员软件工程能力的要求也在逐渐发生改变。从个人开发能力来看,高质量编码已成为企业对软件工程师的基本能力要求之一;从软件开发过程来看,增量、迭代的敏捷开发以及持续集成和持续交付已经成为主流;从开发工具和环境看,基于云的DevOps 开发环境以及软件开发工具链成为主流,软件开发工具和环境的云化成为趋势。以上这些都使得企业对专业学位硕士毕业生的工程能力提出了新要求。与此同时,专业硕士生源来自不同的本科高校和专业,在软件开发能力和工程化素养方面的基础参差不齐。
1 相关研究
专业学位研究生教学是近年来国内外教学研究的热点之一,教学研究人员针对研究生教学与企业需求的差距提出了适合不同教学目标、具有不同教学特点的课程体系,从软件工程知识体系教学到项目化实践教学的融入进行了大量探索[1,5,7]。国内各大高校近年来也对新工科建设中的软件工程实践教学开展了教学改革探索,例如依托基于云的软件开发平台,以软件构造为中心,通过实践化教学帮助学生更好地理解软件工程思想方法等[8]。然而,软件技术的迅速发展仍然使得软件工程研究生教学跟不上企业需求的变化,同时这些改革主要面向本科生教学,在研究生教学中,在软件工程实践内容的广度和深度方面还需进一步加强。
Garousi 等[9]综合分析了来自美国、加拿大、南非等12个国家的研究数据,指出配置管理、软件工程过程、设计、测试等是重要的知识点,但教学与企业需求的鸿沟较大,表明对软件开发生命周期的全链条教学,是专业学位研究生教学的重点之一;Moreno 等[10]给出了本科和研究生的课程体系与业界职业技能需求概貌,分析了职业技能需求在教学中的覆盖性,指出技术领域的教学需要逐步转向业务问题分析等方面,并且需要注意软技能(例如沟通、合作)的教学,但并没有给出具体的项目化实践设计方法和教学方式建议;Stahl 等[11]提出加强企业合作,通过来自企业和政府的利益相关者提供真实的软件开发项目,让学生接近真实需求,解决实际问题,但其研究聚焦于项目化学习设计以及业界指导教师的融入,而没有结合具体的企业软件开发平台或开发方法开展深入的软件工程实践教学指导;Gren[12]在软件工程硕士研究生教学中通过翻转课堂提升学生的学习效果,但其教学仍然是围绕知识点,而没有明确建立工程实践与企业需求的联系;Garcia 等[13]针对传统软件过程改进教学,采用基于Web的工具提升学生的软件过程实践能力,但其教学内容和工具支持主要围绕传统的能力成熟度模型集成(CMMI)开展,侧重于过程评估与改进,与当今业界广泛采用的云开发平台和持续集成、持续部署的软件开发实践仍有较大距离。
由此可以看出,通过与企业合作开展基于云开发平台的软件工程实践教学,并围绕软件开发全生命周期开展用户故事编写、开发迭代安排、持续集成、自动化测试、持续部署的现代化软件过程实践,是一种面向软件工程专业学位研究生的新的教学尝试。
为此,复旦大学计算机科学技术学院通过集中开设的软件过程课程开展了面向专业学位研究生的软件工程能力培养探索。这种软件工程能力培养是对本科软件工程实践化教学与工程能力培养的进一步强化,其目的是面向软件和互联网等相关行业输送适应于工程化与规模化软件开发要求的高端软件开发及管理人才[2-5]。按照这一要求,本文依托软件开发平台DevCloud[6]并引入敏捷开发方法,以及测试驱动开发、持续集成、开发运维一体化等业界实践,通过课程项目开展实践化教学,以提升专业学位研究生的软件工程能力。
2 课程设计
2.1 课程建设思路
作为专业学位研究生的主要课程之一,软件过程课程面向计算机科学技术学院和软件学院的所有专业学位研究生开设。本文首先对当前专业学位研究生的总体软件工程能力水平进行了初步排摸,以便对课程内容、难度、形式等进行精准定位与设计。
通过调研发现:①专业学位研究生的软件开发能力参差不齐。有些学生在本科接受过较为系统的软件开发能力训练,开发能力较强,而有些则明显缺乏相关训练。有一些研究生具有一定工作经验,但已不参与实际软件开发,而侧重于管理工作;②学生对现代企业软件开发前沿实践了解较少。由于缺乏在相关软件开发项目中的锻炼,大部分学生的技术水平仍停留在本科课程项目实践水平,以小型编程项目为主,而缺少敏捷开发、测试驱动开发、代码质量管理、持续集成等现代工程实践经验;③学生现有技术栈差异较大。由于研究方向和技术背景各不相同,学生们掌握的编程语言、技术框架、前后端开发技能等差别较大,因此对后续课程项目的设计带来了挑战;④学生日常有科研任务和其他课程学习任务,时间安排往往比较紧凑,对每门课实践任务的安排需配合学生的可用时间。
为此,针对专业学位研究生的技术能力、实践能力和研究方向差异等问题,软件过程课程的总体建设思路是以软件工程能力培养为导向,以现代软件工程实践为抓手,引入云开发平台,引导学生在实际软件开发项目中逐步熟悉企业软件开发的质量要求以及敏捷开发方法,关注代码质量,并尝试开展基于持续集成和开发运维一体化的业界典型实践。
基于该思路,本文遵循以下具体原则开展课程教学设计:
(1)项目驱动,强调实践。针对学生们所熟悉的业务领域设计软件开发项目,采用小组化点对点辅导方式开展工程开发实践指导,以提升学生的高质量编码能力和增量迭代的软件过程能力。
(2)云平台赋能,借力企业。借助企业级云开发平台,对接现代企业软件产品的开发运维一体化实践,在教学实践内容安排过程中充分听取企业专家建议,精细设计实践内容环节。
(3)理论先行,持续改进。理论联系实际,在讲授方法理论的基础上,推动学生在实践中理解软件过程管理与改进的要点,聚焦敏捷开发方法,重点提升学生在软件开发中的代码质量意识和软件产品持续集成意识,发现软件过程管理中的不足并持续改进。
2.2 教学安排
课程教学主要由方法理论和项目实践两部分组成。在方法理论部分,在对传统的软件过程模型、过程评估、过程改进方法进行简要概述的基础上,重点聚焦当前企业实践中常用的敏捷方法、代码质量保障、持续集成与持续交付、开发运维一体化等实践内容,梳理Scrum 方法、用户故事编写、测试驱动开发、代码评审、代码静态扫描与门禁等关键知识点,并且结合业务案例、代码案例等组织课堂教学内容,开展大班集中教学。在项目实践部分,采取每小组5 人的实践形式,针对一个给定的网上商城Web 应用项目进行功能增强与架构改进,并采取课堂现场分组指导与线上微信群问答相结合的方式,轮流开展小组教学活动。这种“大班教学、小班实践”的教学方式,对于学生专业背景差别大、实践能力参差不齐的情况具有良好的适应性[14]。
考虑到课程本身的工程管理与实践导向特性,方法理论和项目实践的教学课时比例安排为1∶1。在实际教学中,理论课与实践课内容穿插进行,以提升理论联系实际的效果。基于这样的考虑,研究生软件过程课程整体教学安排如表1 所示。课程共有54 学时,时间为16 教学周,每周3 课时,另有2 个考试周用于实践项目完善与课程论文撰写(未在表格中列出)。课程前4 周进行集中的课堂理论教学,以奠定学生的理论基础;然后进行3 周的小组实践,并且每周安排至少与课堂相当的课后时间开展项目集中开发与讨论(具体形式将在1.3 节中介绍);在接下来的3 周里,结合之前实践中所发现的问题,连续开展课堂理论教学,并要求学生结合相关理论尝试解决项目中出现的过程管理问题;之后又是连续3 周的小组实践,以及1 次理论课;最后是2 周的课程实践项目期末汇报。
在这种教学安排下,虽然理论内容相对压缩,但教师可更集中地讲授关键知识点,结合代码案例把知识讲深、讲透。同时,所增加的现场实践与分组讨论内容,可让教师和助教与各个实践小组进行深入探讨,发现各组开发实践中的具体问题,并结合不同小组的技术特点给出针对性建议。
Table 1 Program arrangements of software process course表1 软件过程课程安排
2.3 教学内容设计
在教学中的理论讲授内容主要为以下3 部分:
(1)需求管理。尽管研究生们在本科阶段学习过需求分析的基本方法,但大多数学生没有在现代企业的软件开发项目经验,因此敏捷方法下的需求分析和管理方法是本课程的讲授重点。课程重点阐述如何采用用户故事方法快速获取软件项目的范围、验收标准及迭代计划,并通过Scrum 方法推进迭代增量开发。
(2)基于过程的质量管理。质量管理是软件开发过程的核心目标。在该课程中,质量管理主要从代码质量管理、测试驱动开发、版本管理与分支策略等几方面分别展开。在相关技术介绍中,特别强调了在开发过程中如何利用自动化代码扫描、自动化测试等技术在开发过程中持续保障代码质量。自动化技术的应用不仅需要管理能力,而且依赖于良好的软件设计、软件架构等软件内在的质量水平。因此,该部分课程内容既包含了对质量要素的讲解,又重点讲解了如何通过代码审核、重构、测试驱动等开发方法提高软件的内在质量,让学生理解内在质量与自动化技术、持续交付之间的关联。
(3)软件交付管理。该部分内容已接近课程尾声,其目的是从开发过程整体的角度,将测试先行、自动化质量保障等单点技术提升为基于云平台的持续集成、持续交付及开发运维一体化的现代软件开发流程,使学生对整体的软件过程有进一步认识。具体教学内容主要包括软件交付的反模式和原则、配置管理、自动化流水线与持续交付。软件交付的反模式是业界常见的导致交付困难的各种问题的总结,由此导出如何提升交付频率的原则和方法,进而从依赖管理、部署配置、应用程序参数配置、环境管理、数据管理等方面介绍面向过程管理的配置管理要素。最后以持续交付为抓手,介绍构建部署自动化流水线的方法及其脚本化方法,并结合案例阐明其作用。其中自动化流水线与云平台结合,讲授为何需要持续交付、如何达到持续交付,以及为何持续交付会将传统软件过程研究延伸到软件运维阶段,建立起开发运维一体化格局。
基于上述课程内容,同时考虑到学生实际技术水平,本文配合相关讲授内容设计了具体课程实践项目,使学生学以致用。
3 项目实践
软件过程管理课程实践围绕理论教学内容开展,以敏捷方法以及测试驱动开发、持续集成和开发运维一体化为实践设计主要目标,充分利用DevCloud的过程管理功能,引导学生开展分组实践。
3.1 实践内容设计
在平衡实践内容复杂度与学生整体学业负担的基础上,课程采用维护式开发实践内容,即给定一个现有的软件项目代码,要求学生为该项目开发新功能以及修复原有缺陷。本文采用课程建设企业合作伙伴提供的一个名为“托马斯零食商城”的Web 应用项目,要求学生在该项目基础上扩展新功能,例如购物可用积分抵扣金额、退货、对接外部物流系统、定制促销活动等。开发这些功能都需要有一定工作量,且学生较易理解其业务意义和价值,可比较清晰地描述出其验收规则。
为兼顾学生的技术基础,本文选择的“托马斯零食商城”是一个采用了较老架构(J2EE、JSP+Servlet)的Web 系统,大部分学生可较容易读懂其代码。但由于该架构是前后端耦合的,考虑到目前有更优秀的架构,因此给学生提供了两个选项:学生可在该项目架构基础上进行局部扩展与优化,也可完全从头做起,采用本小组最熟悉的架构从头进行开发。通过这样的设计,让不同技术能力的学生都能尽可能聚焦于新功能迭代增量开发以及对敏捷开发方法、持续集成等教学目标的实践。学生可根据小组成员的能力自主进行决策,决定是更换架构(例如业界常用的前后端分离架构),还是在原架构上进行局部改良。
通过加入一系列新需求,明确每个需求所表达的客户原始出发点,让学生体会到什么是高价值需求,如何完整描述用户故事及其验收测试用例,并合理安排产品交付计划和迭代计划,围绕用户故事列表(或用户故事地图)逐项交付。
实践项目采用DevCloud 作为开发过程管理平台,利用其需求思维导图、用户故事编写、迭代管理、代码静态检查、云端编译构建、云端部署、流水线构建部署等功能,开展全流程实践。具体实践的分步要求是:①学生按5 人分组,要求学生先熟悉该系统代码基本结构,实现基于Dev-Cloud的代码托管;②教师以客户身份提出不同功能需求,要求学生给出用户故事,在DevCloud 上用用户故事树(思维导图)的形式进行组织;③学生讨论用户故事,并初步确定交付计划和首次迭代计划;④针对首次迭代计划讨论用户故事细节,给出可运行的验收测试用例,并细分任务;⑤在开发过程中围绕用户故事交付,采用测试先行的思想编写代码,保障代码质量;⑥选择合适的分支策略,利用DevCloud 实现自动化编译构建、部署,进而集成代码扫描、自动化测试能力到流水线上。
3.2 实践教学形式设计
课程实践教学采用小班形式,考虑到实践效果,项目实践小组成员数量限定不超过5 人。由于选课人数较多,实践小组数量也较多,因此要保证教师与各小组交流效果,在有限的课时条件下就必须采用分批现场指导的方式。
实践课程时间为连续3 周,每次要求1/3的小组到课堂现场进行分组交流,其他小组则自行在课外组织集中讨论与开发,并在DevCloud 上及时更新交付计划、迭代计划及任务看板墙。通过该方式,在每轮项目实践过程中,每组都会有10~15min的时间与教师进行面对面交流,并且教师可在课堂上及课程微信群中直接指出一些共性问题。
采用这种实践组织形式的优势在于教师可对每小组进行针对性指导,深入发现其实践中的问题,并补充大班授课中被学生忽略的一些地方。但这种方式本身也极具挑战性,主要体现在教师需持续与学生互动,以及在课外进行自行讨论的小组需及时更新开发进度并报告讨论效果。
根据上文所述的课程总体安排,项目实践讨论采用“2+1”的形式,即两轮现场开发讨论加一次期末汇报总结。第一轮现场开发讨论聚焦以用户故事获取需求,重点实践如何采用用户故事来快速记录需求,并且明确系统的大致边界。学生不仅需要准确理解用户故事的描述方法,而且需要实践如何在开发过程中充分沟通用户故事的细节,并且将用户故事的交付验收表达为验收测试用例。
第二轮现场开发讨论聚焦于开发编码过程中的质量管理,包括测试先行、自动化测试、代码质量评审与扫描、云端构建与部署等。学生需要选择高价值的用户故事开展完整的能力交付实践,实现所开发功能的完整业务价值。在此过程中,需要灵活运用自动化测试技术以保证所实现用户故事的正确性和价值,并且尽量提升集成、构建频度,使系统尽可能随时处于可发布、可交付的状态。
在最后的期末汇报环节中,要求每个实践小组用10 分钟时间重点展示系统开发维护交付上线的效果、用户故事交付情况、开发过程中的单元测试和自动化测试实践情况以及采用云平台开展增量迭代开发、流水线构建部署的实践情况。
4 工程实践导向教学效果
该教学方式在复旦大学计算机科学技术学院和软件学院的专业学位研究生培养中取得了良好效果。由于同时面向不同研究方向的专业学位研究生,其软件开发技术基础和工程应用能力不同,因此学生普遍反映课程实践项目对其有一定压力,但对于其理解软件工程理论及培养工程化开发能力有很大帮助。
4.1 分小组差异化实践指导效果
由于选课人数较多(每个选课班的人数在120 人以上),而为了保证实践效果,每组规模被限制在5 人,因此每个选课班的实践项目小组有30 多个。因各个小组的技术能力和技术栈差别较大,所以不同小组针对待开发与改造的系统,选择了不同的架构策略。实践中发现,大约1/3的小组选择了成员更熟悉的软件开发技术与架构,例如StringBoot+Vue,以便更好地发挥小组人员的开发技能特长,而其他2/3的小组则在原Servlet+JSP的开发方式上进行改进,以寻求尽可能少的开发工作量,此技术选择分布基本符合预期。在选择更换开发架构的小组中,通常由于前后端分离和引入了Maven 等依赖管理工具,能更好地开展自动化单元测试和基于接口的验收测试。而对于采用原始架构的小组而言,尽管代码改动少,但架构较老,造成自动化单元测试需要采用手工编写脚本的方式,而且仅能对新增功能的代码进行测试,学生需要进行一定探索,因此有一些难度。
通过两轮差异化的分组实践指导,教师可更深入地了解每个小组的开发状态、学生对基础概念的理解情况以及小组技术选型,并帮助小组进行必要的技术评估。由于各个小组对课堂上讲授的一些基础概念的认知与实践可能出现偏差,教师通过与学生面对面的交流能充分发现问题并予以指导。
由于采用个性化、差异化的指导方式,学生有更多机会与教师直接对话,在开发实践中也有更好的参与感。绝大部分小组都反馈了在开发过程中遇到的具体问题,例如如何书写用户故事,如何编写自动化验收测试用例,如何将代码提交与代码检查、编译构建联动起来等。通过与教师的面对面交流,学生能更准确地提出在大班理论教学中难以发现的问题,从而更好地开展软件过程管理实践。
实践过程中还发现个别具有初步团队开发经验、但非软件工程专业出身的学生对所讲授的软件过程方法非常感兴趣,这体现了业界一些小团队的开发方法仍然相对落后,需要采用先进的开发过程进行优化。根据这些学生的反馈,其将所学知识应用于实际软件开发项目中,逐步推行用户故事、验收测试等具体技术,已经在明确开发需求、把握与推进开发进度等方面产生了积极效果。
通过这些学生的反馈可以看到,本课程讲授的理论方法和实践技能与企业实际需求相符,对于提升开发管理人员在实际软件开发项目中的管理水平也有一定帮助,因此能更好地使专业学位研究生的开发技能与企业需求对接。
4.2 实践中反映的主要问题
在实际教学中,各个项目小组对知识的掌握情况存在一些共性问题,主要包括以下几个方面:
(1)对用户故事的理解不准确,没有抓住用户业务价值。由于学生们习惯于按功能进行开发,因此往往倾向于从技术角度思考实现细节,而非该功能对用户而言的业务价值。例如,“购物者能通过购物获得积分”这一需求,从购物者角度而言,需要完成购物后正确累计积分的功能;从商城平台角度而言,需要对积分与消费情况按照商家和用户分别进行统计,从而更好地定义营销策略;从商家角度而言,则希望与商城平台计算积分抵扣情况,从而获得自身销售收益。这3 种情况分别会产生3 个不同的用户故事,需要实现各自的业务价值。但学生往往只从“购物者”这一个视角加以考虑,从而很难回答购物积分到底有什么业务价值。
(2)缺乏验收测试用例来定义用户故事的完成标准。为实现“购物者购物获取积分”这一用户故事,在实际开发过程中,如何利用验收测试用例来定义完成这一用户故事的标准,对学生而言也是一个挑战。学生通常会在讨论汇报时,通过界面展示购物获取积分的功能界面,而不会展示采用了哪些验收测试用例,并且让其自动运行来确保相关功能的正确性。也正是因为缺少验收测试用例,无法进行对用户故事的回归测试,造成一些小组碰到重复出现的功能缺陷。而完成相关验收测试用例的小组成员表示,验收测试用例对开发过程中判断迭代的完成起到了重要作用,将来也可更好地利用验收测试用例来明确定义业务功能的边界。
(3)测试用例编写不足,难以推进持续集成和持续交付。在项目开发中,不仅用户故事的验收测试用例不足,单元测试也不足。学生对测试金字塔[15]需要大量自动化的底层单元测试缺乏直观理解,没有认识到自动化测试与自动化部署流水线、持续集成和持续交付之间的关系,对自动化测试的重视程度不足。对此,教师通过实际项目中的具体需求案例进行说明,使学生了解验收测试和单元测试对于保障软件质量的实际作用。同时,由于开发经验的缺乏,一些学生没有在自己的软件项目中编写过测试用例,更没有在持续集成环境中自动运行测试用例的经验。由于测试框架使用和编写基本测试用例并不属于本课程教学范围,因此给一些学生的实践造成了困难。为此,在分组实践中,教师对各组实践遇到的问题进行讲解,同时各个小组通过自行学习测试技术,提升测试效果。
(4)DevCloud的使用问题。在DevCloud 使用过程中,学生会提出一些平台功能与敏捷开发理论差异的问题。例如,DevCloud的需求思维导图通过“史诗故事”(epic)、“特性”(feature)、“故事”(story)、“任务”(task)4 个级别进行描述,但学生对于这些概念,特别是“特性”的概念并不理解。因为在以用户故事为主导的分析方法中,往往不会特意强调“特性”的概念,因此需要结合实际案例说明如何定义“特性”,以及如何利用这一层抽象结构更好地组织需求。
(5)迭代周期安排问题。敏捷开发所需的固定时间段(fixed timebox)开发与学生的日常学习时间往往会有冲突。由于学生需要完成其他课程以及进行各自的科研项目开发,因此难以建立全时工作量的迭代交付节奏。为此,教师会建议时间冲突严重的小组灵活运用估算方法,寻找最小业务价值点,以便在最短时间内完成价值交付。
5 教学反思与可能的改进方向
本文首次尝试从软件过程的角度,系统地将云开发平台中的用户故事、迭代管理、任务管理、持续集成、流水线构建发布等能力融入软件开发过程的研究生教学,课程内容安排特别是实践安排还有改进的空间。通过反思课程教学全过程,总结出一些可改进的方向:
(1)选择架构更贴近现代开发技术的项目作为实践项目。在选择“托马斯零食商城”时,原本预计学生对其代码会比较容易读懂,但实际上,由于学生技术水平各不相同,仍然有一部分学生并不能很顺畅地理解该项目。对这些学生而言,学习更新的软件架构显然更加有价值。因此,总体而言,选择诸如前后端分离的主流软件架构可令学生更有学习动力。
(2)预先准备更多单元测试用例作为样例,为学生提供参照。大量可自动化运行的单元测试是持续集成的重要组成部分,学生对于单元测试的陌生感往往是推进持续集成的主要困难,如果在代码中预先准备一些可自动运行的单元测试用例以及面向用户故事的自动化验收测试用例,学生在改造和新增相关功能时会有更好的参照,学习效率也能提高。
(3)持续要求学生使用云开发平台管理整个开发过程,哪怕学生无法保证足够的项目开发时间。在实践中,特别是开发后期,本应通过看板墙进行管理的开发任务开始不再活跃,这可能与团队的工作模式以及团队缺少Scrum Master 这一角色有关。作为系统教授软件过程的课程,应当时刻要求任务看板墙中的任务是活跃和清晰的,否则增量迭代与持续集成将难以维持。
6 结语
专业学位研究生的工程管理类课程如何对接企业实际需求,培养学生的软件工程实战能力,是该类课程建设的重要问题之一。云平台赋能的软件过程管理课程聚焦于基于用户故事的敏捷方法、测试驱动开发、持续集成和DevOps 实践,采用DevCloud 作为开发过程管理平台,围绕软件开发全生命周期,引导学生从编写用户故事入手,增量迭代地交付用户关注的业务价值,并开展测试驱动开发、流水线构建部署以及持续集成与持续发布的实践,通过理论牵引、强化实践的方式,让专业学位研究生对现代软件开发过程管理的要素有更加深刻的理解,并融入日常开发实践中。今后,还将进一步考虑采用新的实践项目或便于学生理解业务的开源项目,加强任务看板墙管理,更加突出持续集成与持续交付的实践,使专业学位研究生能更好地适应现代软件企业的工程化软件开发需求。