首页 理论教育 敏捷重构:软件实践教学模式的实施

敏捷重构:软件实践教学模式的实施

时间:2023-11-20 理论教育 版权反馈
【摘要】:学生对教学任务理解得不到位或者有偏差,会导致后续实施过程中部分功能实现不到位,严重的可能会导致交付的软件产品并不是教学任务所要求达到的。依此类推,直到教学任务实施完毕后交付最终的软件版本为止。指导教师指定小组内1名成员作为该组Master,确保小组成员顺利推进敏捷教学过程。

敏捷重构:软件实践教学模式的实施

一个班级可以分为若干敏捷小组,由于每个敏捷小组实施相同的教学任务,因此本案例以一个敏捷小组为例阐述教学实施过程,其余小组的实施过程类似,因而不再赘述。

Day1:教学任务确立、教学规则制定、教学任务分解、工作量估算、任务认领、实施计划制订、开发环境搭建(如表5-7所示)

表5-7 Day1教学时段划分

8:30—9:00教学任务确立、教学规则制定

上课铃声响起,指导教师把用户的真实需求作为教学任务布置给学生(对应教学步骤:教学任务确立),教学任务如下。

用户希望在Android手机上开发一款通讯录APP,要求具备以下功能点:

Fun1 打开通讯录APP首先呈现未展开的扩展列表(如图5-4所示),该扩展列表的一级列表项分别为亲人、朋友、同学、同事、android开发组、老乡和篮球俱乐部7项,每个一级列表项后显示该表项对应的二级列表项数目。如“亲人”后面显示的“1”表示“亲人”对应有1个二级列表项。

Fun2 单击一级列表项后,会呈现二级列表项(如图5-5所示),每个二级列表布局均由左侧的小图标、中部的文本以及右侧的引导图标构成。

Fun3 长按一级列表项(如长按“亲人”),弹出选项菜单,该选项菜单由“添加分组”、“删除分组”、“重命名”和“添加联系人”等选项组成(如图5-6所示)。

Fun4 长按二级列表项(如长按“IBM”),弹出选项菜单,该选项菜单由“删除联系人”、“编辑联系人”和“移动联系人到…”等选项组成(如图5-7所示)。

图5-4 通讯录APP Fun1效果

图5-5 通讯录APP Fun2效果

图5-6 通讯录APP Fun3效果

图5-7 通讯录APP Fun4效果

布置完教学任务后,指导教师在Android手机上将通讯录APP的交付效果向学生演示,以使学生对教学任务有更直观的认识。学生对照交付效果理解教学任务的具体需求,在理解时思考以下问题:

●教学任务有没有不能理解的地方?

●教学任务有没有不合逻辑的地方?

●教学任务是否存在二义性的地方?

这一教学环节不要求学生给出教学任务的具体实施方案或计划,仅仅要求学生理解。为了检验学生对教学任务的理解程度,先让学生相互讨论,再由指导教师针对学生理解教学任务时普遍存在的偏差进行统一讲解和纠偏,确保学生对教学任务理解的准确性和全面性。学生对教学任务理解得不到位或者有偏差,会导致后续实施过程中部分功能实现不到位,严重的可能会导致交付的软件产品并不是教学任务所要求达到的。因此,不管通过何种途径,学生对教学任务应当充分理解并在班级内达成共识。

理解了实践教学任务后,指导教师应当当众宣读制定的敏捷实践教学具体实施规则(对应教学步骤:教学规则制定),对实践教学内容、教学组织形式和教学过程形成等要素做出必要的约束和限定,从而更加有效地管理敏捷实践课堂,也更有助于学生在教学规则的限定下按照敏捷过程实施教学任务。

指导教师与全班学生约定以下几项教学规则:

●教学过程形式:教学任务实施按照敏捷软件开发流程,以迭代开发的形式进行教学任务增量集成。

补充说明:实践教学任务基于敏捷框架理论,以迭代方式进行代码的增量集成,每个迭代周期执行“编码—测试—发布”的过程。

第一个迭代周期:(Fun1模块)编码—测试—发布,交付物为(Fun1版本)。

第二个迭代周期:(Fun1版本+Fun2模块)编码—测试—发布,交付物为(Fun2版本)。

第三个迭代周期:(Fun2版本+Fun3模块)编码—测试—发布,交付物为(Fun3版本)。

依此类推,直到教学任务实施完毕后交付最终的软件版本为止。

●教学组织形式:以小组为任务实施的基本单位,每组6人(以A、B、C、D、E和F指代),组内采用两两结对的形式实施(A-B结对、C-D结对、E-F结对),只有当小组内成员把所有任务都完成,整个实践任务才算完成。

补充说明:采用学生自由组队为主、指导教师协调为辅的原则进行组队,学生先根据自身的技术优势、行为习惯、价值观念等因素进行自由组合,每组6名学生;然后在组内进行两两结对;最后指导教师根据每组学生以及结对学生的专业技术水平进行统筹协调,确保每组学生整体技能水平差不多,并且两两结对的2名学生专业基础存在一定的梯度但相差不大。需要注意的是,技能梯度或差异判断是相对主观的行为,因此,指导教师应当平日对学生充分了解,在此基础上做出判断。

●团队负责人:张三。

补充说明:6名学生组成的敏捷小组为一个完整的团队,应当有一个团队负责人充当Master角色。指导教师指定小组内1名成员作为该组Master,确保小组成员顺利推进敏捷教学过程。

●实践教学实施周期为5天,每天4课时,软件版本交付时间为2018年11月9日中午11:30。

补充说明:实际的教学时间安排各不相同,但总的教学学时相对比较固定,维持在每周20~30课时。本案例以每周20课时计,每天4课时,为便于详细阐述,每天的教学课时都集中安排在上午。假设敏捷实践教学开始时间为2018年11月5日上午8:30,结束时间(交付时间)为2018年11月上午11:30。

●交付物形式:通讯录APP工程源码

补充说明:软件实践教学任务通常是开发一款软件产品,由于软件产品本质上是一系列代码经过编译运行后生成的软件版本,属于虚拟产品,一般的项目交付物为初始的工程源码或者最终编译生成的软件版本。本案例选择通讯录APP的工程源码,指导教师不仅可以看到学生的编码状况(包括编码规范、编码效率和编码质量等),还可以根据工程源码看到运行效果,一举两得。

9:00—9:30教学任务分解

教学任务分解就是把教学任务中颗粒度较大的功能点细分为若干颗粒度较小的功能点,化复杂为简单。因此,后续对于大颗粒度功能点的实施就转化为对若干小颗粒度功能点的实施与集成。教学任务分解给敏捷实践教学课堂带来的好处是显而易见的,一是可以把较为复杂的、涵盖较多技能点的功能,简化为较为简单的、只覆盖一个或少量技能点的若干功能,降低了实施难度,提升了实施效率;二是促使学生通过分解过程再次深入理解和思考教学任务所涉及的功能需求。

比如,在对Fun1进行分解时,学生不得不思考以下问题:

●什么是扩展列表?扩展列表跟普通列表有哪些不同?

●什么是扩展列表的一级列表项和二级列表项?

●一级列表项和二级列表项之间存在哪些关联?

●一级列表项和二级列表项的数据从哪里获取?如何显示?

如果学生能把上面的问题或者需求点都弄明白了,那么他对Fun1任务也就理解到位了。因此,教学任务分解不仅是化大为小、化繁为简的必要手段,更是学生二次理解教学任务的过程。

教学任务分解的课堂组织宜采用学生相互讨论为主、指导教师协助为辅的形式开展。学生之间就分解逻辑、分解过程和分解结果展开讨论,在各抒己见的同时应当仔细倾听其他学生的不同意见和建议。综合自己的理解和其他学生的意见,最终形成自己对该教学任务的理解,并与其他学生的理解和认识达成共识。

学生对教学任务的理解过程一般会经历:个人理解→相互探讨,发现自身理解与其他学生理解存在不一致→参考其他学生的理解,并反思自己的理解→修正或推翻自己的理解→与其他学生再确认→对教学任务理解达成一致。

教学任务分解可以依据功能模块分解,也可以按照知识技能点分解。按功能模块分解,更多的是站在用户角度来考虑问题;而按知识技能点分解,更多的是站在开发人员的角度来考虑问题,将教学任务涉及的所有知识点进行分解,然后把每个知识点嵌入功能中去描述。也就是说,即使按照知识点对教学任务进行分解,最终还是要统一到功能上面,只不过是从知识点和技能角度去描述功能的实施方案。

按照功能模块进行教学任务分解,实践教学任务Fun1—Fun4可以被分解为:

SubFun1 Android扩展列表设计与开发。

SubFun2 数据库和数据库表的创建。

SubFun3 数据库表中的数据初始化

SubFun4 Android扩展列表加载数据库中的数据并显示。

SubFun5 一级列表长按监听、创建选项菜单,该选项菜单由“添加分组”、“删除分组”、“重命名”和“添加联系人”等选项组成。

SubFun6 二级列表长按监听,该选项菜单由“删除联系人”、“编辑联系人”和“移动联系人到…”等选项组成。

按照知识点、技能进行教学任务分解,实践教学任务Fun1—Fun4可以被分解为:

SubFun1 Android ExpandableListView的布局文件设计与逻辑控制设计。

SubFun2 利用SQLiteOpenHelper的子类创建SQLite数据库,利用SQLite语句创建SQLite数据库中的表。

SubFun3 向SQLite数据库中的表插入记录,从而完成数据库表中的数据初始化。

SubFun4 ExpandableList向SQLite数据库表查询数据后进行解析,再把解析后的数据项设置到扩展列表项上并显示出来。

SubFun5 一级列表项设置长按监听器,并在监听处理中创建选项菜单。

SubFun6 二级列表项设置长按监听器,并在监听处理中创建选项菜单。

由此可见,按照知识点、技能点进行教学任务分解,实则是把后续的“实施计划制订”教学步骤与教学任务分解相融合。如果学生专业基础比较扎实,可以采用此方式分解;否则,还是按照功能点进行教学任务分解为宜。

9:30—9:40休息

休息,意味着前一段活动的结束,以及下一段活动的开始。

休息一下,保持头脑清醒,即将开始头脑风暴……

9:40—10:30工作量估算、任务认领

借鉴敏捷过程中“扑克牌估算”的通用做法,敏捷实践教学的工作量估算步骤也可采用类似做法,只不过为了简化流程不再使用扑克牌,取而代之的是小纸条或小纸片,学生可以在纸条上面写上估算的工作量,效果跟扑克牌估算是等价的。

头脑风暴,百度百科上的解释是:一群人围绕一个特定的兴趣领域产生新观点的情境。由于没有拘束,人们就能够更自由地思考,从而产生很多新的观点和解决问题的方法。当参加者有了新观点和想法时就大声说出来,然后在他人观点之上建立新观点。所有的观点都被记录下来但不进行评价,只有头脑风暴会议结束的时候,才对这些观点和想法进行评估。头脑风暴的特点是让参与者打开思路,使各种设想在相互碰撞中激起脑海中的创造性思维,其可分为直接头脑风暴法和质疑头脑风暴法。前者是在专家群体决策基础上尽可能激发创造性思维,产生尽可能多的设想的方法;后者则是对前者提出的设想、方案逐一质疑,发现其现实可行性的方法,这是一种集体开发创造性思维的方法。

将头脑风暴会议用于实践教学任务的工作量评估过程是非常合适的,因为对于工作量的估算,每个人的估算依据和理由都不尽相同,受制于专业基础和实践技能水平,不同思维和逻辑背景下的估算结果产生冲突是避免不了的。引入头脑风暴会议,就是为了通过思维碰撞和理性阐述相结合,使得工作量估算结果趋于一致并最终在团队内部达成共识,以便后续实践教学步骤的开展。在实践过程中,应尽量避免头脑风暴会议走形式、走流程,不能为了风暴而风暴;而应当从教学实际出发,在学生理解教学任务的基础上,引导学生思考如何实现该教学任务,在实现教学任务时主要的难点在哪里,以及实现这些难点需要涉及哪些知识点等因素,以便更加科学、合理、精确地估算出工作量。当然,工作量估算的科学性、合理性和精确性是个相对概念,没有绝对性。因此,工作量估算值是个大概值,只要落到某个特定的区间并且该区间被大多数人认可,那么该估算值就算是成功的。

敏捷小组内所有成员围坐在一起,对分解后的实践教学任务进行工作量评估,即实施周期评估。学生在评估工作量之前需要考虑以下因素:

●实施步骤是否清楚?大致的实施方案、计划和流程是否清楚?

●实施过程中最耗费时间的是哪个或者哪几个模块?

●实施过程所需的知识点和技能点是否掌握?

●实施过程中是否存在不确定性因素?这些因素大概会耽搁多少时间?

●实施过程中是否与团队外部人员或第三方模块有交互?对接时是否存在障碍?这些障碍大概会耽搁多少时间?

把上述因素尽可能多地考虑到,这样评估的工作量才更加准确合理。当不同学生对于同一个子任务得出的工作量评估值相差过大,比如大于预设的阈值,就意味着学生对该子任务实施方案的理解存在较大分歧,可能会出现以下几种可能:

●工作量估算值最大的学生相对而言比较准确,因为他把很多潜在的风险和困难都充分考虑到了,而这些潜在的风险发生的概率,或者困难出现的概率是较大的。

●工作量估算值最小的学生相对而言比较准确,因为他已经把实施方案分析得非常透彻,给出了每个模块的工作量,并且得到指导教师和其他学生的认可。

●工作量估算值最大的学生估算量过大,因为他夸大了工作强度和难度;工作量估算值最小的学生估算量过小,因为他考虑的实施方案遗漏了某些功能点或低估了某些功能点的实施难度。

这时,指导教师就应当从“旁观”状态转变为“指导讨论”状态,组织并全面参与到头脑风暴中,以便发现产生分歧的根本原因,并为消除该分歧最终达成共识进行讲解、交流与讨论。指导教师可以要求工作量评估值最大和最小的两名学生分别说明评估的依据和对该子任务的理解,然后再组织所有学生一起讨论,遇到共性的问题可以统一讲解和演示。反复进行几轮“估算—讨论—重新估算”,直到所有学生对某个子任务的工作量达成共识为止。

第一轮估算环节:工作量评估结果可能如表5-8所示,“SunFun2 数据库和数据库表的创建”和“SubFun4 Android扩展列表加载数据库中的数据并显示”两个子任务的估算有分歧,SubFun2中学生B的估算值最高,为8人课,学生C的估算值最低,为4人课;SubFun4中学生D的估算值最高,为6人课,学生E的估算值最低,为2人课。

对于SubFun2,指导教师要求学生B和C分别说明估算理由和依据。

学生B:SubFun2分为两个功能点,数据库创建和表创建。数据库创建需要新建一个SQLiteOpenHelper类的子类,并实例化该子类;表创建通过SQ命令行实现。要实现SubFun2这个子任务,需要实现2个类、6个方法和1个宏定义,共需要8人课。

学生C:SubFun2数据库和表的创建可以合并到SQLiteOpenHelper子类实现,需要实现2个类和3个方法,共需要4人课。

旁听人员:指导教师和敏捷小组其余学生。

学生B和学生C各自陈述完毕后,所有学生再次就SbuFun2展开讨论。

学生A:赞同学生C的观点,并提出“SQLiteOpenHelper子类需要重写onUpgrade方法”这一实施过程需要对版本号递增做测试验证,建议在学生C的4人课基础上再追加2人课用于重写onUpgrade方法和相关测试。

学生E:同意学生A的观点。

学生F:同意学生A的观点。

此时,学生B和学生C应当结合学生A、E、F的观点,对自己实现的方案进行反思,然后敏捷小组进行重新估算。

SubFun4的估算过程与上述过程相同,不再赘述。

表5-8 第一轮头脑风暴估算结果(单位:人课)

第二轮估算环节:工作量评估结果可能如表5-9所示,SubFun2中学生B和学生C的估算值都调整为6人课,第一轮估算中产生的分歧就消除了,消除的根本原因在于学生B和学生C认识到自身考虑问题不周,并能够及时修正自己的实施方案,最终与其他成员就实施工作量达成共识。因此,6人课用于实施SubFun2是相对合理的。需要注意的是,在第二轮头脑风暴估算中,即便学生D仍然认为7人课是较为准确的估算值,但是基于时间和效率上的考虑,少许的不同也应该是被允许的,实践教学过程中可以灵活处理,只要相差不超过设定的阈值即可。

SubFun4的第二轮估算过程与上述过程相同,不再赘述。最终,4人课用于实施SubFun4是相对合理的。

表5-9 第二轮头脑风暴估算结果(单位:人课)

如果两轮头脑风暴还是无法消除一开始存在的估算分歧,那么指导教师就不能袖手旁观了,而应当把最优的实施方案或思路传递给所有学生,与学生就疑问或分歧点进行深入探讨并集中讲授,从而尽快使分歧收缩并最终得到消除。

综上,经过两轮头脑风暴,之前估算SubFun2和SubFun4的工作量存在的分歧已经被消除,并达成一致意见:SubFun2耗时6人课,SubFun4耗时4人课。

现在是10:25,离10:30还有5分钟,这是留给任务认领环节的时间。

教学任务认领的原则是:

●学生先认领,教师后协调。

学生先结对认领,以学生的意愿为主,这样有利于激发学生实施教学任务的积极性,也便于更加高效地结对编程。但也会存在一些问题,比如有些教学子任务因为难度较高或者其他原因无人认领,有些教学子任务同时被多人认领而无法协调。这时就必须由指导教师根据实际情况进行统筹协调,综合考虑学生的专业技能水平、兴趣爱好、意愿、已认领任务工作量和未认领任务实施难度等因素。

●尽量认领自身擅长的知识点对应的教学子任务。

人总是习惯于做自己做过的或擅长的事情,这是天性。学生也不例外,若认领自身擅长领域的任务,很快就能高质量交付;若认领自身技能劣势或者不熟悉的领域,至少要花费时间成本去学习和熟悉,除交付质量不敢保证之外,实施效率也比较低下。

●尽量认领具有相同功能点或类似功能点的教学子任务。

一方面,对相同或类似功能点的任务开发,可以套用之前的开发模板和经验进行简单的替换和少量变更操作即可完成任务,这意味着实施效率可以成倍提高,多出来的时间可以用于做充足的测试和集成,也可以用于做代码优化重构;另一方面,相同或类似功能点之间的逻辑衔接相对比较容易,思维转换也会比较小,有助于提升软件开发质量。

●小组内不同结对认领的教学子任务的工作量应尽可能相当。

教学任务量相当意味着不同的结对可以在相同或接近的时间内完成认领的教学子任务,而不至于因为工作量不均导致有的结对很早就完成而有的结对很晚才完成。在敏捷实践教学中,所有的教学子任务都完成并且功能都整合在一起,整个教学任务才算完成。

表5-10给出了敏捷实践教学子任务的认领情况,A-B结对认领了Sub-Fun1和SubFun4,C-D结对认领了SubFun2和SubFun3,E-F结对认领了SubFun5、SubFun6和SubFun7。可以看出,E-F结对除了完成功能点开发之外,还要对每个结对的教学任务进行整合,因此总的工作量比其他两个结对都要大一些,但这并不是大问题,C-D和A-B结对实施完成后会协助E-F结对共同完成,因为自组织教学团队就是这么要求的。

表5-10 教学子任务认领结果举例

续表

任务认领完毕后,每个结对需要将认领的任务以需求说明的形式写到便利贴上,然后将便利贴粘贴到敏捷白板的TO DO栏,表示将要实施的教学子任务,如表5-11所示。

表5-11 A-B结对将认领的子任务贴在敏捷白板的TO DO栏*

*表格中的单元格是用来粘贴写有教学子任务的便利贴,单元格内容变换代表敏捷白板上的便利贴位置的移动,表明子任务状态的更新。

10:30—10:40休息

休息,意味着前一段活动的结束,以及下一段活动的开始。

休息一下,保持头脑清醒,即将开始制订实施计划。

10:40—11:00教学计划制订

前期的教学任务分解、工作量估算和任务认领等环节,迫使学生或多或少地考虑实现教学任务的思路和方案,即如何一步一步地把教学任务做出来。因此,真正到了教学计划制订环节反而变得相对容易一些。

教学计划主要由结对学生根据认领到的任务来制订,制订时要考虑以下因素:

●从哪个模块开始做?

选定的这个模块应该是基础模块,其他模块应该在该模块基础上进行增量开发。因此,对第一个开始着手实施的模块应当慎重选择,这将直接影响后续的开发效率和实施情绪。

●代码重构与优化活动在什么时候开始进行?

代码重构与优化是敏捷实践教学实施阶段的重要活动,是交付高价值、高质量软件产品的关键因素之一。代码重构与优化是在现有代码基础上对其结构、稳定性、可复用性、可移植性、可测试性等方面进行改造和优化,以满足软件的高性能指标,从而提升软件产品质量和价值。引入重构与优化的时机和方式显得尤为重要,建议在每轮迭代之间引入,以对上一轮增量迭代的产品进行重构与优化。

A-B实施计划:

开发环境搭建→(迭代开发实施1:Android扩展列表布局设计编码→测试→交付)→(迭代开发实施2:Android扩展列表逻辑设计编码→测试→交付)→(迭代开发实施3:Android读取数据库中的数据并显示编码→测试→交付)

A-B实施详细计划:

(Android Studio 3.1.2集成环境安装→Android SDK下载→路径选择→新建一个Android工程→运行Android工程→开发环境搭建成功)→(迭代开发实施1:Android扩展列表布局文件activity_main.xml设计与编码→预览测试→交付)→(迭代开发实施2:Android扩展列表动态文件Main-Activity.java编码→运行测试→交付)→(迭代开发实施3:MainActivity.java文件的代码重构与优化→运行测试→交付)→(迭代开发实施4:读取数据库返回Cursor格式数据→解析Cursor格式数据→将解析好的数据设置到扩展列表项上面→运行测试→交付)→(迭代开发实施5:迭代开发实施4的代码重构与优化→运行测试→交付)

C-D实施计划:

开发环境搭建→(迭代开发实施1:数据库创建编码→测试→交付)→(迭代开发实施2:数据库表创建编码→测试→交付)→(迭代开发实施3:数据库中字段内容显示编码→测试→交付)

C-D实施详细计划:

(Android Studio 3.1.2集成环境安装→Android SDK下载→路径选择→新建一个Android工程→运行Android工程→开发环境搭建成功)→(迭代开发实施1:新建SQLiteOpenHelper子类→构造方法→实例化该子类编码→预览测试→交付)→(迭代开发实施2:代码重构与优化→运行测试→交付)→(迭代开发实施3:创建数据库表编码→运行测试→交付)→(迭代开发实施4:代码重构与优化→运行测试→交付)

E-F实施计划:

开发环境搭建→(迭代开发实施1:一级列表长按监听编码→测试→交付)→(迭代开发实施2:长按后触发选项菜单编码→测试→交付)→(迭代开发实施3:二级列表长按监听编码→测试→交付)→(迭代开发实施4:长按触发选项菜单编码→测试→交付)

E-F实施详细计划:

(Android Studio 3.1.2集成环境安装→Android SDK下载→路径选择→新建一个Android工程→运行Android工程→开发环境搭建成功)→(迭代开发实施1:一级列表长按监听编码→测试→运行)→(迭代开发实施2:长按后触发选项菜单编码→测试→运行)→(迭代开发实施3:二级列表长按监听编码→测试→交付)→(迭代开发实施4:长按触发选项菜单编码→测试→交付)→(迭代开发实施5:代码重构与优化→运行测试→交付)

整合实施计划:

以E-F结对的软件版本为基础,对其他两个结对的实施结果做整合操作。

(迭代开发实施1:在E-F基础上加入A-B编码→测试→交付)→(迭代开发实施2:在E-F和A-B基础上加入C-D编码→测试→交付)→(迭代开发实施3:代码重构与优化→运行测试→交付)→软件产品交付

11:00—11:30开发环境搭建

教学目标:搭建手机通讯录APP开发环境

教学内容:

(1)下载Android Studio 3.1.2集成环境安装包;

(2)安装Android SAtudio 3.1.2集成环境安装包;

(3)下载SDK(安装Android Studio 3.1.2时会有提示);

(4)环境配置;

(5)新建一个Android工程,启动一个手机模拟器,运行Android工程(这一步是为了验证Android Studio 3.1.2是否可以正常使用。如果可以正常运行Android工程,说明开发环境搭建成功;反之则不成功,需要重新安装)。

教学实践:

软件开发类课程通常需要下载安装包并安装,有的安装包安装过程耗时较长,因此,下载和安装的过程可以安排在课前进行,以节省课堂用于实践的时间,提高实践教学效率。本案例下载和安装过程都是在实践教学开始前预先完成的,课堂上开发环境搭建从上述第4步开始。

敏捷实践教学开始实施时,结对学生要在白板上进行教学子任务状态的更新,将“Android开发环境搭建”子任务从敏捷白板的TO DO栏移动到DOING,表明该子任务当前正在被实施,如表5-12所示。

表5-12 A-B结对将“Android开发环境搭建”子任务从TO DO栏移动到DOING栏

续表

经过半个小时的实践操作,结对学生都完成了环境配置、工程新建并运行显示在PC桌面上,效果如图5-8、图5-9所示。

图5-8 Android Studio环境配置效果展示

图5-9 Android Studio正常运行ContactManager工程效果展示

Day2:每日立会召开、迭代开发实施(引入代码评审或代码走查)

表5-13 Day2教学时段划分

*注意事项:
1.敏捷实践教学的迭代开发实施环节模拟企业现场的工作过程,休息时间比较灵活自由,在教学实践中不作限制。
2.在迭代开发实施过程中引入代码评审或代码走查的时间根据实施进度而定,在教学实践中不作限制。

8:30—8:45每日立会召开

上课铃声响起,指导教师召集敏捷教学小组内所有学生开每日立会。

每日立会,是指敏捷实践教学任务相关人(包括指导教师和所有结对学生)在每天开始实施教学任务之前站在敏捷白板前,由每个结对向大家汇报当前进度和计划(包括昨天已经做了哪些工作,今天计划做哪些工作,预期如何,还剩哪些任务没做,目前遇到难以解决的障碍有哪些)。便利贴位置的移动意味着教学子任务状态的变更,比如便利贴从TO DO栏移动到DOING栏,表明该便利贴所写的教学子任务今天将被实施;如果便利贴从DOING栏移动到DONE栏,表明该便利贴所写的教学子任务现在已做完,处于实施完毕状态。

每日立会在整个敏捷实践教学过程中有特别重要的作用,一是通过汇报形式,指导教师可以及时了解敏捷小组目前的教学任务实施进度和遇到的问题,并据此更加精准科学地设计和实施后续教学过程,以使实践教学过程更加适合学生的实际情况;二是结对成员可以从其他结对成员那里获取解决问题的思路和灵感以用于自己实施的教学任务。

每日立会只有15分钟时间,所以不能由每个结对对实施方案展开叙述,也不建议指导教师对学生汇报的内容当场点评,因为这会浪费整个小组所有学生的实施时间。正确的做法是单独找出现问题或需要获得帮助的学生进行交流与讨论,有针对性地解决其遇到的问题。

以A-B结对的教学任务为例,Day2每日立会开始之前,敏捷白板上的子任务状态如表5-14所示,等立会开完以后,敏捷白板上的子任务状态应当更新为如表5-15所示,表明A-B结对:

●昨天已经完成了“Android开发环境搭建”教学子任务。

●今天计划做“迭代开发实施1”和“迭代开发实施2”。

●还剩下“迭代开发实施3”和“迭代开发实施4”未开始做。

表5-14 Day2每日立会之前A-B结对的任务状态

表5-15 Day2每日立会之后A-B结对的任务状态

续表

表5-16和表5-17分别是每日立会后C-D结对和E-F结对的任务状态。由表5-16可以看出,C-D结对昨天已经完成了“Android开发环境搭建”子任务,今天计划开始实施“迭代开发实施1”、“迭代开发实施2”和“迭代开发实施3”。子任务还剩“迭代开发实施4”未开始实施。

表5-16 Day2每日立会之后C-D结对的任务状态

由表5-17可以看出,E-F结对昨天已经完成了“Android开发环境搭建”子任务,今天计划开始实施“迭代开发实施1”、“迭代开发实施2”、“迭代开发实施3”和“迭代开发实施4”子任务,还剩“迭代开发实施5”、“迭代开发实施6”、“迭代开发实施7”和“迭代开发实施8”未开始实施。

表5-17 Day2每日立会之后E-F结对的任务状态

续表

8:45—11:30 迭代开发实施(实施重点:任务编码实现、结对编程、增量集成、代码走查)

1.A-B结对实施

迭代开发实施1 Android扩展列表布局设计,以为用户提供静态显示,效果如图5-10所示。

●在activity_main.xml布局文件中设计扩展列表。

图5-10 迭代开发实施1效果

图5-11 activity_main.xml设计

●新建activity_group.xml布局文件,设计一级列表项布局,效果如图5-12所示。 (www.xing528.com)

图5-12 activity_group.xml设计

●新建activity_child.xml布局文件,设计二级列表项布局,效果如图5-13所示。

图5-13 activity_child.xml设计

A-B结对编码:

(1)activity_main.xml编码。

A-B结对在编码时非常注重注释的作用,好的注释可以帮助开发者和维护者更快地读懂代码,从而提高开发效率。虽然XML属于标记语言,所见即所得,但在某些重要标记处打上注释,有助于加深记忆和理解。但添加注释并不意味着可以丢弃好的编码习惯,甚至有些错误观点认为“总是有注释可以看而无须遵守编码规范”。

activity_main.xml编码完成后,A-B结对为了提高实施效率,并没有对整个程序进行编译和运行,而是通过预览视图看到编码效果。

(2)activity_group.xml编码。

activity_group.xml可以实现可扩展列表的一级列表项布局。从图5-12可以看出,该一级列表项布局非常简单,左侧是一级列表项名称,表示通讯录分组名称,右侧是该分组下的所有联系人数量,用水平排列的线性布局即可实现。

(3)activity_child.xml编码。

以上对于“迭代开发实施1”的这个完整的迭代周期(编码→测试→交付)已经实施完毕。编码就是对教学子任务写XML代码以完成布局设计。而XML属于所写即所得的标记代码,是需要在预览视图就可以看到XML的视觉效果,相当于迭代周期中的测试环节。预览效果与预期效果一致就可以把迭代开发实施1的所有软件代码交付了,交付形式是工程源码。

至此,“迭代开发实施1”已经由A-B结对全部完成。

“迭代开发实施2 Android扩展列表逻辑功能开发与实现,以为用户提供二级扩展列表进行人机交互”就是基于已交付的工程源码进行增量集成开发。考虑到这个迭代开发实施任务比较复杂,因此把实施流程分为如下两个步骤:

步骤1:自定义MyCursorTreeAdapter适配器继承自CursorTreeAdapter类。

步骤2:在onCreate方法中实例化MyCursorTreeAdapter对象,并把该对象设置到可扩展列表上以显示可扩展列表。

这两个步骤的关系是:步骤2要调用步骤1中的构造方法。

步骤1:自定义MyCursorTreeAdapter适配器继承自CursorTreeAdapter类。

上述重写@Override的5个方法都没有具体实现,只是用注释说明了该方法需要实现的功能,这样做的目的就是要求学生先把框架性、流程性的结构搭建好,然后再由学生向搭建好的框架里面编写具体的代码。

步骤2:在onCreate方法中实例化MyCursorTreeAdapter对象,并把该对象设置到可扩展列表上以显示可扩展列表。

接下来的重点编码工作就变成实现步骤1中5个加有注释的方法。

遇到的难题:A-B结对在接下来的编码过程中发现一个问题,把数据绑定到可扩展列表的一级列表项和二级列表项时,需要先创建数据库和数据库的表,然后还需要查询数据库中的数据。而这部分工作属于C-D结对今天计划完成的“迭代开发实施1:新建SQLiteOpenHelper子类→构造方法→实例化该子类编码”和“迭代开发实施2:创建数据库表”任务。换句话说,A-B结对的编码部分依赖于C-D结对的编码,这就存在两种可能:

●C-D结对编码效率较高,在A-B结对需要调用C-D结对编码结果时,C-D结对已经完成,可被A-B结对调用。

●C-D结对编码效率较低,在A-B结对需要调用C-D结对编码结果时,C-D结对还未完成。

本着“将依赖影响降低到最低限度”的原则,如果出现上述第二种情况,A-B结对可以采用“打桩”的方式获取虚拟数据,但调用结构仍然存在,只不过数据是虚拟的,暂时能够保证代码顺利编译运行而不至于因为这种影响导致其他功能也无法正常运行。待C-D结对完成该功能开发后,就可以把“桩”拆掉,换成真实的接口或数据。

现在就以上述第二种情况为例来说明如何“打桩”,以及如何“拆桩”。

步骤1(打桩):自定义MyCursorTreeAdapter适配器继承自Cursor-TreeAdapter类。

等到C-D结对完成任务后,A-B结对就可以进行“拆桩”操作了。所谓“拆桩”,就是把原先写的虚拟数据替换成调用接口或方法使其能够获取到正确的数据。因此,对上述步骤1进行“拆桩”操作后的结果为:

步骤2(拆桩):自定义MyCursorTreeAdapter适配器继承自Cursor-TreeAdapter类。

经测试通过后,A-B结对已完成“迭代开发实施2 Android扩展列表逻辑功能开发与实现,以为用户提供二级扩展列表进行人机交互”,顺利交付工程源码,圆满完成今天的教学实施任务。

2.C-D结对实施

迭代开发实施1 新建SQLiteOpenHelper子类。

迭代开发实施2 创建数据库表。

迭代开发实施3 对迭代开发实施2进行代码重构与优化。

C-D结对实施主要分为两步:第一步是功能实现,包括迭代开发实施1和迭代开发实施2;第二步是对第一步的代码重构与优化。如果把第一步看作教学任务的功能实现,那么第二步为教学任务的性能优化。

步骤1:新建SQLiteOpenHelper子类并在该子类中创建数据库表。

步骤1完成之后,C-D结对邀请指导教师、A-B结对和E-F结对共同对步骤1中的代码进行代码评审。经过10分钟的代码评审过程,大家的评审意见汇总如下。

指导教师评审意见:

●自定义方法不宜放在SQLiteOpenHelper子类中实现。

●类名、对象名和变量名命名不规范,从命名看不出其功能意义。

A-B结对评审意见:

●数据库的groups表除了用到_id和groupName两个属性之外,没用到其他属性。

●数据库的contacts表也存在类似问题。

E-F结对评审意见:

●初始化数据库表的功能可以封装成方法以调用,从而提高代码的可复用性、整洁性和可维护性。

●随机数功能不是教学任务中体现用户价值的必需功能,应该删除。

软件行业中的代码评审,是指找同事、同行或专家组成评审小组,对软件中的特定代码进行评审,以发现代码中存在的问题以及有必要修改的问题,这些问题有可能涉及功能缺陷、性能不足或代码规范等问题。编写代码的软件开发人员在仔细分析评审意见后,将会对认可的评审意见进行代码修改或重构,以解决评审成员提出的问题,从而提高代码质量。

实践教学中的代码评审,是指当前结对学生请求其他结对成员和指导教师对其编写的某段代码或者特定部分的代码进行评审的过程。A-B结对学生认真分析并接受了所有评审意见,同时着手修改或重构代码。

步骤2:对步骤1中的代码进行重构与优化。

重构与优化后的代码必须通过测试才能交付。在测试前,需要明确测试哪些功能或方法。在步骤2中涉及两个非常重要的功能点:一个是数据库和数据库表的创建;另一个是数据库表的初始化,即向数据库表中插入若干条记录数据。因此,应当重点测试这两个功能点。具体测试步骤如下:

步骤1:如图5-14所示,在Android Studio 3.1.2/View/Tool Windows/Device File Explorer/data/data/[package]路径下,新增了databases文件夹,该文件夹里面有contactsmanager.db文件,这个文件就是创建的数据库文件,与预期效果一致,测试通过。

图5-14 数据库contactsmanager已创建

步骤2:利用第三方SQLite可视化工具SQLiteManager查看contactsmanager.db文件。如图5-15和图5-16所示,contactsmanager.db数据库中包含groups表和contacts表,groups表有两个属性,属性名称分别为id和Name,属性类型分别为INTEGER和TEXT;contacts表有四个属性,属性名称分别为id、Name、groupName和description,属性类型分别为INTEGER、TEXT、TEXT和TEXT。很显然,创建数据库contactsmanager和数据库表groups和contacts的测试结果均与预期效果一致,测试通过。

图5-15 groups表的属性名称和属性类型

图5-16 contacts表的属性名称和属性类型

步骤3:利用SQLite查表命令对groups表和contacts表进行查询以测试其初始化值与预期的是否一致。如图5-17和图5-18所示,groups表中初始化有7条记录,contacts表中初始化有10条记录,均与预期效果一致,测试通过。

图5-17 groups表的7条记录详情

图5-18 contacts表的10条记录详情

至此,C-D结对已完成“迭代开发实施3:对迭代开发实施2进行代码重构与优化”,顺利交付工程源码,圆满完成今天的教学实施任务。

3.E-F结对实施

迭代开发实施1 一级列表长按监听。

E-F结对计划在可扩展列表控件上注册上下文菜单来实现。

步骤1:在可扩展列表上注册上下文菜单,以实现可扩展一级列表项和二级列表项的监听动作。经过编译后在手机模拟器上运行正常,测试通过。(步骤1同时实现了迭代开发实施3)

步骤2:区分监听对象是一级列表项还是二级列表项。在步骤1的基础上,通过判断可扩展列表的长按位置类别来区分。经过编译后在手机模拟器上运行正常,测试通过。

步骤3:创建选项菜单。在步骤2的基础上,分别创建由长按一级列表项触发的选项菜单和由长按二级列表项触发的选项菜单。经过编译后在手机模拟器上运行正常,测试通过。

至此,E-F结对已完成“迭代开发实施4”,顺利交付工程源码,圆满完成今天的教学实施任务。

Day3:每日立会召开、教学任务变更、迭代开发实施

表5-18 Day3教学时段划分

8:30—8:45每日立会召开

上课铃声响起,指导教师召集敏捷教学小组内所有学生开每日立会,结对学生在敏捷白板前汇报,同时将便利贴位置状态做变更,如表5-19—表5-21所示。

表5-19 Day3每日立会之后A-B结对的任务状态

表5-20 Day3每日立会之后C-D结对的任务状态

表5-21 Day2每日立会之后E-F结对的任务状态

8:45—9:15教学任务变更(模拟实际工作中需求变更的场景)

当结对学生准备实施当天的教学任务时,指导教师突然宣布对教学任务做变更,在原先基础上增加“注册登录界面设计”教学任务,如图5-19所示。软件项目需求变更在工作过程中是普遍存在的,敏捷过程中的“迭代”和“增量集成”就是为了应对需求变更而被提出并得到广泛应用。在实践教学领域,当遇到教学任务变更时,敏捷过程也能很好地应对。本案例设置“教学任务变更”环节,也正是为了阐述与之对应的教学过程,以供大家参考。

教学任务变更并不会改变敏捷实践教学的总体步骤和流程,只需在某个步骤做微调即可,教学过程中运用的敏捷教学手段和方法都可以保持相对不变。教学任务变更一般涉及三种情况:一是教学任务改变;二是教学任务增加;三是教学任务删除。

●教学任务改变。

教学任务改变意味着原先的实施方案可能要调整,某些功能模块可能要重写或删除。如果教学任务改变较大,超出基础功能范围,那么这种需求改变导致整个代码变更和重构的难度较大,不太适用于实践教学过程。

●教学任务增加。

教学任务增加意味着原先的基础方案和版本保持稳定不变,只需要把新增加的功能嵌入基础版本里面即可。教学任务增加对应实施方案中新功能模块的开发,实施过程中应侧重新模块的兼容性和适应性。

●教学任务删除。

教学任务删除意味着把某些功能从原先版本中去除,使最新的版本不包括被删除的功能。与教学任务增加类似,实施过程中应侧重考虑要删除的模块与基础版本的兼容性和适应性。

新增教学任务描述:打开通讯录APP,首先显示如图5-19所示的注册登录界面,用户输入用户名和密码后单击“注册”按钮,用户名和密码被保存到数据库;当用户单击“登录”按钮,有两种情况:如果用户名和密码与注册时填写的一致,那么就跳转到可扩展列表界面;如果用户名或密码与注册时填写的不一致,那么就提示用户登录失败,需要重新输入。

图5-19 教学任务增加

指导教师在原先制定的教学规则基础上,新增以下规则:

(1)“注册登录界面设计”优先级最高,今天必须优先实施。

(说明:优先级最高就要求学生暂停当前实施任务转而优先开始“注册登录界面设计”功能的实施,这样设计的目的是通过模拟企业软件项目实际变更场景,培养学生对于突发任务、紧急任务的优先处理能力,特别是把突发任务和已经完成的任务整合与集成的能力。)

(2)注册登录界面静态布局设计由AB结对实施,注册和登录的逻辑控制部分由C-D结对实施,完整功能与原先版本做增量集成由E-F结对实施。

(说明:注册登录界面静态布局设计主要涉及XML编码,实施相对简单;考虑到A-B结对在Day2就已经实施完成了可扩展列表界面XML编码,“一回生二回熟”,指派该功能给A-B结对实施还是比较合理的。注册和登录的逻辑处理部分是新增教学任务的核心功能,实施相对复杂,耗时相对较多。考虑到C-D结对今天原计划实施的任务较少,因此把工作量较多的核心功能交给C-D结对实施是比较合理的。E-F结对原先的实施计划就包含代码整合与集成,将该功能指派给E-F结对一并完成也是比较合理的。)

(3)“注册登录界面设计”交付日期为当日11:30。

从上述新制定的教学规则可以看出,规则制定时已经充分考虑到教学任务分解、工作量估算、任务认领等教学步骤,特别是任务认领环节,已经不再是由学生自由认领,而是指导教师综合考虑原先教学任务实施的实际情况后指派给不同的结对学生实施,主要是为了节省用在流程和形式上的时间,提高开发与实践效率。

各结对学生明确需要优先实施的教学任务后,应当把该教学任务写到便利贴上,然后贴到敏捷白板的DOING栏,而把原计划要实施的教学任务返回到TO DO栏,如表5-22—表5-24所示。

表5-22 Day3新增教学任务之后A-B结对的任务状态

表5-23 Day3新增教学任务之后C-D结对的任务状态

续表

表5-24 Day2新增教学任务之后E-F结对的任务状态

9:15—11:30迭代开发实施(引入单元测试)

1.A-B结对实施

新增迭代开发实施1:注册登录界面静态布局设计。A-B结对用约束布局对注册登录界面进行设计,代码如下所示。通过预览视图进行预览显示,效果与预期一致,通过测试,顺利交付工程源码。

2.C-D结对实施

C-D结对讨论了注册和登录功能的实施计划,具体如下:

迭代开发步骤1:注册功能编码→测试→交付。

迭代开发步骤2:登录功能编码→测试→交付。

步骤1:注册功能编码。将用户输入的用户名和密码保存到SQLite数据库的User表中,编码如下所示。编码完成后查看contactsmanager.db数据库中的User表,验证用户输入的用户名和密码(由于验证过程已在前述小节介绍过,此处不再赘述),测试通过,交付工程源码。

步骤2:在步骤1的基础上对用户登录功能做增量集成,代码如下。

为了确保登录功能逻辑实现正确,C-D结对学生计划对execLogin做单元测试。

单元测试是检验一小段代码的一个很小的、很明确的功能是否正确。通常而言,一个单元测试是用于判断某个特定条件(或场景)下某个特定函数(或方法)的行为。如果将测试比作清洗一台机器,那么单元测试就是清洗机器内部的各个零件。单元测试的作用是获取应用程序中可测软件的最小片段,将其同其他代码隔离开来,然后确定其行为确实和开发者所期望的一致。显然,只有保证最小单位的代码准确,才能有效地构建基于它们之上的软件模块及系统。

遗憾的是,很多高等职业院校往往忽视单元测试的教学与实践,在计算机软件类的实践教学中,真正在项目实施过程中引入单元测试教学环节的可谓凤毛麟角,但这丝毫不会影响单元测试在软件产品开发中的地位。单元测试使代码编写更加规范,虽然开发前期会多花时间在编写测试用例和测试类代码上面,但长期来看,会大大减少花费在调试上的时间,提高软件开发效率和质量。单元测试的作用如下:

1.帮助结对学生编写代码,提升质量,减少漏洞

编写单元测试代码的过程是促使学生思考代码实现内容和逻辑的过程,有助于理清设计思路,代码质量。

2.提升反馈速度,减少重复工作,提高开发效率

结对学生实现某个功能或修正漏洞时,如果有相应的单元测试支持,可以马上通过运行测试类来验证实现或修正效果,而无须反复启动应用服务器、发布工程包或在界面输入数据等烦琐操作。用单元测试来验证代码逻辑的效率比人工方式高得多。

3.确保最后的代码修改不会破坏之前代码的逻辑功能

代码越写越多,特别是涉及共用接口或底层库,谁也不能保证修改的代码不会破坏之前的功能。单元测试确保每个历史功能都有相应的单元测试类验证通过,修改代码后,只要把原先的单元测试类跑一遍就可以验证该修改是否影响其他功能。当然,要达到这种程度需要付出很大代价,不但要求较高的测试覆盖率,还要求较高的单元测试类代码编写质量。

4.代码维护更容易

单元测试需要编写很多测试类代码,相当于给代码增加了规格说明书,有助于开发者理解代码的逻辑实现功能,从而提升代码维护效率。

5.有助于改进代码质量和设计

很多易于维护、设计良好的代码都是通过不断的重构才形成的,虽然单元测试不能直接改进代码质量,但能为代码提供“安全网”,让结对学生能够大胆地改进代码,使代码更清晰、简洁。

单元测试需要在Android Studio 3.1.2构建测试类,假设注册时写入数据库User表中的用户名和密码分别为admin和123,那么构建以下3个测试用例对登录功能进行单元测试,代码如下:

测试类运行结果如图5-20所示,3个测试用例都通过测试,说明execLogin()方法实现逻辑正确,测试通过,交付集成了登录和注册功能的工程源码。

图5-20 测试用例都通过

实践教学过程中,学生在进行软件测试时,不管是单元测试,还是集成测试或者系统测试,都应当掌握必要的计算机专业技能,主要体现在以下三个方面。

1.计算机基础知识

掌握网络、操作系统、数据库、中间件等计算机基础知识,做到“博而不精”。在网络方面,测试人员应当了解基本的网络协议及工作原理,尤其是典型网络环境的配置;在操作系统和中间件方面,应当掌握基本的使用和安装方法等;在数据库方面,应至少掌握SQL Server、MySQL、Oracle等常见数据库中的一种。

2.软件编程技术

只有具备编程技能才能胜任诸如单元测试、集成测试、性能测试等难度较大的测试实践,且应至少掌握一种编程设计语言,如C/C++、Python、Perl、JavaScript等。

3.测试的专业技能

测试的专业技能包括黑盒测试、白盒测试、测试用例设计等基础测试技术和单元测试、集成测试、系统测试、性能测试等测试方法,还包括测试流程管理、缺陷管理、自动化测试等专业技能。

除了必要的计算机专业技能以外,还应当具备一些基本的职业素养。

(1)专心:主要指实施测试任务时要一心一用。思想高度集中不但能够提高效率,还能发现更多的测试缺陷。

(2)细心:主要指实施测试任务时要仔细认真,不可以忽略一些细节。如果不细心某些缺陷很难被发现,如一些界面的样式和文字等。

(3)耐心:很多测试任务很枯燥,需要足够的耐心才能做好。如果比较“浮躁”,就无法做到“专心”和“细心”。

(4)责任心:实施测试任务要尽心尽责,不能敷衍了事,否则可能引起非常严重的后果。

(5)自信心:自信心是实施测试任务必备的素质之一,应当建立“解决一切测试问题”的信心。

(6)团队协作能力:测试人员不仅要与组内人员、开发人员、技术支持等研发人员建立良好的沟通协作关系,还应当学会宽容待人,学会理解开发人员,并尊重开发人员的劳动成果。

(7)表达沟通能力:有效的沟通可以提升测试实施效率,是必备素质之一。

综上所述,软件测试是专业性、技术性和实践性非常强的工作,有效实施软件测试特别是单元测试,需要高素质的复合型技能人才,并应具备高度的责任心和自信心,以及专业技能。指导教师在实践教学过程中,应当有意识地强化测试专业技能培养,使学生通过实践教学,真正学会测试的方法和逻辑,使学生真正成为既具备软件开发技能,又具备软件测试技能的高素质职业人才。

E-F结对实施过程省略。

Day4:每日立会召开、迭代开发实施

表5-25 Day4教学时段划分

由于Day4的教学步骤与Day2大同小异,此处不再赘述。

至此,敏捷实践教学应用于Android基础界面设计(实践)课程的教学案例设计已全部阐述完毕,其中,迭代、增量集成、结对开发、代码重构、单元测试等教学环节应该视为敏捷实践教学过程的核心要素,因为这些核心要素都是为培养或强化学生某方面或某些方面的实践技能。

敏捷实践教学模式,不仅仅适用于Android基础界面设计(实践)课程,而且可以将其推广到计算机软件类的所有实践课程,甚至可以尝试推广到工程类的实践课程中去,使更多的学生在敏捷实践教学过程中快乐地学到教学大纲要求的实践技能。应当指出的是,不同的课程具有各自的教学特点和侧重点,敏捷实践教学模式中的教学步骤或环节应当按需取用,若生搬硬套往往会适得其反,强烈反对“为了敏捷而敏捷”,应避免敏捷实践教学流于形式。我们应当通过较长一段时间的实践体验来验证敏捷实践教学模式的各种优势,仔细分析并指出该模式存在的瑕疵或问题以便不断改进和完善。

【注释】

[1]“人课”是用于衡量授课耗时或学生实践耗时的工作量,1人课表示一个学生为完成授课任务用了1课时。

免责声明:以上内容源自网络,版权归原作者所有,如有侵犯您的原创版权请告知,我们将尽快删除相关内容。

我要反馈