この記事について
先日ポートフォリオ用の Web アプリケーションを公開したのですが、開発を始めて一番最初に困ったのがモデリングです。
言語やフレームワークの学習をして、コンセプトを決めたはいいけれど、「何から手を付けたらいいんだ…?」とお手上げ状態。そもそも要件定義さえもピンときていませんでした。
ICONIX プロセスはそんな私でも非常に取り入れやかったので、簡単に概要を説明しつつ、どのように活用したのかについて紹介しようと思います。
※ ポートフォリオは、服用したお薬の記録をサポートする Web アプリケーションです。アプリケーションの概要や使用した技術を紹介する記事を投稿していますので、詳しくはそちらをご覧ください。
ICONIX プロセスとは?
ICONIX プロセスとは、ユースケースからオブジェクト指向設計を導出するための思考プロセスを提供するオブジェクト指向分析および設計の方法論です。
最終的な目的を「コードが導出可能なオブジェクト指向の設計を生成すること」としており、UML による視覚的な設計が特徴的な手法となっています。
このプロセスはユースケース駆動開発を基盤としており、「ユースケース駆動開発実践ガイド」という書籍において説明されています。
ICONIX プロセスの全体像
ICONIX プロセスは要件定義から設計、実装、テストまでの一連のステップをサポートしています。
具体的には、以下のような流れで開発を進めていきます。
-
要件定義
- ドメインモデリング
- ユースケースモデリング
-
分析・予備設計
- ロバストネス分析
-
詳細設計
- シーケンス図作成
-
実装
- コーディングとテスト
※ 本来は要求レビューや設計レビューのようなマイルストーンが発生しますが、ここでは省略しています。
要件定義
要件定義フェーズでは、以下の作業を行って振る舞い要求群、すなわちユースケースを抽出していきます。
ドメインモデリング
【目的:問題領域を明確な用語で定義する】
■ 手順
1. ドメインの理解と範囲の定義
2. 機能要求から問題領域のオブジェクト (ドメインオブジェクト) を識別
3. ドメインモデルの作成
ドメインモデルとは、プロジェクトで実際に使われる全ての単語を収録した用語集のことで、ドメインオブジェクトとその関係を示すクラス図として表現されます。
ドメインモデリングでは、このドメインモデルを作成する作業を行っていきます。
なお、ユースケースを書く前にドメインモデルを作成するというのが重要なポイントです。
このタイミングでドメインモデリングを行うことで、「現実に基づいた、設計するシステムに近いユースケース」を作成できるようになります。
ユースケースモデリング
【目的:ユーザーとシステムの対話を定義する】
■ 手順
1. ユースケース図の作成
2. 実装対象となるユースケースを識別
3. ユースケースに関係するすべての UI に名前を付ける
4. ユースケース記述の作成
5. ユースケースに機能要求を割り当てる
ユースケースモデリングでは、曖昧で抽象的な機能要求を具体的なシナリオに落とし込んでいきます。
ユースケースでは、ドメインモデルの用語と UI の用語を使うことが重要です。これらの用語を用いることでユースケースとオブジェクトが結び付き、結果として振る舞い要求とオブジェクトモデルがシームレスに繋がるため、オブジェクト指向設計の駆動が可能となるのです。
分析・予備設計
分析・予備設計フェーズでは、要件定義と詳細設計の間にあるギャップを埋めるためにロバストネス分析を行います。
ロバストネス分析
【目的:ユースケースとオブジェクトを関連付ける】
■ 手順
1. オブジェクトの特定
2. オブジェクトの責務と振る舞いの特定
3. ロバストネス図の作成
要件定義フェーズで作成されたドメインモデルとユースケースモデルは、自然言語を中心に据えた抽象的なモデルのため、このままではシーケンス図のような実装レベルのモデルを作成するには難しい状態です。
そのため ICONIX プロセスでは、詳細設計に先立ってロバストネス分析を実施することで、ユースケースと GUI やドメインクラス、ソフトウェア機能といった具体的な要素を関連付け、抽象的な概念から具体的な実装へのスムーズな移行を実現しています。
また、ロバストネス分析はシステムの振る舞いを明確にする手段としても重要です。
外部からの要求やイベントに対するシステムの反応、情報や処理の流れを視覚的に表現することで、システム設計を改善し、洗練させていきます。
詳細設計
詳細設計フェーズでは、シーケンス図を作成して具体的な実装に移行する際の指針を定めます。
シーケンス図作成
【目的:クラスに操作を割り当てる】
■ 手順
1. シーケンス図に登場する主要なオブジェクトの特定
2. 必要なメッセージの洗い出し
3. シーケンス図の作成
シーケンス図では、これまでのフェーズで抽出した振る舞い (ソフトウェア機能) を具体的なクラスに割り当て、システムの動的な振る舞いを視覚化します。
ロバストネス図が理想的な概念設計を表現する一方で、シーケンス図は設計の詳細を明確にし、オブジェクトやクラスの相互作用、メッセージの流れを表現するのが主な役割となります。
実際にやってみて
実際にやってみて感じた ICONIX プロセスの魅力、そして私と同じように未経験かつ独学でモデリングをしたことがないという方にもおすすめする理由としては以下が挙げられます。
- 欲しい機能、気が付いたことの羅列からコードを導出可能な状態にまで持っていける
- 単純で明瞭な手順が具体的に示されており、簡単に始められる
- 概念的なレベルの設計スキルを習得できる
- ユースケースに基づくテストを導出できる
また、完全に自己流ではありますが、非効率に感じた部分や有効活用できそうな部分にいくつか調整を加えたので、簡単に紹介したいと思います。
ユースケース記述を省略
ユースケース記述はユーザーとシステムの対話を詳細に文書化して、システムの振る舞いを言葉で明確に表現します。一方で、ロバストネス図はユースケースに基づいてシステムの振る舞いを視覚的に表現します。
両者は同じものを異なる視点から見たものであり、互いに補完しあう関係性のため、完全に他方を置き換えることはできません。
しかし、今回は途中からユースケース記述を書くのをやめてしまいました。
というのも、作成したアプリは小規模であり、単純で似通った処理が多いため、慣れてくるにつれて似通ったユースケース記述をコピペするだけの形式的な作業になりつつあったからです。
加えて、ユースケース記述は文章形式で記していくので、記述量が多く煩雑になりがちで、修正にかかるコストも大きいです。そのため、今回に限ってはデメリットの方が目立つように感じ始めました。
また、今回は個人開発ということもあり、現時点では詳細なシナリオを他者と共有する必要がありません。今後必要になることがないとは言えませんが、そうなった場合でも十分にロバストネス図から書き起こせると判断しました。
結果として随分と負担が減りましたし、ロバストネス図だけでも十分に効果を発揮できると感じました。
ロバストネス図を拡張利用
ロバストネス図上のオブジェクトは、「バウンダリ」「エンティティ」「コントロール」という 3 つの要素で構成され、それぞれ「GUI 要素」「ドメインオブジェクト」「振る舞い」という具体的な実装と対応します。
そのため、タスクの洗い出しや工数見積もり、進捗管理にも活用することができます。
具体的な例を示します。
以下は「ユーザー名を変更する」というユースケースに対応するロバストネス図です。
このようなロバストネス図の場合、以下のような表を作成してタスクを細分化し、見積もりを行います。
バックエンド
オブジェクト | タスク | 予想 (m) | 実際 (m) | 原因 |
---|---|---|---|---|
リクエストを受け取る / StatusCode204 でレスポンスを返す | ・ユーザー名を変更するリクエストハンドラを作成する ・ユーザーセッションを作成する |
45 | 30 | |
ユーザーのプロフィールを取得する | ・プロフィールを作成する ・プロフィールリポジトリを作成する |
45 | 60 | 適切なリポジトリのテストの実装方法を調べるのに時間がかかった。 |
登録済みのユーザー名か確認する | ・ユーザー名の重複をチェックするドメインサービスを作成する ・登録済みユーザー名かを検証するバリデータを作成する |
45 | 70 | Kotlin でのアノテーションの実装方法を調べるのに時間がかかった。 |
ユーザー名を変更する | ・プロフィールにユーザー名を変更するメソッドを追加する ・プロフィールリポジトリに save メソッドの upsert に変更する ・ユーザー名を変更するアプリケーションサービスを作成する |
60 | 40 | |
StatusCode401 でレスポンスを返す | ・AuthenticationEntryPoint をオーバーライドする |
30 | 20 | |
StatusCode400 でレスポンスを返す | ・バインドエラーレスポンスを作成する ・ApiController 共通の例外ハンドラを作成する |
50 | 40 |
フロントエンド
オブジェクト | タスク | 予想 (m) | 実際 (m) | 原因 |
---|---|---|---|---|
フォームを送信する | ・モーダルを作成する ・ユーザー名入力フィールドを作成する ・fetch でフォームを送信する |
60 | 80 | バインドがうまくいかず、調査に時間がかかった。 |
結果メッセージを表示する | ・バインドエラーメッセージをユーザー名入力フィールドの下に表示する ・その他の例外ハンドリングを行う |
60 | 40 |
この表は一番最初に取り掛かったユースケースに対して作成したものなのでタスクの粒度が小さいのですが、慣れてくるにつれて粒度を大きくしたり、表は作らずロバストネス図に直接時間を書き込んだりして適時調整していました。
予想時間に関しては、自分ができそうだと思う時間に 1.4 を掛けてバッファを持たせています。
最初はもっと小さく設定していたのですが、リファクタリングだったり、予想外のエラーに悩まされたりして予想を超えてしまうことが多かったので、自分にフィットするバッファを探りながら進めました。
開発経験がない私にとって作業時間を見積もるのは非常に難しく、正確に予測できないことも多かったのですが、この方法をとるようになってから随分と改善されました。
また、作業中は実装完了のタイミングで図上のオブジェクトの色を変えることで、全体の進捗状況が一目で把握できるようにしていました(※上図の場合はシナリオの性質や処理などをもとにした色分けとなっています)。
これは作業の抜け漏れ防止としてだけでなく、モチベーション維持の役割としても有効でした。
最後に
言語とフレームワークの基礎を勉強して、アプリケーションのコンセプトも決めた。
だけど、あれ?なにから始めればいいんだっけ?な状態に陥ってしまいました。
ある機能を実装するためにはどういうやり取りが必要になって、どういうコードが必要になるのか、どこから手を付ければいいのか、具体的なイメージが全然湧かなかったんですよね。
それまではチュートリアルを写経して手を加えたり、簡単な TODO アプリくらいしか作ってこなかったのだから当たり前です。
試行錯誤はありましたが、こんな機能が欲しいなぁという曖昧な要求から、具体的な画面、操作、機能が可視化され、コードに落とし込むまでを明確な手順で立ち止まることなく進められので、採用して非常によかったなと感じています。
それから、ICONIX プロセスそのものが非常に有用な手法であるのはもちろんなんですが、書籍「ユースケース駆動開発実践ガイド」が理論から演習まで丁寧に書かれていて、1冊だけで出来そう!という状態にまで持って行けたことが大きかったかなと思います。
同じような悩みを持っている方がいらっしゃいましたら、試してみるのもいいのではないでしょうか。
それでは、最後までお読みいただきありがとうございました!
誤りなどがあれば指摘していただけますと幸いです。
また、ご意見やアドバイスがあれば教えていただけますと嬉しいです。