软工实践寒假作业2/2
基本描述
这个作业属于哪个课程 | 2021春软件工程实践|W班 (福州大学) |
---|---|
这个作业的要求在哪里 |
寒假作业2/2 |
这个作业的目标 | 阅读《构建之法》,对其有所理解,能有自己的思考;学习GitHub的使用;完成WordCount项目要求 |
其他参考文献 | CSDN、博客园 |
任务一:阅读《构建之法》并提出问题
问题1.BUG的出现是针对程序员而言还是针对用户而言?
原文:“什么是好的软件?一些同学认为,所谓好软件,就是软件没有缺陷(Bug),所谓软件工程,就是把软件中的Bug都消灭掉的过程。”
众所周知,软件从开发到正式提交给用户使用,乃至后续很长时间,都难以跳出bug修复这一问题,但是什么样的bug才能真正算是bug呢?从第一章引用汽车为例可以看出,不同用户的需求不一样,或许有人认为***很烂,但是有人认为满足了他们的需求,那么这一问题应该怎么样算?既然已经发布了该软件,是否意味着开发者认为这个软件已经能够满足对应的需求,如此的话为什么有对应需求的用户还会遇上千奇百怪的bug?
问题2.团队在经历了萌芽、磨合、规范三个阶段后,才“终于”可以创造一些有意义的东西?
讲义的第五章——团队合作的阶段中提到“经历了萌芽、磨合、规范阶段,现在团队终于可以创造一些有意义的东西——这就是创造阶段(Performing)。当然并不是所有的团队都能达到这一阶段。”
前文在说到萌芽、磨合、规范三个阶段时,就有提到过每个人的职能、品性,而要看透团队成员,难道不就是在不断地创造有意义的东西吗?只不过创造的价值于每个人不一样。对于参与者而非决策者而言,只是过程就已十分有意义,个人认为不能因为结局失败而认为这个团队所产生的都是没有意义的,即便是对于决策者而言,也是在下次创建团队时的一份参考建议。
问题3.开发者需要怎么样“从用户的角度考虑问题”?
第十二章中提到设计是没有标准答案的。这一点个人很赞同,那么开发者到底应该从哪些角度实现需求呢?一个词就是:用户体验。虽然想到这个东西很简单,但是要怎么样才能真正的做到从“用户体验”着手设计呢?
问题4.非新技术研发人员是否要时刻关注最新的产品?
讲义中的——创新的时机,提到“做前沿研究的人, 可以早于其他人很多年提出新想法, 但是这些想法一般都是在“Innovator” 那个圈子里有影响, 这些想法要等若干年才能由成功的企业家看准时机推向大众市场。”、“很多大家正在使用的“新颖“产品, 往往是经历了迷茫期之后的二代产品, 那些在泡沫最大的时候匆忙出现的第一代的产品大多数都没有等到这一天。”
因此我很好奇,如果我并非在对技术或是次时代产品进行研发攻坚,我是否需要时刻关注最新的相关技术?因为提到的新产品,往往都要等待市场的期望炒热后才能做到走向人们的视野。如果在做着自己本职工作的同时,过多关注此时用不上、未来也不好说的新内容,是否会顾此失彼?
问题5.团队合作的绩效到底应该怎么样算才合理?
文中有提到过让团队分配,讲义中亦有从实际着手,从学生的小组以及某互联网公司的二维评价体系来衡量绩效。但这两种不是有所冲突吗?前者主观上来讲利用了人的“脸皮”以及人情世故,后者也掺杂着评判者的主观情感。讲义中也提到:猪、鸡、鹦鹉三种人对自身的定位都不一定清楚明白,又怎么样衡量绩效?
附加题
1969年,互联网相关技术尚未得到发展,Charles Kline在加州大学洛杉矶分校向斯坦福研究所发出了"LOG IN"的指令,但由于那时候技术力落后,在发出了"LO"以后,计算机就罢工了,因此互联网发出的首条信息内容只有"LO".但这宣告这互联网时代不再是遥不可及。而后不久,4台计算机的互联标志着阿帕网的正式使用,人类正式进入网络时代。相关知识
任务二:根据题意设计程序
项目地址
PSP表格
PSP2.1 | Personal Software Process Stages | 预估耗时(分钟) | 实际耗时(分钟) |
---|---|---|---|
Planning | 计划 | 15 | 20 |
• Estimate | • 估计这个任务需要多少时间 | 15 | 20 |
Development | 开发 | 780 | 810 |
• Analysis | • 需求分析 (包括学习新技术) | 180 | 210 |
• Design Spec | • 生成设计文档 | 30 | 25 |
• Design Review | • 设计复审 | 15 | 10 |
• Coding Standard | • 代码规范 (为目前的开发制定合适的规范) | 30 | 25 |
• Design | • 具体设计 | 60 | 60 |
• Coding | • 具体编码 | 360 | 340 |
• Code Review | • 代码复审 | 25 | 20 |
• Test | • 测试(自我测试,修改代码,提交修改) | 80 | 120 |
Reporting | 报告 | 90 | 100 |
• Test Repor | • 测试报告 | 30 | 40 |
• Size Measurement | • 计算工作量 | 30 | 30 |
• Postmortem & Process Improvement Plan | • 事后总结, 并提出过程改进计划 | 30 | 30 |
合计 | 885 | 930 | |
解决思路描述
拿到题目后首先想到的是可以把需求分为几个小部分
例如文件的读写、统计字符数、单词数等数个小问题
然后从执行顺序出发:读写→字符数→单词数→行数→排序→读写
从而着手开始编码以及查找资料
代码规范
计算模块接口的设计与实现过程
- Lib用于放各类函数,例如读字符串并储存、统计各项数据的方法
- LibTest则用于测试Lib的方法是否正确
—Lib中使用了五个函数来完成需求,其中:
- getCharacters()用于获取文件中的字符串并保存,通过StringBuilder.append(str)将读取的字符串拼接。
- getCharactersNum()用于获取字符串的有效字符数,遍历ASCII在0-127范围内的字符使num++即可。
- getWordsNum()用于获取有效单词数,利用split("\s+")以空格为分隔符进行拆分并存temp[],在利用正则表达式检查是否符合规范,符合规范的单词全部转化为小写并且存入wordsMap。
- sortMap()通过lambda表达式以及compareTo(),将存入的单词以键值(出现次数)进行排序,相同键值即采用字典序进行排序。
- getLinesNum()重新读取一遍文件,采用readLine()进行逐行读取,并使用正则表达式判断是否空行,使统计数num++。(最初想通过在—2—部分一并完成,思路是当读取到ASCII为9(制表符)、10(\n)时,判断上一次读取的ASCII是否为10,从而剔除无效空白行,但是因为有多种空白符,亦不方便测试,就想着尝试使用正则表达式进行匹配,后来经查阅与比较,发现正则表达式虽然方便且不容易错,但是效率并不如通过readLine来得高,因此使用重读文件的方法)
//部分函数关键代码
//—3—
String[] temp=str.split("\\s+");
String regexs="^[a-zA-Z]{4,}.*";
temp[i].matches(regexs)
if (wordsMap.containsKey(insertKey)){
int j=wordsMap.get(insertKey);
wordsMap.put(insertKey,j+1);
}else {
wordsMap.put(insertKey,1);
}
//—4—
Collections.sort(wordList, (o1, o2) -> {
if (o1.getValue().equals(o2.getValue())){
return o1.getKey().compareTo(o2.getKey());
}else {
return o2.getValue()-o1.getValue();
}
});
计算模块接口部分的性能改进
通过CSDN、博客园的资料,发现正则表达式是简单但不够高效,因此在获取有效行的时候没有使用方便的正则表达式
如图可看出即使将正则表达式从读行中移除,其在程序中仍占用了极大一部分的时间(图3所采用的数据与图1、图2不同,仅供看占用时间比例)
计算模块部分单元测试展示
public void testGetWordsNum() {
String testStr="";
String str="word word wordcount\n" +
"count count int\n" +
"file123 123file file File file123\n" +
"count count count\n" +
"window95 window95 window95 window95 window95\n" +
"window2000 window2000 window2000 window2000 window2000\n" +
"\t\t\n" +
"\t\n" +
"window98 window98 window98 window98 window98\n" +
" window98\twindow98\n" +
"your your your your your your\n" +
"fdsfds fdsfs gdsgs uorueow\n" +
"fsgs123 fsdf12 123faf fasf\n";
for(int i=0;i<10000;i++){
testStr+=str;
}
assertEquals(Lib.getWordsNum(testStr),420000);
}
上述构造了一个有各种单词的字符串,包括有效的、无效的,需要字典序的,以及换行符、制表符,以便这个字符串可以用于各种单元测试。loop了10000次使数据量增大。当符合预期时测试通过,否则会提示实际单词数。
计算模块部分异常处理说明
无自定义异常处理,只在单元测试失败时获取与期望不同的实际数目
心路历程与收获
在此前因为做的东西都是小东西,或是负责的东西比较摸鱼,所以很少接触到测试这方面,通过这次作业,让我觉得收获颇深的是通过JProfiler找到了更加有效率的方法,以及在实际动手之前的准备有多重要,以往开始的时候总有一种杂乱无章的感觉,而这次作业让我体会到了前期计划的重要性。