Contents

BUAA-OO-Unit1总结

程序架构

https://gitee.com/michsong/blog-images/raw/master/7a2c5f78cde7f989f6e726377d85f547.png

度量分析

Class OCavg OCmax WMC
MainClass 3.00 3 3
ast.DerivativeFactor 1.50 2 3
ast.ExpFactor 1.50 2 3
ast.Expression 1.50 2 3
ast.ExpressionFactor 1.00 1 2
ast.FunctionFactor 1.00 1 2
ast.NumberFactor 1.50 2 3
ast.SelectorFactor 1.50 2 3
ast.Term 1.33 2 4
ast.VariableFactor 1.50 2 3
core.FunctionDef 1.40 3 7
core.Preprocess 2.00 2 4
core.Process 7.00 7 7
lexer.Lexer 3.80 9 19
lexer.Token 1.50 3 6
lexer.Token.TokenType 1.00 1 2
parser.Parser 2.62 9 34
poly.Poly 4.67 13 56
poly.TermKey 2.00 6 14
Method CogC ev(G) iv(G) v(G)
core.Process.process(String, String[], String) 11 1 8 9
lexer.Lexer.parseLetterTokens(char) 22 7 11 15
poly.Poly.derivative(char) 19 1 10 10
poly.Poly.mul(Poly) 18 1 9 10
poly.Poly.printPow(StringBuilder, TermKey) 12 1 8 9
poly.Poly.toString() 28 6 19 22

(由于方法过多,此处仅展示CogC > 10的方法)
其中v(G)为圈复杂度,衡量程序中线性独立分支数量(即if、for、while、switch分支越多,该值越高), iv(G)衡量该方法与其他方法间的调用复杂度, ev(G)衡量非结构化复杂度(即break、continue等越多,该值越高) CogC衡量理解起来的困难程度, OCavg衡量类中所有方法的平均复杂度 OCmax衡量最大的方法复杂度, WMC为类中所有方法的v(G)之和。
据此分析,如上方法的圈复杂度过高,除去toStringparseLetterTokens等需要对多种不同情况进行判断的方法,其他方法的复杂度可以进行优化。PolyParser等类的复杂度也过高,可以进行职能的删减。

架构设计体验

在第一次作业中,即确定了核心框架(底层Poly类负责运算与输出,Lexer与Parser负责分词与递归下降解析,Core类负责预处理并提供处理入口,MainClass直接与Core交互),并在接下来的迭代中没有经历大规模的重构。在第二次作业中,为实现exp,将Poly类的底层数据结构从存储指数和系数更改为存储系数和Termkey(自定义类,存储x指数和exp多项式,即递归存储),并在其他类中使用了该数据结构的地方进行修改。如果此处对数据结构相关运算做进一步包装,可以减少修改量。在第三次作业中,对Termkey进行更改以适配自变量y,并在底层加入求导运算。

bug分析

在第二次作业中,选择表达式中未被选择的一项如果是多层嵌套f(x),且f(x)本身过于复杂的话,程序会超时。这是因为尽管我在解析的时候先进行选择判断,不去对不选择的分支进行String->Poly的解析,但是由于我对f(x)的做法是预处理直接替换,过长的嵌套导致的不必要的递归替换的效率极低,因而出现超时。此bug在强测及互测中均未被发现,因室友被该测试点hack并探讨原因而发现。此bug是算法决策的问题,与复杂度、耦合度无关。

分析bug策略

利用AI辅助搭建了评测机,但是实测效果并不好,因此放弃。主要还是通过朋友分享和水群分享的思路构造评测点,以及自己在前一次作业中出现的bug(相信一定有人没被测出来)。由于很多bug都是共性问题,所以这些方法确实成功hack。

优化分析

由于本人能力有限,并不会高深的优化算法,担心自己的优化(哪怕是AI辅助)可能带来新的bug,并考虑到优化未必一定得到长度更短的答案,却要付出可能带来的性能下降的代价,因此除去第一次作业的正项提前,没有进行任何优化。

大模型使用

在第一作业中,由于本人对抽象语法树和递归下降一头雾水,因此使用AI辅助理解搭建架构。后续作业使用AI辅助理解题意和需要更改的内容,并让AI帮我做一些杂活(比如把原有的<int, BigInteger>改为<TermKey, BigInteger>时的多处适配工作),以及部分职责明确、算法固定的类的生成(比如快速幂运算)。
与此同时,使用AI搭建评测机、生成数据点、分析bug。但是本人在使用过程中发现,使用AI辅助理解题意,与AI分析bug时考虑的边界情况几乎相同,也就是说,如果存在他没有考虑到的点,他也很难在bug分析中找到。恰好昨天Claude-Code源码泄漏,网上有人分析其中的Prompt工程,发现其使用了很多Prompt限制AI的答案,其中就有设置挑错Agent,或许之后可以借鉴。

心得体会

我觉得本单元最大的困难其实是第一次作业,递归下降已经不太会写,又没有学习过ast相关知识,面对复杂的形式化表述,脑子一团乱,不知道从何下手。或许没有AI,我真的就会写出一大坨屎山代码,然后在后面的作业继续无从下手,甚至可能选择全部重构,推倒重来。在建立了基本框架之后,后面的作业写的就舒服多了,至少脑子是清楚的知道我在干嘛的。

未来方向

或许未来如何平衡AI和古法编程,如何在拥抱AI的同时能更好地学到知识,是我们每一个人应该探索的课题。