【作业】BUAAOO2019第一单元作业总结

写Bug历程回顾

17231153 邓梓良

第一单元的作业是有关多项式求导的简单面向对象程序。

从简单的只有x为变量的幂函数项与常数项合并的表达式求导,到加入正余弦三角函数的三元项表达式求导,最后是多层嵌套表达式的求导。

在拿到第一次作业题目的时候,其实我是拒绝的。 

在之前在与淑芬死缠烂打的时候,我曾经尝试过在网上白嫖大佬的导函数计算器。结果可想而知,除了一无所获,还是一无所获。

然后,天道好轮回,之前想偷的懒,现在还是偷不到,甚至还得为了它写bug工程。。。

孩子做错了什么???救救孩子!


好了,不扯皮了。切入正题,对前两三周的工作做个总结。

一、结构分析

(一)复杂度分析

  第一次作业难度比较低,但是由于是首次写较有工程量的java程序,提前并没有了解过面向对象的编程,所以程序的耦合度比较高。我只使用了两个类,基本所有功能都放置在了Formula类里面,只是由于求导时获取系数的方法过长并且重复性很高,才把这部分功能移到了另一个类中。复杂度分析如下:

第一次作业类复杂度

 

第一次作业方法复杂度

 

  可以从表格中看得出来,绝大多数复杂的功能都集中在了Formula类中,方法加权复杂度高达44,虽然不知道是什么意思,但是看见红红的大数字就知道肯定没啥好事。果然,再深入看看方法复杂度,集中在表达式合并的方法中。这个方法中,我把可能出现的幂函数的形式都列举出来,然后调用GetCoeff类进行求导指数和系数运算,然后再通过HashMap中储存的系数与指数合并成相对成型的求导计算式。由于使用了大循环对传入的字符串数组进行了遍历,这部分复杂度实在是高。

 


 

  第二次作业加入了三角函数的求导。当时我一脸懵,想着这可怎么做啊?与同学们交流之后,得到了启发——每一个项可以变为三元组的形式,即“常数*幂函数*三角函数”的形式。开始设计的时候,我想着要把输入的表达式划分为小的对象,然后再做其他操作,但是由于头脑混乱,写着写着又变成了面向过程的编程。复杂度又很高:

 

第二次作业类复杂度

 

第二次作业方法复杂度

 

  从类名就能看出来,完全的面向过程流水编程……由于写代码的过程中出现了不少bug,在debug时胡乱改动,并且调用了很多只实现单一功能的方法,而这些方法又不能满足特殊的需求,迫于心急,就直接在原来的方法中更改,导致主类复杂度很高,主函数方法也随之升高。在求导和合并同类项的过程中,复杂度最高,同样是大循环遍历所有元素的原因。

 


 

 

  很遗憾,第三次作业我没做出来,只写了判断错误类型的方法。想了两天,被表达式嵌套搞得昏头胀脑。与学长和其他同学讨论过实现方法,但是由于对语言的不熟悉,还有对递归和链表等数据结构使用的不熟练,最重要的是,还是没有掌握面向对象的思想。在听过研讨课同学和学长详细的介绍后,我才彻底明白分层的做法。继续努力吧。

 


 

 

(二)类图分析

第一次作业类图

 

第二次作业类图

  第一次作业逻辑相对简单,第二次作业加入了新元素,自然也就复杂一些。可以看到,面向过程的痕迹一目了然。第二次作业,在最后输出时,为了标准化,调用了本应是合并同类项时使用的FormulaProcess类,所以弄得一团糟,也导致了一个显式bug和可能存在的、未知的bug。

 


 

 

二、bug分析

(一)自己的bug

  第一次作业中被查出了垂直制表符等空白字符方面的问题,一处bug被hack九次,这是没有把指导书完全吃透的后果。直接使用[\s]匹配所有空白字符,会把非目标字符读入,由此导致失分,很可惜。

     第二次作业中被查出了常数求导没有输出进而导致Exception的情况。这就是上文提到的调用不该调用的方法然后胡乱修改导致的。

  从这两次作业的bug中,我吸取到了一个很大的教训——细致分类。把每一个对象、每一个方法,哪怕是有一点重叠,都分开。写出公共方法,再使用方法的重载,会达到事半功倍的效果。第一单元面向对象入门已经结束了,但是我接口和继承还不太会用,赶紧快点学吧……

(二)别人的bug

  由于两次性能分都不高,所以都在B屋参加圣杯战争(极其酸爽)。虽然没进过A屋,但是B屋也有许多踏实的大佬。能够观赏大佬的代码真的是一种享受,有好多同学的代码真的是赏心悦目。抛开正确性不谈,工整的代码,是对未来同事的尊重,也是我们应当放在功能正确性等同重要位置的。

  当然,正确性是第一位的。与我同房间的同学不乏没被刀过的,也有惨遭群殴的。爆栈、空字符、多余符号错误……许多常见错误在第一次作业中非常容易被发现,我的互测屋中也有同学踩坑。但是到第二次作业,之前的问题就改变了许多。然而,随之而来的是表达式复杂带来的新错误类型。这也就解释了为什么每一次被hack过的人数都高居50%以上。新需求导致新bug。

(三)bug发现策略

  两次作业中,我首先是对空字符进行了排查,然后是前导符号等奇怪错误。手工排查太过费时,也吃计算机性能。隔壁大佬对我开8个IDEA的智障行为实在是看不下去,就把他的评测机借我玩了玩,果然发现了我没想全面的错误。可能我避免的错误,其他同学也有犯,这是我没考虑进去的。当然,做个人,第一次做狼人,第二次就人不犯我、我不犯人了。感谢小伙伴们让我看到了这么多漂亮的代码,hack你们真的是抱歉……

 

 


 

三、Applying Creational Pattern

  三次作业只作完两次,南湖捞都捞不上来……但这并不代表我会放弃。接下来会继续努力的。

  由于两次都是用的面向过程编程,所以应用面向对象的规则可谓是方方面面都需要……

  如果把代码重构,大概结构可能会是这样(针对第三次作业):

  读入模块:逐层读入,设置括号栈,把每一层单独存储入链表的每一级

  元素类:针对常数、幂函数、三角函数实现求导接口、同类项合并接口和化简接口

  元式类:针对组合嵌套的类,实现求导和化简接口

  项类:针对用乘法符号组合的式子实现乘法求导法则的接口和化简接口

  表达式类:把求导后的每一项合并,并且实现表达式求导合并接口(因为有嵌套)

  每一个求导规则都差不多,所以通过接口来实现很方便。

  以上就是我对前三次作业的总结。

 

 

原文地址:https://www.cnblogs.com/dzlbuaa/p/10579309.html