寒假作业2/2
这个作业属于哪个课程 | 2021春软件工程实践 W班 (福州大学) |
---|---|
这个作业要求在哪里 | 软工实践寒假作业(2/2) |
这个作业的目标 | 阅读《构建之法》 完成WordCount编程 |
阅读《构建之法》并提问
问题一
在2.3个人开发流程中有提到PSP相关的内容
“不局限于某一种软件技术(如编程语言),而是着眼于软件开发的流程,这样,开发不同应用的软件工程师可以互相比较。”
我不认同这个说法。对于不同应用的开发不应该只着眼于开发流程,而不重视软件技。如果使用框架技术在设计的阶段就能剩下大量时间,代码编写和报告编写时间也能相应缩短,所以我认为软件技术也应该重视。
问题二
在4.5.2章节中提到
在开发层次,结对编程能提供更好的设计质量和代码质量,两人合作解决问题的能力更强。两人合作,还有相互激励的作用,工程师看到别人的思路和技能,得到实时的讲解,受到激励,从而努力提高自己的水平,提出更多创意。
我想到的是如果一方由此产生了对“伙伴总能找到bug”的依赖感而怠惰;或是两人的讨论无法取得统一意见而拖累项目进度,对双方的提升也不能有效体现,这是否也是结对编程的“双刃剑”呢
问题三
3.2中说到
“不分主次,想解决所有依赖问题:另一种极端是过于积极,想马上动手修复所有主要和次要的依赖问题,然后就可以“完美地”达成最初设定的目标,而不是根据现有条件找到一个“足够好”的方案。”
我想到的是,平时在写代码时,发现了bug不都是立马排除、解决的吗?如果只解决主要问题,那么剩下的问题将来产生的隐患或许更加危险。
在查找相关资料时也看到这样一句话,我认为所表达出的意思应该是相同的:
“很多时候对软件造成的影响可能由一系列相关或者不相关的程序缺陷等综合因素积累导致。”
问题四
在博客《项目管理的目标和细节》有这段话
“项目管理的最高目标并不是要保证让 “ideal” 和 “actual” 的线吻合, 因为项目中出现意外和需求的变化是很正常的事。 项目管理的目标是处理这些意外和变化, 让软件能如期发布, 尽量满足客户的要求。
这段话的意思是项目管理的目标是最终让软件如期发布就好了吗?若在开发过程中发生意外或需求变化,管理者处理之时发现剩余的开发时间不足以让软件如期发布。
为了避免这种情况,管理者如何保证项目在最低的“ideal”标准,与“actual”最好地匹配?
问题五
博客《用户体验和质量》提到
“好的用户体验当然是所有人都想要的, 如果它和产品的质量有冲突, 怎么办? 牺牲质量去追求用户体验, 能变成利润么?”
这句话在原文是应该更加关注与用户体验的意思。(在博客后文的例子中可以看出)
我想到的是:用户的体验与产品质量的比重在从 软件发布到后期维护更新 的比重是否应该有变化?
新上架的应用应当尽量偏向于功能质量,以实用性来吸引用户,而在之后的更新时则优化用户的操作,维护好用户的体验。
附加题
键盘是按照英文字母QWERTY排列的。但是这种字母布局最初是为了让打字速度慢下来。这个发明是一个叫Scholes的美国人的创举。早期机械打字机依靠按键驱动后方的字锤进行操作,如果输入过快,前一个字母的字锤还未完全弹起,后面一个字母的字锤就已经落下,相邻键杆就会撞在一起而发生卡壳。于是,Scholes把常用字母安排在了不顺手的地方,这样就能减慢打字员的速度,击节连杆也就不会卡住了。
WordCount编程
项目地址
PSP表格
PSP2.1 | Personal Software Process Stages | 预估耗时(分钟) | 实际耗时(分钟) |
---|---|---|---|
Planning | 计划 | ||
• Estimate | • 估计这个任务需要多少时间 | 10 | 10 |
Development | 开发 | ||
• Analysis | • 需求分析 (包括学习新技术) | 40 | 60 |
• Design Spec | • 生成设计文档 | 30 | 35 |
• Design Review | • 设计复审 | 10 | 10 |
• Coding Standard | • 代码规范 (为目前的开发制定合适的规范) | 20 | 20 |
• Design | • 具体设计 | 20 | 30 |
• Coding | • 具体编码 | 300 | 330 |
• Code Review | • 代码复审 | 20 | 30 |
• Test | • 测试(自我测试,修改代码,提交修改) | 40 | 60 |
Reporting | 报告 | ||
• Test Repor | • 测试报告 | 60 | 75 |
• Size Measurement | • 计算工作量 | 20 | 20 |
• Postmortem & Process Improvement Plan | • 事后总结, 并提出过程改进计划 | 30 | 30 |
合计 | 540 | 710 |
解题思路
分析题目后发现任务由以下几点组成
1.获取txt文件内容;输入到txt文件
用流获取、写入文件用到FileIO的相关类函数
2.统计字符数
获取文件后只需要统计ASCII码的字符数即可
3.统计有效行数
用正则表达式匹配空行后可以间接得出结果
4.统计单词数
题目有单词的格式,可以用正则表达式进行匹配
5.统计词频最高的10个单词
用map保存全部单词,再编写一个比较器排序出出现频率最高的10个单词
代码规范制定链接
设计与实现过程
相关设计
按照功能区分为WordCount类和Lib工具类
WordCount类仅含有主函数,Lib类中实现各种功能
//读取文件
public void readFile() {...}
//字符数统计
private void getChars() {...}
//单词数统计
public void getWords() {...}
//行数统计
public void getLines() {...}
//单词按出现频率排序
public void sortWords() {...}
关键代码
字符数的统计只需要统计ASCII码的个数
//读取文件
BufferedReader reader = null;
try {
reader = new BufferedReader(new FileReader(openFilePath));
StringBuilder builder = new StringBuilder();
int c;
while ((c = reader.read()) != -1) {
if (c>0&&c<128) {
builder.append((char) c);
}
}
reader.close();
file = builder.toString();
} catch (IOException e) {
e.printStackTrace();
}
下面是匹配单词的匹配空行的正则表达式
private String wordPattern = "^([A-Za-z]{4}[A-Za-z]*[0-9]*)";//单词匹配
private String linePattern = "\\s*";//空行匹配
下面是统计有效行数的代码
reader = new BufferedReader(new FileReader(openFilePath));
String line;
while( (line = reader.readLine()) != null ) {
if(!line.matches(linePattern))
countLines++;
}
reader.close();
下面是统计单词数的代码
while((line = reader.readLine()) != null) {
String[] words = line.split("\\W+");//字母数字下划线
Pattern r = Pattern.compile(wordPattern);
Set<String> wordSet = hashMap.keySet();
for (int i = 0; i < words.length; i++) {
Matcher m = r.matcher(words[i]);
if (m.find()) {
String str = m.group(0).toLowerCase();
if (wordSet.contains(str)) {
num = hashMap.get(str);
num++;
hashMap.put(str, num);
countWords++;
} else {
hashMap.put(str, 1);
countWords++;
}
}
}
}
单词的排序使用JAVA8的Stream操作
hashMap = hashMap.entrySet()
.stream()
.sorted(Map.Entry.<String, Integer> comparingByValue().reversed().thenComparing(Map.Entry.comparingByKey()))
.limit(10)
.collect(toMap(e -> e.getKey(), e -> e.getValue(), (e1, e2) -> e2,
LinkedHashMap::new));
性能改进
流的处理上使用了BufferedReader和BufferedWriter,较没有缓冲区的性能更好些
正则表达式的性能比较差,在统计有效行时有考虑过舍弃正则表达式,但没有试出更优解
单元测试
覆盖率截图
如何优化覆盖率
尽量不要用变量传递参数,方法体尽量小
单元测试代码
@Test
public void getWords() {
lib.getWords();
assertEquals(4,lib.countWords);
}
@Test
public void getLines() {
lib.getLines();
assertEquals(6,lib.countLines);
}
构造尽量可能出错的数据进行测试,下面是测试80w个无规则单词结果截图
异常处理说明
只有用try catch块简单处理FileNotFoundException和IOException,没有自定义异常类
心路历程和收获
复习了Java文件数据操作的相关知识,正则表达式的使用。在git上提交代码,进行版本控制,体会到了git平台对于代码整体变化的控制优势,对于我的帮助很大