软件工程寒假作业(2/2)

这个作业属于哪个课程 2021春软件工程实践S班
这个作业要求在哪里 点这你就知道了
这个作业的目标 <阅读《构建之法》提出问题,编写程序,学会使用github管理代码>
其他参考文献 腾讯C++规范参考

part1:阅读《构建之法》并提问

Q1.构建之法8.3获取用户需求中,提到“A/B测试”以及其弱点,但我认为判断A/B测试是否做过头很难,当你意识到
做过头时候,用户都跑光了。(比如我玩的梦幻西游,就因为全新的建模导致一群人弃坑)所以选择性的拿老用户当
“小白鼠”会不会更合适?(比如美团试探性的增加老用户的配送费)

Q2.构建之法8.7的WBS(分治)中提到做好WBS的要点中,认为“要从结果出发,而不是团队的活动” 的意思是,两者
是优先级先后关系吗?如果是这样我认为,其实团队的活动也很重要,因为整个工程肯定得交流的好,分工合理才能
井井有条否则做出来也是残次品。后期维护沟通也麻烦。

Q3.构建之法16.3.4中提出产品的生命周期各个阶段,通过“动量”“加速度”来判断,产品到底属于成熟期,还是衰弱
期,但一般来说衰弱期再往后留下的都是老用户,如果是游戏,他们往往会舍不得离开,如果此时导入新鲜血液,刺
激消费,或许某些情况下,会比文章中提到的“以低成本维护产品”会好呢?亦或者像很多国产游戏一样是在快关服的
时候宰一刀老玩家跑路。

Q4构建之法16.1.3中提出创新之人,如何让别人接受自己的创新中提到“目前大众习惯,已有系统是否兼容”。这句话
的意思我感觉自我矛,。这样子只能算是改进,而不是创新不是吗?

Q5.在构建之法NABC框架模式中有人提到的“D”推广,指出Delivery是在前人实践后意识到Delivery的重要性,那这个
D是跟开发人员 完全无关的吧,在我的认知中推广似乎和技术层面没什么太大的关系吧.所以书中只是提及一下子,并没
有什么太深刻的意思是吗?

附加题: “关于goto语句的争论“”
软件工程热门以来,就有一个一直很火被历代程序员交流的话题——"goto语句"。1974年,D·E·克努斯对于GOTO语句争论
作了全面公正的评述,其基本观点是:不加限制地使用GOTO语句,特别是使用往回跳的GOTO语句,会使程序结构难于理解
,在这种情形,应尽量避免使用GOTO语句。goto语句一直都是讨论的热点,其实我还是觉得,存在即合理,既然goto被人
诟病这么多年仍然没被彻底的摈弃,说明还是有一定的用武之地,就比如跳出很多层的循环,如果不用goto就得额外多设
置很多的判断条件,循环的代码的可读性上就会大大下降,也不便于维护。所以虽然我不怎么用,也会尽量避免,但我还
是觉得goto语句正如D·E·克努斯的意见应该尽量避免,而不是完全不用。

part2:WordCount编程

Github项目地址

github网址

PSP表格

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

解题思路描述

题目主要要求的无非三点,字符数,单词总数,行数。字符数一个个字符的接收然后统计
行数的话用的是getline方法一行行分析的也没什么太大的问题。这个单词总数有点歧义
本想用 两个空格 来锁住一个单词,但后来发现123file123这种不能算作单词,后根据
需求先把两个空格之间的提取出来content,先检测长度是否大于4.因为“ is” 这种的其
实也不能算作单词再检测content的前四位是否都是字母用ASCII来检测

代码规范制定链接

规范链接

设计与实现过程

统计字符数

fstream infile(argv[1],ios::in);
//以下为fstream关键代码
while(!infile.eof())
	{
		char ch;
		infile.get( ch ); 
		a++;
	}
	a-=1;//因为会多读入一个 \0结尾 不在本次要求当中 

统计行数

while(outfile.getline(str,256))
	{ 
    	int tmp = 0;  

    	for(int i = 0; i < strlen(str); i++)
		{	  
	  		if(isnum_str(str[i]))
	  		{ 
				//cnt[0]++;   //曾经想用cnt[0]记字符数后来发现行不通
			        tmp++;     //统计字符数,tmp局部变量用来区分是不是一个空行。
			}    
	}	
	if(tmp != 0){
		cnt[2]++;	//统计行数
	}                
	tmp = 0;
}

统计单词数 可以分为判断是否是一个单词,以及记录是单词的单词两个部分

第一部分判断的主要代码

string::size_type start = 0;
		string::size_type end = eachline.find_first_of(".,?! ");
		int flag=0; 
		while (end != string::npos) //npos就是这一行到头啦;
		{
			string content = eachline.substr(start, end - start);
			map<string, int>::iterator it = mapA.find(content);
			if(content.length()>3&&is_lower_alpha(content[0])&&is_lower_alpha(content[1])
			&&is_lower_alpha(content[2])&&is_lower_alpha(content[3]))//判断是否前四个都是字符 
			{				
				if (it == mapA.end())
				{
					mapA.insert(pair<string, int>(content, 1));//赋值的时候只接受pair类型;
				} else
				{
					++it->second;
				}
			}			
			start = end + 1;
			end = eachline.find_first_of(".,?! ", start);			
		}

第二部分 记录单词总数的代码:

利用map的特性会根据key自动排序,就省去自己从大到小排序词频了,其中mapA是初记录
也是排序用样长度则首字母以a b c 这样排序 mapb则在mapa基础上再将 单词以频率降
序排列

	word_count=0;
	for (map<string, int>::iterator it1 = mapA.begin(); it1 != mapA.end();++it1)
	{
		mapB.insert(pair<int, string>(it1->second, it1->first));//方便map自动根据出现次数排序 
		word_count+=it1->second;//顺手统计 
	}

性能改进

最初判断是否符合“单词的定义”,我将所有的条件层层嵌套

if(is_lower_alpha(content[0])){
    if(is_lower_alpha(content[1])){
        if(is_lower_alpha(content[2])){
              if(is_lower_alpha(content[3])){
                          ++it->second;
                    }
          }
    }
}

这样子实在是太浪费时间了,层层嵌套,看似逻辑有序,实则避免了很多不必要的判断
例如如果content本身就不到四个字符 比如is the 这种 又何谈单词?于是我将所有
判断条件结合在一切少去很多不必要的 判断

	if(content.length()>3&&is_lower_alpha(content[0])&&is_lower_alpha(content[1])
			&&is_lower_alpha(content[2])&&is_lower_alpha(content[3]))

单元测试

单元测试为了方便快捷,现设计出自我测试的函数

void test(ofstream &t){//测试函数 
	for(int a=0;a<100000000;a++){
    	t<<"ddaa ";
    	if(a%50==0&&a!=0){//每行字符数 
    		t<<"\n";
		}
	}
}
  • 对于一些小的测试就不放出统计时间了直接上图

box
异常测试,抛出提示
box
box
识别空白行非有效行,以及各种标识符
box

大数据下的测试程序性能5000w左右的字符程序在5s左右可以算出,由于vs的单元测试方法与其类似
但并无代码覆盖率的功能我就利用c++自带的clock来计算 对应模块从开始到结束 所花的时间
box
5e 相当于500M的文件需要50s左右可见 计算功能的时间复杂度是线性递增的
box
代码覆盖率如下
box

异常处理说明

本次的异常,程序经测试会自动忽略中文,所遇到的异常错误,目前为止只是文件格式异常
或者是失误操作,一般来说文本内容不会集中在一行,所以有些文本例如一行单词太多的。
会直接抛出异常,此时output文件中会提示错误

心路历程与收获

      通过本次的作业,我意识到了团队合作的重要性,我和预期相差最大的就是代码复审,当我选择和我同学连麦一起做的时候
我总会被他看似找茬,实则有用的建议不断的重写,重写再重写代码,合作伙伴总能想到我很多想不到的测试点,这也让我
花了更多的时间在复审,和测试上。
      同时也是第一次接触单元测试,在我好不容易搞清楚如何用vs进行c++的单元测试后(实际上我又花了好多时间重装,下载
vs包括清c盘)我发现单元测试的原理不过是测试每个接口的性能,既然如此,我干脆就自己写一个测试行数,一是因为c盘满了vs
很多东西装不上,而且下载的特别慢因为不是国内的网络,而且我找不到代码覆盖率在哪。这也说明了这次作业我的另外一个弊
端,就是起步慢。因为过年那几天实在不想写,导致后面没有很多时间去弄清楚一些,根本没搞懂的东西。(我重装vs测试的时
候已经是快截止了)而且装了也测试不了代码覆盖率。可能以后更适合我的方法是笨鸟先飞吧。
      同时我也意识到代码规范性的东西重要性,最显著的区别就是,我其实是先写代码再改规范性的。这就让我在改规范性之前
自己都有点看不懂自己的代码(因为是断断续续做的)。

posted @ 2021-03-03 20:42  本多猪四郎  阅读(265)  评论(16编辑  收藏  举报