Slide 1

Slide 1 text

@hoddy3190 Mar. 7th 2019 Android Test Night #6 形式手法について調べてみた Let’s Try Formal Methods

Slide 2

Slide 2 text

鈴木穂高(Hodaka Suzuki) Twitter @hoddy3190 ● 2014年DeNA新卒入社 ● アプリゲーム開発・運用(2014/08 〜 2018/10) ○ サーバー、クライアント、マスター管理ツール、インフラ 整備、マネジメントなど ○ パフォチューが好き ● テスト技術チーム - SWET(2018/10 〜) ○ Android ○ 形式手法

Slide 3

Slide 3 text

目次 ● 動機 ● 形式手法とは ● モデル検査とは ● 形式手法適用のシミュレーション ● メリデメ等 ● まとめ

Slide 4

Slide 4 text

動機 なぜ形式手法を調べようと思ったのか?

Slide 5

Slide 5 text

動機 ゲーム開発をしているときに多かった 仕様の不備(考慮漏れ、記載漏れ、矛盾など)に 開発フェーズの早い段階で気づきたい。 筆者がSWETに異動した理由の1つです。

Slide 6

Slide 6 text

開発フロー 企画 実装 QA リリース 仕様作成 仕様不備があり、仕様を修正せざるを得なくなった場合、 仕様不備の発見が後になればなるほど、 手戻り工数は大きくなる傾向がある。

Slide 7

Slide 7 text

開発チームでも改善の取り組みは行われているが、 場当たり的な対策(チェックリスト、詳しい人に聞くなど)に なってしまったり、工数・スキル的に手に負えない感じもあった。

Slide 8

Slide 8 text

開発チームとは少し異なる立場にいる テスト技術チームだからこそできるアプローチは ないかと探していたところ、形式手法に出会った。

Slide 9

Slide 9 text

形式手法とは

Slide 10

Slide 10 text

形式手法 仕様を明確に記述したり、 記述された設計の性質を機械的に検証する手法の総称。 数学に基づく科学的な裏付けを持つ。 登場は20世紀中頃から。結構古い。

Slide 11

Slide 11 text

用途 ● 記述に不具合がないことを数学的に証明し保証 ● 厳密な言語を用いることで仕様を明確化 ● 記述中に隠れている不具合を開発早期に発見 ● 正しいシステムだけを系統的に開発 ※一番最後の用途は、Correctness by Constrution (CxC)と呼ばれ、 実現は不可能に近いと言われている

Slide 12

Slide 12 text

代表的な手法 ● 形式仕様記述 ○ 矛盾がなく論理的に正しい仕様を作成する ● モデル検査 ○ プログラムの状態をモデル化することで プログラムが正しいことを検証する ● 定理証明 ○ 法則や説明に基づき、理論的に性質が 成り立つことを示していく

Slide 13

Slide 13 text

代表的な記述言語/ツール ● 形式仕様記述 ○ 例: VDM++/Event-B/Z etc. ● モデル検査 ○ 例: Alloy/Promela/TLA+ etc. ● 定理証明 ○ 例: Coq/Isabelle etc.

Slide 14

Slide 14 text

モデル検査 今回は

Slide 15

Slide 15 text

モデル検査 システムを有限個の状態を持つモデルで表現し、 モデルが取りうるすべての状態を機械的かつ網羅的に検査することで、 システムが仕様を満たすことを確認する。 レアケースなど気付きにくいバグでも発見できるので、 品質の高いソフトウェアを開発するための有効な手段の1つに挙げられる。

Slide 16

Slide 16 text

手順 1. 検査したいもの(仕様書、ソースコードなど)から 専用言語でモデルを作成する 2. 検査対象が満たすべき性質から検査式を作成する 3. モデル検査ツールにかける

Slide 17

Slide 17 text

変数a * 変数bの結果は常に9未満である 変数a 表明 変数b

Slide 18

Slide 18 text

変数a * 変数bの結果は常に9未満である 1から3までの任意の値をとる 変数a 表明 1から3までの任意の値をとる 変数b

Slide 19

Slide 19 text

変数a * 変数bの結果は常に9未満である 1から3までの任意の値をとる 変数a 表明 1から3までの任意の値をとる 検査 1. aとbの取りうるすべての組み合わせを探索する 2. 表明に反する組み合わせ(反例)の有無をチェックする 3. 反例があれば表示する 変数b

Slide 20

Slide 20 text

Promelaでの例 inline Choose(n) { if :: n = 1 :: n = 2 :: n = 3 fi } active proctype P() { int a = 0, b = 0 Choose(a) Choose(b) assert(a * b < 9) }

Slide 21

Slide 21 text

Promelaでの例 inline Choose(n) { if :: n = 1 :: n = 2 :: n = 3 fi } active proctype P() { int a = 0, b = 0 Choose(a) Choose(b) assert(a * b < 9) } a、bの値をセットする

Slide 22

Slide 22 text

Promelaでの例 inline Choose(n) { if :: n = 1 :: n = 2 :: n = 3 fi } active proctype P() { int a = 0, b = 0 Choose(a) Choose(b) assert(a * b < 9) } 普通のif文とは異なり、::に続く3つの処理のうちの 1つが非決定的に実行されるという意味

Slide 23

Slide 23 text

Promelaでの例 inline Choose(n) { if :: n = 1 :: n = 2 :: n = 3 fi } active proctype P() { int a = 0, b = 0 Choose(a) Choose(b) assert(a * b < 9) } a、bが満たすべき条件を記述する(表明)

Slide 24

Slide 24 text

Promelaでの例 Spinで検査 $ spin -a -o2 ./sample.pml $ gcc -o pan pan.c $ ./pan -E -c0 -e $ spin -p -t1 sample.pml # 結果出力 Spinはモデル検査ツール。Homebrewでインストール可能。

Slide 25

Slide 25 text

Promelaでの例 結果 using statement merging 1: proc 0 (P:1) a.pml:5 (state 3) [a = 3] 2: proc 0 (P:1) a.pml:5 (state 9) [b = 3] spin: a.pml:13, Error: assertion violated spin: text of failed assertion: assert(((a*b)<9)) 2: proc 0 (P:1) a.pml:13 (state 13) [assert(((a*b)<9))] spin: trail ends after 2 steps #processes: 1 2: proc 0 (P:1) a.pml:14 (state 14) 1 process created

Slide 26

Slide 26 text

Promelaでの例 結果 using statement merging 1: proc 0 (P:1) a.pml:5 (state 3) [a = 3] 2: proc 0 (P:1) a.pml:5 (state 9) [b = 3] spin: a.pml:13, Error: assertion violated spin: text of failed assertion: assert(((a*b)<9)) 2: proc 0 (P:1) a.pml:13 (state 13) [assert(((a*b)<9))] spin: trail ends after 2 steps #processes: 1 2: proc 0 (P:1) a.pml:14 (state 14) 1 process created (a, b) = (1, 1), (1, 2) …, (3, 2), (3, 3) と すべての組み合わせを探索した上で、 a = 3, b = 3 のときが反例であると表示される

Slide 27

Slide 27 text

モデル検査の基本 1. システムが取りうる状態・パスを自動で網羅的に探索する 2. 反例があればトレースとともに表示する

Slide 28

Slide 28 text

形式手法適用の シミュレーション

Slide 29

Slide 29 text

ここからは模索中の話になります 筆者はまだ開発現場に形式手法を適用したことがありません。 形式手法のアプローチやコード、適用実現性等に疑問が残る場合が あるかもしれませんが、ご容赦ください。

Slide 30

Slide 30 text

前提 ● 仕様作成者が作る一次仕様には不備がある ○ 工数、スキルなど原因は様々

Slide 31

Slide 31 text

モデル化するフェーズは? 企画 実装 QA リリース 仕様作成

Slide 32

Slide 32 text

モデル化するフェーズは? 企画 実装 QA リリース 仕様作成 here!!

Slide 33

Slide 33 text

サンプル仕様 ● いいねボタンを設置してください ○ 投稿にいいねは1回のみ押せます ○ ログインしているユーザーしかいいねを押せません 仕様作成者が、実際に仕様をこのように記述し、 持ち込んできたとします

Slide 34

Slide 34 text

実際に形式手法を適用してみよう! 今回はPlusCalという言語で書いてみます。 ※先と同じくPromelaで書かない理由は、いろいろな言語を紹介したい という意図によるものです。

Slide 35

Slide 35 text

PlusCalでの例 ---- MODULE button ---- EXTENDS TLC (* --algorithm button variables pushed \in BOOLEAN, logined = TRUE; begin if logined = TRUE then pushed := TRUE; end if; assert FALSE; end algorithm; *) ====

Slide 36

Slide 36 text

PlusCalでの例 ---- MODULE button ---- EXTENDS TLC (* --algorithm button variables pushed \in BOOLEAN, logined = TRUE; begin if logined = TRUE then pushed := TRUE; end if; assert FALSE; end algorithm; *) ==== 状態を変数で定義

Slide 37

Slide 37 text

PlusCalでの例 ---- MODULE button ---- EXTENDS TLC (* --algorithm button variables pushed \in BOOLEAN, logined = TRUE; begin if logined = TRUE then pushed := TRUE; end if; assert FALSE; end algorithm; *) ==== ボタンが押されているかいないか

Slide 38

Slide 38 text

PlusCalでの例 ---- MODULE button ---- EXTENDS TLC (* --algorithm button variables pushed \in BOOLEAN, logined = TRUE; begin if logined = TRUE then pushed := TRUE; end if; assert FALSE; end algorithm; *) ==== ログイン中か否か(説明の便宜上、TRUE固定にしてある)

Slide 39

Slide 39 text

PlusCalでの例 ---- MODULE button ---- EXTENDS TLC (* --algorithm button variables pushed \in BOOLEAN, logined = TRUE; begin if logined = TRUE then pushed := TRUE; end if; assert FALSE; end algorithm; *) ==== ボタンの初期状態は、押されている場合もあれば 押されていない場合もある(ランダム)

Slide 40

Slide 40 text

PlusCalでの例 ---- MODULE button ---- EXTENDS TLC (* --algorithm button variables pushed \in BOOLEAN, logined = TRUE; begin if logined = TRUE then pushed := TRUE; end if; assert FALSE; end algorithm; *) ==== ログイン中であればボタンを押した状態にする

Slide 41

Slide 41 text

PlusCalでの例 ---- MODULE button ---- EXTENDS TLC (* --algorithm button variables pushed \in BOOLEAN, logined = TRUE; begin if logined = TRUE then pushed := TRUE; end if; assert FALSE; end algorithm; *) ==== 表明を常に満たせないようにすることで、 システムが取りうる全状態を反例として抽出できる

Slide 42

Slide 42 text

PlusCalでの例 TLCで検査 $ pcal button.tla $ tlc button.tla -continue -dfid 100 -dump log $ cat log.dump

Slide 43

Slide 43 text

PlusCalでの例 TLCで検査 $ pcal button.tla $ tlc button.tla -continue -dfid 100 -dump log $ cat log.dump pcalコマンドでPlusCalをTLA+に変換

Slide 44

Slide 44 text

PlusCalでの例 TLCで検査 $ pcal button.tla $ tlc button.tla -continue -dfid 100 -dump log $ cat log.dump tlcコマンドで検査

Slide 45

Slide 45 text

PlusCalでの例 TLCで検査 $ pcal button.tla $ tlc button.tla -continue -dfid 100 -dump log $ cat log.dump 結果出力

Slide 46

Slide 46 text

PlusCalでの例 結果 State 1: /\ logined = TRUE /\ pc = "Lbl_1" /\ pushed = FALSE State 2: /\ logined = TRUE /\ pc = "Lbl_1" /\ pushed = TRUE

Slide 47

Slide 47 text

State 1: /\ logined = TRUE /\ pc = "Lbl_1" /\ pushed = FALSE State 2: /\ logined = TRUE /\ pc = "Lbl_1" /\ pushed = TRUE assert FALSEに至る直前の状態の全パターン PlusCalでの例 結果

Slide 48

Slide 48 text

State 1: /\ logined = TRUE /\ pc = "Lbl_1" /\ pushed = FALSE State 2: /\ logined = TRUE /\ pc = "Lbl_1" /\ pushed = TRUE ログイン中かつすでにボタンは押された状態 PlusCalでの例 結果

Slide 49

Slide 49 text

---- MODULE button ---- EXTENDS TLC (* --algorithm button variables pushed \in BOOLEAN, logined = TRUE; begin if logined = TRUE then pushed := TRUE; end if; assert FALSE; end algorithm; *) ==== 押された状態のボタンを押す?? PlusCalでの例 結果

Slide 50

Slide 50 text

● いいねボタンを設置してください ○ 投稿にいいねは1回のみ押せます ○ ログインしているユーザーしかいいねを押せません ○ 押された状態のボタンを押すと 仕様不備発見 NEW

Slide 51

Slide 51 text

● いいねボタンを設置してください ○ 投稿にいいねは1回のみ押せます ○ ログインしているユーザーしかいいねを押せません ○ 押された状態のボタンを押すとボタンはもとに戻る 仕様不備発見 仕様作成者と相談して決めた

Slide 52

Slide 52 text

---- MODULE button ---- EXTENDS TLC (* --algorithm button variables pushed \in BOOLEAN, logined \in BOOLEAN, enabled \in BOOLEAN; begin NotEnded: either \* push await logined /\ ~pushed /\ ~enabled; pushed := TRUE; or \* unpush await logined /\ pushed /\ ~enabled; pushed := FALSE; or \* lock await ~enabled /\ ~logined; enabled := TRUE; or \* unlock await enabled /\ logined; enabled := FALSE; or \* login/logout logined := ~logined; end either; End: skip; end algorithm; *) ==== PlusCalでの例

Slide 53

Slide 53 text

---- MODULE button ---- EXTENDS TLC (* --algorithm button variables pushed \in BOOLEAN, logined \in BOOLEAN, enabled \in BOOLEAN; begin NotEnded: either \* push await logined /\ ~pushed /\ ~enabled; pushed := TRUE; or \* unpush await logined /\ pushed /\ ~enabled; pushed := FALSE; or \* lock await ~enabled /\ ~logined; enabled := TRUE; or \* unlock await enabled /\ logined; enabled := FALSE; or \* login/logout logined := ~logined; end either; End: skip; end algorithm; *) ==== PlusCalでの例 ボタンが押せる状態になっているか否か

Slide 54

Slide 54 text

● いいねボタンを設置してください ○ 投稿にいいねは1回のみ押せます ○ ログインしているユーザーしかいいねを押せません ○ 押された状態のボタンを押すとボタンはもとに戻る ○ ログインしていない場合、ボタンは押せない状態になる 仕様不備発見 モデル化する過程を通して、 「押せない状態」の存在に気づけた NEW

Slide 55

Slide 55 text

その他、仕様はまだまだ明確化できるが、 どこまでモデル化するのかという話もあるのでここで終える 例: ボタンを押したらいいねがされたことになるのか etc. 重要

Slide 56

Slide 56 text

メリデメ等

Slide 57

Slide 57 text

形式手法導入のメリット ● 検査結果から、仕様の不備に気づける ○ (注意)モデルが間違っていることも多々ある ● モデル化する過程を経ることで、仕様の不備に気づけたり、 仕様に詳しくなれたりする ● 書いたものは、より明確な仕様書として使える場合もある ● etc.

Slide 58

Slide 58 text

形式手法導入のデメリット ● 開発に組み込む際の導入コスト ○ 学習コスト、開発フロー調整コストなど ● モデル化自体が難しい ○ 状態爆発しないようにうまく抽象化しない といけないなど

Slide 59

Slide 59 text

導入をする場合 ● すべての仕様を形式仕様に落とすことはモデル化の容易さ、 工数などの理由から現実的ではないと言われている ● 部分的に導入していくのがよい ○ 部分的導入であれば、世の中に導入事例は観測できる

Slide 60

Slide 60 text

モデル検査適用の勘所 ● モデル化しやすいところ ○ 状態遷移など ● 考慮が複雑なところ ○ 複数プロセス処理など

Slide 61

Slide 61 text

モデル検査で解いてみよう ● N-Queen ● ハノイの塔 ● 有向グラフ ● 数独 モデル検査の入門としてこれらの題材が取り上げられることが多い。 興味があれば是非。

Slide 62

Slide 62 text

まとめ

Slide 63

Slide 63 text

まとめ ● 形式手法は、仕様にはらみがちな、あいまい、不正確、複雑すぎる などの問題の解決策として活用が期待できそう ● 費用対効果は実際に試してみて確かめる必要がある ● 形式手法によっても、得意不得意があるので、形式手法を適用するのか しないのか、現場にマッチした形式手法がどれなのか等はきちんと 吟味する必要がある

Slide 64

Slide 64 text

さいごに ● 現在、複雑な状態遷移をはらむAndroidのプロダクトに対し、 実際に適用することを考えています ● Androidの状態遷移図などもモデル化と相性がよいはずなので、 この場を借りて発表させていただきました