寒假作业(2/2)
| 这个作业属于哪个课程 | 2021春软件工程实践 W班(福州大学) | 
|---|---|
| 这个作业要求在哪里 | 寒假作业(2/2) | 
| 这个作业的目标 | 1、阅读《构建之法》并提出问题 | 
| 2、完成词频统计作业 | |
| 其他参考文献 | ... | 
任务一
问题一 :结对编程是否一定比个人开发更具效率?
得益于随时的复审和交流,结对编程在一定程度上能够弥补个人在开发过程中视野的局限性。
但同时在人力资源上,需要付出双倍的人力成本。结对编程带来的效率提升是否能弥补所带来的成本问题?
个人认为,结对编程适合在开发中大型,时间需求长的项目中,这类项目往往需要花费程序员大量时间精力,且一旦出现错误,可能会影响到整个项目的进度,结对编程能够减少开发初期的错误,显著提高个人开发的效率。
但同时我认为结对编程对程序员的水平有要求,结对的程序员在编程水平上应该相当至少不能差距太大。结对编程在各方面的质量取决于水平高的一位,如果两个人水平差距过大,一个人根本看不懂另一个人在写什么,而水平高的又往往会被水平低的拖慢进度,从而造成两个人效率的损失。
问题2:当软件开发者认为的需求和客户的需求不一致甚至出现冲突时怎么解决?
我认为原则上软件服务于客户,当两者需求不一致时,应当优先满足客户的需求,客户在整个开发过程中仍然是第一主体,客户的需求满足之后,在着手开发另外的需求。
当两者需求发生冲突时,开发团队就必须权衡两者的利弊关系,如果开发者认为的需求能在未来提供更大的收益以至于放弃部分客户也在可接受范围之内,否则依然遵循客户第一的准则。
问题3:什么时候该改良代码,什么时候该重构代码?
问题4:不是非常能理解为什么“魔方理论”最后要将魔方返回混乱的状态。
问题5:书中提到了很多软件被长期使用之后,软件会越发难用。当一个软件在交付给用户以后,用户经过长期使用,对软件产生了厌倦,使得用户丢弃了软件,那么在这种情况下,是用户还是软件开发团队的错误使得软件被弃用呢?
任务二
项目地址
PSP
| PSP2.1 | Personal Software Process Stages | 预估耗时(分钟) | 实际耗时(分钟) | 
|---|---|---|---|
| Planning | 计划 | ||
| • Estimate | • 估计这个任务需要多少时间 | 580 | 995 | 
| Development | 开发 | ||
| • Analysis | • 需求分析 (包括学习新技术) | 60 | 45 | 
| • Design Spec | • 生成设计文档 | 60 | 45 | 
| • Design Review | • 设计复审 | 10 | 10 | 
| • Coding Standard | • 代码规范 (为目前的开发制定合适的规范) | 30 | 10 | 
| • Design | • 具体设计 | 60 | 45 | 
| • Coding | • 具体编码 | 180 | 600 | 
| • Code Review | • 代码复审 | 60 | 60 | 
| • Test | • 测试(自我测试,修改代码,提交修改) | 120 | 180 | 
| Reporting | 报告 | ||
| • Test Repor | • 测试报告 | 70 | 70 | 
| • Size Measurement | • 计算工作量 | 10 | 10 | 
| • Postmortem & Process Improvement Plan | • 事后总结, 并提出过程改进计划 | 60 | 60 | 
| 合计 | 650 | 1065 | 
解题思路
将题目划分为三个部分:文件的输入、文件的处理、文件的输出。
其中文件处理又包括行数统计、单词判定、单词统计、字符统计、非法字符处理等。
输入和输出部分采用fstream类 每次读取单个字符 当读取到换行符时交由字符处理程序 这样每次处理都是一行 节省了判定行数的时间
在存储单词频率的部分 采用哈希表存储 能够在处理字符时加快查找速度 最后再对哈希表进行排序
代码规范制定链接
设计与实现过程
类的设计
AppData负责程序主要的数据存储
TxtInput负责输入流,从文件中读取数据
TxtOutput负责输出流,向文件输出结果
CountChar字符处理
WordCount主函数

具体实现
- AppData
class AppData
{
public:
	static AppData singleton;
	int number_asc;//字符数
	int number_words;//单词数;
	int number_line;//行数
	unordered_map<string, int>words;//单词频率
};
- TxtInput
class TxtInput
{
public:
	 ifstream in;
	TxtInput(string filename)
	{
		in.open(filename, ios::in);
		if (!in.is_open())
		{
			cout << "打开文件失败!" << endl;
		}
	}
};
- TxtOutput
static bool cmp(pair<string, int>&p1, pair<string,int>&p2)
	{
		return p1.first < p2.first;
	}
	void OutTxt(AppData* data)
	{
		out << "characters: " << data->number_asc << "\n";
		out << "words: " << data->number_words << "\n";
		out << "lines: " << data->number_line << "\n";
		vector<pair<string, int>>::iterator it;
		vector<pair<string, int>> all(data->words.begin(), data->words.end());
		sort(all.begin(), all.end(), TxtOutput::cmp);
		for (it = all.begin(); it != all.end(); it++)
		{
			pair<string, int>temp = *it;
			out << temp.first + ": " << temp.second << "\n";
		}
	}
- CountChar
class CountChar
{
public:	
	 static bool isEmptyLine(string word)
	 {
		 for (int i = 0; i < word.length(); i++)
			 if (word[i] != ' ')
				 return 0;
		 return 1;
	 }
	 //判断是否是单词
	 static bool isWord(string word)
	 {
		 if (word.length() < 4)
			 return 0;
		 for (int i = 0; i < word.length(); i++)
		 {
			 if (i <= 3 && (word[i] < 'a' || word[i] > 'z'))
				 return 0;
			 if (!CountChar::numebr_letter(word[i]))
				 return 0;
		 }
		 return 1;
	 }
	 //判断是否是字母数字
	static bool numebr_letter(char c)
	 {
		 if (c >= '0' && c <= '9')
			 return 1;
		 if (c >= 'a' && c <= 'z')
			 return 1;
		 return 0;
	 }
};
计算模块接口部分的性能改进
性能
- 数量:100万行 大约1500万左右字符
 时间21.236s
  
- 数量 :10万行 大约150万左右字符
 时间:2.365s
- 数量 :1万行 大约15万左右字符
 时间:0.29s
因为程序使用单进程 导致CPU占用率较低 大部分时间都在I/O
程序处理能力约为75w字符/s
改进
因为算法基于对单个字符的处理 在不改变输入方式的情况下只能对字符处理方面进行优化
但效果不佳
计算模块部分单元测试展示

- 测试代码
TEST_CLASS(UnitTest1)
	{
	public:
		
		TEST_METHOD(TestMethod1)
		{
			bool is_line = CountChar::isEmptyLine(" ");
			Assert::AreEqual(true, is_line);
		}
	};
	TEST_CLASS(UnitTest2)
	{
	public:
		TEST_METHOD(TestMethod1)
		{
			bool is_Word = CountChar::isWord("1234word");
			Assert::AreEqual(false, is_Word);
		}
	};
	TEST_CLASS(UnitTest3)
	{
	public:
		TEST_METHOD(TestMethod1)
		{
			bool is_Word = CountChar::numebr_letter('s');
			Assert::AreEqual(true, is_Word);
		}
	};
异常处理说明
- 文件不存在
in.open(filename, ios::in);
		if (!in.is_open())
		{
			cout << "打开文件失败!" << endl;
		}
- 非法字符串
 已经在字符串处理程序做了处理 任何非法字符都会被替换成空格
总结
- 单线程程序在处理大量数据的时候是非常艰难的
- 在写代码过程中vs因为某种原因崩溃 vs不会自动保存 所以代码托管还是很有必要的
- 本次作业代码难度不高 但是细节很多 编程时候并不困难 反倒是在后期测试和优化花了大量的时间

 
                
            
         浙公网安备 33010602011771号
浙公网安备 33010602011771号