MIT6.031Software Construction学习笔记:(二)Specification

版权声明:本文为博主原创文章,转载请在下面留个言就好 https://blog.csdn.net/Dylan_Frank/article/details/83783068

首先,什么是 Specification? Specification,就是我们平时看到的API文档的说明,比如java BigInteger

why Specification

Specification 其实是作为用户(调用这个API的人)和实现者(实现API的人)的一条分界线。

在这里插入图片描述

Specification structure

A specification of a method consists of several clauses:

  • a precondition, indicated by the keyword requires
  • a postcondition, indicated by the keyword effects

在这里插入图片描述

如果前提条件不满足,也就是说调用者用户的前提条件不满足,那么实现者可以任意处理输出,这就相当于一个约定 是调用者和实现者之间的一个约定,如果调用者的前提不满足,那么调用者的到的输出也是不可预料的。

在这里插入图片描述

所以这也就引出后面的 行为等价性(Behavioral equivalence)

也就是说实现者再实现这个方法的时候只需要满足,调用者在使用这个方法的前提满足的情况下能得到正确的输出即可,而不需要管具体的实现,即具体的实现可以不同,可是他们表示的是同一个意思

下面的两个方法:

static int findFirst(int[] arr, int val) {
    for (int i = 0; i < arr.length; i++) {
        if (arr[i] == val) return i;
    }
    return arr.length;
}

static int findLast(int[] arr, int val) {
    for (int i = arr.length -1 ; i >= 0; i--) {
        if (arr[i] == val) return i;
    }
    return -1;
}

都满足以下规范

static int find(int[] arr, int val)
requires:
val occurs exactly once in arr
effects:
returns index i such that arr[i] = val

aviod null

Null values are troublesome and unsafe, so much so that you’re well advised to remove them from your design vocabulary. In 6.031 — and in fact in most good Java programming — null values are implicitly disallowed in parameters and return values. So every method implicitly has a precondition on its object and array parameters that they be non-null. Every method that returns an object or an array implicitly has a postcondition that its return value is non-null. If a method allows null values for a parameter, it should explicitly state it, or if it might return a null value as a result, it should explicitly state it. But these are in general not good ideas. Avoid null.

下面是google 对guava 中null 的讨论

Careless use of null can cause a staggering variety of bugs. Studying the Google code base, we found that something like 95% of collections weren’t supposed to have any null values in them, and having those **fail fast ** rather than silently accept null would have been helpful to developers.

Additionally, null is unpleasantly ambiguous. It’s rarely obvious what a null return value is supposed to mean — for example, Map.get(key) can return null either because the value in the map is null, or the value is not in the map. A null value can mean failure, can mean success, can mean almost anything. Using something other than null makes your meaning clear.

what a specification may talk about

简单的来说就是谈论 调用者关心的而屏蔽掉实现的细节:

A specification of a method can talk about the parameters and return value of the method, but it should never talk about local variables of the method or private fields of the method’s class. You should consider the implementation invisible to the reader of the spec.

Test & Specification

这里简单说其中一种观点:

测试也是一种调用者调用,所以也应该满足规范,也就是说测试的前提条件一定要满足,不然不具备意义

Specifications for mutating methods

Just as we’ve said that null is implicitly disallowed unless stated otherwise, we will also use the convention that mutation is disallowed unless stated otherwise.

这一点在在参数上加 final 不就行了吗?总的来说,specificatioin还是没有静态编译检查来的直接,有很多惯例需要实现者与调用者一起遵守

Exceptions

关于 exception, 我前两天正好看见 王垠 有一篇类似的言论

This suggests a more refined rule:

  • You should use an unchecked exception only to signal an unexpected failure (i.e. a bug), or if you expect that clients will usually write code that ensures the exception will not happen, because there is a convenient and inexpensive way to avoid the exception;

  • Otherwise you should use a checked exception.

Here are some examples of applying this rule to hypothetical methods:

  • Queue.pop()throws an unchecked Empty­Queue­Exception when the queue is empty, because it’s reasonable to expect the caller to avoid this with a call like Queue.size() or Queue.isEmpty().
  • Url.getWebPage()throws a checked IOException when it can’t retrieve the web page, because it’s not easy for the caller to prevent this.
  • int integerSquareRoot(int x)throws a checked Not­Perfect­Square­Exceptionwhen x has no integral square root, because testing whether x is a perfect square is just as hard as finding the actual square root, so it’s not reasonable to expect the caller to prevent it.

Summary

  • Safe from bugs. A good specification clearly documents the mutual assumptions that a client and implementer are relying on. Bugs often come from disagreements at the interfaces, and the presence of a specification reduces that. Using machine-checked language features in your spec, like static typing and exceptions rather than just a human-readable comment, can reduce bugs still more.

  • Easy to understand. A short, simple spec is easier to understand than the implementation itself, and saves other people from having to read the code.

  • Ready for change. Specs establish contracts between different parts of your code, allowing those parts to change independently as long as they continue to satisfy the requirements of the contract.

如果规范的预定义条件能加入编译期检查或许能更快的定位错误,即 fail fast

猜你喜欢

转载自blog.csdn.net/Dylan_Frank/article/details/83783068