小组github项目地址:https://github.com/SSS-SY/wordcount-pro
基础功能:
一. PSP表格
PSP2.1 | PSP阶段 | 预估耗时 (分钟) | 实际耗时 (分钟) |
Planning | 计划 | ||
· Estimate | · 估计这个任务需要多少时间 | 30 | 25 |
Development | 开发 | ||
· Analysis | · 需求分析 (包括学习新技术) | 10 | 5 |
· Design Spec | · 生成设计文档 | 20 | 25 |
· Design Review | · 设计复审 (和同事审核设计文档) | 15 | 15 |
· Coding Standard | · 代码规范 (为目前的开发制定合适的规范) | 5 | 5 |
· Design | · 具体设计 | 10 | 10 |
· Coding | · 具体编码 | 30 | 15 |
· Code Review | · 代码复审 | 15 | 10 |
· Test | · 测试(自我测试,修改代码,提交修改) | 20 | 10 |
Reporting | 报告 | ||
· Test Report | · 测试报告 | 15 | 10 |
· Size Measurement | · 计算工作量 | 5 | 5 |
· Postmortem & Process Improvement Plan | · 事后总结, 并提出过程改进计划 | 10 | 10 |
合计 | 185 | 145 |
二.代码实现
在讨论过后,我们将任务划分为四个模块,具体模块和分工如下:
1. 词频统计
功能描述:统计各个单词的出现次数
接口描述:输入一个字符串,输出一个map结构
负责该模块的小组成员:庹舒月
2. 词频排序
功能描述:将统计结果进行排序
接口描述:输入一个map结构,输出一个vector结构
负责该模块的小组成员:俞亮
3. 输出模块、构造和析构函数、文件长度函数
功能描述:
(1). 输出模块:输出结果到result.txt文件
(2). 构造和析构函数:类的构造和析构函数
(3). 文件长度函数:获取输入文件长度
接口描述:
(1). 输出模块:输入一个vector结构,输出一个result.txt文件
(2). 构造和析构函数: 无
(3). 文件长度函数:输出文件长度
负责该模块的小组成员:辜之皓
4. 输入模块、主函数和架构设计
功能描述:
(1). 输入模块:读取文本为一个字符串对象
(2). 主函数:调用其他小组成员的接口,是主要逻辑
接口描述:
(1). 输入模块:输出一个字符串对象
(2). 主函数: 无
负责该模块的小组成员:唐明华
实现描述
我负责的是输入模块、主函数和架构设计
架构设计部分,我考虑将整个程序实现为一个类,将其他成员实现的功能定义成各个成员函数或功能函数,类的定义如下:
class WC { public: typedef std::vector<std::pair<std::string, int>> WordSet; typedef std::unordered_map<std::string, int> WordMap; explicit WC(const char* filename); ~WC(); WordSet simple_count(); WordSet parallel_count(); private: int file_length(); std::FILE* _fp; ThreadPool _pool; }; WC::WordMap word_count(std::string); WC::WordSet word_sort(const WC::WordMap&); void output_result(const WC::WordSet&);
输入部分,使用标准库的fopen函数读取字符,存入一个缓冲区,再初始化为一个string对象,传入其他部分
主要逻辑部分,调用其他成员实现的各个函数,总体代码如下:
WC::WordSet WC::simple_count() { int size = file_length(); char* buff = new (nothrow) char[size + 1]; if (!buff) { return {}; } fread(buff, 1, size, _fp); WordMap wm = word_count(string(buff)); return word_sort(wm); }
三.测试用例
使用了google test框架进行测试
输入部分设计了3个用例,简单的测试了在不同文件大小下是否能正常申请缓存区,以及文件不存在时是否能够正确处理
词频统计部分设计了10个用例,测试了基本功能是否正常、能否正常处理'-'、能否正常处理数字以及其他特殊符号的问题
词频排序部分设计了7个用例,测试了基本功能是否正常、词频相同时如何排序、同一个单词大小写如何排序、出现'-'时如何排序等问题
具体的测试用例如下:
单元测试截图:
测试质量和评价:
感觉把该测的情况都写了一遍,测试过程中没有发现什么问题,说明代码质量良好
四. 小组贡献
经过讨论,各个小组成员根据自己的参与情况、代码质量和代码量得出了如下评分:
庹舒月: 0.28
辜之皓: 0.26
唐明华: 0.23
俞亮: 0.23
扩展任务
一.代码规范
因为我们选择了C++语言进行开发,所以参考了google style guide
我阅读了google style guide之后,发现有一个规则十分有用
在设计一个函数时,关于传引用还是传指针的问题,如果函数需要修改相应的对象,则传指针可以让使用者能够更清楚地意识到他传入的对象将被修改
可以说解决了我很久以来对这个问题的疑问,十分受用
二.选择静态测试工具
使用了google官方提供的cpplint工具进行测试
下载链接:https://github.com/cpplint/cpplint
三.同行评审
经过一定的讨论,我们决定唐明华和庹舒月之间进行代码互评,辜之皓和俞亮之间进行代码互评
我使用cpplint工具对庹舒月的代码进行了检查,输出结果如下:
因为我们都使用了auto formatter工具,所以没有什么代码风格方面的大问题,在其他的设计上,我们互相间也觉得对方的实现遵守了google style guide的规范
重新运行单元测试,结果如下:
四.问题总结和反思
总体来说,经过仔细阅读google style guide,配置了auto formatter,以及各自的debug过程之后,各个小组成员的代码都没有出现什么大问题
高级任务
一.测试数据
我们找了莎士比亚全集的英文版txt文档,有5Mb大小
使用这个数据,我们测试后发现大致需要3秒的时间才能处理完整个文件,运行截图如下:
二.组内评审
针对可能影响程序性能(制约因素),我们小组进行了组内评审,讨论。
主持:
庹舒月
评审:
唐明华、辜之皓、俞亮
评审主题:
1.影响程序性能的主要因素
2.有何建议
讨论结果:
我们讨论之后认为,主要的性能瓶颈在于需要读取整个文件之后再开始统计,因为磁盘读写的速度非常慢,导致了整个程序运行效率低
解决方案:
使用多线程,一边读取数据,一边开始统计读取部分的数据,之后再将各个部分的统计结果合并,可以大大提高性能
三.修改之后的结果
修改之后程序性能有了成倍的提高,运行时间大概在0.7秒左右,提高了大约4倍的性能
运行截图如下:
四.心得体会
经过这次作业,我深深地感受到软件开发、软件测试、软件质量三个过程是密不可分、息息相关的
参考链接:
1. c++参考手册:
http://zh.cppreference.com/
2. goole style guide:
https://github.com/google/styleguide/