バベルの図書館は完成しない

Extended outer memory module
for my poor native memory.

Posts:
2022/02/13 クラビスの CTO になりました
2020/09/28 gendoc という YAML からドキュメントを生成するコマンドを作った
2020/09/13 ISUCON10 の予選を 7 位で通過した
2019/12/01 Puma の内部構造やアーキテクチャを追う
2019/05/27 Golang の正規表現ライブラリの処理の流れをざっくり掴む
2019/04/29 InnoDB の B+Tree Index について
2019/04/29 InnoDB における index page のデータ構造
2019/04/28 InnoDB はどうやってファイルにデータを保持するのか
2019/01/06 Designing Data-Intensive Applications を読んでいる
2019/01/03 年末年始に読んだ本について、など
2019/01/01 Ruby から ffi を使って Rust を呼ぶ
2018/11/10 ブラウザにおける状態の持ち方
2018/07/01 Rust で web アプリ、 或いは Rust における並列処理
2018/05/14 なぜテストを書くのか
2018/05/13 Rust で wasm 使って lifegame 書いた時のメモ
2018/03/12 qemu で raspbian のエミュレート(環境構築メモ)
2018/03/12 qemu で xv6 のエミュレート(環境構築メモ)
2018/03/03 Ruby の eval をちゃんと知る
2018/02/11 Web のコンセプト
2018/02/03 Rspec のまとめ
2018/02/03 Ruby を関数型っぽく扱う

なぜテストを書くのか

この前 テストを書くこと についていい話を聞いたので、聞いた内容を踏まえつつ僕がその時に思ったことを書いてみる。


前提として (アウトプットのおはなし)

そもそもソフトウェアエンジニアリングに限らず、世の中において広くアウトプットを出していくという行動を行う上で、

の 3 つの世界が存在している。

現実 の世界

現実 とは、客観的な視点がこの世に存在すると仮定して、彼が見ているこの世界のことだ。

意図 の世界

意図 とは、現実を我々が我々なりになるべく客観的に見た上で、そこに対してアウトプットを行って価値を生み出そうとしたときの、価値を生み出そうと判断した理由や、どんな価値を生み出そうと思ったのか、という思考の道筋のことだ。

ソフトウェア開発においては特に、経営サイドによるビジネス的な判断やサービス仕様と置き換えられるものだと思う。

アウトプット の世界

アウトプット とは、上の 2 つの世界で起きたことを踏まえて、実際に生み出されるアウトプットのことだ。

それはコードであり、アプリケーション自身であり、サーバーであり、デバイスであり、ユーザーの経験である。

これら 3 つの世界が噛み合っているうちは、各世界は綺麗に回り続けると考えられるけれども、3 つの世界がズレ始めた時にそれぞれの世界で不幸なことが起き始めると僕は考えている。

話が大きくなりすぎるとこの先大変そうなので、ソフトウェアエンジニアリングの世界に絞って話を進めたい。

ソフトウェアエンジニアリングにおいて、エンジニアが日々生活し格闘するのは、主に上で挙げたうちの 3 つめの世界、すなわち アウトプットの世界 だろうと思う。

だけどここまで話してきたように、アウトプットの世界の住民は、現実の世界と意図の世界にも気を配り続けなくちゃいけないと考えている。

僕たちがコードを書いている世界

3 つに分かれた世界においてコードを書くということは、僕たちは自分の住む世界に対してだけじゃなくて、

3 つ全ての世界に対して誠実に直視する義務があるということ に他ならないと思っている。

少なくとも自分の担当するアプリケーションの領域において、僕たち以外に誰が(現実・意図の世界だけでなくて)

アウトプットの世界にまで本当の意味で気を配れるだろうか。

現実の難しさ

しかし 3 つの世界において、現実の世界を誠実に直視することはとっても難しい。

主観・バイアスが絶対に入り込むし、そもそも一人の人間が観測するには広すぎる領域だからだ。

(神様以外にこの世の中を見透かしている存在なんていないはずだ。)

だからこそ

だからこそ、僕たちは最低限、意図の世界アウトプットの世界 のズレがなるべく存在しない状態を保つ責任がある。

この 2 つの世界は現実の世界に比べると、幾分か観測も制御も簡単であることは間違いないからだ。(それでも十分に難しいと思う)

そして、この 2 つの世界を統一する魔法のコンセプトこそが テスト である。そんな風に僕は考えている。

つまり、この前提に立って(時に忘れてしまっていても立ち返ってきて)、 3 つの世界に目を向けつつ、どうやって 2 つの世界を繋げるかを考えることが

あるべきテストを考えることなんじゃないのかなあ、と思っている。

もう少しだけ技術的な話も

インターフェースの重要性

ソフトウェアエンジニアリングにおいて重要なのは、

各責務を持った機能たち不整合のないように上手に統べてあげること だ。

物理的/論理的に、人間が全てに気を配るのには十分に難しすぎる現代の計算機とその上で動くアプリケーション群においては

抽象化による各機能のグルーピング(レイヤー分割) は人間に必須な能力だ。

その上で抽象化された機能たちが最後までビー玉を落とさずにピタゴラスイッチさせてあげるためには、

細かいレールの違いよりも、どこでビー玉はジャンプして、どこに着地するのか、

各ギミックのスタートとゴールの整合性が何よりも重要であることは間違いないのだと思う。

(気をつけて欲しいのは、あくまでそれが対象の 十分な複雑さ によってもたらされる戦略なのであって、

対象から複雑さを上手く取り除いた後は、より 具体 に降りていく必要が出てくるということだ。)

各ギミックのスタートとゴールの整合性を保証してあげることががすなわち、

ソフトウェアエンジニアリングにおける インターフェースの保証 になるのだと考えている。

これは オブジェクト志向型言語 が生まれた理由でもあるのだと思う。

前のギミックがうまいこと狙ったタイミングでビー玉を放り出してくれさえすれば、

次のギミックは、前のギミックが例えどんな愉快なビー玉転がしを行っていようとも、

例えその中身が撮影寸前に大幅に変更されようとも何も気にする必要はない。

そんな状況を作りたいモチベーションからオブジェクト志向が生まれたであろうことはあながち嘘ではないはずだ。(カプセル化の話)

ちょっと余談になってしまうけれども、あるギミックをビー玉が通っている時に、

積み木を落としたり別のビー玉を発射する仕組みがあったとしよう。

さっきは自分の前のギミックが何をやっているか知る必要がない、と言ってしまったけれども

もし積み木が別のギミック内のビー玉の通り道を邪魔したらどうしよう?

あるいはもし別のビー玉が本来のビー玉に当たって、代わりに転がり始めたらどうしよう?

オブジェクト志向で開発を行っているうちに、何人かの人の頭の中にはこんな心配が起こり始めたみたいで、

そこから、副作用のない、参照透明な形で処理をなるべく連ねていくことを目的として

関数型言語 が生まれたのかなーなんて僕は考えている。

話がオブジェクト志向や関数型にふらふらと寄り道してしまったけれども、

ようは テストにおいて第一に考えるべきなのは各処理のインターフェースの保証 だということを主張したかった。

これによって大きな大きなピタゴラスイッチ的装置も全体として問題なく動くはず、とまずは言えるはずだ。

(インターフェースの保証のためには処理の境界地付近でのテストは入念に行うべきだろう。)

しかもインターフェースを保証するテストを書いていて、テストを書くのが難しい時は、

対象が、人間が扱うには難しすぎるということを暗に教えてくれさえする。

テストによるインターフェースの固定はとっても素晴らしいことと考えて間違いないだろう。

人は間違える生き物

人は間違える生き物で、それはアプリケーションにおいても同様だ。

ユーザーに価値を届けたいと思って作ったアプリケーションも、時に意図せぬ挙動をユーザーに対して行ってしまうことがある。(最悪だ!)

そんな時に、膨大なユーザーとのインターフェースの中で、最低限一度失敗してしまった部分を保証してあげるのは悪くないアイデアだと思う。

よりテクニカルには、リグレッションテストの形式で E2E テストを行うのは悪くないアイデアみたいだ。

重たいし、挙動も安定しない E2E テストが嫌いな人はたくさんいると思う。( html の描画はとっても大変な処理だ。)

React みたいな Virtual DOM を利用したフレームワークが出てきているとはいえ、

まだ E2E テストは不完全な状態であるのは間違いないところだと思う。(多分ね)

だからこそ、最低限を保証するために E2E テストを行う。

一度不具合の発生したところをテストする。あるいは、サービスの核となる部分をテストする。

そういった判断でユーザーとのインターフェースをテストしてあげるのは悪くない戦略に思える。

(かなりテクニカルな話になるけど、 CI 環境で E2E テストだけ他のテストと別の環境で回し続ける、みたいな開発スピードを落とさないテクニックがあるらしい)

おわりに

なんかこう (テストって大事だけどなんで大事なんだっけ?)

っていう疑問がたまーに浮かぶくらいは、その前提の話を僕はよく忘れてしまうなと思ったので、

実際に文字に書き起こすかと思い立ち書きました。

まあ、僕のための文章なので、僕がよければいいのです。

追記

(2018/12/08 うーん、と思って色々削った。)

2018/05/14 00:00
tags: test - poem
This site is maintained by furuhama yusuke.
from 2018.02 -