Ruby on Rails + rails-ujsを利用している場合のXSS対策について
この記事は情報セキュリティアドベントカレンダーの12日目の記事です。
開発組織でセキュリティをある程度のレベルに担保するための有効な施策として既にセキュリティ対策が施されているフレームワークを利用するようにする、というものがあります。
自分の勤めている会社では、そうした開発フレームワークとしてRuby on Railsを用いています。
Ruby on Railsでは、XSS対策としてViewに変数を表示するため、ERBの <%= %>
を用いると、出力が自動的にエスケープされるため、自分でHTMLを出力するプログラムを書いて実行するよりも安全だといえます。
しかし、Railsを普通に使っていても出力がエスケープされない部分も存在します。
それが、rails-ujsでAjax操作する場合のdataパラメータの部分です。 rails-ujsはRailsを使って開発している際、ちょっとしたAjax操作を簡単に開発できるようにしてくれるライブラリです。
link_toヘルパーメソッドなどで、
<%= link_to '削除する', item_path(@item), method: :delete, data: { confirm: "#{@item.name}を削除しますか" } %>
のように、method属性を指定したり、data属性を指定したりして用います。この場合は、リンクをクリックすると「アイテム名を削除しますか」といったダイアローグが表示される動作となります。
Railsでは、基本テンプレートエンジン(ERB)の出力で出力内容をエスケープしてくれるのですが、このrails-ujsで出力される部分はテンプレートエンジンで出力されるのではなく、JavaScriptで出力されるのでエスケープされません。
上のコードの場合、"#{@item.name}を削除しますか"
の部分がエスケープされずそのまま表示されることになり、XSS脆弱性が入り込むポイントとなります。
ですので、こういった箇所にはsanitizeメソッドで出力していいHTMLタグを制限したり、escapeHTML(別名h)メソッドでHTML入力文字を、無害なHTML表現形式に置き換えたりします。
このように、フレームワークを使ったから安心というわけではなく個別のメソッドをよく理解してセキュリティホールを埋め込まない体制を作っていきましょう。
参考
オブジェクト指向設計実践ガイド ~Rubyでわかる進化し続ける柔軟アプリケーションの育て方の7~9章を読んで
上記の本の7~9章を読んで印象に残った部分をまとめました。
7章
- 継承の手法を使い「ロール(役割)」を共有する解決法について
- クラスの継承などの関連がなかったオブジェクト同士が持つ共通の振る舞い「ロール」
- 隠れたロール(役割)を明らかにし、その振る舞いをすべての担い手どうしで共有するためのコードを書いていく
- Preparerロールの存在が示唆するのは、対応するPreparableロールの存在(対となるロールの存在)
- 共有の振る舞いをモジュールに入れる正しい方法
- クラス名をいくつも確認したうえで、ある変数に代入する値を決定するくらいなら、変数名をメソッドにして、オブジェクトに問い合わせるようにする
- メッセージに基づく期待はクラスの境界を超越し、ロールを明らかにする
- オブジェクトは自身の振る舞いは自身で持つべき
- 一つの具象クラスでまずロールの振る舞いを実装し、それを複数の具象クラスで使えるものに再構成する
- クラスによる継承はis-aの関係、モジュールによる継承はbehaves-like-aの関係
- ロールの設計のアンチパターン
- typeやcategoryによってどんなメッセージを送るかselfに送るか決めている => クラスによる継承を使った方が良い
- メッセージを受け取るオブジェクトのクラスを確認してから、どのメッセージを送るかをオブジェクトが決めている => ダックタイプを見落としてしまっている
- 一部のクラスでしか使わないようなコードがモジュールに置かれている
- サブクラスはスーパークラスのインターフェースに含まれるどのメッセージが来ても応えられるべきであり、同じ種類の入力を取り、同じ種類の出力を行わなければならない
- ほかのオブジェクトに自身の型を識別させ、自身の扱いや何が期待できるのかを決めさせることは、どんなことであっても許されない
- 継承可能なコードを書くための最も基本的なコーディングの手法は、テンプレートメソッドパターンを使うこと
- テンプレートメソッドは、アルゴリズムのうち変化する場所を表す
- 継承する側でsuperを呼び出すようなコードを書くのは避ける。代わりにフックメッセージを使う。
8章
- コンポジションとは、組み合わされた全体が、単なる部品の集合以上となるように、個別の部品を複雑な全体へと組み合わせる(コンポーズする)行為
- コンポジションにおいては、より大きいオブジェクトとその部品が、「has-a」の関係によって繋げられる
- 個々の部品(part)は「ロール(役割)」であり、自転車自体は、そのロールを果たすほかのどんなオブジェクトとも喜んで協力する
- コンポジションは、「hasa」関係を持ち、かつ、包含される側のオブジェクトが包含する側のオブジェクトから独立して存在し得ないものを指す -集約は、まったくもってコンポジションのようなものですが、一点、包含される側のオブジェクトの存在が独立していることが異なる
- クラスによる継承もコンポジションも「コード構成のテクニック」
9章
- 変更可能なコードを書くことに必要な3つのスキル
- オブジェクト指向設計の理解
- コードのリファクタリングに長けていること
- 価値の高いテストを書く能力(この章の主題)
- テストをすることの真の目的は、設計の真の目的がまさにそうであるように、コストの削減
- テストから優れた価値を得るには、意図の明確さが求められる
- テストの意図
- バグを見つける
- 仕様書となる
- インターフェースに依存したテストを作ることで内部設計に関する決定を遅らせる
- 適切なテストがなければ抽象度の高いコードベースの改修は厳しい
- 設計の欠陥を明らかにする ... テストのセットアップに苦痛が伴うのであれば、コードはコンテキストを要求しすぎている
- テストの意図
- 何を、いつ、どのようにテストするかを知る必要がある
- 論理的に考えれば、パブリックインターフェースに定義されるメッセージを対象としたものを書くべき
- テストは、オブジェクトの境界に入ってくる(受信する)か、出ていく(送信する)メッセージに集中すべき
- オブジェクトは、自身のパブリックインターフェースを構成するメッセージに対して「のみ」、状態についての表明を行うべき
- 送信メッセージには、副作用がまったくないもの(クエリ)と副作用があるもの(コマンド)がある
- クエリメッセージは、受け手のパブリックインターフェースの一部であり、必要な状態テストはすべてそちらで実装している
- コマンド(命令)メッセージが適切に送られたことを証明するのは送り手のオブジェクトの責任
- テストを最初に書く意味があるのならば、いつでもそうすべき
- 適切な時間に、適切な量で終われば、テストをすることと、テストファーストでコードを書くことは、全体的なコストを下げる
- テスティングのメインストリームに居ることには多くのメリット
- テストから優れた価値を得るには、意図の明確さが求められる
- 受信メッセージをテストするときは
- 使われていないメソッドを見つけたら削除する
- パブリックインタフェースをテストする
- テスト対象以外のオブジェクトをテストしなくていいようにオブジェクトが利用しているパブリックインタフェースを持ったロールを導入して依存オブジェクトをテスト用の簡素なもの(テストダブル)にする
- テストダブルを使うと、本番のコードが壊れているのにテストは通る場合があるが本番のコードを作るコストとの兼ね合いで使い分ける
- プライベートメソッドをテストするときは
- テスト中ではプライベートメソッドを無視する
- プライベートメソッドをそもそももたない(持ちすぎない)ようにする(そのようなクラスは単一責任の原則から外れている匂いがする)
- 複雑なコードをリファクタリングする場合など意味がある場合に限ってプライベートメソッドのテストを書く
- 送信メッセージをテストするときは
- クエリメッセージはメッセージの受け手のパブリックインタフェースとしてテストされるので無視する
- コマンドメッセージは送信したオブジェクトの責任としてテストをする
- メッセージが問題のオブジェクトに送信されたかどうかはモックを使ってテストする
- ロールの担い手が共有できるテストを書くには
- (MiniTestの場合)モジュールでインターフェースに応答するかどうかのテストを書き、includeでロールの担い手間でテストを共有する
- テストダブルと本番アプリケーションのクラスの間に同様のテクニックを用いて、インターフェースが変更された場合にテストダブルを利用している箇所が壊れていることを検出できるようにする
- ロールの担い手にロールの利用者側からメッセージが送信されているかどうかにはモックを用いてテストを行う
- (MiniTestの場合)モジュールでインターフェースに応答するかどうかのテストを書き、includeでロールの担い手間でテストを共有する
- 継承されたコードをテストするには
オブジェクト指向設計実践ガイド ~Rubyでわかる進化し続ける柔軟アプリケーションの育て方の4~6章を読んで
上記の本の4~6章を読んで印象に残った部分をまとめました。
4章
- オブジェクト指向アプリケーションは「クラスから成り立つ」のですが、メッセージによって「定義される」
- インタフェースには次の二種類がある
- クラス内にあるインタフェース
- そのうち、他のオブジェクトから使われるメソッドから成るパブリックインタフェース
- 複数のクラスにまたがり、どのクラスからも独立しているもの(仮想のクラスのようなものを作る)
- クラス内にあるインタフェース
- クラスのパプリックインタフェースの特性
- クラスの主要な責任を明らかにする
- 外部から実行されることが想定される
- 気まぐれに変更されない
- 他者がそこに依存しても安全
- テストで完全に文書化されている
- クラスのプライベートインタフェースの特性
- 実装の詳細に関わる
- ほかのオブジェクトから送られてくることは想定されていない
- どんな理由でも変更され得る
- 他者がそこに依存するのは危険
- テストでは、言及さえされないこともある
- ドメインオブジェクト
- アプリケーションにおいて、「データ」と「振る舞い」の両方を兼ね備えた「名詞」を表すクラス
- 大きくて目に見える現実世界のものを表し、かつ最終的にデータベースに表されるもの
- こだわりすぎると設計が無茶なものになってしまう。オブジェクトそのものよりオブジェクト間のメッセージに注目する
- オブジェクトとメッセージについて見当をつけるためのものとしてシーケンス図がある
- シーケンス図を書くことでメッセージ交換の様子があらわになり「この受け手はこのメッセージに応える責任を負うべきだろうか」という疑問が湧くようになる
- クラスの責任を考える議論からメッセージを決めどこに送るかの議論になっている
- シーケンス図を書くことで責任を持ちすぎているクラスやメッセージの受け手となるクラスの存在が明らかになる
- どうやって望むかではなく何を望むかによってメッセージを決めるとパブリックインタフェースが小さくなる
- コンテキストはあるクラスを利用する際、どうしても必要になるコード
- 依存オブジェクトの注入で相手が誰かを知らずにクラスの共同作業ができるようになるのでコンテキストが小さくなる
- 他のオブジェクトを信用することでコンテキストに縛りつけずに作業できるようになる
- インタフェースを作るコツ
- パブリックインタフェースを作るときは
- 明示的にパブリックインタフェースとわかるようにする
- 「どのように」よりも、「何を」になっている
- 名前は、考えられる限り、変わり得ないものである
- プライベートインタフェースを作るときはprivate修飾子や_などの接頭辞でそれとわかるようにする
- ほかのクラスと協力する際は、それらのパブリックインターフェースのみを使って、ベストを尽くす
- どうしてもプライベートインタフェースに依存する場合は、メソッド内に依存を隔離する
- パブリックインターフェースを構築する際は、そのパブリックインターフェースが他者に要求するコンテキストが最小限になることを目指す
- パブリックインタフェースを作るときは
- デメテルの法則はオブジェクトを疎結合にするためのコーディング規則
5章
- ダックタイプはいかなる特定のクラスとも結びつかないパブリックインターフェース
- クラスへの高コストな依存が、メッセージへのより寛容な依存で置き換えられる
- Rubyにおける、オブジェクトの振る舞いについての一連の想定は、パブリックインターフェースへの信頼というかたちで行われる
- もしあるオブジェクトがほかのオブジェクトの型を知っていれば、どのメッセージにそのオブジェクトが応答できるかを知っていることになる
- クラスは、オブジェクトがパブリックインターフェースを獲得するための1つの方法でしかない
- ダックタイピングはクラスに囚われないパブリックインターフェイスの定義の仕方で注意深く利用する必要がある
- あるメソッドで具体的なクラスのインスタンスを受け取り、それも引数に異なるクラスを受け取る場合
- それぞれのクラス名を見てメソッド名を具体的に探しにいくと依存が爆発的に増加してしまう
- 一つのメソッドの目的は一つなのだからその引数も一つの目的を達成するために渡されてくると考える
- 既存のクラスを引数にそのまま使うのではなく(オブジェクトのクラスについての不明瞭さを大目に見る)、クラス間にその目的に沿うパブリックインタフェースを定義する
- ダックタイプをうまく定義できると、その後の拡張が簡単になる
- オブジェクト指向プログラミングでのポリモーフィズムは、多岐にわたるオブジェクトが、同じメッセージに応答できる能力
- ポリモーフィックなメソッドは「送り手の視点から見て」入れ替え可能であることに合意する
- ダックタイプが必要であることに気づくことと、そのインターフェースを抽象化することのパターン
- 次のものはダックで置き換えられる ... まだパブリックインターフェースを発見できていないオブジェクトを見逃している印
- クラスで分岐するcase文
- kind_of?とis_a?
- 「メソッドがその引数のそれぞれから望むものは何だろうか」を問いかけて共通のパブリックインタフェースを用意する
- Ruby on RailsのRubyのコアクラスへの依存のようにダックタイプに直さなくても十分な例もある
- responds_to?
- 次のものはダックで置き換えられる ... まだパブリックインターフェースを発見できていないオブジェクトを見逃している印
6章
- 継承を適切に使ったコードをどのように書くかの話
- 継承とは、根本的に「メッセージの自動委譲」の仕組みにほかならない
- 理解されなかったメッセージに対して、転送経路を定義するもの
- 継承を宣言するだけで自動的に二つのクラス間で転送が行われるようになる
- 具象クラスの中にstyleやtypeやcategpryで場合分けするクラスがあればその具象クラスの中に共通する要素はあるけれど異なる部分もある複数のクラスが埋め込まれている可能性が高い
- その含まれるクラスが具象クラスの特化である場合は継承を使って解決できる可能性が高い
- クラス間の関係を整理するのにUMLのクラス図が使える
- 継承のルール
- モデル化しているオブジェクトが一般-特殊の関係をしっかりと持っていること
- 正しいコーディングテクニックを使っていること
- 本で行われていた継承を使ったリファクタの手順
- 一旦具象クラスだったスーパークラスをそのままサブクラスにして代わりに空の抽象クラスを作ってスーパークラスにする
- コードをスーパークラスに昇格させるよりも、サブクラスに降格させるほうがかんたん
- 全てのサブクラスに共通する振る舞いをスーパークラスに昇格させる
- スーパークラスの初期値をメソッドで包んで継承したサブクラスに上書きする機会を与える
- 「テンプレートメソッド」パターン ... スーパークラス内で基本の構造を定義し、サブクラス固有の貢献を得るためにメッセージを送るというテクニック
- サブクラスにアルゴリズムを知ることを許し、superを送るよう求めるのではなく、スーパークラスが代わりに「フック」メッセージを送るようにする
- フックメッセージは、サブクラスがそれに合致するメソッドを実装することによって情報を提供できるようにするための専門のメソッド
- 一旦具象クラスだったスーパークラスをそのままサブクラスにして代わりに空の抽象クラスを作ってスーパークラスにする
オブジェクト指向設計実践ガイド ~Rubyでわかる進化し続ける柔軟アプリケーションの育て方の2~3章を読んで
上記の本の2~3章を読んで印象に残った部分をまとめました。
2章
- 変更が簡単であることの定義
- 変更は副作用をもたらさない
- 要件の変更が小さければ、コードの変更も相応して小さい
- 既存のコードは簡単に再利用できる
- 最も簡単な変更方法はコードの追加である。ただし追加するコードはそれ自体変更が容易なものとする
- 2つ以上の責任を持つクラスは簡単には再利用できない。どう見つけるか
- あたかもそれに知覚があるかのように仮定して問いただす
- 1文でクラスを説明してみること(「それと」と「または」に要注意)
- クラス内の全てがそのクラスの中心的な目的に関連していればそのクラスは凝縮度が高い、もしくは単一責任である
- 変更を受け入れられるようにコードを構成するテクニック
- インスタンス変数をアクセサメソッドで包み隠す(変数はそれらを定義しているクラスからでさえも隠蔽する)
- Structクラスを使って配列のインデックスというデータ構造を隠蔽しよう(配列のインデックスへの参照がオブジェクトへの具体的なメッセージの送信に形を変える)
- メソッドを単一責任にする(繰り返しとその中身を別のメソッドに分ける)とクラスがやっていることもはっきりする
3章
- オブジェクトに依存関係があるとき
- 他のクラスの名前を知っているとき
- self以外のどこかのオブジェクトに送るメッセージの名前を知っているとき
- いくつものメッセージをチェーンのように繋いで遠くのオブジェクトに存在する振る舞いを実行しようとする場合
- そのメッセージが要求する引数を知っているとき
- それら引数の順番を知っているとき
- 依存を減らすための具体的なコーディング技法
- 依存オブジェクトの注入
- 依存の隔離
- 外部のクラスに依存している部分を一つのメソッド内に隔離してしまう
- self以外に送られるメッセージをメソッドに隔離する(そのメッセージが変わりやすそうなら)
- インスタンス変数の作成を分離
- 外部のクラスのインスタンス変数を生成する部分をメソッドに分離して外部のクラスに依存していることをはっきりさせる
- 引数の順番への依存を取り除く
- 初期化の引数にハッシュを使う
- キーワード引数を使う Ruby キーワード引数で見通しを良くするゾ - かもメモ
- 外部フレームワークなど引数が固定順でいじれないならラッパーを用意してラッパーに隔離する
- 依存の方向は自分より変更されないものに依存するようにする
ユーザーストーリーマッピング 13章から18章を読んで
上記の本を読んでいて、13章から18章まで各章ごとに印象に残ったことをメモりました。
13章 オポチュニティから始める
- 浮かんだばかりの大きなアイデアはエピックと呼んだりオポチュニティ(作者はこちら)と呼んだりする
- オポチュニティはすべて構築するのではなく、詳細に検討して先へ進むかボツにするか再考するか決める
- その手法として、オポチュニティキャンバスがある
- やるべきことがロードマップに載っているものでも誰のために何をなぜ作るのかについて会話を行おう
- ストーリーマッピングでジャーニーマップを作ってホットスポットからオポチュニティを探す
- ジャーニーマップに暗黙の前提がないか暴き出す手法としてリハーサル・リ・マッピングがある
- オポチュニティはすべて受け入れたとしてもダメ
14章 ディスカバリーを介して共通理解を築く
- ディスカバリーは構築ではなく学習のための仕事でオポチュニティに対し、問題の形、価値、利用可能性、実現可能性を問うて答えていくプロセス
- 議論する製品や機能の細部はすべて小さなストーリーのタイトルになる
- ディスカバリーの4つの基本的なスタイル
15章 ディスカバリーによる検証された学習
- 私たちはほとんどの機能追加の際、成果を出せないリリースをしてしまう
- それなのに、昔は素晴らしいアイデアだと肉づけることや素晴らしいリリースだったことに見せかけることに手間をかけていた
- デザイン思考を使おう
- 「その製品のユーザーになると、実際どう感じるものなのか」を理解するため、課題についてユーザー、顧客と「共感」しよう
- 共感フェーズで学んだことからこれから重点的に取り組む「特定の人々」および「特定の問題」を「定義」しよう
- 定義フェーズで定義した問題に対するソリューションの「アイデア」を意図的に複数「創出」しよう
- シンプルな「プロトタイプ」を作ってソリューションを研究し、顧客とユーザー自身が評価できるくらいまでプロトタイプを改良しよう
- ユーザー、顧客の問題が本当に解決できるソリューションかどうかを「テスト」しよう
- 動くように見せかけるフェイクを使っても問題解決に役立つかのテストに使える
- デザイン思考はビジネスニーズとターゲットとする人々をはっきりさせなかったり、調査と理解のために時間をかけすぎたりすることで簡単に失敗するプロセスになる
- リーンスタートアップ思考では、製品全体のプランを立てるのではなく最も小さいプロトタイプを作るように努力する
- ディスカバリーの段階では構築段階とストーリーの使い方に大きな違いがある
16章 リファイン、定義、構築
- カード - 会話 - 確認の3つのCのうち、最後のCに到達するために最後の最良の会話(ストーリーワークショップ)を行う
- ストーリーワークショップに参加すべきなのは通常は以下の3~5人
- 開発者
- テスター
- ユーザー
- UIデザイナーやビジネスアナリスト
- 会話に参加するかどうか、チームメンバーにオプトインを認めよう
- ストーリーワークショップは具体的に何を作るのかという質問に答えることに集中する
- その中で分割とスリム化を行うが、ストーリーの分割方法としてグッド・ベター・ベストゲームという手法がある
- デリバリーの状況を確認するためにストーリーマップを活用する
17章 ストーリーは実際にはアステロイドに似ている
- ストーリーは少しずつ、タイミングよく分解していかなければならない
- オポチュニティでは、ストーリーが誰のためのもので、彼らが解決したい問題は何か、その仕事が会社の事業戦略に沿ったものか、といった方向性の議論が中心で、それでも膨れ上がったオポチュニティを分解することはある
- ディスカバリーでは、誰がどのようにしてプロダクトを使うのかの具体的な内容を議論するため、何度も分解を行う
- 開発戦略のプランニングでは、リスクがどこにあるかを議論する。学習を念頭において岩を砕く
- 次の開発サイクルのプランニングでは、完成したことを確認する方法について意見を一致させる。一つのストーリーが一つの合意を満たすようにするために、ストーリーをさらに分割することになる場合がある
- バックログをクリーンにするため、小さなストーリーを一つにまとめる
- 機能についてのストーリーを語るために必要なだけマッピングをする
18章 構築するすべてのものから学ぶ
ユーザーストーリーマッピング 7章から12章を読んで
上記の本を読んでいて、7章から12章まで各章ごとに印象に残ったことをメモりました。
7章 より良いストーリーテリングのために
- 以下のようなシンプルなテンプレートを使って会話を始めよう(以下のテンプレートでストーリーに書かれている内容の理解が十分なわけではない)
[ユーザータイプとして]、私は[これこれの結果を得る]ために、[これこれを]したい。
- バックエンドやセキュリティ問題についてのストーリーは難しいものになることがあったり、ストーリーのテンプレートに収めるのに難しいアイディアもある
- そういうときはストーリーのテンプレートに従わなくてもいい
- 誰が、なぜ、何を、どのくらいの期間で、など詳細についてもきちんと話をしよう
- 話すべきことはたくさんあるので、話を思い出すのに役立つものを必ず記録しておこう
8章 カードに書かれていることがすべてではない
- すべてのストーリーについて、様々な人の間で様々な種類の会話が行われる
- ストーリーは図書館のカード目録のようなもので、ストーリーのカードの他にどこかにどんどん増え続けている情報があることがわかっている
- ストーリーに本当に書かれているものは何か
- 短いタイトル
- 簡単な説明
- ストーリー番号
- 見積り、規模、または予算
- 価値
- メトリクス
- 依存関係
- 状況
- 日付
- ストーリーに本当に書かれているものは何か
- 共通理解を築くのにホワイトボードの前でポストイットという武器を持って頭を突き合わせて話をする以上の方法はない。リモートでもカメラやウェブカメラを利用したりそれ用のツールを使おう
- 計画した仕事の進行状況の順位付け、追跡、分析にはツールを使おう
9章 カードは始まりに過ぎない
- アジャイル開発サイクルのモデル ... 5つのC
- Card
- Conversation
- Confirmation ... ここまでがカードの3C
- Construction(構築) ... 議論の場で記録したメモや写真を見て細部を思い出しながらチームはソフトウェアを作る
- Consequences(結果) ... 作ったものを最初はチームとして次にビジネスステークホルダーとともに評価し最後に顧客、ユーザーとのテストで評価する
- 構築時に議論の中でできた同じ見取り図を構築のメンバーが頭の中に持っている必要がある
- ストーリーの詳細を誰かに渡してソフトウェアを作ってもらおうとしてもうまく行かないししてはならない
- ストーリーを理解している人とストーリーを語るために集めた情報があればストーリーを共有するのにかかる時間は大幅に短くできる
- ストーリーを形にするための効率的な議論や意思決定のために全員は必要ない
- ソフトウェアが完成したら品質について話し合う
- ユーザーエクスペリエンスの質/機能の品質/コードの品質
- 自分たちが作り上げたものに変更を加えなければならない点を見つけてしまった場合
- 私たちは合意した通りのものを作ったか?
- 合意した通りのものを作ったとしてそれを見た結果何か変更を加えるべきか?
- ユーザーの横に座ってユーザーがあなたの製品を使っているところを見た方がいい
- 学ぶことを計算に入れてプランを立てる必要がある
10章 ケーキのようにストーリーを焼く
- ストーリー(デリバリー可能で、評価可能なものを表現したストーリー)を開発チームに持っていくとデリバリータスク(ストリーの実現に必要な作業を表現する)ができる
- デリバリータスクの詳細を話すのではなく、誰がなぜそれを使うのかを話題にする
- ストーリーが表しているソリューションがコストのかかりすぎるものなら目標達成に近づく別のソリューションを検討しよう
- ストーリーが大規模な場合、早いうちに進行状況を評価、確認できる小さなプランのものに分割しよう
11章 岩を砕いていく
- 立場によって適切なサイズのストーリーの規模は変わる
- ユーザーの視点から見た適切なサイズのストーリーは、ニーズを満たすストーリーだ
- 開発チームの視点から見た適切なサイズのストーリーとは、ビルド、テストに数日しかかからないストーリー
- ビジネスの視点から見た適切なサイズのストーリーは、会社が業績を上げるのに役に立つストーリー
- エピックは(開発者から見て)分解することが必要だとわかっている大きなストーリーだが、ビジネス、顧客、ユーザーから見て適切なサイズのストーリーである
- 分解したストーリーをテーマというかたまりを使ってまとめよう
- ストーリーの岩を砕いていくサイクル
- 新機能、新製品、既存機能の改良などのアイデア(オポチュニティ)に名前をつけて、オポチュニティバックログに入れる
- 誰が何をなぜを深く議論してそれぞれのアイデアについてボツにするか先に進むか決める
- 前進するアイデアを深く掘り下げて、できる限り小さく価値のあるものを作ることを追求する(ディスカバリー段階)
- ソフトウェアをビルドするために、細部を開発チームと話をしてストーリーをさらに分割する
- 構築中も細部を埋め、作成中のものにフィードバックするために会話を利用する
- 作られた部品をスプリントレビュー(スプリントレトロスペクティブ)で最初の評価をする
- 意味のある量の動くソフトウェアを顧客、ユーザーとともにテストして学習する
- ビジネスステークホルダーとともに評価を行い、進捗状況を見える化しておく
- 測定とユーザーとの面談を通じて、目標としてきた結果が得られたかどうかを正確に把握する
- 新機能、新製品、既存機能の改良などのアイデア(オポチュニティ)に名前をつけて、オポチュニティバックログに入れる
12章 岩を砕く人
- 優れたプロダクトオーナーは、自分が良い判断をするために必要な人々を周りに集めているが、決定はプロダクトオーナーが行う
- プロダクトオーナーが率いる小規模な組織横断チームがプロダクトディスカバリーの仕事を取り仕切る
- プロダクトリーダーがいない場でもストーリーをめぐって無数の会話が交わされても構わない
- ストーリーワークショップ(何を作るかについて具体的に決定を下す最後で最良の会話)には、テスター、製品ディスカバリチームのメンバー、開発者の一人が必要だ
- プロダクトオーナーは簡単な仕事ではないので、ビジネスピープルに押し付けるのではなく、ビジネスピープルを手助けするプロデューサーを見るけることをお勧めする
- ストーリーマッピングは、大きなストーリーを小さなストーリに分解するために役立つ方法の一つ
- 「製品を使う人々」と「何があれば彼らに成功をもたらすことができるのか」を会話の中心に置きながら進めることができる
ユーザーストーリーマッピング 0章から6章を読んで
上記の本を読んでいて、0章から6章まで各章ごとに印象に残ったことをメモりました。
0章 まず最初に読んでください
- 言葉で表現された文章が正確な製品の実態を示すものではない
- ストーリーを用いるときは、ストーリーを作ること自体ではなく絵や写真も用いて「共通理解」を築くことが大切
- アウトプットを最小限に抑えて、最大限の成果とインパクトの獲得を目指す
1章 全体像
- ただ単にストーリーを作っていくとその粒度の差から開発可能な粒度に揃えると全体像が見えなくなってしまう
- ストーリーマッピングでは、1つのストーリーを掘り下げる前に全体像としてどのようなストーリーがあるか明らかにする
- その過程で思考の穴が見つかりやすくなる
- 複数のユーザーのストーリーが見つかることもある
- ストーリーマッピングでは、ストーリーの全体像を作ってから詳細や代替案を考えていく
2章 作るものを減らすためのプラン
- いつでも作る量に対して、時間や資源は少なすぎる
- 複数のチーム間で共通理解を深めたりチーム間でタスクに漏れがないか確認するためにストーリーマッピングを用いることができる
- マップの最上部がバックボーンと呼ばれ、バックボーンがマップを体系化する
- ユーザーが必要とすること(成果)が生まれるリリースを切り出し、リリースの優先順位の基準に成果を用いよう
- MVPは、仮定を証明または反証するために作れる、あるいは実行できる最小のものである
3章 より早く学ぶためのプラン
- 大きなアイディアをオポチュニティとして扱い、オポチュニティの枠組み(そもそも何か/顧客は誰か/ユーザーは誰か/彼らはなぜ製品を使いたいと思うか/なぜ私たちはそれを作るのか)の枠組みを確認する
- 顧客開発パートナーと話をして、解決しようとしている問題が本当にあるか確かめよう(その結果によってオポチュニティは変化する)
- ソリューションをイメージするためにプロトタイプを作り、ユーザーに見てもらおう
- 人々が実際に毎日それを使うことを選んだときに証明は得られる
- minimum未満のものを作ってviableになるまで開発パートナーに対するリリースを繰り返す
- その時々ごとに利用することができ学ぶことがあるような形でリリースをしよう
- MVPに向かう過程でさまざまなツールやテクニックを使って行っていることをプロダクトディスカバリーと呼ぶ
- 目標は自分が正しいものを作っているかどうかをできる限り早く学ぶことだ
4章 時間通りに終わらせるためのプラン
- マップは会話の助けに必要な分だけ作ればよい
- 最良の見積もりは、自分が何を見積もっているのかを本当に理解している開発者から出てくるので開発チームと共通理解を築く必要がある
- 機能の最後まで道をつなげるスライス(歩くスケルトン)、それをもっと良くするスライス、機能を磨けるだけ磨くスライスを分ける
- 上記スライスは開発用マイルストーンなのでいちいち顧客にリリースしない
- 作るのにどれだけかかったか測定することで多少は見積もりを正確にできる
- リスクの多いプロジェクトの場合、リスクストーリーを追加することで状況を可視化できる
- インクリメンタル戦略(個々の部品を順に完成させていく)とイテレーティブ戦略(下書きから徐々に構図や色を変更していく)
- イテレーティブ思考で評価し、インクリメンタル思考で追加し続けよう
- リリースバックログを製品全体に関わる基礎的な機能や基本的なユーザー行動、リスクの高い部分に注力する序盤、仕上げの部分を埋めていく中盤、リリースを磨く終盤に分ける
5章 あなたはもうやり方を知っている
- タスクは短い動詞句で構成され、目標を達成するためにすることを表している
- ユーザータスクはソフトウェアを使う人々が目標達成のためにしているタスク
- ゴールレベルの概念を使って、小さなタスクを一つにまとめたり、大きなタスクを分割したりしよう
- ストーリーのマッピングは、ナラティブフローを使って左から右へ向かう
- 細部、代わりのタスク、変種、例外などはマップの縦方向に入る
- 目的ごとにタスクをアクティビティという形で集約する
- アクティビティと大まかなタスクがストーリーのマップのバックボーンを形成する
- 特定の目標を実現しやすいようにタスクをスライスする
- ユーザーが将来、製品を届けられたときに振る舞う将来のマップと現在の振る舞いについてのマップがある
6章 ストーリーについての本当のストーリー
- 私たちは同じドキュメントを読むことができるが、違う理解をする
- ストーリーという名前は、どのように書くべきかではなくどのように使うべきかについて付けられた名前だ
- ストーリーの思想は語ることにある
- ロン・ジェフリーズの3つのC ... スローリーのプロセスの説明
- Card ... ソフトウェアに望むことをインデックスカードに書いていく
- Conversation ... 集まってどのようなソフトウェアを作るかについて豊かな会話を交わす
- Confirmation ... ソフトウェアが完成したことをどのように確認するかについて意見を統一する
- 製品全体、あるいは既存の製品に加えたいすべての変更を記述しているカードの山のことをプロダクトバックログと呼ぶ