一、Planning:
PSP2.1 |
Personal Software Process Stages |
Time |
Planning |
计划 |
|
· Estimate |
· 估计这个任务需要多少时间 |
2h |
Development |
开发 |
|
· Analysis |
· 需求分析 (包括学习新技术) |
2h |
· Design Spec |
· 生成设计文档 |
1h |
· Design Review |
· 设计复审 (和同事审核设计文档) |
1h |
· Coding Standard |
· 代码规范 (为目前的开发制定合适的规范) |
30min |
· Design |
· 具体设计 |
1h |
· Coding |
· 具体编码 |
3h |
· Code Review |
· 代码复审 |
1h |
· Test |
· 测试(自我测试,修改代码,提交修改) |
3h |
Reporting |
报告 |
|
· Test Report |
· 测试报告 |
1h |
· Size Measurement |
· 计算工作量 |
30min |
· Postmortem & Process Improvement Plan |
· 事后总结, 并提出过程改进计划 |
1h |
合计 |
17h |
二、Development:
1、需求分析
对题目中的要求进一步剖析,明确要注意的点以及需要进一步明确的技术等。
- 参数内容的获取方式
- 按照算术表达式的生成语法规则来进行构造和解析,空格将作为分隔符号,并且应该注意需求345的约束条件
- 对于重复问题,先判断结果是否相同,结果相同再判断他们是否能够通过有限次的交换来转化
- 将题目和答案分别记录到相应的文件中去
- 对给定的题目和答案文件进行判定,需要解析题目的语法
2、生成设计文档
a) 类的创建:
i. 根据计算的需求,在这个项目中需要对自然数和分数进行运算,那么就有必要创建一个新的类用于表示自然数和分数
于是设计一个class Item,其主要的成员变量是 denominrator(分母)和numerator(分子);
然后重载+-*/这四个运算符来实现计算;
同时还有一个关键的函数是toString(),用于方便后面放进具体的表达式中。
ii. 最终是为了生成表达式,那么就需要创建一个表达式类class Expression
其主要的成员curValue 来记录当前表达式的值,expressionString用于记录表达式的字符串形式,level用于记录当前表达式有多少个运算符,lastoperator用于记录最后一个运算符的类型;
同时为了后面能够判断表达式是否重复,还分别记录了表达式中各种运算符号的个数,并且将生成过程中的子表达式的值也给保留了;
然后在构造函数中,需要的参数是数的范围以及运算符的数目,具体的表达式构造方式请见下一部分。
b) 表达式的生成方式:
主要是根据表达式中运算符的数目,利用递归的方式从更简单表达式(运算符数目更少)生成。比如2运算符-表达式可以用1运算符-表达式加上一个符号一个操作数来生成。于是,我决定采用的方式是:先生成1-运算符的表达式,再用它去生成2-运算符表达式,然后再考虑生成3-运算符表达式。这个生成顺序也是我的计算顺序,相当于先 生成的表达式我都保证运算时优先,这时候如果它的最后运算是加减法我就加上括号。
这样一来生成的表达式的值我就能够很好地把控住。
c)如何判断重复,以及如何解决参数要求是否能够满足:
用排列组合的方法也只能差不多推导出上界和下界,然而好像并不能很好得去确定是否能够生成足够的不重复表达式。所以我还是偏向于从概率的角度,如果连续生成的好几个新的表达式都被判断出与已有的表达式重复,则说明可能差不多无法再生成不重复的表达式,就直接终止程序。
而如何重复就是用我的表达式对象中的各个参数进行比较,如果都相等,这个时候重复的概率非常大,所以直接舍去。
d) 对于检验对错:
就是解析字符串,先将中缀表达式转换成后缀表达式,然后将后缀表达式进行求值,这个过程中利用了栈之后将很好完成。
3、设计复审
4、代码规范
(这两个方面在实际过程中几乎是隐藏在和同学们的交流和讨论中的,没有很严肃严格得进行这两个环节)
5、具体编码
这个过程是整个项目开发中费时最多的环节,然后也是烦恼最多的部分,遇到了很多细节问题和bug。具体有以下几个方面:
a) 字符问题:由于考虑输入输出中有extend ASCII, 也就是× 和÷ 号,所以在处理过程还是费了很多时间去弄明白它们在char, char*和string中的存储方式,最后试验之后还是发现使用起来比较方便。
b) 运算方面的细节问题:有一些表达式的逻辑没能处理得很好,然后有一些漏洞,最后在分析计算结果的时候花费了较大的时间。
这个方面我觉得可能以后注意在开发的过程中注意单元测试,然后尽量在小规模代码下将基本问题解决,可能会有利于问题的解决。
c) 涉及语言的熟悉度方面的问题。(在点滴中消耗了很多时间)
6、代码复审
主要是debug,然后解决的分别是字符问题,输入输出问题,运算正确度问题。
7、测试(这个部分也是我判断自己程序正确性的初步环节)
首先测试各种参数组合形式的输入。
再来是尝试生成表达式,并且抽样检查是否规范。
接下来是输入特定组合的表达式,检查求值情况。
多轮下来,最后发现基本没有什么问题。
三、性能分析与优化
在分析性能的时候选的参数是-n 10000 -r 20
在性能问题上主要是后期生成的每个表达式都需要与前面生成的大量表达式进行判重。能明显觉察到后期生成表达式的速度变慢了。
为了能够进一步优化的时间的复杂度,可以选择考虑用新的结构将表达式组织起来,从而能够更快的判断是否重复。
经过和同学们的讨论发现,其实有几个同学采用的就是打表的方式,每生成一个表达式划掉一个值,这样判断重复就快多了。
总结:
实际的使用时间
PSP2.1 |
Personal Software Process Stages |
Time |
Planning |
计划 |
|
· Estimate |
· 估计这个任务需要多少时间 |
1h |
Development |
开发 |
|
· Analysis |
· 需求分析 (包括学习新技术) |
2h |
· Design Spec |
· 生成设计文档 |
2h |
· Design Review |
· 设计复审 (和同事审核设计文档) |
1.5h |
· Coding Standard |
· 代码规范 (为目前的开发制定合适的规范) |
1h |
· Design |
· 具体设计 |
2h |
· Coding |
· 具体编码 |
6h |
· Code Review |
· 代码复审 |
1h |
· Test |
· 测试(自我测试,修改代码,提交修改) |
3h |
Reporting |
报告 |
|
· Test Report |
· 测试报告 |
1h |
· Size Measurement |
· 计算工作量 |
0.5h |
· Postmortem & Process Improvement Plan |
· 事后总结, 并提出过程改进计划 |
2h |
合计 |
23h |
四、收获与感悟
1、关于程序存在的几点漏洞说明:
a) 对程序的输入格式要求比较严格
比如在检验四则运算的正确性这个环节,我的程序的读入方式要求在序号的“n.”后面紧跟着一个空格,然后再是表达式或者答案。
其实这个问题在使用过程中还是会存在一些问题的,因为没有给用户进行提示说明就将输入的格式限制住了,其实对用户体验来说不是很好,下一轮要改正这个缺陷。
b) 在性能上面存在一些缺陷
在这里比较表达式是否重复实际上是O(n2)的复杂度,或许可以采用某些特殊的方式在这里进行优化。
2、关于项目开发的计划、设计与实现方面的体会:
我个人的体会是计划固然是非常重要的,但是在现阶段个人能力以及经验还是明显不够的,所以在对项目各个阶段用时的估计上面会过分乐观,结果反而容易造成在开发过程中对时间的把控显得不够,影响整个开发的节奏。
然后是设计与实现,设计应当细化到什么程度呢?
这是我一直很疑惑的问题。经过这么多次的类似项目(作业)的实践经历,我想我认识到了一点,对我个人来说,一定要勇敢去实践,因为对我个人来说,我喜欢将很多东西放到脑袋里面然后让它不断发酵,同时让自己在有意无意中去产生灵感、好的想法来解决问题,这种方式有时固然能够带来很多惊喜,但是同时也让我越来越不重视编码的这个过程,而实际上在编程过程中无论是语言工具的使用还是算法的运用方面都会遇到一些小的阻碍。
所以我认为现阶段我给自己定的提高方法是:增加敏捷度。提高设计的效率,然后在实现的过程中去不断碰到问题解决问题。有时不是要越过问题,而是要通过对相关问题理解认识来旁敲侧击,从而在主要问题上面有新的理解和认识。所以要习惯于专注编程的过程,在这个过程中不断优化设计,不但回归理论和知识,然后甚至多次迭代。
毛主席《实践论》中的哲理也可以用到设计和具体实现过程中来,要两者不断补充,从而使提高开发效率,提高产品质量。
3、在个人习惯和心态方面的感悟
看到有的同学做的PSP安排和规划,确实感觉到了软件工程师的个人习惯和态度在很大程度上会决定它的项目是否能够顺利在预期时间内完成,并且在很大程度上会影响产品的质量。
发现自己确实在今后这门课的学习上面要更加投入一些,珍惜这次锻炼的机会,借助这次课的机会好好体验软件开发以及团队合作,开发出让人满意的产品。