HIT-SC-Chapter Five

HIT-SC-Chapter Five

Designing Specification

1 Functions & methods in programming languages

  • Method
public static void threeLines(){
	STATEMENTS;
}
public static void main(String[] arguments){
    System.out.println("Line 1");
}
  • Parameters

    • image-20220608223608849
    • 参数类型的匹配在静态类型检查阶段完成
  • Return Values

    • image-20220608223702617
    • 返回类型的匹配,也在静态类型检查阶段完成
  • Variable Scope

  • image-20220608223805051

  • Building Blocks:

    • 方法可以单独开发、测试和重用
    • 方法的用户不需要知道它是如何工作的——这被称为“抽象” s

2 Specification: Programming for communication

(1) Documenting in programming

  • Java API:

    • 类层次结构和实现的接口列表。
    • 直接子类,对于接口,实现类。
    • 类的描述
    • 构造函数的总结
    • 方法摘要列出了我们可以调用的所有方法
    • 每个方法和构造函数的详细描述
      • 我们可以看到返回类型、方法名和参数。我们也看到了例外。目前,这通常意味着该方法可能会遇到错误。
      • 完整描述
      • 方法参数的描述。
      • 返回值的描述
  • 记录假设

    • 变量的数据类型定义
      • Java实际上会在编译时检查这个假设,并确保程序中没有违反这个假设的地方。
    • final关键字定义了设计决策:“不可改变”
      • Java也会进行静态检查
    • 变量定义时即意味着程序员的假定,这既是一种抉择
    • 代码本身就蕴含着你的设计决策,但是远远不够
  • 为了交流而编程

    • 因为编程中充满了它们,如果我们不把它们写下来,我们就不会记住它们,而其他需要阅读或修改我们程序的人也不会知道它们。他们得自己猜。
    • 代码种的“设计决策”:给编译器读
    • 注释形式的“设计决策”:给自己和别人读

(2) Specification and Contract (of a method)

  • Spec or called Contract

  • the 关键

  • 没规约,没法写程序;即使写出来,也不知道对错;

  • acts as a contract 契约:

    • 实现者负责满足契约,而使用该方法的客户端可以依赖契约。
    • 程序和客户端达成的一致
      • 说明方法和调用者的职责
  • Why

    • s
    • ……

image-20220608230109074

  • 包含
    • Method signature (type specifications) 输入/输出的数据类型
    • Functionality and correctness expectations 功能和正确性
    • Performance expectations 性能
    • What the method does, not how it does it 只讲“能做什么”,不讲 “怎么实现”
    • 接口(API),而不是实现
    • image-20220608230306152

(3) Behavioral equivalence

  • 为了确定行为等价性,问题是我们是否可以用一种实现替代另一种实现
  • The notion of equivalence is in the eye of the client (站在客户端视角看行为等价性).
  • 这两个函数符合这个规约,故它们等价。
  • 单纯的看实现代码,并不足以判定不同的implmentation是否是“行为等价的”
  • 需要根据代码的spec(开发者与client之间形成的contract)判定行为等价性
  • 在编写代码之前,需要弄清楚spec如何协商形成、如何撰写

(4) Specification structure: pre-condition and post-condition

  • spec’s consistions:
    • Precondition , indicated by the keyword requires
    • Postcondition , indicated by the keyword effects
    • Exceptional behavior: what it does if precondition violated 意外行为
  • 前置条件:对客户端的约束,在使用方法时必须满足的条件
  • 后置条件:对开发者的约束,方法结束时必须满足的条件
  • 契约:如果前置条件满足了,后置条件必须满足。
    • 前置条件不满足,则方法可以做任何事情
    • 当我们的前提条件被违反时,客户端就有漏洞。我们可以通过快速失败使错误更容易被发现和修复,尽管我们没有义务这样做。

(5) spec in Java

  • 静态类型声明是一种规约,可据此进行静态类型检查static checking。

  • 方法前的注释也是一种规约,但需人工判定其是否满足

    • 参数由@param子句描述,结果由@return和@throws子句描述。

    • Put the preconditions into @param where possible, and postconditions into @return and @throws.

    • image-20220608234645328

  • 每一个参数,一个@param 语句

    • @param 参数名 解释参数的语句
  • 有返回值

    • @return 解释返回值的语句
    • 无变量名
  • 这个练习表明,在规范中,可能会在@param和@return子句之外的地方找到部分前置条件和后置条件,所以仔细阅读是很重要的。

(6) What a specification may talk about

  • 只讨论方法的参数值和返回值,不讨论方法的类的局部变量或私有域
    • 您应该考虑实现对规范的读者是不可见的
    • 在Java中,您的规范的读者通常无法获得该方法的源代码,因为Javadoc工具从您的代码中提取规范注释并将它们呈现为HTML。

(7) Spec for mutating methods

image-20220608235450484

  • 除非后置条件里声明过,否则方法内部不应该改变输入参数

  • 应尽量遵循此规则,尽量不设计mutating的spec,否则就容易引发bugs。

  • 程序员之间应达成的默契:除非spec必须如此,否则不应修改输入参数

  • 除非另有说明,否则不允许变异

  • 尽量避免使用mutable的对象

  • 可变对象使得合约变得复杂

    • 别名情况
  • 可变对象使简单的契约变得复杂

    • 可变的全局变量
    • 客户是否有义务不修改取回的物品?
    • 实现者是否有义务不保留它返回的对象?
  • image-20220609000514759

    image-20220609000637986

    开发者可以在其方法内部得到这个引用并改变值

3 Designing specifications

(1) Classifying specifications

  • 规约的确定性

    • 一组输入
    • 一个输入
  • 规约的陈述性

  • 规约的强度

  • 比较规约

    • 规约的强度

      • 前提条件更

      • 后置条件更

      • 则更强

      • 那么满足更强的规约的实现也可以用来满足更弱的规约的实现,并且在程序中替换是安全的

      • 对他人宽容,对自己严格

    • image-20220609001433772

    • image-20220609092453851

    • image-20220609092700718

    • image-20220609092721527

    • 会有不可比的情况出现

  • 当规范被加强时,

  • 越强的规约,意味着implementor的自由度和责任越,而client的责任越


  • Deterministic vs. underdetermined specs
    • deterministic:当呈现一个满足前提条件的状态时,结果是完全确定的。
      • 只能有一个返回值和一个最终状态。
      • 不存在任何有效输入对应多个有效输出。
      • 确定的规约:给定一个满足precondition的输入,其输出是唯一的、明确的。
      • image-20220609093704234
    • Under-deterministic: 同一个输入,可能有多个输出
    • image-20220609093758845
    • 同一个输入,多次执行时得到的输出可能不同
    • 在spec中提供了一个由实现者在实现时做出的选择
    • 一个不确定的spec通常由一个完全确定的实现来实现。
    • image-20220609093939917

  • Declarative vs. operational specs
    • 操作式规约:
      • 例如伪代码
      • 规范给出了该方法执行的一系列步骤;伪代码描述是可操作的。
    • 声明式规约:
      • 没有内部实现的描述
      • 只有“初-终”状态
      • 对于客户和代码维护者来说,这是最清晰的。
    • 声明性规范更可取。
      • 它们通常更短,更容易理解,最重要的是,不会无意中暴露客户机可能依赖的实现细节。
    • Why operational spec. exists?
      • 程序员使用规范为维护人员解释实现。
      • 必要时,在实现体中使用注释,而不是在规范注释中。
    • image-20220609094716233
    • image-20220609094749982

(2) Diagramming specifications

  • 这个空间中的每个点代表一个方法实现。

  • 一个规约在所有可能实现的空间中定义了一个区域。

  • 某个具体实现,若满足规约,则落在其范围内;否则,在其之外。

    • 程序员可以在规约的范围内自由选择实现方式
    • 客户端无需了解具体使用了哪个实现
      • 他们必须尊重规范,但也有自由改变他们使用实现的方式,而不必担心它会突然中断。
  • 规约更强,区域更小

    • 较弱的spec定义较大的区域。
    • 更强的后置条件意味着实现的自由度更低了,在图中的面积更小
    • 更弱的前置条件意味着实现时要处理更多的可能输入,实现的自由度低了,面积更小
  • image-20220609095341362


(3) Designing good specifications

  • Quality:

    • 是简洁的
    • 清晰
    • 结构良好的
  • guidelines:

  • The specification should be coherent (内聚的)

    • 描述的功能一个单一、简单、容易理解
    • 若做了多件事,就要分离成多个方法
  • The results of a call should be informative

    • 不能让客户端产生理解的歧义
  • The specification should be strong enough

    • 在指定特殊情况时,我们必须格外小心,以确保它们不会破坏原本有用的方法
    • 太弱的spec,client不放心、不敢用 (因为没有给出足够的承诺)。开发者应尽可能考虑各种特殊情况,在post-condition给出处理措施。
  • The specification should also be weak enough

  • 太强的spec,在很多特殊情况下难以达到,给开发者增加了实现的难度(client当然非常高兴)。

  • 相反,规范应该说明一些更弱的内容:它试图打开一个文件,如果成功,该文件具有某些属性。

  • The specification should use abstract types

    • 用抽象类型编写规范给了客户端和实现者更多的自由。
    • 在Java中,这通常意味着使用接口类型,如Map或Reader,而不是特定的实现类型,如HashMap或FileReader。
    • image-20220609100533000
  • 先决条件和后置条件?

    • 是否使用先决条件,如果是,方法代码是否应该在继续之前尝试确保先决条件已经满足?
    • 不写Precondition,就要在代码内部check;若代价太大,在规约里加入precondition,
      把责任交给client。
    • 客户端不喜欢太强的 precondition,不满足precondition的输入会导致失败。
    • 惯用做法是:
      • 不限定太强的precondition,而是在postcondition中抛出异常:输入不合法
      • 尽可能在错误的根源处fail,避免其大规模扩散
    • 衡量代价的标准:检查参数合法性的代价
  • image-20220609100901937


Summary

image-20220609100923766

image-20220609100932358

image-20220609100954745

posted @   三金同志  阅读(15)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· winform 绘制太阳,地球,月球 运作规律
· 震惊!C++程序真的从main开始吗?99%的程序员都答错了
· AI与.NET技术实操系列(五):向量存储与相似性搜索在 .NET 中的实现
· 超详细:普通电脑也行Windows部署deepseek R1训练数据并当服务器共享给他人
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理
点击右上角即可分享
微信分享提示