软工实践寒假作业(2/2)
这个作业属于哪个课程 | 软件工程2021W班 |
---|---|
这个作业要求在哪里 | 作业要求 |
这个作业的目标 | 作业目标 |
作业正文 | ...... |
其他参考文献 | ... |
part1:阅读构建之法并提问
问题1
我看了这段文字(市面上有这么多不完美的产品,软件团队为什么还要把这些不完美的软件发布出来呢?为什么不能等到它们完美之后再发布?**软件工程的一个重要任务,就是要决定一个软件在什么时候能“足够好”,可以发布。)有这个问题(如何决定一个软件足够好)我的困惑是(除了确保bug尽可能少之外,还应进行哪些操作)
问题2
我看了这段文字(既然代码复审能发现这么多问题,有这么好的效果,如果我们每时每刻都在代码复审的状态,那不是很好么?事实上,极限编程(Extreme Programming)正是这一思想的体现——为什么不把一些卓有成效的开发方法用到极致(Extreme),让我们无时无刻地使用它们? ——p84页 极限编程对工程师提出了更高的要求。这种要求不关乎技术水平,也不关乎学历水平或工作经验。这种要求是对一个人的心智、道德修养的更高要求。结队编程中,编码不再是私人的工作,而是一种公开的“表演”。程序员的代码、工作方式、技术水平都变得公开和透明,这也许是一些人不喜欢这一方式的原因。 ——P87)有这个问题(极限编程和结对编程是什么,它们有怎样的联系)通过查询资料可知(极限编程是一种轻量级的、灵巧的、简单的软件工程方法。与传统的开发过程不同,极限编程的核心活动体现在需求→测试→编码→设计过程中。因此适用于规模小、进度紧、需求变化大、质量要求严的项目。它希望以最高的效率和质量来解决用户目前的问题,以最大的灵活性和最小的代价来满足用户未来的需求。结对编程,也就是两个人写一个程序,其中,一个人叫Driver,另一个人叫Observer,Driver在编程代码,而Observer在旁边实时查看Driver的代码,并帮助Driver编程。并且,Driver和Observer在一起时可以相互讨论,有效地避免了闭门造车,并可以减少后期的code review时间,以及代码的学习成本。)仍存在的困惑是(它们二者之间有什么联系)
问题3
我看了这段文字(用户体验设计的一个重要目的就是要降低用户的认知阻力(Cog-nitive Friction),即用户对于软件界面的认知(想象某事应该怎么做,想象某操作应该产生什么结果)和实际结果的差异。我们来看一个具体的例子,如果用户(一个生活在中国二线城市,有高中文化水平,有基本计算机基础的成年人)要在一个文稿中写居中的一句话,在下表所列的各种工具中,用户是怎么才能做到的。 倘若认知阻力大,学习曲线就会比较陡;但是经过学习和练习,如果用户适应了新的认知模式,工作效率便会有较大的提高。)我的问题是(如果大多数用户都对某种功能不了解,也不经常用到,是否需要继续用户体验设计)我认为(针对这类功能应该配备简要的使用流程图,进行推广)
问题4
我看了这段文字(单元测试必须由最熟悉代码的人(程序的作者)来写。)提出的问题是(如果程序的作者没有意识到某些问题,是否需要其他人的协助)仍存在的疑惑是(几个人一起完成单元测试,共同商讨会不会更好)
问题5
我看了这段文字(软件团队的人员也会流动,新的成员要尽快读懂已有的程序,了解程序的设计,这叫做程序理解。)我的提问是(如果程序较为复杂,通过何种方式能最大效率的进行程序理解)我认为(不断在写程序的同时,扩展视野,对于加快读懂程序很有帮助)。仍存在的疑惑是(如果只是刚开始涉足某个领域的话,通过什么方法能高效率的进行程序理解)
附加题(大家知道了软件和软件工程的起源,请问软件工程发展的过程中有什么你觉得有趣的冷知识和故事?)
软件工程专业正式开始的标志:1968年和1969年,北约(NATO)科学委员会(NATO Science Committee)赞助了两场关于软件工程的会议(Garmisch,Germany - see conference report),这给了该领域最初的推动力。许多人认为这些会议标志着软件工程专业的正式开始。
part2:WordCount编程
github项目地址
PSP表格
PSP2.1 | Personal Software Process Stages | 预估耗时(分钟) | 实际耗时(分钟) |
---|---|---|---|
Planning | 计划 | ||
Estimate | 估计这个任务需要多少时间 | 2500 | 2900 |
Development | 开发 | ||
Analysis | 需求分析 (包括学习新技术) | 60 | 80 |
Design Spec | 生成设计文档 | 60 | 90 |
Design Review | 设计复审 | 60 | 80 |
Coding Standard | 代码规范 (为目前的开发制定合适的规范) | 60 | 45 |
Design | 具体设计 | 120 | 180 |
Coding | 具体编码 | 1200 | 1500 |
Code Review | 代码复审 | 120 | 240 |
Test | 测试(自我测试,修改代码,提交修改) | 360 | 480 |
Reporting | 报告 | ||
Test Report | 测试报告 | 0 | 0 |
Size Measurement | 计算工作量 | 20 | 20 |
Postmortem & Process Improvement Plan | 事后总结, 并提出过程改进计划 | 80 | 90 |
合计 | 2140 | 2805 |
解题思路描述
将功能划分为统计字符数,统计行数,统计有效单词,统计词频。
对有效单词的判断使用到正则表达式,如果满足正则表达式则让单词数加1.
对词频的统计用到pair(对组).对vector中的第一个数据到最后一个数据排列。因为vector中的数据类型是pair,根据自定义的比较函数,当pair的second(词语出现次数)相等时,first(单词)小的在前面(若有并列,则按递增字典序输出)。
代码规范制定链接
设计与实现过程
charNum统计文件中的字符数
lineNum统计行数
wordNum统计有效单词数
wordFre统计词频
WordCount主函数
具体实现
charNum
int charNum(char * filename)//计算字符数,包括(空格,制表符,换行等)
{
int count = 0;
char c;
ifstream file;
file.open(filename);
if (!file.is_open())
{
cout << "文件打开失败";
}
while ((c = file.get()) != EOF)
{
count++;
}
file.close();
return count;
}
lineNum
int lineNum(char *filename)//计算有效行数
{
ifstream file;
file.open(filename);
if (!file.is_open())
{
cout << "文件打开失败";
}
int count = 0;
string s;
while (getline(file, s))
{
if (s != "\0")
{
count++;
}
}
file.close();
return count;
}
wordNum
int wordNum(char * filename)//计算符合条件的单词总数
{
ifstream file;
file.open(filename);
if (!file.is_open())
{
cout << "文件打开失败";
}
int count = 0;
string s;
regex r("\\b[a-zA-Z]{4}[a-zA-Z0-9]*", regex::icase);
while (file >> s)
{
smatch m;
while (regex_search(s, m, r)) //搜索符合正则表达式的单词
{
count++;
s = m.suffix().str();
}
}
file.close();
return count;
}
wordFre
map<string, int> Map;
void wordFre(char *filename)//频率最高的十个单词
{
ifstream file;
file.open(filename);
if (!file.is_open())
{
cout << "文件打开失败";
}
string s;
regex r("\\b[a-zA-Z]{4}[a-zA-Z0-9]*", regex::icase);
while (file >> s)
{
for (int i = 0; i < s.size(); i++)
{
if (s[i] <= 'Z'&&s[i] >= 'A')//不区分大小写,将所有大写字母变成小写
{
s[i] = s[i] + 32;
}
}
smatch m;
while (regex_search(s, m, r))
{
Map[m[0]]++;
s = m.suffix().str();
}
}
file.close();
}
WordCount
int main(int argc,char** argv)
{
int count = 10;
ofstream fileOutput;
char filename[105]= "input.txt";
fileOutput.open("output.txt", ios::app);
fileOutput << "characters: " << charNum(filename) << endl;
fileOutput << "lines: " << lineNum(filename) << endl;
fileOutput << "words: " << wordNum(filename) << endl;
wordFre(filename);
vector<pair<string, int> > vec;
extern map<string, int> Map;
for (auto u : Map)
{
vec.push_back(u);
}
sort(vec.begin(), vec.end(), cmp);
for (auto u : vec)
{
if (count)//输出频率最高的10个单词
{
fileOutput << "<" << u.first << ">" << ":" << " " << u.second << endl;
count--;
}
else break;
}
return 0;
}
性能改进
原来在有效单词判断时采用一个字符一个字符判断,后来改成用正则表达式判断符合要求的单词。
单元测试
测试了字符,行数,空白文件等输出是否正确。
异常处理说明
文件打开失败
if (!file.is_open())
{
cout << "文件打开失败";
}
心路历程与收获
本次实践虽然代码量不大,但是需要注意的细节有很多,稍不注意就会有许多麻烦产生。这更加让我感受到了编写一个程序,一定要专注。
一种功能的实现可以有多种方法,通过本次实践让我学会了一种方法如果存在问题,始终不能解决,要及时寻找其他方法,可能会更轻松。
学会了github的使用,让写好的代码能够有序的保存。
通过单元测试,可以判断自己的代码的准确性,对任何一个程序都十分重要。