软工实践寒假作业(2/2)
软工实践寒假作业(2/2)
这个作业属于哪个课程 | 2021春软件工程实践|S班 (福州大学) |
---|---|
这个作业要求在哪里 | 软工实践寒假作业(2/2) |
这个作业的目标 | 重新阅读《构建之法》并提出问题,学会使用GitHub管理代码,按要求编写程序 |
其他参考文献 | 《腾讯C++代码规范》 、SCDN |
目录
-Part1:重新阅读《构建之法》并提出问题
-Part2:实现WordCount程序
--- GitHub项目地址
--- PSP表格
--- 解题思路描述
--- 代码规范制定链接
--- 设计与实现过程
--- 单元测试
--- 异常处理说明
--- 心路历程与收获
Part1:重新阅读《构建之法》并提出问题
Q1、原文:P146.MSF团队模型
MSF模型定义了成员的角色和要职。疑问就是,成员不一定都是100%的高手,必然出现“短板”,不一定能达到质量目标,用雷达图来比喻就是图形不是正多边形。对于一个畸形的多边形,做出如何的选择才能让面积最大化,也就是目标最优化,这其中必然有取舍,如:牺牲时间,保证质量,但客户等不及;功能不完善,从而限制产品的使用方式,但很快就被市场淘汰......所以,在各种条件的约束下,怎样才做出好产品,满足需求?
Q2、原文:P176.计划、估计与决心
我觉得这是一个很不常见的问题却又十分重要,因为在我的周围很少人会对写代码进行系统一样的行为,多是把好的idea进行实现,或许已经在脑海里进行了计划但自己不知道。于是,这两个名词,我是第一次听到,我自己都很难想象。但我觉得,大项目或任务是肯定要提前规划的吧?以至于都还没开始进行,脑海里就已经有了宏伟蓝图。所以,计划、规划在我脑海里没什么轻重的概念,那我想形成这种思维,应该如何计划,做什么样的的计划?
Q3、原文:P362.创新的时机
对我来说创新的时机是一个很麻烦的事,我通常会在需求分析的进行创新。但现实是,一开始的创新或者过早的创新会对工作增加不成比例的难度,实现起来非常难,以至于严重阻塞任务进程。于是乎,放弃了一开始的不切实际的想法,尽量完成任务需求,直到完成。最后发现平平无奇的代码就产生了,然后又想进行创新,发现没地方下脚?或者一插足就立马遇到N多bug,然后工作又回到了原点。最后一种是我感觉最慢的方式,就是边进行工作边创新,毫无疑问问题是环环相扣的。所以,时机是在什么时候最恰当?
Q4、原文:P408.划分等级和公开刺激的做法
对团队成员进行ABC等级划分并贴上标签的做法,我觉得有没有一种情况是:对A会A+,对C会C-呢?在中间得B因为觉得无所谓,他会变成A或是C,虽然我们可能会说得看他本人。话虽如此,但我得想法是,划分等级和贴标签的出发点是什么?是鼓励员工吗?还是在筛选员工,C淘汰,A和B留下?说到底ABC什么的确确实实会存在,但员工并不像商品那样随意拨动。我觉得程序员在社会中应该是以复数的形式存在,一个人能力如何出众,脑子都有累的时候,一个人是不可能项目开发的,从需求分析到维护都是一个人的话?谁又会进公司呢?既然这种方式各有利弊,那么划分等级对程序员来说是好是坏?
Q5、原文:P422.大马哈鱼洄游模型
这个模型的名字挺有意思的,于是就仔细了解了一下。让我想起了我们大学里学专业课,貌似不是按照瀑布模型来的吧?从开学第一学期就在稳定阶段:学生开始写代码。可是没有在做需求分析阶段的事。这似乎很矛盾,《面向对象设计与分析》并不是入学的第一门课。假设,是第一门课的话,那么第一个学期内学生是不是都在对代码纸上谈兵呢?但又有人说,学好理论基础对敲代码不是好处更多吗?显然易见,一次瀑布模型感觉力度不够,于是多次瀑布模型才是大马哈鱼洄游模型。但是,这对普通的软件工程学生来说,我们不是成熟的大马哈鱼,洄游适合我们吗?还是说那是我们进社会的事了?(虽然我脑海里一直闪烁“优胜劣汰”)
Part2:实现WordCount程序
[GitHub项目地址](https://github.com/Lious-Rios/WordCount/tree/main/221801202)
PSP表格
-
PSP2.1 Personal Software Process Stages 预估耗时(分钟) 实际耗时(分钟) Planning 计划 • Estimate • 估计这个任务需要多少时间 4天 6天 Development 开发 • Analysis • 需求分析 (包括学习新技术) 120 150 • Design Spec • 生成设计文档 30 50 • Design Review • 设计复审 10 20 • Coding Standard • 代码规范 (为目前的开发制定合适的规范 40 30 • Design • 具体设计 60 70 • Coding • 具体编码 720 1200 • Code Review • 代码复审 50 40 • Test • 测试(自我测试,修改代码,提交修改) 600 540 Reporting 报告 • Test Report • 测试报告 120 90 • Size Measurement • 计算工作量 30 20 • Postmortem & Process Improvement Plan • 事后总结, 并提出过程改进计划 90 60 合计 4天内的1870min 6天内的2270min
解题思路描述
刚看到题目的时候,已经初步想好了对几个功能的实现:1.定义一个文章类Paper,里面有两个函数:fread()和fwrite()对文件进行操作,用map接收单词。2.单词类Words定义了有效词频。3.判断是否为分隔符的函数。4.判断是否为有效单词的函数。5.字符统计、行数统计、单词统计、词频统计。6.先词频排序,然后字典排序。
代码规范制定链接
设计与实现过程
-
Paper类
class Paper{//文章类 public: void fread(char * filename); void fwrite(char * filename); private: map<string,int> words; };
-
sort排序
int cmpare(const pair<string, int>& x, const pair<string, int>& y){ //value比较 return x.second > y.second; } void sort(map<string, int>& tMap,vector<pair<string, int> >& tVector){ //排序 for (map<string, int>::iterator curr = tMap.begin(); curr != tMap.end(); curr++) tVector.push_back(make_pair(curr->first, curr->second)); sort(tVector.begin(), tVector.end(), cmpare); }
-
判断的关键函数
bool isSeparator(char c){//判断分隔符:所有非数字且非字母 return !(isupper(c)||islower(c)||isdigit(c)); } bool isValidWord(string str){//判断有效单词 if (str.length()<4) return false; char c[10000]; strcpy(c,str.c_str());//转为字符数组 for (int i=0;i<4;i++){ if((!(isupper(c[i])||islower(c[i])))){ return false; } } }
-
行数获取
int CountLines(char *filename){//获取行数 ifstream ReadFile; int n=0; char line[wordsmax/wordsPerRow]; string temp; ReadFile.open(filename,ios::in);//用只读的方式读取文件 if(ReadFile.fail()){//文件打开失败:返回0 return 0; } else{//文件存在 while(getline(ReadFile,temp)!=NULL){ n++; } return n; } ReadFile.close(); }
-
特别注意
因为试了很多方法,最终选择了如下函数将FILE和file判断为同一个单词
transform(word.begin(),word.end(),word.begin(),::tolower);//读字符串转为小写字母
/*在fwrite()中对单词的操作*/ while (fin >> word) { transform(word.begin(),word.end(),word.begin(),::tolower); if(isValidWord(word)){//判断为有效单词 pair<map<string,int>::iterator,bool> ret = tMap.insert(make_pair(word, 1)); if (!ret.second) ++ret.first->second; wcnt++; } } vector<pair<string,int> > tVector; sort(tMap,tVector);
单元测试
-
代码覆盖率如下图,我是挺意外的,不知该喜该悲
异常处理说明
在对文件操作,方式为ios::in|ios::out时会覆盖原文件,因为我的几个统计函数是单独的,一直出现lines覆盖characters和words的情况,于是采用追加的方式。
fin.open("input.txt",ios::app|ios::out);//打开文件
fout.open("output.txt",ios::app|ios::out);
文件打开失败
if(!fin.good()){//情况一
cout<<"ifstream open file error"<<endl;
}
if(fin.fail()){//情况二
cout<<"ifstream open file error"<<endl;
}
if(!fin){//情况三
cout<<"ifstream open file error"<<endl;
return -1;
}
心路历程与收获
- 首先谈谈感触最深的地方:这次实践非常符合我内心的期望,尽管我绝对没做好,但是让“重新做人”的我认识到了,怎样去规划时间,想做快一点,实力不允许,效率地下;想做慢一点,时间不允许,效率低下。在期间,对于某个功能的实现让我陷入了死局,比如词频的排序(都还没涉及到字典),我第一个接触到的就是冒泡排序,这个的效率大家有目共睹。然后我尝试其他方法,什么都去尝试了,果然没让我失望,情理之中、意料之中的卡、死机,还有从没见过的error,我发誓,就算去百度了也只得到翻译,虽然看得懂。所以我把这种情况总结为:腿麻了的人想要奔跑——没实力。有点想自责,这是肯定的,而且并不归咎于其它因素。这一次战战兢兢地完成每一个功能,能实现到什么地步,心底没什么底,因此不能保证太高的正确率,因为瑕疵是有的,是真实存在的。那种“要是再给我一点时间,我肯定能完成”之类的没有自知之明的话,是极度不负责的,因为完成这道作业的时间是100%充裕的。完成作业后,我在深刻地反省。
- 然后谈谈非常不错的收获:毋庸置疑的是,多多少少学会github的使用。其次,耐心是最大的收获,不再有轻浮、自大的自我意识过剩,哪怕敲得再烂、再臭,我都敲出来了,不会就学、查资料,搞懂为止!懒惰是我最大的敌人,畏首畏尾、不敢去尝试是我最致命的弱点。于是前段时间我把自己关进小黑屋里敲代码,物理意义上的小黑屋!我要改变自己!