扩大
缩小

软工实践寒假作业(2/2)

这个作业属于哪个课程 2020春S班 (福州大学)
这个作业要求在哪里 软工实践寒假作业(2/2)
这个作业的目标 1.疫情统计程序
2.github初使用
3.代码规范制定
作业正文 软工实践寒假作业(2/2)
其他参考文献 CSDN、百度、博客园、缪雪峰的git教程

1.Gitub仓库地址

我的仓库

2.PSP表格

邹欣老师在《构建之法》中把枯燥的理论概念讲解得非常生动,寓教于乐,深入浅出,举出的例子也是形象而易懂,读完之后很受启发。
第一章中,作者为我们介绍了一些关于软件工程的基本知识。

软件=程序+软件工程。
软件开发的不同阶段:玩具阶段→业余爱好阶段→探索阶段→成熟的产业阶段.
软件的特殊性:复杂性、不可见性、易变性、服从性、非连续性。

第二章主要学习了单元检测和个人开发流程PSP。PSP是卡耐基梅隆大学(CMU)的专家们针对软件工程师所提出的一套模型:Personal Software Process (PSP, 个人开发流程,或称个体软件过程)。

PSP特点:
(1)不局限于某一种软件技术,而是着眼于软件开发的流程,这样,开发不同应用的软件工程师可以互相比较。
(2)不依赖于考试,而主要靠工程师自己收集数据,然后分析、提高。
(3)在小型、初创的团队中,很难找到高质量的项目需求,这意味着给程序员的输入质量不高。在这种情况下,程序员的输出(程序/软件)往往质量也不高,然而这并不能全部由程序员负责。
(4)PSP依赖于数据(工程师输入数据的时间代价、数据可能遗失或者不准确的风险、可能会出现一些数据不利于工程师本人的情况)
(5)PSP目的是记录工程师如何实现需求的效率,而不是记录顾客对产品的满意度,工程师有可能很高效地开发出一个顾客不喜欢的软件。

第三章主要介绍了软件工程师个人能力的衡量与发展以及职业发展。


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

3.解题思路描述

  1. git、github、github desktop的学习
    对git了解很少,首先学习这个部分的新知识。老师给的知识链接对于零基础的我看的有点模糊,所以花了一部分时间查找资料。在缪雪峰的git教程里学习有关git部分的所有知识,包括git命令行的使用、gitignore等等。
  2. 命令行参数处理
    百度学习main函数参数的相关知识
    Java中参数是以字符串数组形式传入,根据题目要求

list命令 支持以下命令行参数:
-log 指定日志目录的位置,该项必会附带,请直接使用传入的路径,而不是自己设置路径
-out 指定输出文件路径和文件名,该项必会附带,请直接使用传入的路径,而不是自己设置路径
-date 指定日期,不设置则默认为所提供日志最新的一天。你需要确保你处理了指定日期之前的所有log文件
-type 可选择[ip: infection patients 感染患者,sp: suspected patients 疑似患者,cure:治愈 ,dead:死亡患者],使用缩写选择,如 -type ip 表示只列出感染患者的情况,-type sp cure则会按顺序【sp, cure】列出疑似患者和治愈患者的情况,不指定该项默认会列出所有情况。
-province 指定列出的省,如-province 福建,则只列出福建,-province 全国 浙江则只会列出全国、浙江

使用一个字符串数组保存读取到的命令以便后续处理。第一个参数必是list,是用来判断命令的。以-开头的参数开始处理,根据上面的要求可得知一个参数的值可以为多个。这里用if-else语句匹配相应的参数,进行相应的处理。
3. 日志文件的读取
根据题目要求,日志文件以日期名命名,日志的形式有以下8种

<省> 新增 感染患者 n人
<省> 新增 疑似患者 n人
<省1> 感染患者 流入 <省2> n人
<省1> 疑似患者 流入 <省2> n人
<省> 死亡 n人
<省> 治愈 n人
<省> 疑似患者 确诊感染 n人
<省> 排除 疑似患者 n人

首先是根据-log获取文件路径,结合-date打开相应的文件。然后按行读取日志文件的内容,使用正则表达式匹配,匹配成功则进行相应的计算操作,将结果保存在一个二维数组里。
4. 输出结果
不同参数输出结果不同

-date没有参数,输出最新一天的情况
-type有多个参数,按序输出;没有参数,输出所有类型
-province的参数全国总是排第一个,别的省按拼音先后排序;没有参数,输出全国+文件中包含的省份的情况,

解题思路

4.设计实现过程

  • 数据结构
    数据结构
  • 文件读取
    readFile方法:
    readFile方法
  • 命令行处理
    ProcCmd方法:
    此处输入图片的描述
  • 输出结果
    writeFile方法:
    此处输入图片的描述

5. 关键代码与思路

  • 数据结构

      public String path_in;//读取日志目录
      public String path_out;//输出日志目录
    
      //获取格式化日期
      Date dt = new Date(System.currentTimeMillis());
      String strDateFormat = "yyyy-MM-dd";
      SimpleDateFormat sdf = new SimpleDateFormat(strDateFormat);
      String date=sdf.format(dt);
      
      public String[] province = {
      		"全国", "安徽", "澳门" ,"北京", "重庆", "福建","甘肃","广东", "广西",
      		"贵州", "海南", "河北", "河南", "黑龙江", "湖北", "湖南", "吉林",
      		"江苏", "江西", "辽宁", "内蒙古", "宁夏", "青海", "山东", "山西", "陕西", 
      		"上海","四川", "台湾", "天津", "西藏", "香港", "新疆", "云南", "浙江"};
      /*二维数组
       * 一维表示省份
       * 二维分别表示{是否需要列出,ip,sp,cure,dead}*/
      public int[][] situation=new int[35][6];
      
      //类型输出顺序,默认ip,sp,cure,dead
      public int type_order[]= {1,2,3,4};
      public String[] type= {"感染患者", "疑似患者", "治愈", "死亡"};
    
  • 处理命令行参数

      //处理参数
      public boolean ProcessPara(){
      	
      	//判断命令是否正确	
      	if(!args[0].equals("list")){
      		System.out.println("命令错误");
      		return false;
      	}
      
      	int i;
      	for(i = 1;i<args.length;i++){
      		//读取-log
      		if(args[i].equals("-log")){
      			path_in=args[++i];
      		} 
      		//读取-out
      		else if(args[i].equals("-out")){ 
      			path_out=args[++i];
      		} 
      		//读取-date
      		else if(args[i].equals("-date")){
      			i=getDate(++i);
      			if(i==-1) {
      				System.out.println("日期超出范围!");
      				return false;
      			}
      		} 
      		//设置-type输出顺序
      		else if(args[i].equals("-type")){ 
      			i=setType(++i); 
      		} 
      		//读取-province
      		else if(args[i].equals("-province")){ 
      			i=getProvince(++i);
      		}
      	}
      	return true;
      }
    
  • 日志文件的读取

      //读取日志
      public void readLog() {
      	File file=new File(path_in);
      	File[] listFiles=file.listFiles();
      	String path;
      	
      	int i=0;
      	while(i<listFiles.length){
      		path=listFiles[i].getName();
      		if(path.compareTo(date)<=0) {
      			try {
      				BufferedReader b=new BufferedReader(new InputStreamReader(
      						new FileInputStream(new File(path_in+path)), "UTF-8"));
      				String line;
      				while((line=b.readLine())!=null) {
      					if(!line.startsWith("//")) {
      						String p1 = "(\\S+) 新增 感染患者 (\\d+)人";
      				    	String p2 = "(\\S+) 新增 疑似患者 (\\d+)人";
      				    	String p3 = "(\\S+) 治愈 (\\d+)人";
      				    	String p4 = "(\\S+) 死亡 (\\d+)人";
      				    	String p5 = "(\\S+) 感染患者 流入 (\\S+) (\\d+)人";
      				    	String p6 = "(\\S+) 疑似患者 流入 (\\S+) (\\d+)人";
      				    	String p7 = "(\\S+) 疑似患者 确诊感染 (\\d+)人";
      				    	String p8 = "(\\S+) 排除 疑似患者 (\\d+)人";
      				    	if(Pattern.matches(p1, line)) 
      				    		IP(line);
      				    	if(Pattern.matches(p2, line)) 
      				    		SP(line);
      				    	if(Pattern.matches(p3, line)) 
      				    		Cure(line);
      				    	if(Pattern.matches(p4, line)) 
      				    		Dead(line);
      				    	if(Pattern.matches(p5, line)) 
      				    		IPgo(line);
      				    	if(Pattern.matches(p6, line))
      				    		SPgo(line);
      				    	if(Pattern.matches(p7, line))
      				    		SPtoIP(line);
      				    	if(Pattern.matches(p8, line))
      				    		notSP(line);
      					}
      				}
      				b.close();
      			} catch (UnsupportedEncodingException e) {
      				// TODO 自动生成的 catch 块
      				e.printStackTrace();
      			} catch (FileNotFoundException e) {
      				// TODO 自动生成的 catch 块
      				e.printStackTrace();
      			} catch (IOException e) {
      				// TODO 自动生成的 catch 块
      				e.printStackTrace();
      			}
      		}
      		i++;
      	}			
      }
    
  • 输出日志

      //输出日志
      public void writeLog(){
      	try {
      		FileWriter fw=null;
      		fw=new FileWriter(path_out);
      		if(situation[0][0]==-1)
      			situation[0][0]=1;
      		int i=0;
      		while(i<35) {
      			if(situation[i][0]==1) {
      				//System.out.println("a");
      				fw.write(province[i]+" ");
      				for(int k=1;k<5;k++)
      					for(int j=0;j<4;j++) {
      						if(type_order[j]==k) {
      							String string=type[j]+situation[i][j+1]+"人"+" ";
      							fw.write(string);
      							break;
      							//System.out.println(string);
      						}
      					}
      				fw.write("\n");	
      			}
      			i++;
      		}
      		fw.write("// 该文档并非真实数据,仅供测试使用");
      		fw.close();				
      	}catch (Exception e) {
      		// TODO: handle exception
      		e.printStackTrace();
      	}
      }
    

6.单元测试截图和描述

学习资料:
关于单元测试和回归测试
Eclipse中进行单元测试
测试结果:
单元测试

  1. 测试ListOut1.txt

     /*全国 感染患者15人 疑似患者22人 治愈2人 死亡1人
      * 福建 感染患者5人 疑似患者7人 治愈0人 死亡0人
      * 湖北 感染患者10人 疑似患者15人 治愈2人 死亡1人
      * // 该文档并非真实数据,仅供测试使用
      * // 命令:list -log D:\log\ -out D:\ListOut1.txt -date 2020-01-22
      */
     @Test
     public void testListOut1() {
     	InfectStatistic.main("list -log D:\\log\\ -out D:\\ListOut1.txt -date 2020-01-22".split(" "));
     }
    

此处输入图片的描述

  1. 测试ListOut2.txt

     /*
     福建 感染患者5人 疑似患者7人 治愈0人 死亡0人
     河北 感染患者0人 疑似患者0人 治愈0人 死亡0人
     // 该文档并非真实数据,仅供测试使用
     // 命令:list -log D:\log\ -out D:\ListOut2.txt -date 2020-01-22 -province 福建 河北
     */
     @Test
     public void testListOut2() {
     	InfectStatistic.main("list -log D:\\log\\ -out D:\\ListOut2.txt -date 2020-01-22 -province 福建 河北".split(" "));
     }
    

此处输入图片的描述

  1. 测试ListOut3.txt

     /*
     全国 治愈4人 死亡3人 感染患者42人
     福建 治愈1人 死亡0人 感染患者9人
     浙江 治愈0人 死亡0人 感染患者0人
     // 该文档并非真实数据,仅供测试使用
     // 命令:list -log D:\log\ -out D:\ListOut7.txt -date 2020-01-23 -type cure dead ip -province 全国 浙江 福建
      */
     @Test
     public void testListOut3() {
     	InfectStatistic.main("list -log D:\\log\\ -out D:\\ListOut3.txt -date 2020-01-23 -type cure dead ip -province 全国 浙江 福建".split(" "));
     }
    

此处输入图片的描述

  1. 默认不存在-date,-type,-province的输出结果

     //默认不存在-date,-type,-province的输出结果
     @Test
     public void testDefaultAll() {
     	InfectStatistic.main("list -log D:\\log\\ -out D:\\output4.txt".split(" "));
     }
    

此处输入图片的描述

  1. 测试超出最晚日志日期

     //测试超出最晚日志日期
     @Test
     public void testOutOfDate() {
     	InfectStatistic.main("list -log D:\\log\\ -out D:\\output5.txt -date 2020-02-22".split(" "));
     }
    

此处输入图片的描述

  1. 测试日期不存在对应的日志文件

     //测试日期不存在对应的日志文件
     @Test
     public void testBetweenDate() {
     	InfectStatistic.main("list -log D:\\log\\ -out D:\\output6.txt -date 2020-01-25".split(" "));
     }
    

此处输入图片的描述

  1. 测试只列出指定省份:全国、浙江、福建

     //测试只列出指定省份:全国、浙江、福建
     @Test
     public void testAllAndProvince() {
     	InfectStatistic.main("list -log D:\\log\\ -out D:\\output7.txt -province 全国 浙江 福建".split(" "));
     }
    

此处输入图片的描述

  1. 测试不列全国,列省份

     //测试不列全国,列省份
     @Test
     public void testProvince() {
     	InfectStatistic.main("list -log D:\\log\\ -out D:\\output8.txt -province 福建 江苏".split(" "));
     }
    

此处输入图片的描述

  1. 测试-type指定一个时

     //测试-type指定一个时
     @Test
     public void testOneType() {
     	InfectStatistic.main("list -log D:\\log\\ -out D:\\output9.txt -type sp".split(" "));
     }
    

此处输入图片的描述

  1. 测试-type指定多个时的输出顺序

    //测试-type指定多个时的输出顺序
    @Test
    public void testType() {
    	InfectStatistic.main("list -log D:\\log\\ -out D:\\output10.txt -type cure sp ip".split(" "));
    }
    

此处输入图片的描述

7.单元测试覆盖率优化和性能测试

学习资料:eclipse中代码测试覆盖率
覆盖率:
覆盖率

  • Coverage:代码测试覆盖率
  • Covered Instructions:覆盖到的指令行
  • Missed Instructions:没覆盖的指令行
  • Total Instructions:总指令行数

性能测试:此处输入图片的描述

内存使用情况:此处输入图片的描述

8.代码规范

https://github.com/FZU-YXJ/InfectStatistic-main/blob/master/041701320/codestyle.md

我的git仓库

9.心路历程与收获

  第一遍读题,毫无思路,有很多不理解的概念。什么是git,什么是github,GitHub desktop是用来干嘛的?fork是什么,commit是什么?pull request是什么? 命令行要怎么处理?单元测试是什么东西?作业中给的链接的知识点看了也不是能理解的很清楚,所以我只能自学许多知识。与此同时,还面临着java语法的遗忘。这次的作业让我收获很多,从一开始看缪雪峰的git教程,到后面学习命令行参数的处理,复习java对文件的读写操作,最后又学习了利用JUnite 4进行单元测试,利用JProfiler进行性能测试......勉勉强强掌握了这次作业要求的技能,学会使用GitHub,复习了java,学习了单元检测和性能测试的方法,以及对《构建之法》这本书的学习。
  正如《构建之法》中所说,软件=程序+软件工程:正是因为对软件开发活动(构建管理、源代码管理、软件设计、软件测试、项目管理)相关的内容的完成,才能完成把整个程序转化成为一个可用的软件的过程。软件工程包括了开发、运用、维护软件的过程中的很多技术、做法、习惯和思想。软件工程把这些相关的技术和过程统一到一个体系中,叫“软件开发流程”,软件开发流程的目的是为了提高软件开发、运营和维护的效率,以及提升用户满意度、软件的可靠性和可维护性。
  《构建之法》第二章的个人技术和流程以及软件工程师的成长,改变了我长期以来对我这个专业发展方向的很多困惑和误解,我一直觉得我作为一个程序员只要学如何写代码,顶多把数据结构和算法掌握清楚、操作系统和计算机网络的知识学习扎实,会写前端会折腾数据库就可以了。读了这本书之后我才明白自己其实离一个优秀的程序员还差得很远,努力得还远远不够。而且光局限自己把代码写好是远远不够的,团队协作、小组敏捷开发、迭代会议、单元测试和代码复审这些部分都是我之前完全不了解的。
  例如代码复审,目的是找出代码错误、发现逻辑错误、发现算法错误、发现潜在的错误和回归性错误、发现可能需要改进的地方、传授经验。“敏捷流程”是一系列价值观和方法论的集合。步骤大概就是,找项目,分配任务,每日例会报告目标和完成的任务,和自己遇到的问题。统一流程Rational Unified Process,团队的各种成员在一个复杂的软件项目中的不同阶段做不同的事。这些不同类型的工作在RUP中叫做规程或者工作流。分为四个阶段:初始阶段(达到生命周期目标里程碑)、细化阶段(达到生命周期结构里程碑)、构造阶段(达到初始功能里程碑)、交付阶段(达到产品发布里程碑)。MSF是微软解决方案框架。MSF过程模型是从传统的软件开发瀑布模型和螺旋模型发展而来的。MSF过程模型的基本元素是阶段和里程碑。

心路历程:
此处输入图片的描述

10.技术路线图相关的5个仓库

名称 链接 简介
很棒的机器学习 链接 精选的很棒的机器学习框架,库和软件的列表(按语言)
算法/python 链接 用python实现所有的算法
Deep Learning for humans 链接 用Python编写的高级神经网络API,能够在TensorFlow,CNTK或Theano之上运行。它的开发着眼于实现快速实验。能够以最小的延迟将想法付诸实践。
tensorflow 链接 TensorFlow提供了稳定的Python 和C ++ API,以及其他语言的非保证的向后兼容API。是用于机器学习的端到端开源平台。
神经网络和深度学习 链接 包含《神经网络与深度学习》一书的代码示例。该代码是为python2.6或2.7编写的。

[20320/codestyle.md

posted @ 2020-02-21 22:02  FZU_YXJ  阅读(150)  评论(2编辑  收藏  举报