寒假作业(2/2)

这个作业属于哪个课程 <2021春软件工程实践W班>
这个作业要求在哪里 <寒假作业2/2>
这个作业的目标 对《构建之法》提出更具体详细的问题,设计一个程序,能够满足一些词频统计的需求,学习使用github
其他参考文献

阅读《构建之法》提问

问题1.

在4.4.1中在新成员在做代码复审时是否应该在完全掌握了这些方面之后再写代码?的回答是:理论上是,但要“完全掌握”,可能需要比较长的时间,如果不开发实际的软件,这样的“完全掌握”有意义么?可我觉得某一个整体(公司之类的)所写的代码,所写的程序在以后都是有可能要维护,或者说要再优化的,如果新成员不必完全掌握这些代码,那在以后那些所写代码的老成员可能已经不在同一个部门或者跳槽那类似程序维护中这些之前的新成员岂不是会很吃力?

问题2.

在5.3.5中关于老板驱动的流程,当软件订单的获得不是主要靠技术实力,而是靠个人关系,或者暗箱操作的时候,老板的能力(社交?)决定了一个团队是否能获得订单,毕竟具体功能并不重要(或者哪个团队做水平都差不多),首先我觉得这句话中具体功能不重要就不是很正确的一句话。然后是这段描述似乎并没有把其他很多因素给放进去,只有说到功能一样老板不同导致的后果。那价格这种比较重要的因素之类的并没有将之计算在内,即使是真有关系,在利益面前还是会选择利益,如果有价格稍微便宜的还会继续这份“关系”吗,还是说文中的这个老板能力已经达到让人不考虑经济条件等方面的因素来选择他的team。

问题3.

在7.2.3中的充分授权和信任一个高效的团队中,所有成员都应该能得到充分授权,他们充分信任其他同事能实现各自的承诺。确实大家都信任对方会使得事半功倍,但在一个大型的程序中,比如某人体力消耗过多导致自己工作能力下降,以及其它关乎个人利益的问题可能会使得这种大家彼此完全信任的状态有下滑,那之前有提到的代码审查不也是一种不充分完全信任的行为,而且一项工程下来大家还要多多少少的观看一下其它成员的工作详情,然后才根据对工程进行修改。那这样应该大家应该都要留一定并且还不是一小点的怀疑态度才能说的通吧?

问题4.

在7.2.5重视商业价值,提供渐进的价值中的如果我们没有搞清楚我们的项目会解决什么问题,为谁解决问题,为什么它会解决问题那项目还不能算是真正开始。都已经提及项目这个词了,不应该是已经确定好我们要往哪个方向出发,去解决什么样的问题了吗。在之后提及的要保证在两个方面 保证客户的利益:1.我们提供的新版本对用户真的有价值。2.和客户商讨一个最优的新版本的发布频率。那现在有很多换汤不换药的行为比如某果,新版本不但之前有在搞老顾客,并且也很少与所谓的客户交流那些所需要的是什么全由他们自己来定义这样还算成功的团队算是重视着商业价值吗?

问题5.

在8.3中软件开发的过程,就是“用户最需要的东西”在下面这一链条中传送、转换、实现、扭曲或丢失的过程。那依据这种说法,所开发的软件慢慢偏离了用户的需求,那这算是开发团队的锅吗,但按理来说开发团队应该是依据用户的需求来制定的开发规划等等应该一来就已经明确了一个八九不离十的目标,怎么会还会传送、转换、实现、扭曲或丢失呢?

软件工程发展冷知识

世界上第一位程序员是位英国女性,而且还是著名的浪漫主义诗人拜伦的女儿——Ada Lovelace,那时候活跃在伦敦社交界的Ada通过了老师玛丽·萨默维尔认识了查尔斯·巴贝奇。查尔斯·巴贝奇就邀请Ada观看他设计的差分机原型,一种能提高乘法速度和改进对数表等数字表精确度的机器。1842年,意大利数学家路易吉·米那比亚对巴贝奇最新的计算机设计书(即分析机概论)留下了一篇备忘录,由于不通意大利语,巴贝奇请求Ada帮他翻译。在1842-43年的9个月中,Ada都在翻译这篇备忘录。翻译的过程中,Ada加深了对于差分机的了解,也开始提出了自己的想法。她在其中详细说明用计算机进行伯努利数的运算方式,这也被认为是世界上第一个电脑程式,因此,Ada也被认为是世界上第一位程序员。
参考来源-https://www.sohu.com/a/424167230_120415997

词频统计个人作业

GitHub项目地址

https://github.com/noHAHA123/PersonalProject-Java

PSP表格.

PSP2.1 Personal Software Process Stages 预估耗时(分钟) 实际耗时(分钟)
Planning 计划 10 20
• Estimate • 估计这个任务需要多少时间 5 10
Development 开发 600 840
• Analysis • 需求分析 (包括学习新技术) 60 120
• Design Spec • 生成设计文档 30 30
• Design Review • 设计复审 20 20
• Coding Standard • 代码规范 (为目前的开发制定合适的规范) 20 15
• Design • 具体设计 30 15
• Coding • 具体编码 300 560
• Code Review • 代码复审 60 90
• Test • 测试(自我测试,修改代码,提交修改) 60 30
Reporting 报告 20 40
• Test Repor • 测试报告 20 40
• Size Measurement • 计算工作量 5 5
• Postmortem & Process Improvement Plan • 事后总结, 并提出过程改进计划 10 15
total 合计 1250 1850

解题思路

拿到题目首先想到的是io流,filereader和filewriter读写的使用,然后划分出三个功能,一个用来统计字符,一个用来统计行数,一个来进行单词总数和单词词频的统计。但因为涉及到要清空之前执行程序txt中的内容且单词总数和词频放于一个方法里输出顺序行数在单词总数之下,则把统计字符和统计行数功能返回各自统计数再作为参数一起传递给单词统计功能一起输出到结果输出txt文件。单词频率则通过键值对形式来统计,在做题过程中得知要用字典序处理相同词频的单词。而如何进行排序不太熟悉在网上找了相关内容。

代码规范链接

https://github.com/noHAHA123/PersonalProject-Java/blob/main/221801402/codestyle.md

计算模块接口的设计与实现过程

总的有两个类,一个wordCount来执行主程序,另一个Lib用来储存方法,方法整体有三个,一个计算并返回文件字符数,一个计算并返回文件行数,一个统计单词和词频并且接受之前统计出的字符数和行数并在此方法里将之输出到目标文件

public int CountChar(String inpath){}
public int CountLine(String inpath){}
public void CountWord(String inpath,String outpath,int charNum,int lineNum){}

统计字符数,按字符流的形式来读取文件并将总数返回

public int CountChar(String inpath) {
            File file = new File(inpath);
            int i = 0;
            try {
                FileReader fr = new FileReader(file);
                BufferedReader bufr = new BufferedReader(fr);
                while(((char) bufr.read()) != (char)-1){
                    i++;
                }
                bufr.close();
                fr.close();
            }
            catch(Exception e)
            {
                e.printStackTrace();
            }
            return i;
        }

统计行数,只要文件还有行就读下去并将计数值+1,并将行数返回

public int CountLine(String inpath){
            File file = new File(inpath);
            int i = 0;
            try {
                FileReader fr = new FileReader(file);
                BufferedReader bufr = new BufferedReader(fr);
                while (bufr.readLine() != null) {
                    i++;
                }
                bufr.close();
                fr.close();
            } catch (Exception e) {
                e.printStackTrace();
            }
            return i;
        }

将这两数都返回到wordcount,并作为参数传递给CountWord

 int charNum,lineNum;
 Lib a=new Lib();
 charNum=a.CountChar(inPath);
 lineNum=a.CountLine(inPath);
 a.CountWord(inPath,outPath,charNum,lineNum);

在CountWord里首先要把文件的字符串进行分割,非a-zA-Z0-9的字符作为分割符,将文件内容一行一行的进行分割,且在之前进行小写转换处理

FileReader fr = new FileReader(file);
BufferedReader bufr = new BufferedReader(fr);
while ((line = bufr.readLine()) != null) {
                line = line.toLowerCase();
                String[] words=line.split("[^(a-zA-Z0-9)]+");
                ...
}

再对这些单词进行匹配,符合前4位都为英文字符的放置与map中,若是初次匹配成功则值位1,之后加1,之后进行排序并且同时进行单词总数的统计用sum变量保存

int sum=0;
String regex = "[a-zA-Z]{4,}[a-zA-Z0-9]*";
for(String word :words) {
                    if (word.matches(regex)) {
                        if (map.get(word) == null) {
                            map.put(word, 1);
                            sum++;
                        } else {
                            map.put(word, map.get(word) + 1);
                            sum++;
                        }
                    }
                }

利用hashmap,单词作为键,出现次数作为值来保存单词与出现次数并根据值和字典顺序进行排序后输出

ArrayList<HashMap.Entry<String, Integer>> list =
                    new ArrayList<HashMap.Entry<String, Integer>>(map.entrySet());
            Collections.sort(list, new Comparator<HashMap.Entry<String, Integer>>() {
                public int compare(Map.Entry<String, Integer> o1, Map.Entry<String,Integer> o2) {
                    if (o1.getValue() < o2.getValue()) {
                        return 1;
                    } else {
                        if (o1.getValue().equals(o2.getValue())) {
                            if (o1.getKey().compareTo(o2.getKey()) > 0) {
                                return 1;
                            } else {
                                return -1;
                            }
                        } else {
                            return -1;
                        }
                    }
                }
            });

再通过List的大小得出单词种类数,若单词数目不够10种时则就把这些词频数据都输出,还有list储存的单词词频内容连同传进来的characters和lines值一起输出到目标文件

FileWriter out = new FileWriter(outpath);
int n = list.size();
out.write("characters:"+charNum+"\n");
out.write("words:"+sum+"\n");
out.write("lines:"+lineNum+"\n");
if (n>10){
      n=10;
}
for (int i = 0; i < n; i++) {
   out.write(list.get(i).getKey()+":"+list.get(i).getValue()+"\n");
}

性能改进

一开始在运行时我直接将文件内容放进字符串里直接分割,换行符不会让单词分割,于是我将内容一行一行的进行分割。

单元测试

字符数测试

@Test
    public void countChar() {
        String a="input.txt";
       try{
           PrintWriter pw=new PrintWriter(a);
           pw.write("");
           pw.flush();
           pw.close();
           FileWriter out = new FileWriter(a);
           out.write("12345 \n\r");
           out.flush();
           out.close();
           System.out.print(Lib.CountChar(a));
           assertEquals(Lib.CountChar(a),8);
       }catch (Exception e){
           e.printStackTrace();
       }
    }

行数测试

@Test
    public void countLine() {
        String a="input.txt";
        try{
            PrintWriter pw=new PrintWriter(a);
            pw.write("");
            pw.flush();
            pw.close();
            FileWriter out = new FileWriter(a);
            for(int i=0;i<10000;i++) {
                out.write("\n");
            }
            out.flush();
            out.close();
            System.out.print(Lib.CountLine(a));
            assertEquals(Lib.CountLine(a), 10000);
        }catch (Exception e){
            e.printStackTrace();
        }

单词统计测试

@Test
    public void countWord() {
        String a="input.txt";
        String b="output.txt";
        try{
            PrintWriter pw=new PrintWriter(a);
            pw.write("");
            pw.flush();
            pw.close();
            PrintWriter pw1=new PrintWriter(b);
            pw1.write("");
            pw1.flush();
            pw1.close();
            FileWriter out = new FileWriter(a);
            out.write("Hello\r\nWorld Windows2000 Windows1998 123file ");
            out.flush();
            out.close();
            Lib.CountWord(a,b,2,1);
        }catch (Exception e){
            e.printStackTrace();
        }
    }




如何提高覆盖率?
构造出的测试用例符合场景。代码尽量简化,尽量用简单的逻辑
某一示例:执行程序对应的两文件内容

异常处理说明

对主程序参数不足和IOException进行捕获,出现异常将输出异常信息。

心路历程与收获

对github的不熟悉,网站连接慢和以及密密麻麻的英文内容有被吓到,在程序编写前期并不敢接触github导致只能在自己的编译器上差不多把程序完成了才通过问同学的方式得到vpn,和git使用将自己的代码传至github.说实话畏难情绪一直存在,在最前面几天的时候甚至因为github网站不给力的原因而搁置作业。好在有同学的帮助终于可怜巴巴地舒服地用上了github。还粗浅的使用到了单元测试,可以更简便的对自己的代码进行审查

posted @ 2021-03-05 15:37  大不列颠恰饭王  阅读(45)  评论(4编辑  收藏