2021S软件工程——结对项目第一阶段
1020 1169
1 结对感受
总体来说,结对编程与之前的个人编程感觉有很大的不同。有如下几个方面:
- 在写代码的时候要慎之又慎,因为不仅要自己审核,也要面对同伴的审核,这是很重要的点。
- 如何配合也是一个很重要的点。怎样把时间有效的利用起来,而不是在消磨在内耗、扯皮上。
- 如果不能面对面编程,怎样利用好腾讯会议。
- 不同于单人编程,怎样在结对编程中复审。
从我们结对的情况来看,因为是第一次结对编程,遇到了很多未曾设想的困难,我就想当然的认为:结对编程嘛,就是他带电脑,我拿键盘,他写累了我写,我写累了他写的编程,有什么的呢?
-
不思考整体框架,直接上手:
但是上手之后就不一样了,往往伙伴敲了几行,我就会问他:你创建这个变量什么目的?这个问题你打算怎么解决?我们该怎样设计类?该设计怎样的接口呢?你这个方法是打算怎么设计呢?调用几个变量呢?用什么容器呢?......全是这样细枝末节的事情,导致的就是双人编程效率奇低,因为没有写几行就被打断了。
而且,两个人的话,不怎么适合深入思考,想的都是——我怎么赶快给伙伴一个答复,然后就删了改、改了删。我认为,这是因为我们没有提前写好设计文档,直接上手编程,想着脚踩西瓜皮,滑到哪里算哪里。这在这样的小工程、小项目还比较好说,但是到了大工程、大项目的情况下,就有可能遇到推倒重来的问题。应当对于整个软件的大体结构、框架有初步的认识,再开始编程。
-
不写注释,可读性差:
此外,双人的结对编程,比起单人编程,更加强调代码的可读性。当我们编写代码的单元测试的时候,发现很多方法仅仅靠一个方法名来望文生义,是不够的了解这个方法是做什么的。导致进行单元测试的时候,我需要重读方法,需要了解这个的大体流程,然后才能编写测试样例。最终测试本身花费了不少时间。
主要原因,是没有写注释的习惯。可能我们的编程还停留在——“功能完成就行”的程度,毕竟之前都是那样写的,写注释也不加分hhhhh,时间还那么紧,哪有时间写注释?但是仔细想想,其实重读代码的时间,不见得就比写注释少很多。而且写注释这件事情,实在是功在当代,利在千秋。注释应当包含:创作者、联系方式、变量用途、方法目的、输入格式、大体实现方法之类的增加程序可读性成分的东西。养成写好注释的方法是我们需要总结的事情。
-
任务分配不明确:
这主要体现在两个人的编程水平不同,对于项目涉及的领域所了解的深度不同。导致一个伙伴“能者多劳”,另一个伙伴“紧抱大腿”(说的就是我)。目前来看,因为作业给的时间本身就比较紧张,小组也想赶快把作业完成,而且交给弱鸡去写可能又慢、bug还多,会耽误太多的时间,然后就出现了上面的问题。(ps:某个弱鸡找到了bug还不会改,改了还引入新bug,还是大佬亲自下手操刀解决的问题。)我觉得可能不止我们小组存在这样的问题(也可能确实我们小组的弱鸡太菜了),那么任务应当怎样的分配呢。
我想作为被动的一方,应当主动阅读代码,主动理解代码的功能,主动去写设计文档和单元测试,总结的时候也要仔细考虑后续的迭代,主动了解集成测试、主动了解怎么写单元测试。否则总是做这种紧抱大腿的事情不好hhhhh。
总体而言,目前来看,遇到的很大的问题就是以上所列举的。结对编程,或者是未来的团队编程,怎么做好交流是一个很重要的课题:怎样能够有效交流?怎样能够不浪费时间?
这些问题是我们之后的编程过程中会不断遇到、不断磨合的。而遇到这些问题总结的经验,可能在我们之后的生产实践中会用得上。
2 设计与实现思路
设计思路:
- 将文件与目录的共性特征抽象出来,建立一个父类
- 整个文件系统为树形结构,根节点即为根目录,每个目录/文件为一个节点,每个节点记录自己的父节点
- 文件为叶节点、目录可以有子节点
- 创建、删除操作即对文件系统树增加、删除节点
- 对文件有特殊的写入操作
- 文件系统类中记录当前所在节点,cd操作时更新该记录
实现思路:
根据以上的设计思路,抽象出了四个类:MyFileSystem
File
Directory
FileOrDirectory
,其中,FileOrDirectory
为File
Directory
的父类。
MyFileSystem
继承官方包的FileSystem
类,实现相关方法
FileOrDirectory
的设计如下:
成员变量:
private final String name;
private BigInteger size;
private final int createTime;
private int modifyTime;
private Directory prev;
方法:
public int getModifyTime();
public void setModifyTime(int modifyTime); //在文件或目录发生变化时调用
public void setSize(BigInteger size); //在文件或目录大小发生变化时调用
public BigInteger getSize();
public String getName();
public Directory getPrev();
public void setPrev(Directory prev); //为根目录特殊设计
public String getAbsolutePath(); //获取当前文件或目录的绝对路径
public String getInfo(); //获取Info
File
类增加成员变量content
,并有写入/修改content
的方法,并且修改时更新直到根目录的所有目录大小,较简单。
Directory
类设计如下:
成员变量:
private final HashMap<String, Directory> subDirs;
private final HashMap<String, File> files;
使用HashMap
存储子目录和子文件,实现使用文件或目录名字作为key
,需要查询复杂度较低。
方法:
public void addDir(Directory subDir, int modifyTime);
public void addFile(File file,int modifyTime);
public Directory getSubDir(String name);
public File getFile(String name);
public boolean nameDuplicated(String name); //判断是否重名
public String getList(); //获取所有子目录和子文件
public void deleteFile(String name, int modifyTime); //删除文件时更新直到根目录的目录大小
public void deleteDir(String name, int modifyTime); //删除目录时更新直到根目录的目录大小
整体的uml图如下:
3 时间记录
PSP2.1 | 预估耗时(分钟) | 实际耗时(分钟) |
---|---|---|
Planning | 20 | 10 |
·Estimate | 20 | 10 |
Development | 800 | 990 |
·Analysis | 30 | 120 |
·Design Spec | 60 | 20 |
·Design Review | 30 | 10 |
·Coding Standard | 10 | 10 |
·Design | 30 | 20 |
·Coding | 300 | 420 |
·Code Review | 60 | 30 |
·Test | 300 | 360 |
Reporting | 120 | 120 |
·Test Report | 60 | 70 |
·Size Measurement | 30 | 20 |
·Postmortem & Process Improvement Plan | 30 | 30 |
Total | 940 | 1120 |