以软件构造为中心的软件工程实践化教学探索
2021-06-25彭鑫
彭 鑫
(复旦大学 软件学院,上海 200438)
0 引言
软件工程是一门实践性很强的课程,课程实践对于巩固课堂教学成果、培养学生软件工程能力具有重要作用,因此实践化教学已成为软件工程课程建设的一个基本方向[1-4]。本文所讨论的软件工程课程是指软件工程概论课程,一般会作为软件工程或计算机专业本科生基础课在大学二年级或三年级开设,从而为软件需求、软件设计、软件测试等后续专业课程学习打下基础。例如,复旦大学软件学院的软件工程课程在大二下学期开设,后续还开设了多门软件工程专业课程以及软件实践课程。因此,这类概论性质的软件工程课程实践教学的主要目的是通过实践巩固与加深对课程内容的理解,同时初步培养学生的软件工程能力。在此基础上,可在高年级专门开设综合性的软件实践课程,并突出规模性、综合性、集成性、创新性等方面的实践要求[2]。
软件工程课程实践应当贴近工业界的软件开发实践,以一种迭代化的方式开展。通过多次迭代的系统理解、分析、纠错、改进等演化式的开发活动,不仅可增强学生的代码理解、修改等软件开发实践能力,还可强化对其软件设计准则、编码和文档习惯以及软件测试能力的培养[5]。考虑到授课对象的专业基础及可接受性,本文在软件工程课程教学与实践中采用以软件构造活动为中心的思想。软件构造是指通过将编码、验证、单元测试、集成测试及调试相结合,具体创建可运行的软件的过程[6]。作为刚经过1~2 年专业学习、初步掌握编程能力的本科生而言,软件构造活动所覆盖的软件工程专业知识及能力是其最容易理解与接受的学习内容。以软件设计为例,其中包含两个层次[6]:体系结构设计关注软件顶层结构和组织,以及识别各种可用组件;详细设计关注为每个组件(或模块)提供足够的细节以支持软件构造。在这两个层次中,体系结构设计通常在大规模、分布式软件系统开发中有较多考虑,但在此阶段的学生由于缺乏所需专业知识和软件开发经验,一般很难理解体系结构设计。属于软件构造活动一部分的详细设计则建立在面向对象设计等更贴近编码开发能力的基础上,比较适合在软件工程课程中进行介绍与实践。此外,课程设计还充分考虑了软件工程师成长路径,按照局部编码、详细设计、总体设计、需求分析与测试的顺序逐步开展课程教学与实践。
按照以上指导思想,本文设计了软件工程课程教学及配套实践内容,在复旦大学软件学院开展课程教学,并依托华为软件开发云DevCloud 平台[7]开展实践教学,取得了良好效果。
1 课程教学及实践安排
根据软件工程实践化教学的需要,同时考虑修读本课程学生的专业基础及可接受度,本文确定了以下3 条课程教学内容安排基本原则:
(1)以软件构造活动为中心。以详细设计、编码、单元测试等软件构造活动以及与之密切相关的版本管理等协作支持能力为中心,强调本科生可深入理解并切实掌握的软件工程能力。
(2)突出实践化培养特色。通过课程实践项目加强学生对相关知识的理解、锻炼对应的软件工程能力,课程教学内容及进度安排配合实践项目进展过程。
(3)体现软件工程师成长路径。课程教学内容安排体现企业中软件工程师的成长路径,按照局部编码、详细设计、总体设计、需求分析与测试的顺序逐步培养学生的软件工程能力,同时穿插版本管理和配置管理等团队协作能力培养。
根据以上原则,本文设计了课程相关教学模块及实践内容。
1.1 课程教学模块设计
课程教学内容模块及其教学顺序如表1 所示。软件工程概述部分为学生提供了一个关于软件工程思想及其基本内容的概览,为其理解后续学习内容提供一个基本的上下文知识背景。后续学习过程从个人开发技能和必要的软件过程与团队协作能力开始,逐步展开软件设计、软件需求、软件测试等教学内容。其中,个人开发技能和软件设计两部分中与软件构造密切相关的内容是教学重点,属于学生较容易接受并掌握的基础开发能力。各个课程教学模块都需要与课程实践及相应的软件开发环境和工具相结合,突出各部分的实践要点。
Table 1 Modules of software engineering course表1 软件工程课程模块
1.2 课程实践内容设计
课程的重点教学内容需要通过课程实践让学生进行体验与巩固。为此,本文设计了配套的课程实践项目。除第一次的体验性实验外,整个实践项目都是围绕一个开发项目(如“在线论文投稿系统”)要求,以一种小组协作和迭代化的方式开展。教学侧重点从编码能力、设计能力到分析能力逐步进阶,同时伴随着软件需求逐步增加与变更。实践项目依托华为软件开发云DevCloud 平台进行,可实现整个软件开发与协作过程全程留痕,帮助学生更完整与系统地理解工程化软件开发,同时为课程项目评分提供依据。课程实践项目以4 人为一组,设置组长1 名,根据交付及完成情况进行整体评估打分,期末再通过组内协商或互评将实践项目评分分解到人。整个课程实践项目分阶段安排如下,其中针对卓越工程师班的特殊要求需单独注明。
阶段1(个人任务):熟悉DevCloud 及Git 版本库,在事先准备好的Web 项目内容基础上通过fork 操作建立自己的代码仓库,利用Maven 完成项目构建,并在华为云上进行在线部署。
阶段2(小组任务—初始项目开发):利用Spring Boot +Vue 实现一个在线论文投稿系统的注册、登录以及会议申请等基本功能,并在华为云上进行部署;要求使用Dev-Cloud 的需求规划、工作分配以及代码质量检查功能,确保功能实现的正确性和完整性,同时注重版本提交等开发过程的规范性。
阶段3(小组任务—代码质量):实现系统中的会议申请与管理等相关功能;实践单元测试,要求项目中的代码测试覆盖率不低于80%;提升代码质量,要求使用DevCloud代码质量检查工具进行代码质量检查,并解决检查中暴露出来的代码质量问题。
阶段4(小组任务—设计与持续集成):完成系统的稿件分配与审稿功能,回顾并检视软件设计质量,进行必要的重构与改进;为提交的代码打标签(如按照每次迭代后实现的功能打标签),根据标签实现选择性地编译构建;利用华为云平台构建CI/CD 流水线,尝试持续集成、持续交付与持续部署(卓越班要求)。
阶段5(小组任务—需求分析与测试):完成系统中的会议评审意见答复(rebuttal)与论文录用相关功能;开展需求分析,检视此前软件实现中的需求完备性和准确性;在单元测试的基础上实践集成测试;结合DevCloud 和Sonar-Qube 的代码检测能力进一步改善代码质量;进一步完善CI/CD 流水线,使每个任务的健康度都达到四星及以上(卓越班要求)。
以上课程实践项目安排通过迭代化的方式逐步完善项目各项功能,每个阶段结束后都有可交付、可运行的软件版本。这种演化式的开发过程更有利于学生理解真实的软件开发过程,同时对软件代码和设计质量等方面要求有更深刻的理解与体会。与此同时,在每个课程项目阶段中都加入与课程教学内容相对应的实践要求。例如,第2阶段在完成初始项目功能开发的基础上,要求学生利用DevCloud 的代码质量检查功能发现代码质量问题并进行修复,同时建立基本的版本提交规范;第3 阶段在增量需求开发的基础上,进一步要求学生实践单元测试并解决大部分代码质量问题。此外,整个课程实践项目过程都贯穿了对软件设计能力和团队协作能力的要求:通过迭代化和演化式的开发过程让学生体验软件设计(特别是模块化设计)质量对软件持续演化与扩展能力的支持;持续的小组任务要求学生在项目中考虑前后端分离、模块划分、接口定义等设计问题,同时建立有效的分工协调、进度管理、交流讨论、版本分支与合并、集成与测试、构建与部署等团队协作机制。
2 实践教学效果
采用上述实践化教学方式在复旦大学软件学院开展本科软件工程教学取得了良好效果。学生普遍反馈课程实践项目对其有一定压力,但对于理解软件工程理论及培养工程化开发能力有很大帮助。
2.1 实践中存在的问题
在课程实践项目的每个阶段,都会对各小组交付情况进行评估,并通过课堂交流的方式邀请一些小组进行分享。通过该过程也发现了学生在课程实践中的一些问题,主要包括以下几个方面:
(1)逻辑不严密、测试不充分。对输入的合法性检查不够,例如密码长度限制检查、必填数据项的非空检查等;未使用登录拦截器,可在未登录状态下直接使用URL 访问特定页面。
(2)代码提交不规范。一些小组提交频率过低,仅在项目开始和结束时各进行了一次提交;一些版本提交的粒度过大或逻辑不完整,对提交消息的描述也不够准确;有些小组的代码提交说明内容非常随意,缺乏可读性(如图1所示,其中第一列和第二列分别是代码提交ID 和提交说明)。
Fig.1 Examples of nonstandard code submission message图1 不规范的代码提交消息示例
(3)缺少必要的分支管理。一些小组成员在各自分支上进行开发,主分支合并较晚,因而导致较多冲突,修复负担较重。
(4)代码质量存在问题。典型的代码质量问题包括代码重复率和圈复杂度过高、标识符命名不规范、方法参数过多、在发布版本中包含alert 语句、不合理的代码重复等。
(5)用户界面不友好。界面上存在一些对用户不友好的情况,例如点击按钮后系统没有任何提示、执行操作后无法看到操作结果、一些重要信息无处查看等。
(6)前后端分离及模块划分不佳。一些小组没有意识到在前后端分离及模块化开发过程中建立接口契约的重要性,出现了模块实现未按照契约编写的情况,导致小组项目集成时问题较多,拖慢了开发进度。
2.2 进一步的实践探索
大部分小组通过阶段性反馈意识到相关问题后都进行了改进,最终大部分小组不仅圆满完成了各项基本要求,而且还在多个方面进行了一些有意义甚至创造性的实践探索,具体包括以下几个方面:
(1)需求规划和任务交流。使用DevCloud 进行需求分解与开发任务规划,在此基础上通过视频会议或即时通信讨论组的方式进行沟通讨论及结对开发,通过共享文档的方式约定开发接口、记录会议纪要以及协作完成实验报告。
(2)设计思维和体系结构理解。在前后端分离的基础上,明确定义了后端接口及其契约,同时给出了包含后端模块划分及前端Web 组件结构的完整设计方案,在设计方案基础上进行开发任务分配与协同。
(3)演化式设计与软件重构。在迭代化的开发过程中不断评估设计方案的不足,据此对代码进行整理与重构,从而完善设计方案。
(4)分支策略和开发协作。制定适合团队开发模式的分支策略,例如将主分支、特性分支、开发分支进行分离,建立规范化的代码分支(branching)与合并(merging)实践模式,保持主干清晰,及时提交并解决代码冲突;规范版本提交过程,采用规范化的模板,并按照新增特性、缺陷修复、重构改进等不同目的编写提交消息。
(5)高质量编码。建立良好的代码注释风格;充分体现防御式编程,在前端输入验证的基础上,后端代码也进行输入值的合法性验证,并在发现问题时抛出异常;充分利用DevCloud 的代码质量检查工具对前后端代码进行全面扫描,根据检查结果改进代码质量;开展代码评审实践,在发现代码缺陷的同时,也促进了组员对代码的理解与共享。
(6)软件测试。初步建立测试驱动开发实践,通过JUnit 工具编写测试用例,对类或方法进行单元测试,并保证一定的代码覆盖率;采用Web 自动化测试方法,通过大量测试用例的自动运行保证后台接口质量。
3 结语
课程实践是软件工程课程的重要组成部分,也是帮助学生理解与巩固课堂教学内容、培养软件工程能力的重要支撑。以软件构造活动为中心并依托基于云的软件开发平台,使得软件工程实践教学的开展更加契合修读软件工程概论课程本科生的专业基础和接受能力,引导其逐步理解与接受软件工程的思想、方法及相关的工程师文化。今后还将结合翻转课堂思想,加强课堂教学的互动性和研讨性,同时进一步打通课堂理论教学与课程实践相关内容,继续推进软件工程的实践化教学之路。