形式手法ってなんだろう?

18923dca590d68fe7cfacce3c1ee5145?s=47 scarletplover
December 14, 2019

 形式手法ってなんだろう?

WACATE2019冬での形式手法のセッションの発表資料です。

18923dca590d68fe7cfacce3c1ee5145?s=128

scarletplover

December 14, 2019
Tweet

Transcript

  1. 5.

    設計書におけるさまざまなバリエーション › ユーザ検索 – ユーザを検索する。 – ユーザリストからEmailでユーザを検索する。 – 与えられたEmailをもってユーザリストから 同じEmailをもつユーザを検索し、返す。

    – ①与えられたEmailをもってユーザリストから同じEmailをもつ ユーザを検索。②取得したユーザを返す。 人によって書き方 はそれぞれ・・・
  2. 11.

    形式手法とは › 仕様を記述・検証する手法 › 「数論理学を基盤としている手法」 石川冬樹(2011年)『VDM++による形式仕様記述 (トップエスイーシリーズ 実践講座)』 – 数論理学:「A⋏B」「A→B」「集合」「再帰」等々・・・

    – システムをモデル化し、厳密に定められた文法で仕様を記述、検証する › 厳密に定められた文法で仕様を記述することによって、抽象度の揺れや曖昧な部分を少なく する。 › 厳密に定められた文法で仕様を記述すれば、仕様のチェックを網羅的に行うことができる。 › 「開発上流工程からの品質確保への技術アプローチ」 中島震(2012年)『形式手法入門―ロジックによるソフトウェア設計― )』オーム社 › 宇宙工学系(NASAとか航空とか)のエラー処理など、「ミッションクリティ カル」なシステムで使われる。 – その他、AWSの設計等でも・・・。
  3. 13.

    設計書におけるさまざまなバリエーション › ユーザ検索 – ユーザを検索する。 – ユーザリストからEmailでユーザを検索する。 – 与えられたEmailをもってユーザリストから 同じEmailをもつユーザを検索し、返す。

    – ①与えられたEmailをもってユーザリストから同じEmailをもつ ユーザを検索。②取得したユーザを返す。 検索して どうするの? 何で検索するの? 句読点を適切に 読めない人が存在する くどい 日本語難しい
  4. 14.

    形式手法で書いた場合・・・ public ユーザ取得byEmail: seq of char ==> ユーザ ユーザ取得byEmail(pEmail) ==

    --下記の意味は「ユーザリストの中にあるEmailがp_Emailと同じユーザを返す」 --「let x in set s be st 『xの条件』in 『xを使った式or文』」は --「s集合の中で『xの条件』を満たすxについて『xを使った式or文』を実行する」 let u in set 登録リスト be st u.Email = pEmail in return u --検索するユーザがリストにいなければならない pre exists1 u in set 登録リスト & u.Email = pEmail;
  5. 15.

    形式手法で書いた場合・・・ public ユーザ取得byEmail: seq of char ==> ユーザ ユーザ取得byEmail(pEmail) ==

    --下記の意味は「ユーザリストの中にあるEmailがp_Emailと同じユーザを返す」 --「let x in set s be st 『xの条件』in 『xを使った式or文』」は --「s集合の中で『xの条件』を満たすxについて『xを使った式or文』を実行する」 let u in set 登録リスト be st u.Email = pEmail in return u --検索するユーザがリストにいなければならない pre exists1 u in set 登録リスト & u.Email = pEmail; 仕様を厳密に書ける →明確に意味を1つに 絞れる
  6. 16.

    疑問:プログラム言語そのままでいいじゃない public ユーザ取得byEmail: seq of char ==> ユーザ ユーザ取得byEmail(pEmail) ==

    --下記の意味は「ユーザリストの中にあるEmailがp_Emailと同じユーザを返す」 --「let x in set s be st 『xの条件』in 『xを使った式or文』」は --「s集合の中で『xの条件』を満たすxについて『xを使った式or文』を実行する」 let u in set 登録リスト be st u.Email = pEmail in return u --検索するユーザがリストにいなければならない pre exists1 u in set 登録リスト & u.Email = pEmail; 仕様を厳密に書ける →明確に意味を1つに 絞れる
  7. 17.

    疑問:プログラム言語そのままでいいじゃない public User GetUser(String pemail) { for(int i = 0;

    i < UserList.size();i++) { if (UserList.get(i).email == pemail){ return UserList .get(i); } } }
  8. 18.

    疑問:プログラム言語そのままでいいじゃない public User GetUser(String pemail) { for(int i = 0;

    i < UserList.size();i++) { if (UserList.get(i).email == pemail){ return UserList .get(i); } } } 何をやりたかっ たかコードには 表現されない (ことが多い) 繰り返しなどで 欠陥が混入する 可能性
  9. 21.
  10. 22.

    形式手法の側面 –仕様の記述方法- › 形式仕様記述 – 仕様を形式的に記述する – モデル規範 › 記述の要素が持つ意味を、数学的な実体(意味モデル)である集合、関係、列、関

    数などに対応させる。 – VDM、Bメソッド、Alloy、SPIN・・・ › モデル化・・・システムの側面を抽象化&捨象 › 目標とする分析や検証を踏まえて、システムのどういう側面どう抽象的にモデルとして表 現する(モデル化)か※ということが肝要 – VDM・Bメソッド・・・状態ベース – Alloy・SPIN・・・状態遷移モデル ※石川冬樹(2011年)『VDM++による形式仕様記述 (トップエスイーシリーズ 実践講座)』
  11. 23.

    形式手法の側面 –仕様の検証方法- › 正当性検証(Verification) – 「ある活動の実際の結果がその活動への要求と適合しているかどうかを調査決定す る過程に関わるもの。」※ – 開発製品が仕様と合致をしているかを評価すること ›

    妥当性検証(Validation) – 「製品が利用者のニーズに適合しているかを検査する過程にかかわるものである。」 ※ – 製品が要求に対して妥当なものかかをチェックする →「仕様」が妥当なものかをチェックする 通常ユーザ受入テスト等で行う →形式手法であれば設計段階で確認ができる(かもしれない) ※ジョン・フィッツジェラルド、ピーター・ゴルム・ラーセン、ポール・マッカージー、ニコ・プラット、マーセル・バーホフ(2010年)『VDM++によるオブジェクト指向システムの高品質設計と検証」』翔泳社
  12. 24.

    形式手法の側面 –仕様の検証方法- › 形式検証 – 定理証明 › 法則に基づいた検証※ › 記載された仕様に論理的な破綻がないかどうかを検証する。

    – X機能で使用されているA,BがA→Bなら、Y機能でもA→Bじゃないとおかしい! – モデル検査 › 観測に基づいた検証※ › 記述されたモデルがとりうると考えられる状態を自動的に網羅することで検証を行う。並行処 理の仕様の検証に有用。 – X機能、Y機能をツールで網羅的に検証してみて、仕様の齟齬がないことを確認。 › ライトな検証 テスト・プロトタイピングによる検証 ※ジョン・フィッツジェラルド、ピーター・ゴルム・ラーセン、ポール・マッカージー、ニコ・プラット、マーセル・バーホフ(2010年) 『VDM++によるオブジェクト指向システムの高品質設計と検証」』翔泳社
  13. 25.

    VDMとは › VDM(Vienna Development Method) – 1970年代、IBMウィーンで始まった構造設計に主眼を置く 形式手法の名前。 – 形式仕様記述言語として、VDM-SLやVDM++を用いる。

    – モデル規範。 › VDM-SL(Specification Language) – VDMを行うための形式仕様記述言語。1996年にISO標準化 › VDM++ – VDM-SLをオブジェクト指向に対応するために拡張したもの
  14. 26.

    VDMとは › モデル化の対象 – 機能仕様(データ型、変数、関数・操作など)をモデル化 (クラスという単位を用いる) › モデルの抽象度と開発プロセスでの位置づけ – VDM++は様々な抽象度での記載が可能。

    › システム外部仕様のみを中心に記載することも可能 › Java等のプログラミングによる実装に近い書き方を行うことも可能 › 検証対象となる性質 – システムの状態が常に満たすべき条件(不変条件)や、個々の操作・関数が実行前、実行後 に満たすべき条件(事前条件・事後条件)を、インタプリタによる実行を通して検証を行う。 › 検証の方法 – 一般的にはテスト・プロトタイピングによる検証 – 定理証明を行うことも可能 ※石川冬樹(2011年)『VDM++による形式仕様記述 (トップエスイーシリーズ 実践講座)』 荒木 啓二郎監修、近代科学社 を参考にまとめた
  15. 29.

    VDMとは › モデル化の対象 – 機能仕様(データ型、変数、関数・操作など)をモデル化 (クラスという単位を用いる) › モデルの抽象度と開発プロセスでの位置づけ – VDM++は様々な抽象度での記載が可能。

    › システム外部仕様のみを中心に記載することも可能 › Java等のプログラミングによる実装に近い書き方を行うことも可能 › 検証対象となる性質 – システムの状態が常に満たすべき条件(不変条件)や、個々の操作・関数が実行前、実行後に満たすべ き条件(事前条件・事後条件)を、インタプリタによる実行を通して検証を行う。 › 検証の方法 – 一般的にはテスト・プロトタイピングによる検証 – 定理証明を行うことも可能 ※石川冬樹(2011年)『VDM++による形式仕様記述 (トップエスイーシリーズ 実践講座)』 荒木 啓二郎監修、近代科学社 を参考にまとめた
  16. 30.

    VDM++の書き方 1. モデルの目的を定める。 2. 要求を読む。 3. 要求から読み取れる機能的振る舞いを分析する。 4. 候補となるクラスまたは型を(主に名詞から)抽出し、同時に操作を(主に動作指示から)抽出して一覧にする。一覧の各項目に説明を加 えて辞書を作成する。

    5. UMLのクラス図を用いて、クラス群のスケッチを行う。この作業では属性やクラス間の関連の定義も行う。このモデルをVDM++へと変換し、内 部の一貫性をチェックする。 6. 操作のシグニチャを仮に決めていく。この段階でもVDM++を用いてモデルの一貫性をチェックしておく。 7. 要求から候補となる不変条件を抽出して形式化を行い、クラス(とデータ型)の構造の定義を完成させる。 8. 各操作の事前条件と事後条件そして操作本体を決定することにより、操作を完成させる。必要に応じて型の定義を変更する。 9. 仕様を体系的なテストとラピッドプロトタイピングを用いて検証する。 10. モデルから自動コード作成または手作業によるコーディングによって実装コードを作り上げる。 ジョン・フィッツジェラルド、ピーター・ゴルム・ラーセン、ポール・マッカージー、ニコ・プラット、マーセル・バーホフ(2010年) 『VDM++によるオブジェクト指向システムの高品質設計と検証」』翔泳社
  17. 31.

    形式手法で書く 1. 要求を読み込み、振る舞いを分析する 2. モデルにおこす 3. 形式手法で記述 – 型定義 –

    インスタンス変数定義 – 操作定義 etc・・・ 4. 検証を行う 5. プログラム実装etc・・・
  18. 32.

    1.要求を読み込み、振る舞いを分析する › テストユーザ登録システム – WACATEゲームサイトを作成するにあたり、ベータテストに参加するユーザをユーザ リストに仮登録するシステムを作成する。 – ユーザは12歳超で、30名まで登録できる。 – ニックネームはゲーム内で使うので、一意でなければならない。

    – ユーザの「本名、Email、ニックネーム、誕生日」を入力してユーザリストに登録する。 – ユーザ登録状況確認のために、ユーザリストを一覧取得する必要がある。 – ユーザの調査のために、ユーザのEmailを指定してユーザリストを検索し、該当する ユーザ情報を取得できる必要がある。 – ユーザの調査のために、ユーザのニックネームを指定してユーザリストを検索し、該当 するユーザ情報を取得できる必要がある。 – ユーザリストからEmailを指定して検索し、該当するユーザの情報を削除する機能 を設ける必要がある。
  19. 33.

    1.要求を読み込み、振る舞いを分析する › テストユーザ登録システム – WACATEゲームサイトを作成するにあたり、ベータテストに参加するユーザをユーザリストに 仮登録するシステムを作成する。 – ユーザは12歳超で、30名まで登録できる。 – ニックネームはゲーム内で使うので、一意でなければならない。

    – ユーザの「本名、Email、ニックネーム、誕生日」を入力してユーザリストに登録する。 – ユーザ登録状況確認のために、ユーザリストを一覧取得する必要がある。 – ユーザの調査のために、ユーザのEmailを指定してユーザリストを検索し、該当するユーザ 情報を取得できる必要がある。 – ユーザの調査のために、ユーザのニックネームを指定してユーザリストを検索し、該当する ユーザ情報を取得できる必要がある。 – ユーザリストからEmailを指定して検索し、該当するユーザの情報を削除する機能を設け る必要がある。
  20. 34.

    2.モデルにおこす › クラスとか型になりそう – ユーザリスト – ユーザ › 本名 ›

    Email › ニックネーム › 誕生日 › 操作になりそう – 一覧取得 – Emailでのユーザの取得 – ニックネームでのユーザの取得 – ユーザの登録 – ユーザの削除 ※モデルは説明しやすさを最優先にしてます
  21. 36.

    3.形式手法で記述(自然言語で書いた場合) › 型定義 – ユーザ › 本名:文字列 › Email:文字列 ›

    ニックネーム:文字列 › 誕生日:日付型 › 変数定義 – 現在日付:日付型 – 登録リスト:登録したユーザの集合 › 30人までしか登録できない。ユーザのニックネームは一意とする。 › 機能 – 一覧取得 › 登録された登録リストを返す – ユーザ検索byEmail › 与えられたEmailをもってユーザリストから同じEmailをもつユーザを特定し、該当ユーザのユーザデータを返す。 – ユーザ検索byニックネーム › 与えられたニックネームをもってユーザリストから同じニックネームをもつユーザを特定し、該当ユーザのユーザデータを返す。 – ユーザ登録 › 新規ユーザの本名、Email、ニックネーム、誕生日をユーザデータとして、登録リストに登録する。 (ただし、ユーザの年齢は12歳超とする) – ユーザ削除 › 与えられたEmailをもってユーザリストから同じEmailをもつユーザを特定し、該当ユーザを登録リストから削除する。
  22. 39.

    class クラス名 end クラス名 3.形式手法で記述 › クラス定義 types 型定義・・・クラスで用いる型(データの概念) instance

    variables インスタンス変数定義・・・クラスで用いる変数 operations 操作定義・・・クラス内の変数を操作する処理
  23. 41.

    class クラス名 end クラス名 3.形式手法で記述 ー型定義ー › 型定義 types 型定義・・・クラスで用いる型(データの概念)

    instance variables インスタンス変数定義・・・クラスで用いる変数 operations 操作定義・・・クラス内の変数を操作する処理
  24. 44.

    3.形式手法で記述 ー型定義ー › 型定義 – クラスで用いる型(データの概念)を定義できる --下記は「レコード型」といって、 --他の型の固定的な組み合わせ --個々の要素に名前と定義をつけられる --実際の値は以下のとおり記述

    --mk_ユーザ(“べにちどり”,”test@test.co.jp”,”scarletplover”,new 「日付」(2011,1,14)) --seq of char = 「文字の集合」=文字列 --「日付」は別のクラスで定義されてるものとする public ユーザ :: 本名 : seq of char Email : seq of char ニックネーム : seq of char 誕生日 : 「日付」;
  25. 45.

    class クラス名 end クラス名 3.形式手法で記述 ーインスタンス変数定義ー › インスタンス変数定義 types 型定義・・・クラスで用いる型(データの概念)

    instance variables インスタンス変数定義・・・クラスで用いる変数 operations 操作定義・・・クラス内の変数を操作する処理
  26. 48.

    3.形式手法で記述 ーインスタンス変数定義ー › インスタンス変数定義 – クラスで用いる変数を定義できる – 基本はprivate等を設定し、外のクラスから触らせないようにする。 --「日付」は別のクラス --インスタンス変数には、型定義同様、別のクラスをあてることができる

    private 現在日付 : 「日付」; --「set of x」と記載するデータ型は --「集合型」といって、順番を持たない集まり --下記は「(型定義で記載した)ユーザ型のデータの集合」という意味 private 登録リスト: set of ユーザ := {};
  27. 50.

    3.形式手法で記述 ーインスタンス変数定義ー › インスタンス変数定義(不変条件:inv) – 定義した変数が絶対に守らなければならない条件を記載する private 登録リスト: set of

    ユーザ; --inv:不変定義 --「card s」 は集合sの要素数を返す式 --下記の意味は「登録リストに含まれるユーザ数の上限は30まで」ということ inv card 登録リスト <= 30; --下記の意味は「登録リストにあるすべての任意のユーザ1、ユーザ2について、 -- ユーザ1とユーザ2が異なるデータのとき、ニックネームも違うこと -- (つまりニックネームは一意)」ということ --「forall x in set s 」&「条件」:集合sの中のすべてのxは「条件」を満たす --「a => b 」:aがtrueであればbもtrue inv forall ユーザ1,ユーザ2 in set 登録リスト & (ユーザ1<>ユーザ2)=>ユーザ1.ニックネーム <> ユーザ2.ニックネーム;
  28. 51.

    class クラス名 end クラス名 3.形式手法で記述 ー操作定義ー › 操作定義 types 型定義・・・クラス定義で用いる型(データの概念)

    instance variables インスタンス変数定義・・・クラス定義で用いる変数 operations 操作定義・・・クラス内の変数を操作する処理
  29. 53.

    3.形式手法で記述 ー操作定義ー › 操作定義 – クラス内の変数を操作する処理を記載する。 › ユーザ取得byEmail、ユーザ登録、ユーザ削除・・・ – 基本的に入力を得て結果を返す。

    – 書き方には陰定義と陽定義がある。 › 陰定義:操作定義に記載する処理のロジックではなく、 処理開始時または処理結果に要求される特性を記載する。 › 陽定義:実際の処理で行う操作の仕様を記述する。
  30. 54.

    3.形式手法で記述 ー操作定義ー › 操作定義(陰定義) – 陰定義:操作定義に記載する処理のロジックではなく、 処理開始時または処理結果に要求される特性を記載する。 処理で使用するインスタンス変数を明記してかく必要がある。 – 事前条件:「この処理を行うときに満たされていなきゃいけない条件はなにか」

    →この処理を適用する際に期待している条件を論理式で記載する。 – 事後条件:「処理の結果、どうなっていてほしいのか」 →処理結果に要求される特性を論理式で記載する。 public ユーザ削除(pEmail:seq of char) ext wr 登録リスト:set of ユーザ pre exists1 u in set 登録リスト & u.Email = pEmail post not exists u in set 登録リスト & u.Email = pEmail;
  31. 55.

    3.形式手法で記述 ー操作定義ー --public/protected/private 操作定義名(引数名:引数のデータ型) public ユーザ削除(pEmail:seq of char) --ext:使用するインスタンス変数を指定。 --wrは書き込みをするという意味

    ext wr 登録リスト:set of ユーザ --pre:事前条件 --「処理の前、登録リストにはEmailが同じユーザが1つだけ存在する」 --「exists1 x in set s &『条件』」の意味は -- 「s集合内に『条件』を満たす要素xがちょうど1つだけあるかどうか」 pre exists1 u in set 登録リスト & u.Email = pEmail --post:事後条件 --「処理の後、登録リストにはEmailが同じユーザが1つも存在しない」 --「exists x in set s &『条件』」の意味は -- 「s集合内に『条件』を満たす要素xがすくなくとも1つだけあるかどうか」 post not exists u in set 登録リスト & u.Email = pEmail; › 操作定義(陰定義(事前条件・事後条件))
  32. 56.

    3.形式手法で記述 ー操作定義ー › 操作定義(陽定義) – 陽定義:実際の処理で行う操作の仕様を記述する。 › 入力と結果の型を与え、結果を仮引数の組み合わせで表現する式を与える。 › 通常1文のみ

    (複数の文も記述できるが、処理の実装をずらずらと書くことは想定していない)。 › 事前条件、事後条件を書くことも可能。 › if文やcase文、for文も使用可能。 public ユーザ削除: seq of char ==> () ユーザ削除(pEmail) == 登録リスト :=登録リスト ¥ {let u in set 登録リスト be st u.Email = pEmail in u } pre exists1 u in set 登録リスト & u.Email = pEmail post not exists u in set 登録リスト & u.Email = pEmail;
  33. 58.

    3.形式手法で記述 ー操作定義ー › 操作定義(陽定義) --public/protected/private 操作定義名 引数のデータ型 ==> 返り値の型 public

    ユーザ削除: seq of char ==> () --操作定義名(引数名)== ユーザ削除(pEmail) == --下記の意味は「登録リストに、(今までの)登録リストと、 -- 登録リストでEmailが合致するユーザを集合にしたものとの差分を抽出する --(登録リストから該当ユーザを引く)」 --「s1とs2の差を抽出」はs1 ¥ s2 登録リスト :=登録リスト ¥ {let u in set 登録リスト be st u.Email = pEmail in u } --pre:事前条件 --「処理の前、登録リストにはEmailが同じユーザがちょうど1つだけ存在する」 --「exists x in set s &『条件』」の意味は -- 「s集合内に『条件』を満たす要素xが少なくとも1つあるかどうか」 pre exists1 u in set 登録リスト & u.Email = pEmail --post:事後条件 --「処理の後、登録リストにはEmailが同じユーザが1つも存在しない」 --「exists x in set s &『条件』」の意味は --「s集合内に『条件』を満たす要素xが少なくとも1つあるかどうか」 post not exists u in set 登録リスト & u.Email = pEmail;
  34. 60.

    4.検証 › 整合特性検査:仕様齟齬のチェック – 型・構文チェック › 間違った型などを使っていないかの確認 – 部分演算子についての整合性チェック ›

    0で割る、集合にないデータの検索など、値を返せない処理が存在しないか →不変条件・事前条件・事後条件の追加 – 不変条件のチェック › インスタンス変数などの不変条件が操作定義などの処理で守られない可能性はないか ※ツール(VDMToolsなど)では「証明課題の作成」等の補助機能あり › ツールでのテスト実行 – テストクラスの作成と、実行 →VDMToolsのAPIと組み合わせればプロトタイプでのテストも可能 ※ツールはVDMToolsやOvertureが存在 VDMTools: http://fmvdm.org/index.html Overture: http://overturetool.org/
  35. 62.

    4.検証 › 整合特性検査:仕様齟齬のチェック – インスタンス定義の不変条件 – 操作定義のユーザ登録 --inv:不変定義 --「card s」

    は集合sの要素数を返す式 --下記の意味は「登録リストに含まれるユーザ数の上限は30まで」ということ inv card 登録リスト <= 30; public ユーザ登録: seq of char * seq of char * seq of char * 「日付」 ==> () ユーザ登録(p本名,pEmail,pニックネーム,p誕生日) == 登録リスト := {mk_ユーザ(p本名,pEmail,pニックネーム,p誕生日)} union 登録リスト --pre:事前条件 pre p誕生日.年齢算出(現在日付) > 12 --登録リストが30人以下であるためには、ユーザ登録前は29人である必要がある。 --事前条件を複数書きたいときにはandでつなげて書く。 and card 登録リスト <= 29;
  36. 64.

    4.検証 › 整合特性検査:仕様齟齬のチェック – 部分演算子のチェック public ユーザ取得byEmail: seq of char

    ==> ユーザ ユーザ取得byEmail(pEmail) == --下記の意味は「ユーザリストの中にあるEmailがp_Emailと同じユーザを返す」 --「let x in set s be st 『xの条件』in 『xを使った式or文』」は --「s集合の中で『xの条件』を満たすxについて『xを使った式or文』を実行する」 let u in set 登録リスト be st u.Email = pEmail in return u --検索するユーザがリストにいなければならない pre exists1 u in set 登録リスト & u.Email = pEmail;
  37. 65.

    やってみよう!テストユーザ登録システム › ユーザ管理機能 1. ユーザ取得byニックネームの処理をVDM++で記載してみよう › ユーザ取得byEmailを参考に、同じように書いてみよう 2. ユーザ管理機能の不変条件・事前条件・事後条件を俯瞰して確認し、 何か問題がないか確認してみよう

    › 不変条件(inv)、事前条件(pre)、事後条件(post) › 登録・検索・削除で問題がないか、それぞれの定義の不変条件・事前条件・事後条件 を見比べてみよう – 不変条件はあるのに事前条件・事後条件はない、あるいはその逆 – 登録はできるのに削除はできない › 問題を見つけたら、どう定義を変更するか考えてみよう(余裕があれば)
  38. 67.

    やってみよう!テストユーザ登録システム › ユーザ管理機能 1. ユーザ取得byニックネームの処理をVDM++で記載してみよう › ユーザ取得byEmailを参考に、同じように書いてみよう 2. ユーザ管理機能の不変条件・事前条件・事後条件を俯瞰して確認し、 何か問題がないか確認してみよう

    › 不変条件(inv)、事前条件(pre)、事後条件(post) › 登録・検索・削除で問題がないか、それぞれの定義の不変条件・事前条件・事後条件 を見比べてみよう – 不変条件はあるのに事前条件・事後条件はない、あるいはその逆 – 登録はできるのに削除はできない › 問題を見つけたら、どう定義を変更するか考えてみよう(余裕があれば)
  39. 69.

    やってみよう!テストユーザ登録システム › ユーザ管理機能 1. ユーザ取得byニックネームの処理をVDM++で記載してみよう › ユーザ取得byEmailを参考に、同じように書いてみよう 2. ユーザ管理機能の不変条件・事前条件・事後条件を俯瞰して確認し、 何か問題がないか確認してみよう

    › 不変条件(inv)、事前条件(pre)、事後条件(post) › 登録・検索・削除で問題がないか、それぞれの定義の不変条件・事前条件・事後条件を見 比べてみよう – 不変条件はあるのに事前条件・事後条件はない、あるいはその逆 – 登録はできるのに削除はできない › 問題を見つけたら、どう定義を変更するか考えてみよう(余裕があれば) 所要時間:10分
  40. 70.

    やってみよう!テストユーザ登録システム › 問題1解答 public ユーザ取得Byニックネーム: seq of char ==> ユーザ

    ユーザ取得Byニックネーム(pニックネーム) == -「ユーザリストの中にあるニックネームがpニックネームと同じユーザを返す」 let u in set 登録リスト be st u.ニックネーム = pニックネーム in return u --検索するニックネームのユーザがリストにいなければならない pre exists1 u in set 登録リスト & u.ニックネーム = pニックネーム;
  41. 71.

    やってみよう!テストユーザ登録システム › 問題2解答① --inv:不変定義 --下記の意味は「登録リストにあるすべての任意のユーザ1、ユーザ2について、ユーザ1とユーザ2が異なるデータのとき、 --ニックネームも違うこと(つまりニックネームは一意)」ということ inv forall ユーザ1,ユーザ2 in

    set 登録リスト & (ユーザ1<>ユーザ2)=>ユーザ1.ニックネーム <> ユーザ2.ニックネーム; public ユーザ登録: seq of char * seq of char * seq of char * 「日付」 ==> () ユーザ登録(p本名,pEmail,pニックネーム,p誕生日) == 登録リスト := {mk_ユーザ(p本名,pEmail,pニックネーム,p誕生日)} union 登録リスト --pre:事前条件 pre p誕生日.年齢算出(現在日付) > 12; and card 登録リスト <= 29 --ニックネームが一意であるためには、登録時に同じニックネームのユーザがいてはならない。 and not exists u2 in set 登録リスト & u2.ニックネーム = pニックネーム and ・・・
  42. 72.

    やってみよう!テストユーザ登録システム › 問題2解答② – ユーザ登録処理で同じEmailアドレスを登録すると以下の問題 › ユーザ削除処理で削除処理をすると、事前条件エラー › ユーザ取得byEmail処理をすると、事前条件エラー public

    ユーザ登録: seq of char * seq of char * seq of char * 「日付」 ==> () ユーザ登録(p本名,pEmail,pニックネーム,p誕生日) == 登録リスト := {mk_ユーザ(p本名,pEmail,pニックネーム,p誕生日)} union 登録リスト --pre:事前条件 pre p誕生日.年齢算出(現在日付) > 12; and card 登録リスト <= 29 and not exists u2 in set 登録リスト & u2.ニックネーム = pニックネーム --ユーザ削除で適切に削除されるためには、登録時に同じEmailのユーザがいてはならない。 and not exists u in set 登録リスト & u.Email = pEmail pre exists1 u in set 登録リスト & u.Email = pEmail;
  43. 73.

    やってみよう!テストユーザ登録システム › 問題2解答③ public ユーザ登録: seq of char * seq

    of char * seq of char * 「日付」 ==> () ユーザ登録(p本名,pEmail,pニックネーム,p誕生日) == 登録リスト := {mk_ユーザ(p本名,pEmail,pニックネーム,p誕生日)} union 登録リスト --pre:事前条件 pre p誕生日.年齢算出(現在日付) > 12; and card 登録リスト <= 29 and not exists u2 in set 登録リスト & u2.ニックネーム = pニックネーム --ユーザ削除で適切に削除されるためには、登録時に同じEmailのユーザがいてはならない。 and not exists u in set 登録リスト & u.Email = pEmail --inv:不変定義 --Emailも一意であるべきであった。 inv forall ユーザ1,ユーザ2 in set 登録リスト & (ユーザ1<>ユーザ2)=>ユーザ1.Email <> ユーザ2.Email;
  44. 76.

    形式手法のいいところ › 仕様を厳密にかける。 – 読み手側で行間を推測して読む必要がない。 – 資料の抽象度を一定にしやすい。 › 「実装」ではなく「仕様」を記述することが可能 –

    検索などの仕様を、実装ではなくそのまま厳密に記述することが可能 › 実装前に検証が可能 – 不変条件・事前条件・事後条件などが厳密に書かれており、 確認しやすい – 厳密に書いているのでツールでの検証・デバックができる。 →仕様状態でのデバック実行が可能
  45. 77.

    VDM++を書くときのガイドライン 1. 辞書中の名詞は、モデルの目的に照らして、もし読み書きに加えて警備な機能しか必要としていないなら、型としてモデル化されるべきである。 2. 異なるクラス間の正確な関係と関連を表現するための全体クラスを作成する。 3. 関連を定義するときには、いつでもその多重度を考慮しなければならない。そしてその関連が利用される方向にロール名を付ける。 4. もし関連がある値に依存している場合には、その関連は、限定子を加えたものとする。限定子の名前はVDM++の型名と同じものとする。 5.

    カプセル化を保つためには、インスタンス変数をprivateまたはprotectedとして宣言する。もし利用者が何も指定しなけらばprivateが自動的に想定される。 6. クラスのスケルトンが生成されたら、それ以上の機能を追加する前に、、すぐ一貫性をVDMToolsでチェックすること。 7. token型は、まだ詳細が決まっていない値を扱う。抽象的モデルを定義する際に有用である。 8. 引数と戻り値の型について注意深く考えることは、しばしばクラス図中で不足している関連を発見する役に立つ。 9. 重要な性質や性質を不変条件として記述せよ。 10. ある昨日を実現する複数の手段がある場合には、陰定義を用いて開発の後工程に影響を与えないようにすることができる。 11. 操作を定義する際には、同時により多くの不変条件を探すようにせよ。 12. 陽操作定義を精確かつ明解に行うこと。その場合でもプログラミング言語による記述よりも抽象的であるように心がけること。 13. あるクラスがインスタンス変数に関する不変条件を持ち、かつ構成子を定義しているときに、もしその構成子が不変条件に関係する変数への代入を行うなら、不変条件 を分離した関数として定義しておくことには価値がある。 ジョン・フィッツジェラルド、ピーター・ゴルム・ラーセン、ポール・マッカージー、ニコ・プラット、マーセル・バーホフ(2010年) 『VDM++によるオブジェクト指向システムの高品質設計と検証」』翔泳社
  46. 80.

    形式手法で大事なこと › 何が複雑なのかを把握 – 何が複雑だから形式手法を用いたいのか →使用する手法、モデリングの内容を考える →どの抽象度でモデルを記載するべきなのかを考える › どう検証するか –

    並行処理を検証したいのか – 仕様の整合性を確認したいのか – 実際の実装に入るまえに仕様を確認したいのか →適している形式手法を考える
  47. 81.

    形式手法の種類 › VDM – 開発者に受け入れられやすい、ライトな形式手法。 – インタプリタ実行による検証。 › Bメソッド –

    段階的詳細化と定理証明を軸とした技法。 › Alloy – 自動解析可能なモデル規範形式仕様言語。 › SPIN – モデル検査検証ツール。状態遷移モデルの観点で仕様を記述。並行処理 の検証で使われる。
  48. 82.

    参考文献 1. ジョン・フィッツジェラルド、ピーター・ゴルム・ラーセン、ポール・マッカージー、ニコ・プラット、マーセル・バーホフ (2010年)『VDM++によるオブジェクト指向システムの高品質設計と検証」』翔泳社 2. 石川冬樹(2011年)『VDM++による形式仕様記述 (トップエスイーシリーズ 実践講座)』 荒木 啓二郎監修、近代科学社

    3. 中島震(2012年)『形式手法入門―ロジックによるソフトウェア設計― )』オーム社 4. SQuBOK策定部会 (2014年)『ソフトウェア品質知識体系ガイド -SQuBOK Guide-(第2版) 』 オーム社 5. 「「VDM++による形式仕様記述」Webサイト」 http://research.nii.ac.jp/~f-ishikawa/vdm/index.html(2019月12月アクセス) 6. 「ディペンダプルシステムのための形式手法の実践ポータル」 http://formal.mri.co.jp/ (2019月12月アクセス)
  49. 85.

    VDM++の書き方 › クラス定義 class クラス名 value 定数値定義 types 型定義 instance

    variables インスタンス変数定義 operations 操作定義 end クラス名 fucntions 関数定義 thread スレッド定義 sync 同期制約
  50. 86.

    VDM++の書き方 -データ型ー › データ型 型 意味 例 bool ブール型 true/false

    nat1 非負整数(n≧1) 1、2、3・・・ nat 正整数(n≧0) 0、1、2、3・・・ rat 有理数(整数または分数で表せる数値) -1/3、-1/2、0、1/2・・・ real 実数 -√2、-1、1/3・・・ char 文字型 a、b、c、あ・・・ quote 引用型(列挙型のときに用いられる) <赤>、<青>、<黄> token トークン型(内部構造を指定しない) ※ 文字列は「seq of char」と記載する ※石川冬樹(2011年)『VDM++による形式仕様記述 (トップエスイーシリーズ 実践講座)』をもとにまとめたもの
  51. 87.

    VDM++の書き方 -データ型ー › 演算子(共通) 演算子 意味 a = b 相当判定(aとbは同じ)

    a <> b 不等判定(aとbは違う) ※石川冬樹(2011年)『VDM++による形式仕様記述 (トップエスイーシリーズ 実践講座)』をもとにまとめたもの
  52. 88.

    VDM++の書き方 -データ型ー › 演算子(bool型) 演算子 意味 not a bではない(否定) a

    and b aとbの両方が成り立つ(論理積) a or b aとbの少なくとも片方が成り立つ(論理和) a => b aが成り立つならばbが成り立つ a <=> b aとbの真偽値が一致する(同値) →aがtrueならbもtrue aがfalseならbもfalse ※石川冬樹(2011年)『VDM++による形式仕様記述 (トップエスイーシリーズ 実践講座)』をもとにまとめたもの
  53. 89.

    VDM++の書き方 -データ型ー › 演算子(数値型) 演算子 意味 -x 負等号 abs x

    xの絶対値 floor x xを超えない最大の整数 x + y x – y x * y x / y 四則計算 x div y 整数除算の商 (x ÷ y = a 余り b のaの部分) x mod y x rem y 整数除算の余り (x ÷ y = a 余り b のbの部分) x ** y べき乗(xのy乗) ※石川冬樹(2011年)『VDM++による形式仕様記述 (トップエスイーシリーズ 実践講座)』をもとにまとめたもの
  54. 90.

    VDM++の書き方 -データ型ー › 複合データ型 型 意味 宣言例 値例 合併型 列挙されている値のいず

    れか char|int <赤>|<青>|<黄> a <青> 選択型 列挙されている値のいず れか またはnil(未選択) [bool] [<赤>|<青>|<黄>] true <赤> nil 組型 他の型の固定的な組み合 わせ nat1 *bool mk_(3,true) レコード型 他の型の固定的な組み合 わせ 個々の要素に名前をつけ られる ユーザ :: ID : nat1 名前 : seq of char mk_ユーザ(31,”やま”) ※石川冬樹(2011年)『VDM++による形式仕様記述 (トップエスイーシリーズ 実践講座)』をもとにまとめたもの
  55. 91.

    VDM++の書き方 -データ型ー › 複合データ型 – 動的な集合の場合は以下のとおり記載する {f(x) | x in

    set s & 『論理式』} (集合sの中の値で『論理式』を満たすxについて、f(x)を計算した値を、新たな集合とする。) › 例){x + 1 | x in set {1,2,3,4,5} & x mod 2 = 0} →{1…5}の中で2で割ると0の値について、1を加えた値の集合 → {1…5}の中で2で割ると0になる値は「2、4」、これらにそれぞれ1を加える →答えは{3,5} 型 宣言 宣言例 値例 集合型 順番を持たない集まり {1,2,3,4} seq of char (文字の塊) {1,2,3,4} {‘a’,’b’,’t’} (={‘b’,’a’,’t’}) ※石川冬樹(2011年)『VDM++による形式仕様記述 (トップエスイーシリーズ 実践講座)』をもとにまとめたもの
  56. 92.

    VDM++の書き方 -データ型ー › 演算子(集合型1ページ目) 演算子 意味 例 s1 union s2

    s1とs2を合併する {1,2,3} union {2,3,4} → {1,2,3,4} s1 inter s2 s1とs2の共通部分を抽出 {1,2,3} inter {2,3,4} → {2,3} s1 ¥ s2 s1とs2の差を抽出 {1,2,3} ¥ {2,3} → {1} e in set s1 eはs1に帰属する 1 in set {1,2,3,4} → true e not in set s1 eはs1に帰属しない 1 not in set {2,3,4} → true s1 subset s2 s1はs2に含まれている {2,2,3} subset {2,3,4} → true {2,3,4} subset {2,2,3} → false s1 psubset s2 s1はs2に含まれているが、 s1はs2と同じではない {2,2,3} psubset {2,3,4} → true {2,3,4} psubset {2,3,4} → false ※石川冬樹(2011年)『VDM++による形式仕様記述 (トップエスイーシリーズ 実践講座)』をもとにまとめたもの ※石川冬樹(2011年)『VDM++による形式仕様記述 (トップエスイーシリーズ 実践講座)』をもとにまとめたもの
  57. 93.

    VDM++の書き方 -データ型ー › 演算子(集合型2ページ目) 演算子 意味 例 s1 = s2

    s1とs2は同じ {2,4,3} = {2,3,4} → true ([2,4,3] = [2,3,4] → false) s1 <> s2 s1とs2は同じではない {2,4,3} <> {2,3,4} → false ([2,4,3] <> [2,3,4] → true) card s1 s1の要素数 card {2,3,4} → 3 dunion ss ss内のすべての集合を 合併する dunion {{1,2},{2,3,4},{4,5}} →{1,2,3,4,5} dinter ss ss内のすべての集合について 共通部分を抽出 dinter {{1,2,3},{2,3,4}} → {2,3} power s1 有限冪集合 power {1,2} → {{},{1},{2},{1,2}} ※石川冬樹(2011年)『VDM++による形式仕様記述 (トップエスイーシリーズ 実践講座)』をもとにまとめたもの
  58. 94.

    VDM++の書き方 -データ型ー › 複合データ型 型 宣言 宣言例 値例 列型 順番をもつ集まり

    [1,2,3,4] seq of char (文字列) [1,2,3,4] [’b’,’a’,’t’] (<>[‘a’,’b’,’t’]) “bat” 写像型 ある値の集合 (domain=定義域) から、別の値の集合 (range=値域) を紐づけた型 map (seq of char) to nat map 型1 to 型2 Inmap 型1 to 型2 (単射) {“太郎” |-> 1, “次郎” |-> 2} 定義 値 太郎 1 太郎 2 ※石川冬樹(2011年)『VDM++による形式仕様記述 (トップエスイーシリーズ 実践講座)』をもとにまとめたもの
  59. 95.

    VDM++の書き方 -式または文ー 文 意味 例 a := b aにbを代入する X

    := 9; (Xに9に代入する →Xは9になる) X :=N; (XにNを代入する →XはNに入っていた値になる) ※石川冬樹(2011年)『VDM++による形式仕様記述 (トップエスイーシリーズ 実践講座)』をもとにまとめたもの
  60. 96.

    VDM++の書き方 -式または文ー 意味 構文 例(式) もし『条件』に該当するならば 『文また式』を実行する。 合わない場合には『その他』を実 行する。 if

    『条件』 then 『文or式』 else 『文or式』 if x = 3 then “参” else “零” (xが3だったら参、違う場合は零) 『式』が『パターンn』のとき 『式または文n』を行う、 パターンがどれにも合わない場合 には『その他』を実行する。 cases 『式』: 『パターン1』-> 『式or文1』, 『パターン2』-> 『式or文2』, ・・・ 『パターンn』-> 『式or文n』, others -> 『その他』 end cases x : 3 -> “参” , 4 -> “肆” , others -> 0 end (xが3だったら参、4だったら肆、 全部違う場合は零) 『パターン』を『式1』とし、 『パターンを使った式or文』を実 行 def (let)『パターン』=『式1』 in 『パターンを使った式or文』 def x = 3 in x + 3 (xが3としてx+3を計算→6) s集合の中で『xの条件』を満たす xについて『xを使った式or文』を 実行する let x in set s be st 『xの条件』 in 『xを使った式or文』 let x in set {1,2,3} be st x>2 in x+1 (1,2,3の中で2より大きいものにつ いて、1を加える→4) ※石川冬樹(2011年)『VDM++による形式仕様記述 (トップエスイーシリーズ 実践講座)』をもとにまとめたもの
  61. 97.

    VDM++の書き方 -式または文ー 意味 構文 例 s集合内のすべての要素xが、 『条件』を満たすかどうか forall x in

    set s &『条件』 forall x in set {1,2,3} & x>0 (集合「1,2,3」のすべての要 素はxよりも大きいか) s集合内に『条件』を満たす 要素xが少なくとも1つある かどうか exists x in set s &『条件』 exists x in set {1,2,3} & x>1 (集合「1,2,3」の要素の中で 1よりも大きい要素が存在す るか) s集合内に『条件』を満たす 要素xがちょうど1つだけあ るかどうか exists1 x in set s &『条件』 exists1 x in set {1,2,3} & x>2 (集合「1,2,3」の要素の中で 2よりも大きい要素がちょう ど1つだけあるか) ※石川冬樹(2011年)『VDM++による形式仕様記述 (トップエスイーシリーズ 実践講座)』をもとにまとめたもの