那么软件工程,大三下再见~

那么软件工程,大三下再见~

软件工程是必修啦,之后可能会遇到JSF2.0也不一定呢?

写在前面

这次的写在前面有点难产,一直在思考应该写些什么呢?抒发情感或者总结陈词,还是差不多就可以了?好的,我觉得应该是“差不多就可以了”。
在OO课程之前,在写代码方面,我没有差不多就行的概念,写代码就是尽力做到自己认为的“完美”,从代码风格到核心逻辑再到测试验证,几乎全部都是尽力完成,应该属于在代码方面有些偏执的完美主义。这样的心态让我在第一次OO作业就身心俱疲——比较简单的任务要求被我拆分解构,尽力考虑各种边界情况。尽力考虑各种边界情况==hack==插==寻找常规思维下隐藏的逻辑漏洞,以至于代码还没写几行就快累得不行了——一边上瘾一般地hack自己的设计,一边想着这门课真的惨无人道——第一次作业就难成这样。最后,我的第一次作业有将近一千行。
在这样下去可能真的对身体不好。我开始慢慢放弃。于是我想说OO使我放弃努力?
在某种程度上说,是这样的,但更应该按下面这样说。
我在学习OO的过程中明白了这样几件事:

  1. 人的精力十分有限;
  2. 以蛮力做到面面俱到有明显的天花板;
  3. 靠天分视编程为艺术想要达到工程意义上的优秀比靠工程化方法视编程为技术更耗费精力;
  4. 适当的惰性也许能让人找到更有效率的方法。

简言之,方法很重要。于是在后续的课程中我将精力更多地放在了如何降低工程复杂度上,尝试找寻复杂度、工作量和成果质量的平衡(发现自己可以把用脑子摸鱼说得比较清新脱俗呢~)。
对于我个人而言这样的经验还是很重要的,改变了我一直以来都有的观念:完成任务的过程越艰难,完成质量就越高。现在则认为影响投入产出比的因素有很多,尽量不要选择想都不想就开始蛮力用脑子的方式。
这次的写在前面可能有些词不达意而显得不太重要,但这可能是我这一学期最为重要的收获之一。

  

测试与正确性论证  

去年的计组课程中也出现过相似的问题,在差点想复制黏贴的时候,发现过了半年又有了不一样的理解。  

测试

给定数据输入集并按照规则设定好预期的输出集(这里输出集是广义的,包含显示的数据的输出也包含隐式的软件行为输出)。这种验证软件正确性的方式,能够在比较短的时间里给出程序在一定状态域内基本可以正常运行的保证。这一方法模拟了程序运行的环境,使程序能够在最接近真实情况的条件下运行,能够检测出工程里不起眼的小错误,这些小错误在逻辑验证正确性时可能因为人的思维惯性而被遗漏。在一定程度上降低人的参与已达到从多角度验证正确性,这是测试的优势。同时注意到,目前基本所有工程项目都会在工程内建立集成测试和单元测试以验证在软硬件环境有差异的情况下工程能否达到预期效果,这在一定程度上说明了测试的重要性。但测试也有一定的局限性:从理论角度,测试只能说明程序在测试集所覆盖的有限状态域内可以有一定概率地正常工作,并不能扩展到软件的所有状态域。  

正确性论证

正确性论证则是希望采用逻辑上的推理来论证程序的正确性。这与数理证明类似,将代码行为抽象,在抽象领域内(一阶逻辑或高阶逻辑)验证程序预期行为的正确性,而不需要枚举状态域内的具体情况(测试需要枚举具体情况)。验证正确性的智力难度增加了,但是却减少了绝对工作量。但这一方法也无法100%验证程序的正确性。这里仅指出一点:程序设计思想的正确性与程序行为的正确性并不直接相关,其中还有将思想实践成具体代码的环节,有很多不确定因素。  
OO课程为我们提供了一个简单的论证模板:

  1. 抽象对象有效实现论证
  2. 对象有效性论证
  3. 方法实现正确性论证  

抽象对象的有效实现论证,主要是在逻辑上对需求的域进行的划分并论证在不同前件下程序的域转换在逻辑上是否符合需求。除了逻辑验证,也有相应的设计原则(如:SOLID等)可以辅助验证设计的正确性。   
对象有效性主要是判断在合法的操作域内(符合各方法的REQUIRES),程序的状态域转换是否会越界,即在正常运行状态域意外转移到非正常域。这在一定程度上保证了论证的封闭性。  
方法实现的正确性论证就是对信息输入域按照方法的逻辑进行划分,推演状态转移得出信息输出域,将输出域与预期结果作对比来论证正确性。
这一方法的优势是可以从抽象角度验证程序设计的正确性,但要注意到,这里强调了程序设计的正确性,而非程序实现和最终结果的正确性。从理论论证,可以得到理论的正确性,但离实践结果正确性还有一段距离。另一方面,正确性验证推理也是人来完成的,这依然没有办法从根本上保证设计完全符合预期。但总体来说是从另一个角度提供了一种验证正确性的方法。  

选择  

我认为没有一种现实可用的方法可以100%验证程序的正确性,可以运用多种不同的验证正确性方法来提高验证结果的可靠性。换言之,结合使用两种方法会有更好的效果。

OCL (Object Constraint Language) VS JSF

OCL是工程上常用的形式化无二义性基于一阶谓词逻辑的语言(JSF也基于一阶谓词逻辑)。其语法模式复杂,可表示域大且严谨,相比之下JSF在规定范围内可表示域较小,在实践中容易超出规定范围,导致二义性(使用了自然语言)。OCL每一个表达式都需要指定上下文,OCL是一种声明式语言,大部分表达式执行后会返回一个布尔值,也有一些表达式会用来选择一个单一值或者一个对象/值的集合。相比之下JSF要求每个表达式都能判定逻辑真值。
总的来说,JSF是面向教学的轻量级规格描述语言,OCL是面向工程的规格描述语言。

UML图

类图

时序图

状态图

总结

看写在前面

其实还有写在后面。

建议

面向对象本身的概念

在完成整个学期的学习后,扪心自问我对面向对象的理解依然十分浅薄。我将自己的疑惑划归为以下几个问题。

  1. 如何用面向对象思想开始一个工程的开发?有哪些步骤?
    1.1 什么是问题域?
    1.2 如何从问题域中抽象具体工程需求?
    1.3 自顶向下设计时如何解决工程主体的架构问题?是否需要先设计主体架构?设计的时序矛盾(如父类应如何抽象子类的使用规则,在实际设计中往往需要确定子类的问题域以后才能进行抽象,而子类的问题域归纳又依赖于父类的使用规则抽象)如何解决?
  2. 如何使用面向对象思想应对重构的需求?
  3. 面向对象程序设计思想的弊端是什么?
  4. 类的继承设计和高阶谓词逻辑什么样关系?

会有这些疑问代表着在完成课程作业时我还没有真正将面向对象的思想融入到代码设计之中,徒有其表,对其内涵没有真正很好地理解与掌握。这有些遗憾,我似乎没有足够的能力在完成作业的同时真正结合思想。但这里想提的一点建议是:在作业中是否可以将重心更多地放在“面向对象思想”本身的实践上,即设计更多的面向对象思想的实践项目,比如给定某个问题域,基于此合理抽象出类。可能在互测上会遇到很多问题,所以也许可以由助教检查(对不起下一届助教哇。。)。这可能更有助于抽象对象思想的理解。

(大三继续~)

猜你喜欢

转载自www.cnblogs.com/neolinsu/p/9226022.html