软工实践寒假作业(2/2)
软工实践寒假作业(2/2)
这个作业属于哪个课程 | 2021春软件工程实践S班(福州大学) |
---|---|
这个作业要求在哪里 | 软工实践寒假作业(2/2)要求 |
这个作业的目标 | 再次学习《构建之法》,熟悉软件开发整体流程,提升自身项目能力 |
作业正文 | 221801338_冯浩_软工实践寒假作业(2/2) |
GitHub地址 | 我的GitHub-C |
其他参考文献 | 《构建之法》、CSDN相关博客 |
目录:
part1:阅读《构建之法》并提问
问题一:P106
材料截图:
问题内容:
在书中讲述了团队中的分工和流程,当我在看到书中提到的“要完成一个复杂的软件项目,团队的成员要在不同阶段做不同的事情”这句话事,我想到在团队开发流程中,由于每个人的性格、习惯各不相同,有人有事立马就做,有人却每次到ddl了才开始做,导致出现两极分化,这样在开发过程中就可能产生工作冲突、工作进展缓慢等问题。
本人案例:在去年疫情期间,我和小伙伴组队参加了国际用户体验大赛,由于团队积极性没有被调动起来,大家完成任务的时间各有不同,加上大家经验不足,最后导致项目烂尾,没能完成比赛。也有可能是大家都是在家线上操作,没有参赛氛围导致的。
那请问遇到这种情况如何协调和解决这件事情,保证团队的高度团结和团队开发的效率?
问题二:
问题内容:
问题还是源于上面,在公司中团队分工可能回很明确,每个人各司其职,但是我们在做比赛项目中,可能由于时间、能力有限,无法按照流程进行开发,在任务分配时能否采取主次任务分工?或者在开发人员及技术有限的情况下,应该如何分配任务?
例如我今年参加了服务外包创新创业大赛,小组共五人,配置为:产品、UI、前端、后端、市场各一位。但是开发时间有限,前后端开发人员压力巨大。我们使用的方式是:产品主要负责产品然后兼任ui(给ui打杂),ui主要负责ui设计然后兼任前端(给前端打杂)...。
请问就这种方式是否合理?
问题三:P123
材料截图:
问题内容:
书中截图部分有提到:团队很弱会适得其反,团队很强又不需要。这部分看起来好像有点矛盾,既然如此迅敏这一思想有何意义呢?
或者说迅敏这一思想是适用于大部分中等水平的团队?如果是,请问为什么?
问题四:P165
材料截图:
问题内容:
这个问题是看到”竞争性“和”创新“,两个词想到的,在做需求分析时,如果遇到竞争团队也在做相关的需求分析,那么我们应该如何保证我们能够完成需求并保证我们找到的需求不被盗取?(需求被盗取可能会在问卷调查或者用户调研的过程中被盗取)
本人案例:我之前有一个自己想到的点子,想将它实现成产品,但是在需求分析、市场调查的过程中,生怕别人看到,将这个点子偷走(毕竟目前大学生“白嫖”现象比较严重)。导致我不想在宿舍、实验室完成,最后我只好在自己空闲时间去图书馆将其完成。这种“偷偷摸摸”做需求的感觉让我这个北方人感觉很不爽。但是想法被嫖也会让我很不爽。(在此向老师道歉,本次作业的参考书籍使用了扫描版,本人只想到了学习知识、完成任务,却忽略的对正版的支持。十分抱歉!)
问题五:181
材料截图:
问题内容:
这个问题是我看到时间花费结合需求分析想到的,在我们做项目的过程中,需求做完后需要开发一段时间,但在开发的这段时间内,原有的需求发生了改变或者需求优先级发生了变动,此时应该怎么办?是应该停止开发重新定位需求还是应该继续开发下去?
这个问题虽然在我这还没有发生,但是不怕一万就怕万一。对于这种情况我感觉停止开发可能会让项目时间边长,但重新做完需求的项目可能会让它更完美。但是继续开发下去貌似也是可取的,一个产品总有版本迭代。这两点让我感觉有些矛盾。
不知道老师有何见解?
附加题
有趣的冷知识和故事
这个故事是我之前无意间看到的,看到这次作业,脑袋第一闪就想到了这个。
当我第一次看到这个的时候,我竟觉得不可思议。
这个故事是:世界上第一个程序员
其实这个故事在第一次作业的时候我就想到了,那时候好像是看到有位女同学的博客,我印象里那篇博客好像是有写她作为一个女生学软件工程这个专业不自信(大致应该是这样),然后下面有助教老师鼓励的评论。希望以后助教老师遇到类似问题,这个案例可以用得上~同时,作为男生的我更应该以此励志好好努力!
part2:WordCount编程
Github项目地址
PSP表格
PSP2.1 | Personal Software Process Stages | 预估耗时(分钟) | 实际耗时(分钟) |
---|---|---|---|
Planning | 计划 | ||
• Estimate | • 估计这个任务需要多少时间 | 360 | 320 |
Development | 开发 | ||
• Analysis | • 需求分析 (包括学习新技术) | 120 | 120 |
• Design Spec | • 生成设计文档 | 30 | 30 |
• Design Review | • 设计复审 | 30 | 45 |
• Coding Standard | • 代码规范 (为目前的开发制定合适的规范) | 30 | 20 |
• Design | • 具体设计 | 120 | 135 |
• Coding | • 具体编码 | 800 | 900 |
• Code Review | • 代码复审 | 60 | 50 |
• Test | • 测试(自我测试,修改代码,提交修改) | 180 | 240 |
Reporting | 报告 | ||
• Test Repor | • 测试报告 | 30 | 20 |
• Size Measurement | • 计算工作量 | 30 | 30 |
• Postmortem & Process Improvement Plan | • 事后总结, 并提出过程改进计划 | 60 | 90 |
合计 | 1850 | 2000 |
解题思路描述
题目需求分析
实现基本需求
假设有一个软件每隔一小段时间会记录一次用户的搜索记录,记录为英文。输入文件和输出文件以命令行参数传入。例如我们在命令行窗口(cmd)中输入:
//C语言类
WordCount.exe input.txt output.txt
//Java语言
java WordCount input.txt output.txt
则会统计input.txt中的以下几个指标
1.统计文件的字符数(对应输出第一行):
- 只需要统计Ascii码,汉字不需考虑
- 空格,水平制表符,换行符,均算字符
2.统计文件的单词总数(对应输出第二行),单词:至少以4个英文字母开头,跟上字母数字符号,单词以分隔符分割,不区分大小写。
- 英文字母: A-Z,a-z
- 字母数字符号:A-Z, a-z,0-9
- 分割符:空格,非字母数字符号
- 例:file123是一个单词, 123file不是一个单词。file,File和FILE是同一个单词
3.统计文件的有效行数(对应输出第三行):任何包含非空白字符的行,都需要统计。
4.统计文件中各单词的出现次数(对应输出接下来10行),最终只输出频率最高的10个。
- 频率相同的单词,优先输出字典序靠前的单词。
例如,windows95,windows98和windows2000同时出现时,则先输出windows2000
- 输出的单词统一为小写格式
然后将统计结果输出到output.txt,输出的格式如下;其中word1
和word2
对应具体的单词,number
为统计出的个数;换行使用'\n',编码统一使用UTF-8。
characters: number
words: number
lines: number
word1: number
word2: number
...
解题思路
- 首先,我拿到题目的时候看到能用C++来编写,我就没做思考直接上手编写了(就像之前写OJ一样)。
- 后面我发现不对劲,好像我写的不太符合老师要求。就重新开始思考、编写。
- 之后,我先定义了一个文件类,设置公有参数:content存放文本文件数据,私有参数:characters记录字符数,lines记录行数,words记录单词数,定义计算字符数、单词数、行数的函数。
- 然后从计算行数开始做,接着是字符数,最后是分割单词,把从文件读入的字符串存入testfile类的公有参数content里,大写转小写,并对content进行单词分割操作。
- 分割单词后将单词逐个存入map关联式容器,并在map容器进行排序。
代码规范制定链接
设计与实现过程
类定义:
class testfile
{
public:
testfile countcha(char*, testfile);//计算字符数
testfile countword(char*, testfile);//计算单词数
testfile countline(char*, testfile);//计算行数
int getcharacters();
int getlines();
int getwords();
char* content;//存放文本文件数据
void init();
private:
int characters;
int words;
int lines;
};
首先定义一个文件类,设置公有参数:content存放文本文件数据,私有参数:characters记录字符数,lines记录行数,words记录单词数,定义计算字符数、单词数、行数的函数。
类函数
计算字符数
char c;
myfile >> noskipws;//强制读入空格和换行符
while (!myfile.eof())
{
myfile >> c;
if (myfile.eof())
break;//防止最后一个字符输出两次
i++;
}
f1.characters = i;
myfile.close();
调用c++语言中的文本文件输入功能,以按字符输入统计字符数。按项目要求必须强制读入空格和换行符。并进行文本文件打开与否的差错判断。
计算行数
while (getline(myfile, temp))
{
if (temp.empty())
continue;
i++;
}
f1.lines = i;
myfile.close();
调用c++语言中的文本文件输入功能,以按按行输入统计行数。
计算单词数
myfile >> noskipws;
while (!myfile.eof())
{
myfile >> c;
if (myfile.eof())
break;//防止最后一个字符输出两次
if (c >= 65 && c <= 90)
c += 32;//大写字母转小写
f1.content[n++] = c;//把文本文件内的数据存入类的content字符数组中
}
myfile.close();
char temp[4];
int i = 0, j = 0, flag = 0, words = 0, m = 0, k = 0;
for (i = 0; i < n; i++)
{
if (!((f1.content[i] >= 48 && f1.content[i] <= 57) || (f1.content[i] >= 97
&& f1.content[i] <= 122)))//跳过非字母和非数字字符
continue;
else
{
for (j = 0; j < 4 && i < n; j++)
{
if (!((f1.content[i] >= 48 && f1.content[i] <= 57) || (f1.content[i] >= 97 && f1.content[i] <= 122)))
break;
temp[j] = f1.content[i++];//temp中存入四个非空格字符
}
if (j == 4)
{
for (m = 0; m < 4; m++)
{
if (temp[m] < 97 || temp[m]>122)
{
flag = 1;
break;//判断这四个字符是否都是字母
}
}
if (flag == 0)//四个字符都是字母的情况,判断为一个单词
{
char* w = new char[100];//存放单词
for (m = 0; m < 4; m++)
{
w[k++] = temp[m];//temp中字符存入w
}
while (((f1.content[i] >= 48 && f1.content[i] <= 57)
|| (f1.content[i] >= 97 && f1.content[i] <= 122)) && i < n)//继续存入单词剩余字符
{
w[k++] = f1.content[i++];
}
w[k] = '\0';
loadword(w);//可以在此处插入一个外部函数返回一个单词存入map红黑树
delete[]w;
words++;
k = 0;
}
else
{
flag = 0;
j = 0;
}
}
}
}
f1.words = words;
统计单词数并逐个把单词存入map关联式容器。map内部自建一颗二叉树具有自动排序的功能,按照字典序排好。并返回单词出现的频次。单词分割把从文件读入的字符串存入testfile类的公有参数content中,并将大写转小写,对content进行单词分割操作,以非字母数字的符号为分隔符。
主函数调用
f1 = f1.countcha(argv[1], f1);
f1 = f1.countline(argv[1], f1);
f1 = f1.countword(argv[1], f1);
sWord* ww = new sWord[f1.getwords()];//给结构体分配一个大小为单词数目的动态空间
sWord* temp = new sWord[f1.getwords()];
map<string, int>::iterator it;
it = mapword1.begin();
for (it; it != mapword1.end(); it++)
{
ww[num].w = it->first;
ww[num].count = it->second;
num++;
}
sort(ww, temp, 0, num - 1);//把已经按字典序排号按出现频率进行从大到小的归并排序
//输出
ofstream fout;
fout.open(f);
输出
cout << "characters: " << f1.getcharacters() << endl;
fout << "characters: " << f1.getcharacters() << endl;
cout << "words: " << f1.getwords() << endl;
fout << "words: " << f1.getwords() << endl;
cout << "lines: " << f1.getlines() << endl;
fout << "lines: " << f1.getlines() << endl;
if (num < 10)
{
for (i = 0; i < num; i++)
{
cout << "<" << ww[i].w << ">" << ": " << ww[i].count << endl;
fout << "<" << ww[i].w << ">" << ": " << ww[i].count << endl;
}
}
else
{
for (i = 0; i < 10; i++)
{
cout << "<" << ww[i].w << ">" << ": " << ww[i].count << endl;
fout << "<" << ww[i].w << ">" << ": " << ww[i].count << endl;
}
}
delete[]temp;
delete[]ww;
free(f1.content);//动态空间释放
clock_t ends = clock();
cout << "运行时间 : " << (double)(ends - start) / CLOCKS_PER_SEC << "秒" << endl;
这边为了便于进行测试,我添加了一个运行时间输出。
性能改进
- 之前第一次编写的时候,我把所有类、函数都放在了一个文件,导致之后查找、修改特别困难。之后用了Lib.h头文件。
- 在最先的测试时,我忽略了单词的大小写,后来经过修改,将所有单词转换为小写。
单元测试
在测试时,我分别使用了
10行10个不同长度同字母单词:
100行100个不同长度同字母单词:
500行500个不同长度同字母单词:
1000行1000个不同长度同字母单词:
2000行2000个不同长度同字母单词:
5000行5000个不同长度同字母单词:
10000行10000个不同长度同字母单词:
20000行20000个不同长度同字母单词:
1000行1000个不同长度不同字母单词:
20000行20000个不同长度不同字母单词:
大小写及汉字:
异常处理说明
- 文件异常(input.txt)
if (!argv[1])
{
cout << "未输入文件名或文件不存在" << endl;
return 0;
}
- 文件异常(output.txt)
string f = argv[2];
ofstream fout;
fout.open(f);
if (!fout)
cout << "文件打开失败" << endl;
心路历程与收获
历程
- 1.在刚看到这次作业的时候,说实话,感觉特别繁琐,甚至看得心烦。再加上作业刚发布的时候,我正在练习考科目三。但是当我考试过了之后,静下心来再看题目时,将题目内容一条条梳理之后,发现其实还好,必我们当时程序设计实践的作业要简单很多。
- 2.可以说这次的作业又简单又难。编写程序不是很难,但是难在细节。虽然是个小程序,但是花费了不少的时间。特别是在改bug过程中,改bug的时间比编程的时间还要长。
- 3.有件事不得不说!网络!由于我在新疆,然后我这边的网络进不去GitHub(可能是疆内ip被封了),周没办法我使用了福大VPN,但是福大VPN并不给你,登上去几分钟就会掉。遇到这种情况第一反应应该是“FQ”,但是新疆管这一块可能比较严,去年我在家上网课的时候翻过一次,被查出来了教育了一番。之后我就不敢在家FQ了。。。。。最后无奈的我只好用我之前做项目的服务器,通过远程服务器来访问GitHub(那服务器部署了一个教学网站,导致用起来超卡)。所有我在这段时间git学期方面并不是很好,打算回学校后在系统性的学习、操作一遍。
- 4.此处再次对编写《构建之法》的老师道歉,由于在网上买的书本新疆不发货,我就使用了书本的印刷pdf版,而不是查看作者博客,接下来的学习过程中我会保证使用正版书籍,尊重原创。
收获
- 1.这是第一次接触软件工程项目,之前其实有接触过git但是重来没有上传过项目,通过这次作业基本了解了git。
- 2.这段时间做作业让我逐渐的适应了学习生活,经过一个假期的休息自己干事情变得越发怠慢,做项目和学习读很随性,没有人催。但是有了作业加上助教们在群里与我们不断交流,使我慢慢的开始运作了起来,也慢慢的适应了学习的节奏。
- 3.这次作业让我熟悉了C++编程,我已经有两个学期没有使用过C++了,这次作业本来想用Java来做的,但是想着Java是上上学期学的,C++学的太久远了,想再重新拾起。同时这次的作业也让我对算法也温习了一遍。
- 4.这次作业也让我自己看到了自己在编程及分析上的不足,而且这次作业的学习我自我感觉不是很好,所以等返校后还需要认真的学习一遍,特别是Git。
学习资料
C++教程
C++ main函数命令行参数使用
const char * 、char const *、 char * const 三者的区别
C++中map的用法
VS2017中对C++的单元测试
廖雪峰Git教程