118
社区成员
恭喜你已经完成了软工实践的第一次作业,并将逐步迈进到第二次作业的能力提升中。本次作业将聚焦于世界游泳锦标赛跳水赛事项目,期待各位同学大展身手哦!
为了不遗漏作业内容,这里有一份checklist方便你快速查阅
完成对世界游泳锦标赛跳水项目相关数据的收集,并实现一个能够对赛事数据进行统计的控制台程序
根据你选择的编程语言,从下面两个项目中Fork一个到自己的仓库,然后在根目录中新建一个学号为名的文件夹。(将自己的文件全部保存在以自己学号命名的文件夹下!!!)
https://gitcode.net/xxdhd1/project-c
https://gitcode.net/xxdhd1/project-java
复制example(在project-c项目仓库中)下的目录结构到你新建的目录下;不要修改example文件夹和根目录下的README
语言支持:
'\n'
,编码统一使用UTF-8
在开始实现程序之前,在PSP表格[附录1]记录下你估计在程序开发各个步骤上耗费的时间,在你实现程序之后,在PSP表格记录下你在程序的各个模块上实际花费的时间。
使用GitCode[附录2]来管理源代码,代码有进展即签入GitCode,至少进行10次以上的commit修改。签入记录不合理的项目会被助教抽查询问项目细节。
请制定自己的代码规范并撰写成markdown文件,随代码一起上传至GitCode仓库中。可以参照《码出高效_阿里巴巴Java开发手册》/《腾讯c++代码规范》等主流代码规范来制定你自己的编程规范。编码要求项目代码的风格要符合你制定的代码规范。
除了目录组织说明提及的文件,其它自己产生的文件都应该在.gitignore
忽略,如编译器生成的项目文件、输出文件、class、jar包、exe等,确保不会提交到GitCode上,参考 [附录3]。
进行性能分析和改进
使用单元测试对项目进行测试,并使用插件查看测试分支覆盖率等指标;并写出至少10个测试用例确保你的程序能够正确处理各种情况。
在完成项目后,deadline之前,请正确发起一个Pull Requet [附录2],并确保自己的代码最终成功签入。(如果成功签入会在原始项目主页看到自己学号为名的文件夹)
实现一个命令行程序,不妨称之为DWASearch。
本次作业所需数据均爬取自世界游泳锦标赛官网的跳水项目比赛结果和参赛选手信息【该爬取行为仅用于课程教学】
数据收集部分可以参考往届优秀作业[参考链接]
如果对收集数据感到困难,助教这里也提供了相关的数据,供同学们使用,数据保存在仓库中example/data
文件夹内。
假设有一个软件可以输出2024世界游泳锦标赛跳水项目的选手信息和比赛结果。
输入指令和输出文件以命令行参数传入。例如我们在命令行窗口(cmd)中输入:
//C语言类
DWASearch.exe input.txt output.txt
//Java语言
Java -jar DWASearch.jar input.txt output.txt
功能1:输出所有选手信息
当input.txt的内容为
players
则会输出参与世界游泳锦标赛跳水项目的所有选手信息到output.txt,输出格式如下:
Full Name
对应选手全名,Gender
为选手性别, Country
为国籍。输出格式:
Full Name:string
Gender:string
Country:string
-----
...
-----
Full Name:string
Gender:string
Country:string
-----
输出样例:
Full Name:HART Alexander
Gender:Male
Country:Austria
-----
Full Name:LOTFI Dariush
Gender:Male
Country:Austria
-----
...
-----
Full Name:DICK Elaena
Gender:Female
Country:Canada
-----
功能2:输出决赛每个运动项目结果
当input.txt的内容为
result women 1m springboard
则会输出女子1m跳板的决赛结果到output.txt,输出格式如下:
Full Name
对应选手姓名。Rank
为排名。格式如'1'
。Score
表示决赛中该选手的成绩。格式如'score1 + score2 + score3 + ··· + score7 = totalPoint'
。输出格式:
Full Name:string
Rank:string
Score:string
-----
...
-----
Full Name:string
Rank:string
Score:string
-----
输出样例:
Full Name:MULLER Jette
Rank:1
Score:51.60 + 52.00 + 51.75 + 46.80 + 46.80 = 248.95
-----
Full Name:ROLLINSON Amy
Rank:2
Score:46.00 + 42.90 + 50.70 + 54.00 + 46.80 = 240.40
-----
...
-----
Full Name:SANTIAGO Dominique
Rank:12
Score:42.00 + 18.20 + 35.70 + 34.50 + 32.55 = 162.95
-----
附加功能:输出详细结果
当input.txt的内容为
result women 10m platform detail
则会输出世界游泳锦标赛跳水项目女子10m跳台的所有比赛结果到output.txt,输出格式如下:
Full Name
对应选手姓名。Rank
为排名。格式如'1 | 2 | 3'
表示初赛排名为1,半决赛排名为2,决赛排名为3。部分比赛若无半决赛或初赛又或者选手未参加半决赛或决赛的则用'*'
占位表示,如'* | * | 1'
。Preliminary Score
表示初赛中该选手的成绩。格式如'score1 + score2 + score3 + ··· + score7 = totalPoint'
。若无初赛则用'*'
表示。Semifinal Score
表示半决赛中该选手的成绩。格式如'score1 + score2 + score3 + ··· + score7 = totalPoint'
。若无半决赛或者选手未参加则用'*'
表示。Final Score
表示决赛中该选手的成绩。格式如'score1 + score2 + score3 + ··· + score7 = totalPoint'
。若选手未参加则用'*'
表示。'A & B'
按照选手名(Last Name)从小到大排序,例如'JACHIM Filip & LUKASZEWICZ Robert'
输出格式:
Full Name:string
Rank:string
Preliminary Score:string
Semifinal Score:string
Final Score:string
-----
...
-----
Full Name:string
Rank:string
Preliminary Score:string
Semifinal Score:string
Final Score:string
-----
输出样例:
Full Name:FUNG Katelyn
Rank:1 | 4 | 2
Preliminary Score:60.20 + 56.00 + 57.60 + 54.00 + 70.40 = 298.20
Semifinal Score:46.20 + 30.80 + 68.80 + 61.50 + 67.20 = 274.50
Final Score:58.80 + 54.60 + 57.60 + 54.00 + 72.00 = 297.00
-----
...
-----
Full Name:SANTIAGO Dominique
Rank:14 | 11 | 11
Preliminary Score:39.20 + 21.00 + 41.85 + 31.20 + 13.05 = 146.30
Semifinal Score:42.00 + 22.50 + 17.55 + 42.90 + 39.15 = 164.10
Final Score:42.00 + 28.50 + 20.25 + 41.60 + 44.95 = 177.30
-----
补充说明:
对于input.txt,有可能会出现多行输入的样例,例如:
players
result women 1m springboard
result women 1m springboard
players
此时的输出文件output.txt中的内容为:
Full Name:HART Alexander
Gender:Male
Country:Austria
-----
Full Name:LOTFI Dariush
Gender:Male
Country:Austria
-----
...
-----
Full Name:MULLER Jette
Rank:1
Score:51.60 + 52.00 + 51.75 + 46.80 + 46.80 = 248.95
-----
Full Name:ROLLINSON Amy
Rank:2
Score:46.00 + 42.90 + 50.70 + 54.00 + 46.80 = 240.40
-----
...
-----
Full Name:MULLER Jette
Rank:1
Score:51.60 + 52.00 + 51.75 + 46.80 + 46.80 = 248.95
-----
Full Name:ROLLINSON Amy
Rank:2
Score:46.00 + 42.90 + 50.70 + 54.00 + 46.80 = 240.40
-----
...
-----
Full Name:HART Alexander
Gender:Male
Country:Austria
-----
Full Name:LOTFI Dariush
Gender:Male
Country:Austria
-----
...
-----
Full Name:MYALIN Igor
Gender:Male
Country:Uzbekistan
-----
其中,每个指令的输出紧贴上一个指令的输出,无需空行。
指令区分大小写,指令中所有的英文字母都采用小写的形式。
假如输入无法处理的指令,例如:
Error
N/A
women 1m springboard
women 3m springboard
women 10m platform
women 3m synchronised
women 10m synchronised
men 1m springboard
men 3m springboard
men 10m platform
men 3m synchronised
men 10m synchronised
N/A
。input.txt样例:
player
Players
resultwomen 1m springboard
result women 10m springboard
result sss
result detail
result women 1m springboard details
result men 10m synchronised
players
output.txt输出:
Error
-----
Error
-----
Error
-----
N/A
-----
N/A
-----
N/A
-----
N/A
-----
N/A
-----
Full Name:HART Alexander
Gender:Male
Country:Austria
-----
Full Name:LOTFI Dariush
Gender:Male
Country:Austria
-----
...
-----
Full Name:MYALIN Igor
Gender:Male
Country:Uzbekistan
-----
如果现在我们要把这个功能放到不同的环境中去(例如,命令行,Windows图形界面程序,网页程序,手机App),就会碰到困难:代码散落在各个函数中,很难剥离出来作为一个独立的模块运行以满足不同的需求。
这些代码的种类不同,混杂在一起对于后期的维护扩展很不友好,所以它们的组织结构就需要精心的整理和优化。
我们希望把基本功能里的:
这两个功能独立出来,成为一个独立的模块(class library, DLL, 或其它),这样的话,命令行和GUI的程序都能使用同一份代码。为了方便起见,我们称之为计算核心"Core模块",这个模块至少可以在几个地方使用:
把计算核心在单元测试框架中做过完备的测试后,我们就可以在算法层级保证了这个模块的正确性。
但我们知道软件并非只有计算核心,实际的软件是交付给最终用户的软件,除了计算核心外,还需要有一定的界面和必要的辅助功能。
这个Core模块和使用它的其他模块之间则要通过一定的API来交流。那么API应该怎么设计呢?
为了方便起见,我们可以从下面的最简单的接口开始(仅举例,你的代码里可能没有这个函数):
int countChar(File *file)
这个函数表示输入一个文件指针,返回这个文件的字符数。
假设我们用Core封装了这个接口,那么我们的测试程序可以是这样:
File *in = fopen("input.txt","r");
int count = 100;
Assert(countChar(in) == count);
当然,这样的测试程序并不充分,希望大家测试时不要像这样偷懒。
请根据自己以往积累的测试经验,在编码完成之后,提交产品之前,设计测试用例,并编写单元测试,对自己的项目进行测试。
首先,至少应采用白盒测试用例设计方法来设计测试用例,其他测试方法不限。其次,要设计至少10个测试用例,确保你的程序能够正确处理各种情况。最后,结合测试评估的要求,对自己的测试设计进行评价,这些测试用例能满足该程序测试的要求吗?
另一个重要的措施是要把单元测试自动化,这样每个人都能很容易地运行它,并且可以使单元测试每天都运行。每个人都可以随时在自己的机器上运行。团队一般是在每日构建中运行单元测试的,这样每个单元测试的错误就能及时被发现并得到修改。
助教在测试时,将运行自动测试程序编译源文件并运行,进行批量测试,因此请保证项目的组织目录符合要求。
对于使用Java语言的项目有以下要求:
DWASearch.java
文件,且DWASearch.java中包含 public static void main(String[] args)
方法xxxxxxxxx (文件夹名字为学号)
|- src
|- DWASearch.java(主程序,可以从命令行接收参数;确保文件名一致、区分大小写)
|- Lib.java(包含其它自定义函数,可以有多个,对名字不做要求)
|- data(文件夹,存放程序的数据)
|- DWASearch.jar
|- README.md
描述你的项目,包括如何运行、功能简介、作业链接、博客链接等
|- codestyle.md
描述你之前定的代码风格
对于使用C++ 语言的项目有以下要求:
DWASearch.cpp
文件,且DWASearch.cpp的main函数可以接收命令行参数(如int main(int argv, char** argc)
)xxxxxxxxx (文件夹名字为学号)
|- src
|- DWASearch.cpp(主程序,可以从命令行接收参数;确保文件名一致、区分大小写)
|- Lib.cpp(包含其它自定义函数,可以有多个,对名字不做要求)
|- Lib.h(包含其它自定义函数,可以有多个,对名字不做要求)
|- data(文件夹,存放程序的数据)
|- DWASearch.exe
|- README.md
描述你的项目,包括如何运行、功能简介、作业链接、博客链接等
|- codestyle.md
描述你之前定的代码风格
本次自动测试会加入各种各样出错情况的测试,要求开发者程序不能崩溃,并且能够尽可能精确报错。你可以有“容错性”的出错设计,但必须输出必要的提示或说明。
若有对题目不理解的地方,可在QQ群中直接提问。
PSP是卡耐基梅隆大学(CMU)的专家们针对软件工程师所提出的一套模型:Personal Software Process (PSP, 个人开发流程,或称个体软件过程)。
PSP | Personal Software Process Stages | 预估耗时(分钟) | 实际耗时(分钟) |
---|---|---|---|
Planning | 计划 | ||
• Estimate | • 估计这个任务需要多少时间 | ||
Development | 开发 | ||
• Analysis | • 需求分析 (包括学习新技术) | ||
• Design Spec | • 生成设计文档 | ||
• Design Review | • 设计复审 | ||
• Coding Standard | • 代码规范 (为目前的开发制定合适的规范) | ||
• Design | • 具体设计 | ||
• Coding | • 具体编码 | ||
• Code Review | • 代码复审 | ||
• Test | • 测试(自我测试,修改代码,提交修改) | ||
Reporting | 报告 | ||
• Test Repor | • 测试报告 | ||
• Size Measurement | • 计算工作量 | ||
• Postmortem & Process Improvement Plan | • 事后总结, 并提出过程改进计划 | ||
合计 |
一个功能完备的程序不是一蹴而就的。通过将每日赛程的统计需求划分为4个部分,可将一个大任务划分为可操作的小任务,同时最好按照任务难度或紧急程度指定各个任务的完成次序。因此,在动手开发之前,要先估计将在程序各模块开发所需耗费的时间,以及完成整个项目所需的时间,将这个[估计值]记录下来,写成PSP 的形式。
PSP的目的是:记录工程师如何实现需求的效率,和我们使用项目管理工具(例如微软的Project Professional,或者禅道等)进行项目进度规划类似。
有关PSP的更多内容,请自行阅读邹欣老师的博客:工程师的能力评估和发展
请阅读邹欣老师的博客:源代码管理,了解源代码管理的10个实践问题。
本次作业要求使用GitCode进行源代码管理,代码有进展即签入GitCode。签入记录不合理的项目会被助教抽查询问项目细节。
对代码签入的具体要求如下:根据需求划分功能后,每做完一个功能,编译成功后,应至少commit一次。具体的功能划分,请自行定义,并在撰写博客时体现出来,遵循自己对需求的功能划分来提交代码即可。
如果对Gitcode的内容不熟悉,可以点击《git入门》进行学习
请根据自己以往积累的测试经验,在编码完成之后,提交产品之前,设计测试用例,并编写单元测试,对自己的项目进行测试。以下是对测试的几个具体要求:
首先,至少应采用白盒测试用例设计方法来设计测试用例,其他测试方法不限;
其次,要设计至少10个测试用例,确保你的程序能够正确处理各种情况;
最后,结合测试评估的要求,对自己的测试设计进行评价,这些测试用例能满足该程序测试的要求吗?
另一个重要的措施是要让单元测试自动化,这样每个人都能很容易地运行它,随时在自己的机器上运行,并且可以使单元测试每天都运行。团队一般是在每日构建中运行单元测试的,这样每个单元测试的错误就能及时被发现并得到修改。
有关单元测试的更多内容,推荐阅读邹欣老师的博客:单元测试和回归测试
这个作业属于哪个课程 | <班级的链接> |
---|---|
这个作业要求在哪里 | <作业要求的链接> |
这个作业的目标 | <写上具体方面> |
其他参考文献 | ... |
|这个作业属于哪个课程|<班级的链接>|
|-- |-- |
|这个作业要求在哪里|<作业要求的链接>|
|这个作业的目标|<写上具体方面>|
|其他参考文献|... |
[toc]
作业基本信息...
## Gitcode项目地址
## PSP表格
## 解题思路描述
### 问题1
### 问题2
...
## 接口设计和实现过程
...
## 关键代码展示
...
## 性能改进
...
## 单元测试
...
## 异常处理
...
## 心得体会
...
作业基本信息...
## 目录:
1. [Gitcode项目地址](#1)
2. [PSP表格](#2)
3. [解题思路描述](#3)
4. [接口设计和实现过程](#4)
5. [关键代码展示](#)
6. [性能改进](#)
7. [单元测试](#)
8. [心得体会](#)
## <span id="1">1. Gitcode项目地址</span>
### 问题1
### 问题2
### ...
## <span id="2">2. PSP表格</span>
...
## <span id="3">3. 解题思路描述</span>
...
## <span id="4">4. 接口设计和实现过程</span>
...
## <span id="5">5. 关键代码展示</span>
...
## <span id="6">6. 性能改进</span>
...
## <span id="7">7. 单元测试</span>
...
## <span id="8">8. 异常处理</span>
...
## <span id="9">9. 心得体会</span>
...