软件工程结对作业——第三阶段

项目内容
这个作业属于哪个课程 2021春季软件工程
这个作业对应的GitLab项目地址 软件工程结对作业
学号后四位 3439和3358

结对项目实践反思

问题分析

第一阶段

第一阶段指导书中并没有和复杂的说明和操作,出现的bug大概有以下几种:

  1. 一些极端情况并未考虑到,比如路径输入为/的情况以及对...的处理。

  2. 进行编码时思路不清晰和一些手误,导致一些变量的初始值出错,一些循环中的循环变量初始值和循环过程变量的赋值等错误出现,在进行编码时未考虑清楚,在后面进行测试时才发现问题的存在。

  3. 对指导书阅读不仔细产生的问题。比如在强测中测出非法路径的bug,在我们进行课下测试时并未注意到对路径长度的限制。

以上的bug中,1和3对于正常范围的测试数据是可以正常运行,但遇到极端测试数据和边界条件时,会出现严重问题,甚至会导致程序崩溃。bug2的影响很大,存在此bug时,程序会在普通测试中出现很大的漏洞甚至连基本测试都无法通过,严重影响代码的质量。

第二阶段

第二阶段中指导书中对文件系统的扩展,出现了很复杂的过程和多种情况的判断,出现的bug也随之增加。出现的bug如下:

  1. 对于指导书的理解不到位。这个原因大概是80%bug出现的原因。在实现过程中,对于每一个路径的对应对象的查找,文件的覆盖、移动、修改等操作以及异常抛出的类型、次序等都曾进行了反复的分析和修改,直到满足指导书以及issue中的解答。

  2. 头脑不清晰时,编码的偶尔手误。第二阶段中的mv和cp分出了很多情况进行判断和分析,在复杂情况编码时,手误导致使用错误的方法和变量。

  3. 代码结构不正确导致的代码重构问题。在正式编码前确认了代码了整体架构,但当实现时却发现当前架构出现了一些意料之外的bug和一些无法处理的情况。

以上bug中

  • bug 1的存在是不可避免的,在编码过程中对指导书进行仔细的分析和讨论是一项必须进行的过程,指导书也在过程中不断的进行修改,程序行为和指导书行为不一致时需要进行及时的修改。此bug的出现对程序质量的影响很大。当对指导书理解不正确时,在某些测试下会出现程序崩溃或者陷入死循环。

  • bug 2的存在可能需要耗费更多的经历去进行代码的审查,对于代码质量的影响可能是微乎其微,也可能导致程序无法通过基本测试。

  • bug 3的存在涉及到了代码的整体架构,对于代码质量影响很大,当架构出现问题时整个代码中的实现细节、数据结构以及调用过程都有可能发生很大的改变。代码的重构可能会让上述出现的bug复现,并出现新的bug。代码重构风险很大,需要谨慎对待。

需求分析

在结对项目中,需求分析的实践主要是对指导书进行解读和分析。毫无疑问在结对项目中,对于指导书的理解决定了整个项目实现的正确性,只有当程序表现的行为和指导书一样时,才能称为正确的程序。

体会

  • 用户的需求可能是在变化的,需要忍受不断变化的需求对于代码实现的影响。在结对项目的第二阶段中,指导书的修改贯穿了整个阶段,并在issue中对指导书进行了多次的澄清和解释,让我们充分感受到了需求不断变化所带来的一系列的影响。同时也让我对《构建之法》中Page 116中对于敏捷开发冲刺阶段不允许修改需求的原则有了更加深刻的理解。在实际的编码实现中,需求的变化往往意味着代码实现方式的改变、代码结构的变化以及各种实现细节的修改,并不得不重新进行单元测试和总体测试,这会极大的降低开发效率并导致很多的重复工作。

  • 我们需要在完全理解用户的需求(最好列出表格和具体需求)之后,再进行数据结构的设计和代码结构的设计,并在开发过程中尽量不能改动程序架构。我们在开发过程中发现了我们在阅读指导书时没有想到的一些需求,导致我们需要在开发中途对程序架构进行重新考虑,相当于是在对程序架构打补丁,这样导致程序的架构呈现一种拼凑之感,在未来进行扩展和需求变化时,往往再需要进行打补丁,修修补补最终结果代码架构会非常混乱(尽管看起来很稳定,如下图)

    

  • 用户的需求变化是很正常的事情,我们需要对代码进行良好的封装,做好代码复用,这样子当需求变化之后需要改动的地方也不会特别多。

bug分析

第一阶段
  • 没有考虑非法路径的存在,导致强测中的一个点出现了错误。在阅读指导书时忽略了路径非法的情况,在对路径进行解析时没有对非法长度路径抛出异常。

第二阶段
  • mv 指令中,指导书所涉及到的覆盖一次,在初始完成mv指令时并未真正理解,在完成cp之后才真正理解到覆盖一词所指。在代码第一版完成之后,对mv涉及到覆盖一词的情况进行了重构。

  • mv指令中涉及到的修改次数,在完成第一版之后进行代码测试时,发现了指导书中关于子目录和子文件的最后一次修改时间的定义,又在mv指令中添加了对子目录和子文件最后一次修改时间进行修改的代码。

  • cp指令中对于一个将目录复制到一个目录的情况,需要修改目录的最后一次修改时间。在开始时多加了对于目录文件和目录数量的判断,如果数量未变,则不更新最后一次修改时间。但第二阶段指导书修改了关于目录最后一次修改时间的说辞,去除了“当且仅当“一词,所以需要去除对文件数量的判断,即便文件和目录数量没有发生变化也需要更新被复制目录的最后一次修改时间。

  • 异常抛出的顺序。在mv指令中,由于异常抛出中认定前面的参数的异常优先级高于后面参数的异常,需要将所有srcPath参数的异常放到dstPath参数异常的前面。而在实现mv时并未考虑到此异常抛出顺序。

  • mkdir -p中所表述的内容理解出现偏差。根据Ubuntu 18.04 实际运行结果发现:此指令中,如果创建目录路径不合法,中间路径中的每一个目录都不会创建,但如果合法,中间路径中的每一个目录都需要进行创建,仔细分析指导书中的表述也可以发现是和Ubuntu 18.04表现一致,但我们最终的实现仅仅实现了前面的不合法的过程路径,并未实现合法路径中中间目录的创建。

架构设计

体会

  • 修修补补的做法不可取。在这两次作业中,我们的架构设计过程是一个很曲折的过程或者说在开始并没有对架构有进行很认真的思考,只是顺其自然,架构怎么简单怎么来,这导致我们在第二阶段的中途不得不临时更改架构并重构一系列的方法。这样的态度设计架构只会增加代码的重构次数和低效率的重复工作。

  • 可以对架构进行大胆且合理的猜测,并进行实现。关于第二阶段增加Entry接口增加,其实在第一次作业的架构设计之初,笔者有提出增加此接口的想法并准备付诸实现,但当时我们一致认为这只是一个可有可无的接口,后期即便扩展也应该用不到,这个想法便作罢,但后面开发过程中表明此接口是不可或缺的存在。

bug分析

架构导致的bug是在第二阶段未对架构进行更改时出现了findDirfindFile两个方法对软硬链接的处理问题。由于当时不更改结构很难实现,所以也就是代码实现工作已经无法继续进行了。

进度、质量和沟通

体会

  • 在每次进行结对编程之前,应该充分了解每次结对时的任务,并仔细阅读该部分指导书,并思考如何实现以及相对应的测试,这样才能在结对中充分利用时间,提高结对时的效率和质量。

  • 沟通时,无论是线上还是线下都需要表达清晰,必要时需要辅助一些样例和图示。特别是线上,我们都属于一种聊天喜欢发短句的人,在线上交流时往往会抛出一些很短的问题——提出疑问时往往是先提出一个毫无铺垫的问题,然后等对方询问之后再进行解释——这导致我们线上交流往往会有一种恍然大悟的感觉:我懂你的问题了。显然这样的沟通方式效率很低,往往需要两个人的一问一答之中才能讲清楚提问题一方的问题。

bug分析

当两人理解不一样时,我们会停下来进行讨论而不是进行继续代码的实现。所以并没有发现由于两个人理解不同出现的bug。

建议

  • 结对编程前,两人需要确定编程规范和习惯,并熟悉对方的编程方式和思想。

  • 在结对编程之前对结对项目要有充分的准备和自己的思考,这样才能在结对过程中进行有价值的讨论并产出高质量代码。

  • 在开始进行代码实现之前,需要进行全面的需求分析。在充分了解需求之后,再进行架构的讨论和设计。

  • 结对过程中需要适度的休息,来保持大脑的清醒。不清醒状态下不宜进行结对编程,否则不仅仅起不到结对编程的作用,还会让代码质量下降,漏洞百出,在后面仍然需要进行重写和修补bug。

CI感想

3439

这次项目的CI是课程组提供的自动评测,我们需要做的是打包官方jar包,并进行本地测试,输出程序覆盖率。体验感极好,自动化测试和提交方便了课程组也方便了我们进行测试和更新。

3358

  • 使用体验总体上还是不错的,可以非常方便的查看自己的单元测试的结果,可以看到自己和队友的修改是否正确。但是有一个比较让我们难受的点是,如果yml文件中出现了一点错误,他需要运行一段时间才能够反映出来那个错误,然后又得重新提交一次。当然这个问题也与我们对于yml的了解还不够有一定的关系。

  • CI是一个非常好用的工具,能够非常方便的进行单元测试。代码更新之后可以立即检测这次的更改是否是正确的,并且项目成员都能够看到这一次的结果,对于一个团队来说,确保每一个人写的代码至少满足基本要求是非常重要的。

结对编程感想

结对过程

  • 我们结对编程的方法是挑一个时间段,然后一起出去讨论和敲代码,一个人写代码一个人看代码,等到全部代码写完之后,我们会各自测试对应的函数,如果发现了bug,我们会首先与对方交流,然后讨论出一个比较合适的修改办法。之后才会推到远程库中,这样也保证了我们项目能够时刻同步

  • 结对编程中刚开始是有一些困难的,比如写代码的习惯相差比较大,有时候会在函数的实现方法上会出现一些争议,但是在这争议的过程中,却能够学习到对方身上的优点。

  • 结对编程的优点就是,一般写出来的的代码都是符合两个人的想法的,除非是两个人对于一个函数的理解都出了问题,才会出错。这种情况还是非常少见的。结对编程大大提高了代码的准确率与质量。

  • 缺点就是当两个人出现不同的理解之后,会用比较多的时间来说明自己得想法得好处,这个做法本身是没问题的,但是会占用大量的时间。写代码的效率不是很高。

结对工具

  • IDE使用了IDEA,用Maven来进行项目管理,用IDEA的插件来查看了代码覆盖率。同时在本机上安装了Maven工具,让我们在本机上就可以执行yml中的命令。

队友评价

3439

我和他(3358)在以前就曾经一起组队做过项目,彼此之间还是比较熟悉的。我们之前一起开发了一个安卓APP项目,我做后端,他做前端,当时给我的感受是他不拘小节,很有耐心,也很有想法,我们之前的合作效果很好,但由于是前后端分离的工作,所以对他编写代码的风格和习惯不是很熟悉。

这次结对编程又和他组队,这次能够和他一起合作很幸运,过程也很开心。在结对过程中他儒雅随和,一直很有耐心的给我讲解他的想法和代码习惯,并且包容我对他的设备的各种要求。在遇到分歧时,他也会认真的和我进行讨论、分析,并会认真分析我有时候不太靠谱的想法,并提出建议,让我受益匪浅。他在进行复杂分析时往往会思考的比我更加全面和细致,很多边界情况都是他思考提出的。

当然人无完人,他也有一些不足的地方。编程时习惯性打错变量名;修bug时可能会导致新的bug出现;提交时不喜欢写commit信息;也会因为我菜的抠脚的操作而不再那么有耐心。但不管怎么样两周的结对编程,这些不足都不会影响我们对于写代码的激情、找到bug的兴奋以及我们之间合作的友谊。我相信我们以后都会变得越来越好。

3358

之前就和他做个组队项目,彼此之间非常熟悉的,所以在这次结对编程的过程中互相之间的交流还是非常简单的。在之前组队的时候就感觉他是个很厉害的人,这次很幸运地和他再一次组队,让我在他的身上学到了不少东西,非常开心。

在编代码的时候他会非常认真地封装复用代码,并且对于变量的命名也非常认真,这让我学到了不少,在我写一些奇怪的代码的时候,他会认真的跟我讨论,怎样写才是最好的,让我能够把代码的结构改善的更好。最重要的是他对于代码复用的追求,每次在写功能性的方法的时候,他都会思考后面要实现的方法中是否需要调用这个方法,并且怎么写才能够让这段代码被更多的复用。这让我们的代码非常精简。在阶段二结束的时候,我们的代码比我舍友的少了两三百行。除此之外,他在出现bug的时候,首先会非常认真的看代码,找代码的逻辑漏洞,这是比我的处理方法好很多的。在他的身上,我真的学到了很多敲代码的好习惯。

当然他也是有一点小小的不足的,比如有时候会钻牛角尖,会一直思考那个问题,然而事实上这个问题并不是那么重要;对于指导书的阅读不是那么仔细,有时候会出现阅读理解上的问题;但是这些问题并不会影响到他身上的优点。我相信经过这一次的结对编程之后下次要是有机会,我们会配合的更好的。

吐槽

  • 希望指导书能够更加的准确和严谨一些,减少需求修改次数。

  • 指导书上有一些没有定义的情况,有时候我们思考到这种情况,却不知道怎么处理。指导书更新的内容应该做个汇总。特别是更新的内容比较多的时候。

 

 

posted @ 2021-04-07 21:27  Donke55  阅读(113)  评论(4编辑  收藏  举报