Mit软件构造学习心得

在学习软件构造课程之前,我对于编程工作的理解就是简单的写一写代码,改一改bug。但学完这门课后我对于编程有了更加深刻的认识。

软件构造基本过程

首先在宏观上软件的生命周期基本可以划分为:需求收集和分析,可行性分析,系统分析,软件架构设计,编写代码,测试代码,整合代码,打包交付,运行和维护。但在具体实现过程又有不同的方式,比如传统的瀑布模型和现在比较流行的敏捷开发。

对于瀑布模型,其核心思想是按工序将问题化简,将功能的实现与设计分开,便于分工协作,即采用结构化的分析与设计方法将逻辑实现与物理实现分开。并基本严格按照上述的软件生命周期来自上而下的分工,具有相互衔接的固定次序,如同瀑布流水一样逐级下落。

而敏捷开发以用户的需求为核心,采用迭代、循序渐进的方法进行开发。在敏捷开发中,把一个大项目分为多个相互联系,但也可独立运行的小项目,并分别完成,在此过程中软件一直处于可使用状态。其核心原则是主张简单,只基于现有的需求进行建模,并时刻准备着迎接新的变化,同时保证项目的可持续性。由于在实际开发时用户的需求不可能在一开始就完全确定,因此这样的敏捷开发原则更加实用,效率更高。

同时我觉得敏捷开发的思想对我们现在的编程也很有启发性,比如老师在实验的设计过程中会加入“新的变化”这一部分,来考验我们是否考虑了需求的可能变化。

测试:

测试优先编程——在写代码前先写好测试用例,尽早发现bug。
利用分区与分区边界来选择测试用例。
白盒测试与声明覆盖率。
单元测试——将测试模块隔离开来。
自动化回归测试杜绝新的bug产生。
还记得好软件具备的三个属性吗?试着将它们和测试联系起来:

远离bug 测试的意义在于发现程序中的bug,而“测试优先编程”的价值在于尽可能早的发现这些bug。
易读性 测试并不会使代码审查变得容易,但是我们也要注意正确书写测试注释。
可改动性 我们针对改动后的程序进行测试时只需要依赖规格说明中的行为描述。(这里的测试针对的是正确性而不是鲁棒性)。另外,当我们完成修改后,自动化回归测试能够帮助我们杜绝新的bug产生。

代码评审:

代码评审是一种广泛应用的软件质量提升方法。它可以检测出代码中的各种问题,但是作为一个初学课程,这篇阅读材料只提及了下面几个好代码通用的原则:

不要重复你的代码(DRY)
仅在需要的地方做注释
快速失败/报错
避免使用幻数
一个变量有且仅有一个目的
使用好的命名
避免使用全局变量
返回结果而非打印它
使用空白符提升可读性
下面把代码评审和我们的三个目标联系起来:

远离bug. 通常来说,代码评审使用人的审查来发现bug。DRY使得你只用在一处地方修复bug,避免bug的遗漏。注释使得原作者的假设很清晰,避免了别的程序员在更改代码的时候引入新的bug。快速报错/失败使得bug能够尽早发现,避免程序一直错更多。避免使用全局变量使得修改bug更容易,因为特定的变量只能在特定的区域修改。
易读性. 对于隐晦或者让人困惑的bug,代码评审可能是唯一的发现方法,因为阅读者需要尝试理解代码。使用明智的注释、避免幻数、变量目的单一化、选择好的命名、使用空白字符都可以提升代码的易读性。
可更改性. DRY的代码更具有可更改性,因为代码只需要在一处进行更改。返回结果而不是打印它使得代码更可能被用作新的用途。
规格说明:
一个规格说明就好像是实现者和使用者之间的防火墙。它使得分别开发成为可能:使用者可以在不理解源代码的情况下使用模块,实现者可以在不知道模块如何被使用的情况下实现模块。

规格说明和我们三大目标之间的联系:

远离bug. 一个好的规格说明会清晰明确的要求实现者和使用者遵守相关的制约。而Bug经常是因为实现者和使用者对于接口的理解冲突导致的,规格说明会明显的减小这种可能性。在模块中使用一些能够交由机器检查的特性,例如静态检查、异常等而不是注释会进一步降低bug的可能性。
易读性. 一个简洁准确的规格说明会比源代码本身更易读易懂。
可改动性. 规格说明在实现者和使用者之间建立了一个“契约”——只要这两方遵守这份“契约”,他们可以对自己的代码进行任何改变。
设计规格说明:
规格说明在使用者和实现者之间起着一道防火墙的作用——对于人和代码之间也是一样。正如上篇阅读谈到的规格说明,这使得独立开发成为可能:使用者可以在不阅读模块源码的情况下将源码应用到各个地方,使用者可以不在意模块被使用的环境(只要他们都遵循规格说明的要求)。

在实际使用中,声明性的规格说明是最重要的。前置条件(弱化规格说明)使得使用者更困难(确保输入合法),但是合理的使用会使得实现者能够做出一些假设,从而选择更合适的实现方案。

和我们的三个目标联系起来:

远离bug. 如果没有规格说明,即使是最小的更改都有可能使得整个程序崩溃,改动起来也是很麻烦的。一个结构良好、逻辑明确的规格说明会最小化使用者和实现者之间的误解,并帮助我们进行静态检查、测试、代码评审等等。
易于理解. 一个好的规格说明会让使用者不必去阅读源码也能正确安全地使用模块。例如,你可能永远不会去阅读Python dict.update ,但是通过阅读对应的声明性规格说明你就能很好的应用它。
可改动性. 一个合理的“弱”规格说明会给实现者一定的自由,而一个“强”的规格说明会给使用者一定的自由。我们甚至可以改变规格说明本身:只要我们是加强了它而不是削弱了它(减弱前置条件或者增强后置条件)。
可变性与不变性:
在这篇阅读中,我们看到了利用可变性带来的性能优势和方便,但是它也会产生很多风险,使得代码必须考虑全局的行为,极大的增加了规格说明设计的复杂性和代码编写、测试的难度。

确保你已经理解了不可变对象(例如String)和不可变索引(例如 final 变量)的区别。画快照图能够帮助你理解这些概念:其中对象用圆圈表示,如果是不可变对象,圆圈有两层;索引用一个箭头表示,如果索引是不可变的,用双箭头表示。

本文最重要的一个设计原则就是不变性 :尽量使用不可变类型和不可变索引。

接下来我们还是将本文的知识点和我们的三个目标联系起来:

远离bug.不可变对象不会因为别名的使用导致bug,而不可变索引永远指向同一个对象,也会减少bug的发生。
易于理解. 因为不可变对象和索引总是意味着不变的东西,所以它们对于读者来说会更易懂——不用一边读代码一边考虑这个时候对象或索引发生了哪些改动。
可改动性. 如果一个对象或者索引不会在运行时发生改变,那么依赖于这些对象的代码就不用在其他代码更改后进行审查。

你可能感兴趣的:(作业)