1、github地址
https://github.com/Hare-Lucius/WordCountPro
基本功能(分别以个人和小组形式提交至github)
2、 PSP2.1表格
PSP2.1 |
PSP阶段 |
预估耗时 (分钟) |
实际耗时 (分钟) |
Planning |
计划 |
30 |
20 |
· Estimate |
· 估计这个任务需要多少时间 |
30 |
20 |
Development |
开发 |
470 |
550 |
· Analysis |
· 需求分析 (包括学习新技术) |
30 |
20 |
· Design Spec |
· 生成设计文档 |
20 |
20 |
· Design Review |
· 设计复审 (和同事审核设计文档) |
30 |
20 |
· Coding Standard |
· 代码规范 (为目前的开发制定合适的规范) |
30 |
30 |
· Design |
· 具体设计 |
30 |
40 |
· Coding |
· 具体编码 |
180 |
240 |
· Code Review |
· 代码复审 |
30 |
30 |
· Test |
· 测试(自我测试,修改代码,提交修改) |
120 |
150 |
Reporting |
报告 |
90 |
90 |
· Test Report |
· 测试报告 |
30 |
30 |
· Size Measurement |
· 计算工作量 |
30 |
30 |
· Postmortem & Process Improvement Plan |
· 事后总结, 并提出过程改进计划 |
30 |
30 |
|
合计 |
590 |
660 |
3、接口设计
我负责完成核心处理部分,即单词词频统计,排序等功能。输入模块会以String形式传入待处理的文件名,本模块将文件内的单词进行词频统计,并按照词频进行升序排列,对于频率相同的单词,按照字母顺序进行二次排列,并将单词和频率分别存入两个数组中。本模块的输出为两个数组的数组名,将传入输出模块进行后续处理。在实际代码编写过程中,对文件进行行处理。规定a-z、A-Z和“-”为单词字符,对每一行进行扫描,遇到非单词字符则跳过,遇到单词字符则进行标记直至遇到非单词字符,再向前扫描至非“-”字符,所得子串为一个单词。判断该单词是否已录入数组,若是则频率自增,否则录入该单词并设频率为1。对文章统计完毕后,将频率数组进行排序,考虑到时间开销 ,此处采用快速排序,交换频率次序的同时也要交换单词的次序。之后,对于同频率的单词,利用Arrays.sort()函数进行单词排序,由于频率相同,故只需交换单词次序。
词频统计:
File fi=new File(file); Scanner in = new Scanner(fi); //String[] sto=new String [100]; while (in.hasNextLine()) { int i=0,start=0,end=0,sf=0; String str = in.nextLine(); while(i<str.length()) { char b=str.charAt(i); if(b>='a'&&b<='z'||b>='A'&&b<='Z'||b=='-') { if(sf==0) { start=i; sf=1; } i++; } else { if(sf==1) { end=i-1; //b=str.charAt(end); while(str.charAt(end)=='-') { end--; } sf=0; list(str.substring(start, end+1).toLowerCase()); } i++; } //System.out.println(end); } if(sf==1) { end=i-1; //b=str.charAt(end); while(str.charAt(end)=='-') { end--; } sf=0; list(str.substring(start, end+1).toLowerCase()); }
频率排序:
public static int partition(int []array,int lo,int hi) { int key=array[lo]; String keys=slist[lo]; while(lo<hi) { while(array[hi]>=key&&hi>lo) { hi--; } array[lo]=array[hi]; slist[lo]=slist[hi]; while(array[lo]<=key&&hi>lo) { lo++; } slist[hi]=slist[lo]; } array[hi]=key; slist[hi]=keys; return hi; } public static void sort(int[] array,int lo ,int hi) { if(lo>=hi) { return ; } int index=partition(array,lo,hi); sort(array,lo,index-1); sort(array,index+1,hi); }
同频率单词排序:
int m=0,n=0; while(m<=record&&n<=record) { while(fqc[m]==fqc[n]) n++; Arrays.sort(slist,m,n); m=n+1; n=m; }
4、测试设计
测试用例覆盖函数中所有的判断语句,同时针对同单词的不同形式识别、排序最差情况、词频排序、字母排序等各种情况设计测试用例。
5、单元测试截图
测试质量:测试涵盖了重要的函数,并从多个不同方面设计了40个测试用例对核心部分进行了单元测试,可以认为测试具有较高的质量。
被测模块的质量:从测试的正确率可以看出,被测模块的质量较高,对于一些常见的输入情况都能做出正确的输出。此外,从测试时间也可以看出,被测的函数的时间复杂度并不高,经常是很快的时间就能输出结果。
6、小组贡献分
我负责的核心模块在小组内编码量最多,同时也承担了组内一半的测试用例,故小组贡献分为0.38。
(小组情况:17044:核心模块,0.38;17062:输入模块,0.2;17065:输出模块,图形界面,0.32;17064:其他模块,0.1)
扩展功能(仅以小组形式提交至github)
7、开发规范说明
选取《阿里巴巴 Java 开发手册》中“编程规约-代码格式”中的前九条强制要求进行代码评审。我负责评审17065的代码(输出模块)。
8、交叉代码评审
(下面将列出评审要求,若未满足则在括号内予以说明,若满足则无说明;同时将待评审代码张贴如下)
a、大括号使用:1) 左大括号前不换行。(未满足) 2) 左大括号后换行。 3) 右大括号前换行。 4) 右大括号后还有else等代码则不换行;表示终止的右大括号后必须换行。
b、左小括号和字符之间不出现空格;右小括号和字符之间也不出现空格。
c、if/for/while/switch/do等保留字与括号之间都必须加空格(未满足)。
d、任何二目、三目运算符的左右两边都需要加一个空格(未满足)。
e、采用4个空格缩进,禁止使用tab字符(部分未满足)。
f、注释的双斜线与内容之间有且仅一个空格(未满足)。
g、单行字符数限不超过 120 个,超出需要换行,换行时遵循如下原则:1) 第二行相对第一行缩进4个空格,从第三行开始不再继续缩进(未满足)。 2) 运算符与下文一起换行。 3) 方法调用的点符号与下文一起换行。 4) 方法调用时,多个参数,需要换行时,在逗号后进行。 5) 在括号前不要换行。
h、方法参数在定义和传入时,多个参数逗号后边必须加空格(未满足)。
i、IDE的text file encoding设置为UTF-8; IDE中文件的换行符使用Unix格式,不要使用Windows格式。
public class Output { private String[] name; private int[] num; private int length=0; private int record; public Output(String[] name,int[] num,int record) { this.record=record+1; this.name=name; this.num=num; } public void out() throws IOException{ if(record>100) record=100; else if(record==0) { System.out.println("没有统计到单词"); //return 0; } // if(name.length!=num.length) // { // System.out.println("单词数量统计错误"); //return 1; // } System.setOut(new PrintStream(new BufferedOutputStream(new FileOutputStream("output.txt")),true)); for(int i=0;i<record;i++) { if(num[i]<0) { System.setOut(new PrintStream(new BufferedOutputStream( new FileOutputStream(FileDescriptor.out)),true)); System.out.println("单词数量统计错误"); //return 1; } System.out.println(name[i]+" "+num[i]); } //return 2; } }
9、静态代码扫描
静态代码检查工具:阿里巴巴Java开发代码检测IDE插件;
下载网址:https://github.com/alibaba/p3c。
10、扫描结果
代码的主要问题如下图所示
下面举例说明代码的不规范之处:
a、if语句中由于只有一行代码,未使用大括号,属于较严重的不规范之处
b、没有类的创建者信息
11、组内代码分析
小组成员的代码总体上实现所需的功能,但在代码规范上都或多或少地存在不足之处。除了格式问题,还有一些诸如存在未使用的变量、未尽可能地考虑异常处理等问题。
改进方案:规范代码格式,减少无用变量的声明,更多考虑异常。
12、代码改进
我按照静态测试的结果和小组评审的结果修改了代码(具体见github),再运行单元测试后,发现运行时间并未得到太大的改变,分析原因如下:
原代码中多为不规范之处,但并无严重影响代码效率的语句,故修改代码会有利于代码维护和更新,但不会对运行效率有太大的影响。
高级任务(仅以小组形式提交至github):
13、设计测试数据集
在软件设计完成后,设计多个不同大小的文本文档作为输入文件,作为测试数据集。对于每个文件,随机产生数字,再整除26,得到0-25的整数,将这些整数映射到a-z得到字符。
14、测试结果
未对代码进行方法优化,但通过性能测试改进了大数据时的代码不足。
使用20000字符,40000字符,80000字符,160000字符,640000字符(大小为59kb,118kb,235kb,469kb,1875kb)作为测试用例,多次测试,取平均结果,测试结果如下:
20000字符 63ms
40000字符 94ms
80000字符 140ms
160000字符 250ms
640000字符 874ms
结论:随着文件内字符数增加,运行时间也逐渐增加,且两者成一定的线性关系。
15、同行评审过程描述
小组成员及分工:U201517065 徐豪 记录员,主持人 ;
U201517062 练志东 评审员;
U201517044 陆犇圆 作者,讲解员;
评审过程:(1)指明讨论过程中的角色分工(主持人、作者、讲解员、评审员、记录员);(2)说明评审目的;(3)指明讨论过程中,各评审员的评审意见;(4)列出最终的评审结论,例如,发现并确认的缺陷清单;(5)说明本次评审中存在的不足,或者遇到的困难。
评审目的:优化代码性能。
16、性能分析(评审结果)
每次运行时间存在差异,主要原因可能是系统其他进程的影响,这种影响一般不大,但偶尔会出现使结果出现较大波动。
对于运行时间影响最大的因素是统计单词列表,其中的循环和判断语句会耗费比较多的时间,因此如果要提高性能,应尽可能精简单词判断方法。
其次的因素则是对于频率的排序,采用快速排序,已经尽肯能减小排序所带来的时间开销。
对于单词的输入输出部分,由于没有过多判断而且循环长度不大,因此对性能影响不大。
17、性能优化
通过测试,在输入不变的情况下,若通过注释减少单词判断方法内的判定语句的数量,可以减少运行时间(但这样显然得不到正确结果,故仅作为性能测试的依据,不予以实践);而对于其他模块的修改,减少的运行时间量明显不如前者,如此可以印证评审结论。
18、实践感想
软件开发和软件测试都是软件生命周期的重要组成部分,都是软件过程之中的重要活动。软件开发为软件测试提供对象,软件测试是保证软件质量的重要手段。软件开发是一个创造的过程, 软件测试是一个维护的过程,二者的目的都应该是致力于提高软件的质量。平时我们可能会忽略软件测试的重要性或者草草了事,但实践证明,软件测试的所需时间和重要性并不亚于软件开发。只有二者兼顾,才能真正保证软件的质量。
19、附加题
图形界面(在完成高级功能后加入,故github中只有最后一次提交的内容有图形界面)
20、参考文献
java实现快速排序:https://blog.csdn.net/u010853261/article/details/54884784
git创建标签:https://blog.csdn.net/wangjia55/article/details/8793577/