※2019/4/上旬 ユースケース駆動開発実践ガイドを読んであまりにも適当にユースケース記述及びロバストネス図を書いていたことがわかったため、修正しました。あとタイトルも修正して、この記事で注目してほしいキーワードを入れました。
TL;DR
システムにおける画面の設計や配置をなんとなくでやっている方、以下の記事を一読してみることをお勧めします。
私はデザインのデの字も知らずに画面設計していたので目から鱗でした。
OOUX – オブジェクトベースのUIモデリング
OOUI の目当て
はじめに
社内で使うようなあまりだれも関心を持っていないようなシステムを開発した際に意図せずタスクベースのUIになってしまってました。
上記記事を読んで画面の設計の仕方について学ぶことが出来たため、自分が失敗した点を含めて投稿してみます。
OOUX(OOUI)とはなんだ?という話はしません(できません)。上記記事に詳細に書かれています。
ざっくり要件定義と概念設計
自分が失敗した部分についてのみフォーカスしてます。
機能要求
- ユーザー毎に一意な番号を管理したい
- ユーザーは名前、権限(管理者 or 一般)の情報を持っている
- ユーザーの追加、変更、削除を行いたい
RDBMS的に1テーブルで済むならばCRUDで済むような話です。けどまあしっかり順を追って設計しました。
ざっくりドメインモデル
[](
@startuml
title ドメインモデルざっくり
abstract class ValueObject {
}
class ユーザーID {
+ID: Guid
}
class 名前 {
+名前: string
}
enum 権限 {
管理者: 0
一般: 1
}
class 権限種別 {
+権限: 権限
}
権限種別 -down- 権限
ValueObject <|-up- ユーザーID
ValueObject <|-up- 名前
ValueObject <|-up- 権限種別
class ユーザー {
+ユーザーID: ユーザーID
+名前: 名前
+権限種別: 権限種別
}
note left: エンティティ兼集約ルート
ユーザー o-- ユーザーID
ユーザー o-- 名前
ユーザー o-- 権限種別
class ユーザー一覧 {
+一覧: List<ユーザー>
}
note left: ファーストクラスコレクション
ユーザー一覧 --> ユーザー: use
@enduml
)
パッケージ図とユースケース図
[](
@startuml
title パッケージ図
package 管理 {
actor 利用者
usecase ユーザーを追加する as a
usecase ユーザーを編集する as b
usecase ユーザーを削除する as c
利用者 -[hidden]down- a
a -[hidden]down- b
b -[hidden]down- c
}
@enduml
)
[](
@startuml
left to right direction
title 「管理」パッケージのユースケース図
actor 利用者
利用者 -- (ユーザーを追加する)
利用者 -- (ユーザーを編集する)
利用者 -- (ユーザーを削除する)
@enduml
)
通常の設計ではユースケースが大量に発生するため、パッケージ図にて類別したほうが良いそうです。
ユースケース記述とロバストネス図
ICONIXではユースケース図とユースケース記述を書いた後に要求レビューを行い、その後にロバストネス分析を行うのですが、今回は要求レビューを飛ばします(実際なら要求レビューで今回の画面の構成について指摘が出るのかな?)
「ユーザーを追加する」ユースケースのユースケース記述とロバストネス図
[](
@startuml
title 「ユーザーを追加する」ユースケース記述とロバストネス図
note as abc
基本コース:
システムは「メニュー画面」を表示する。
利用者は「ユーザーを追加する」ボタンを押し、システムは「ユーザー追加画面」を表示する。
利用者は「名前」を入力し、「権限種別」を選択し、「追加」ボタンをクリックする。
システムは「ユーザー」を作成し保存する。システムは「メニュー画面」を表示する。
代替コース:
「名前」に許可しない文字列が入力された:システムは「入力できません」画面を表示する。
存在しない「権限種別」が選択された:システムは「存在しない権限種別です」画面を表示する。
保存に失敗した:システムは「保存に失敗しました」画面を表示する。
end note
actor 利用者
boundary メニュー画面
boundary ユーザー追加画面 as z
control "「ユーザー追加画面」を表示する" as a
control 名前を入力する as b
control 権限種別を選択する as c
control ユーザーを保存する as d
control "名前は許容できるか?" as e
control "権限種別は範囲内か?" as f
control "「権限種別が範囲外の値である」メッセージを表示する" as g #gray
control "「許容できない名前である」メッセージを表示する" as h #gray
control "保存に成功したか?" as i
control "「保存に失敗した」メッセージを表示する" as j #gray
control メニュー画面を表示する as p
boundary エラー画面 as y #gray
entity ユーザー
利用者 --> メニュー画面
メニュー画面 --> a: 「ユーザーを追加する」ボタンクリック
a --> z
z -- b
z -- c
z -- d: 「追加」ボタンをクリック
d -- ユーザー
b -- e
e -- h: いいえ
h -- y
c -- f
f -- g: いいえ
g -- y
d -- i
i -- j: いいえ
j -- y
i -- p: はい
p -- メニュー画面
@enduml)
「ユーザーを編集する」ユースケースのユースケース記述とロバストネス図
[](
@startuml
title 「ユーザーを編集する」ユースケース記述とロバストネス図
note as abc
基本コース:
システムは「メニュー画面」を表示する。
利用者は「ユーザーを編集する」ボタンを押し、システムは「ユーザー一覧」を取得して「ユーザー編集画面」を表示する。
利用者は「ユーザー」を選択するとシステムは選択された「ユーザー」の情報を表示する。
利用者は「名前」を入力し、「権限種別」を選択し、「編集」ボタンをクリックする。
システムは「ユーザー」を作成し保存する。システムは「メニュー画面」を表示する。
代替コース:
「名前」に許可しない文字列が入力された:システムは「入力できません」画面を表示する。
存在しない「権限種別」が選択された:システムは「存在しない権限種別です」画面を表示する。
保存に失敗した:システムは「保存に失敗しました」画面を表示する。
システムにユーザーが存在しない:システムは「編集できるユーザーが存在しません」画面を表示する。
end note
actor 利用者
boundary メニュー画面
boundary ユーザー編集画面 as z
control "「ユーザー編集画面」を表示する" as a
control 名前を入力する as b
control 権限種別を選択する as c
control ユーザーを保存する as d
control "名前は許容できるか?" as e
control "権限種別は範囲内か?" as f
control "「権限種別が範囲外の値である」メッセージを表示する" as g #gray
control "「許容できない名前である」メッセージを表示する" as h #gray
control "保存に成功したか?" as i
control "「保存に失敗した」メッセージを表示する" as j #gray
control ユーザー一覧を取得する as k
control "ユーザーが存在するか?" as l
control "「編集できるユーザーが存在しません」メッセージを表示する" as m #gray
control "ユーザーを選択する" as n
control "ユーザー情報を表示する" as o
control メニュー画面を表示する as p
boundary エラー画面 as y #gray
entity ユーザー
entity ユーザー一覧
利用者 --> メニュー画面
メニュー画面 --> a: 「ユーザーを編集する」ボタンクリック
a -- k
k -- l
l -- m: いいえ
m -- y
k -- ユーザー一覧
a -- z
z -- n
n -- o
o -- ユーザー
z -- b
z -- c
z -- d: 「編集」ボタンをクリック
d -- ユーザー
b -- e
e -- h: いいえ
h -- y
c -- f
f -- g: いいえ
g -- y
d -- i
i -- j: いいえ
j -- y
i -- p: はい
p -- メニュー画面
@enduml)
「ユーザーを削除する」ユースケースのユースケース記述とロバストネス図
[](
@startuml
title 「ユーザーを削除する」ユースケース記述とロバストネス図
note as abc
基本コース:
システムは「メニュー画面」を表示する。
利用者は「ユーザーを削除する」ボタンを押し、システムは「ユーザー一覧」を取得して「ユーザー削除画面」を表示する。
利用者は「ユーザー」を選択するとシステムは選択された「ユーザー」の情報を表示する。
「削除」ボタンをクリックする。
システムは選択された「ユーザー」を削除する。システムは「メニュー画面」を表示する。
代替コース:
削除に失敗した:システムは「削除に失敗しました」画面を表示する。
システムにユーザーが存在しない:システムは「削除できるユーザーが存在しません」画面を表示する。
end note
actor 利用者
boundary メニュー画面
boundary ユーザー削除画面 as z
control "「ユーザー削除画面」を表示する" as a
control ユーザーを削除する as d
control "削除に成功したか?" as i
control "「削除に失敗した」メッセージを表示する" as j #gray
control ユーザー一覧を取得する as k
control "ユーザーが存在するか?" as l
control "「削除できるユーザーが存在しません」メッセージを表示する" as m #gray
control "ユーザーを選択する" as n
control "ユーザー情報を表示する" as o
control メニュー画面を表示する as p
boundary エラー画面 as y #gray
entity ユーザー
entity ユーザー一覧
利用者 --> メニュー画面
メニュー画面 --> a: 「ユーザーを削除する」ボタンクリック
a -- k
k -- l
l -- m: いいえ
m -- y
k -- ユーザー一覧
a -- z
z -- n
n -- o
o -- ユーザー
z -- d: 「削除」ボタンをクリック
d -- ユーザー
d -- i
i -- j: いいえ
j -- y
i -- p: はい
p -- メニュー画面
@enduml
)
以下の点がユースケース駆動開発実践ガイドを読んで特に学んだところです。
- ユースケース記述はロバストネス図に一緒に記載しても良い
- ユースケース記述のテンプレートは「基本コース」と「代替コース」の二種類で良い。
- ユースケース記述は叙述的に書くべき。~は~を~する。
- ユースケース記述はシステム側も書くべき。ユーザーとシステムの対話を表すべき。
- 代替コースの洗い出しのほうが大事。システムの複雑さの半分以上は代替コース。
- 「~~を表示する」コントローラをさぼらない。初期表示など必要な内容が含まれている。
- 代替コースの色は変えるべき。
- 「~~を入力する」コントローラは使用するアーキテクトによっては必要ないかもだけどこの段階では抽象設計なのでさぼらず記載するべき。
実際にはユースケース記述やロバストネス図の作成と並行して
- ユビキタス言語の抽出
- ユースケース(クリーンアーキテクチャ的な。オニオンアーキテクチャだとアプリケーションサービス)の抽出
- ドメインイベントの抽出
- ドメインモデルの更新
等々行いドメインを蒸留していきますが割愛。
しかしバウンダリ(UI。画面etc)に関しては特になんの疑問も抱けずそのままにしていました。
そして出来た画面が以下。
ワイヤーフレーム
メニュー画面
7ZZNj5swEIZ/jY9ZAYYAR0w+KlW9NFWrHg04YK3BqXEa0l9f25gEFiJVWu32sr7geWfswTMPFgCmdbcX+FR94QVhwHOKDsAN8DwXxr56aOXaK6Ef9kIpaGGD7sKB/iFWdKx6pgVpJ4GScybpaSrmvGlILicaFoJfpmFHzqZZT7gkM+GQYzZXf9BCVr0aRPCufyK0rGxm37WODOfPpeDnxqYDHjya0btrPGxlz9lWuOCXkQS3AKaCc9nP6i4lTJd2qFq/bvfAe3ttQRr5LwvWYZiFWRT7ceAGbhys7A6/MTuT4QjmReV1qM2lopIcTjjX9kX1H0BUyZopy1VTc3qi93eUdTugNhjOCEO3EqWccaFcDW+IDpWCP5NBVJVzzLh5hkboJEfK2IvlR97IHa4p08h9J6LADbay5cv1rL2UAzNaNkrLVeWIcqKc1zS36eZlHepEhCTdSLJl3hNeEymuKsR6h45fp+ZlRFdgtWpEFoysiC3R5W3ne1vVxHZ2ucuwxen+869i1bIsoj+/buCOrCCct3oLgUI8WdsJSs3EA2imxCo4AFEMogRsYxDHIPGNy9XzPiZCM3bmnRyRM2GlwG01puikd6i7Ut83T5S3TxSdpeTNEji+GfNm208Rosws/UY6U+UJJNELutSywoyx7vUOuAmCdaAcS5/EDKgHxCxw9RAifwqR688pcuESRW8Gkf9aiEKAQpBEBiIEovUHRO8MUfzfGQpey1AE0A6gjbmREpA4Hwy9M0NveA8p8/47ZHyjX064/Qs=
)
追加画面
7Zddb5swFIZ/jS9bAYYELkM+OmmbNK3Tpl0acMCqwZlxlmS/frYxBMe03aqsmrS5F7XfY+NwnvfYCYDL+njH0a56zwpMQeAVRwBXIAh8mITyn1JOnTIP551QclKYSWfhnvzARvSMuicFbq2JgjEqyM4Wc9Y0OBeWhjhnB3vallF71x0qsSPc54i66hdSiKpToxie9TeYlJXZOfRNIEP5Q8nZvjHbgQBudevCNeofZd6zrVDBDiMJrgFccsZE16uPS0xVavusdes2j0SHj81xI35lwWw+z+ZZnIRJ5Ed+Et2YJ3xHdI/7V9AfVJz63BwqIvD9DuVqfJD8AUwrUVM58mVXvz1Wz/fkaHhBNaAowzQdUrRklHEZaliD1VTB2QPuRZk5T7ch0oNQm2wJpRfLt6wRG1QTqiz3GfMCNcjIxl9+YMZTeyBKykZqucwclsE0ZzXJzXZuWvs8YS7wcSSZNN9hVmPBT3KKifbET/bwMHJXZLRq5CwYGxEZR5fDk89YZceQnaYMW7S8e/utuGlpFpOvH1dwg2+C8HnUI6wWyAK11RjxTs2vj6U6DG4z6V5JDO1uOde1mXIDIJqiXOh2wfRcN3KFtBppynd4q3ISeRdQwxE8qudcMh52mHLuFdCGNtrQRRtMov1jZCOX7DoCiQfilerEiepcmbVKfboXgjUvBu6pv0cwcdzKRw5n7nRRPu3z53mOiIVPAOOYIkG+21fF9SnGExTnYLEGC191FM4ZWMdAnhBx5ODsScmd5KWJ3XRfnK6jSKKbjEjGBcFWLeW62Sf+RfXZ9RpelOvcrc+Zbv398IG1RBBloxXvcm/78foF63tuxfqRy7/Xro86mUAdglSzVYRjsFj+PmGs2z9J2Id/GWIYTCCGIA7AYqU7ECyg6aTQhNK0D6Uufec70YsOcMLaWzKc245RQt1coMPlnOmln/BRJ9AyQuw60j36gy4gr4poFj1y9jtfza5xBCS2QeDMNcgsfMVLG8IJg8Qg3YC0u7QXYOH9d8GVXeC9mgvk8PyzTsdGP53h+ic=
)
編集画面
7Vltc6M2EP41+piMQYDhI29OO21nOk2nnX4UINvMycgn44vTX9+VEC8C7LtLSOY6d8pMIu2KXbHPSnqWIBwfLg+CHPe/8YIyZK+KC8IJsm0LBw78kZLnRrJ21o1gJ8pCT+oFj+W/VAtXWnouC3oyJtacs7o8msKcVxXNa0NGhOBP5rQtZ6bXI9nRieAxJ2wq/bss6n0jdX3cy3+i5W6vPTuWVmQk/7AT/Fxpd8jGW9Ua9YG0pvR7nvak4E8DEU4RjgXnddM7XGLKZGjbqDXPba5ou2ULWtVf8oC3XmfrzA+cwLVcK3DvtIVPhJ1p+wpqofVzG5unfVnTxyPJ5fgJ8Ec42tcHBiMLuurtqbS/glH3gnLASEZZ1IUo5owLUFW8onJqLfgH2gohcivVOk0LhHSyLRkbPb7lVb0hh5LJlPuLioJURIt1flm2Hs/5IKzcVSDLIXIUlFHOD2Wu3U3D2saJippeBiId5gfKD7QWzzBFa1vEn83h0yC7XC3bDzIL+1pIdEbvOss9rNDRyM6jjE8kfvjlY3F3Yplf/vNHgjf0rkXWgNpj4DeqSQZgQzZzUdAmUN7Hs8zJyOq7xuo7PQTTdo1JOSzmSIqirHbGVMeY1SdYK9TGQ1C2VlfN3DZAM6pmyXc5Z4wcT7SZ040GDr2d/tu8ccbhqBoLxey6+j0u3chEkj4gl8g6Dxy7W4qpbI8BY536FY4X6YgzwEvNDfxsa1s3VruXCaETtp/G6LaeeSjFCM6t0NOdKFYdG0W95OekNZ2JsTNILunvVStwUbBCfiI7fiA7C9r2UOijMEBpgIJA+rllWwonb3gN51dBVLQS34+CNPA2KydynSRwwyAJrQTbrmNv4jj2b0e+uG4YpQ6KfAQHBLw6wOinrzC1RmGKQkt2JFSQGsqy79608FXhvLZtKNnaBV5oZ3RLTG0rcSMntX0Lbrc0jPwQYp6m/mbjxZa7eUWsIONiFatR2L8cL/jtSyOLxXaZmL08Ju/04Decb//P2Enh3NUn5Q0JaOUjEgisR8oHvG9C3/KV/EEmWetvQhxxYE9bptihnILG3HEB1oVdg3VZzgztst0p7bLejnY5n2fYw6gO+XNBTvshsz7K+YfLTtZg9xkUDYABOd4LoUqiSGje686hU6h2A50TMHygbL/KaxdsKCAHXNpBPWdWV/OEWnce5gqGBbB1TEY9A609y6jfDFl3iuwM81kWaxn66FzXvHox4Cv5cwUmQU9gsit152uh23n+eTwHiDk3ABOUkbr8ZFboy6Poz6B4gx2N4GyRAk+lqj/G4R4VtQNNoBpoAOOipMZeylUzD9zR7jP3qzParuvp/vRUQ7os/52fyrqUaZSIJvZmPi6/YVXlNtqx1txZ7L4V1MEM1FOO9rUIU9W+S4Qt/I1BjGc+cjTVb5i0hTFuy2DcFsZdzTzlPdNPUS86wEt+ui+7c3uSKI5qU0C7yzlTj/6pSFhiJoI/zcjp0W83CrgqXM+9cvZPvogtcQQEZoJgb5ognvOOlzbGs8d9tJZfFeQnhUge9z+yYNksWL1bFsCw/5qudIP/WOD0Pw==
)
削除画面
7Vhdj5s4FP01fpwKMCbmka/Mrlb70qm26qMBB1AdnBLSZPrr9xpsPgIZTXfSaiuVkSb2uZd77XsP+CQIR/vLY8MO5d8y5wI5Vn5BOEaOY2PfhQ+FPPfIxt30QNFUuXYagafqG9egpdFTlfPjzLGVUrTVYQ5msq551s4w1jTyPHfbSTHPemAFXwBPGRNL9GOVt2WPEopH/A9eFaXO7NrakLLsc9HIU63TIQfvuqs375kJpfd5LFkuzxMIJwhHjZRtP9pfIi5UaU3V+vu2N6zDshtet6+5wdts0k1KfdcnNrF98qAjfGXixM0WuoW2z6Y257Jq+dOBZWp+hv4jHJbtXsDMhmG3e67iWzAbNqgmgqVchEOJIilkA6Za1ly5to38zA0IlbO6a7CYRqgku0qIq9t3sm63bF8JRbl/eJOzmmlY88t29HwtBxNVUQOWQeU4GMNM7qtMp1uW1dSJNy2/TCBd5kcu97xtnsFFW03Hn+fT84RdRGPlhFmYapBpRhdD5LGtMNCdXe8yPrLo8a8v+cNRpLT69D7GW/5gOjtrtScgb9iyFJoNbJZNzvtCeV9OipOhPQ5nqx/sUEyHzJwyWMyB5XlVFzNXd+Y1EsyAOngARhPV6n1NgVZM/ZIfMikEOxx57zPMJgm9Qn/2O04lvKquwWZ1XeMzrtIoIqkcwCW2yXzXGZYyN5rXwGydeguHi0okBfSr8/VpunPsF1ZbKkJowo5ugu/alZsSjOC9FXh6EEbdwEHhiPwZm9Bpc50MyKXyvWkFBPkWorEaUF8N7hjbQwFFgY8SH/m+yvNSbAUudnirz29qUW4QSkM/8b2t5YbEjX0S+HFgx9ghrrONooi+XPn8dmCUuCikCF4QsHVoI03eEGqDggQFthqoVgE1usiUvBjhu8p567HhbOfk+E5PxrDExLFjErqJQ2043ZIgpAHUPEnodutFNtm+oVbAuKir1VXZX98v+E9VkLvV9j41++81+Uk3/o/59mvWToFrR5/CexFg8CsRCKpH4RPdt5BvmaX+0FysjSchDiWop53o1KFyQdfa8YbEWhFiN1UXJjPV5a6oLocsVZf9w1QXXlFd/XEcxOakxuZcxuakHg7xZSOW2njak6n6ztmxnOryg4qwvxTqG9y7Sh7fVeGpbWW91ku3u9BCPg+9TLtbP3SsiNFMdtMlBfLumuJOb8AxIR4Bw9qXjIVEvwNBXH+uy7G3pIjnrujyH0YQvEKQXjYFWuME7m8W3JkF1k9jAUzHr/edbfITCk7+BQ==
)
とまあ見事なタスクベースなUIが出来てしまいました。
作った当時は要件満たしてるし良いじゃんと思ってたのですが、OOUX – オブジェクトベースのUIモデリングやOOUI の目当ての記事を読んでからだと以下の点で問題があると認識できました。
- 追加するとしても追加する予定の人が既に追加済みか確認したいから既存のユーザー一覧が見たい
- そもそも追加も編集も削除もしたくなくてただユーザーの一覧見たいんだけどどこでみるの?
- ただユーザーを閲覧するための機能(画面)を用意する?
要件に「ユーザー一覧を閲覧する」って記載されてないですが使う側からすればあって当たり前の機能なんですよね。
OOUX(OOUI)の考えにのっとって変更
あの図を作成
オブジェクトベースのUIへと転換する際に役に立つあの図(モデリング図?)を書いてみます。上記紹介記事に載っています。
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
)
-
Object
ロバストネス図で登場するエンティティの中から主要なオブジェクトを選定します。
各ロバストネス図を見比べて主要なエンティティが同じ場合はひとつの画面でユースケースを処理できるのではないか?と思えるはず。 -
View
エンティティ毎に<collection>と<single>を用意します。
<single>は必要ないかもしれないし複数必要かもしれません。
今回の場合だと閲覧と編集を兼ねる画面でも良いかもしれません。
<collection>がないエンティティも有り得ます。
少なくともエンティティを画面上で表現しようと思ったら<collection>と<single>という概念があることが意識出来ます。 -
Controller
各ViewにControllerを生やしてロバストネス図で登場するコントロールを配置します。
ロバストネス図には出てこなかった画面特有のコントロールも出てきますがこれもユースケース(アプリケーションサービス)になるかもです。
削除する機能は一覧画面でも閲覧画面でも行っても良いことに気付けました。
「ユーザーを追加する」ユースケースのユースケース記述とロバストネス図
[](
@startuml
title 「ユーザーを追加する」ユースケース記述とロバストネス図
note as abc
基本コース:
システムは「メニュー画面」を表示する。
利用者は「ユーザー一覧」ボタンを押し、システムは「ユーザー一覧画面」を表示する。
利用者は「追加」ボタンを押し、システムは「ユーザー追加編集画面」を表示する。
利用者は「名前」を入力し、「権限種別」を選択し、「保存」ボタンを押す。
システムは「ユーザー」を作成し保存する。システムは「メニュー画面」を表示する。
代替コース:
「名前」に許可しない文字列が入力された:システムは「入力できません」画面を表示する。
存在しない「権限種別」が選択された:システムは「存在しない権限種別です」画面を表示する。
保存に失敗した:システムは「保存に失敗しました」画面を表示する。
end note
actor 利用者
boundary メニュー画面
boundary ユーザー一覧画面 as z
boundary ユーザー追加編集画面 as x
control "「ユーザー一覧画面」を表示する" as a
control "「ユーザー追加編集画面」を表示する" as aa
control 名前を入力する as b
control 権限種別を選択する as c
control ユーザーを保存する as d
control "名前は許容できるか?" as e
control "権限種別は範囲内か?" as f
control "「権限種別が範囲外の値である」メッセージを表示する" as g #gray
control "「許容できない名前である」メッセージを表示する" as h #gray
control "保存に成功したか?" as i
control "「保存に失敗した」メッセージを表示する" as j #gray
control メニュー画面を表示する as p
boundary エラー画面 as y #gray
entity ユーザー
利用者 --> メニュー画面
メニュー画面 --> a: 「ユーザー一覧」ボタンクリック
a -- z
z -- aa: 「追加」ボタンクリック
aa - x
x -- b
x -- c
x -- d: 「保存」ボタンクリック
d -- ユーザー
b -- e
e -- h: いいえ
h -- y
c -- f
f -- g: いいえ
g -- y
d -- i
i -- j: いいえ
j -- y
i -- p: はい
p -- メニュー画面
@enduml
)
「ユーザーを編集する」ユースケースのユースケース記述とロバストネス図
[](
@startuml
title 「ユーザーを編集する」ユースケース記述とロバストネス図
note as abc
基本コース:
システムは「メニュー画面」を表示する。
利用者は「ユーザー一覧」ボタンを押し、システムは「ユーザー一覧」を取得して「ユーザー一覧画面」を表示する。
利用者は「ユーザー」を選択するとシステムは選択された「ユーザー」の情報を表示する。
利用者は「編集」ボタンを押し、システムは「ユーザー追加編集画面」を表示する。
利用者は「名前」を入力し、「権限種別」を選択し、「保存」ボタンを押す。
システムは「ユーザー」を作成し保存する。システムは「メニュー画面」を表示する。
代替コース:
「名前」に許可しない文字列が入力された:システムは「入力できません」画面を表示する。
存在しない「権限種別」が選択された:システムは「存在しない権限種別です」画面を表示する。
保存に失敗した:システムは「保存に失敗しました」画面を表示する。
end note
actor 利用者
boundary メニュー画面
boundary ユーザー一覧画面 as z
boundary ユーザー追加編集画面 as x
control "「ユーザー一覧画面」を表示する" as a
control "「ユーザー追加編集画面」を表示する" as aa
control 名前を入力する as b
control 権限種別を選択する as c
control ユーザーを保存する as d
control "名前は許容できるか?" as e
control "権限種別は範囲内か?" as f
control "「権限種別が範囲外の値である」メッセージを表示する" as g #gray
control "「許容できない名前である」メッセージを表示する" as h #gray
control "保存に成功したか?" as i
control "「保存に失敗した」メッセージを表示する" as j #gray
control ユーザー一覧を取得する as k
control "ユーザーを選択する" as n
control "ユーザー情報を表示する" as o
control メニュー画面を表示する as p
boundary エラー画面 as y #gray
entity ユーザー
entity ユーザー一覧
利用者 --> メニュー画面
メニュー画面 --> a: 「ユーザー一覧」ボタンクリック
a -- k
k -- ユーザー一覧
a -- z
z -- n
n -- o
o -- ユーザー
z -- aa: 「編集」ボタンクリック
aa -- x
x -- b
x -- c
x -- d: 「保存」ボタンクリック
d -- ユーザー
b -- e
e -- h: いいえ
h -- y
c -- f
f -- g: いいえ
g -- y
d -- i
i -- j: いいえ
j -- y
i -- p: はい
p -- メニュー画面
@enduml
)
「ユーザーを削除する」ユースケースのユースケース記述とロバストネス図
[](
@startuml
title 「ユーザーを削除する」ユースケース記述とロバストネス図
note as abc
基本コース:
システムは「メニュー画面」を表示する。
利用者は「ユーザー一覧」ボタンを押し、システムは「ユーザー一覧」を取得して「ユーザー一覧画面」を表示する。
利用者は「ユーザー」を選択するとシステムは選択された「ユーザー」の情報を表示する。
利用者は「削除」ボタンをクリックするとシステムは選択された「ユーザー」を削除する。システムは「メニュー画面」を表示する。
代替コース:
削除に失敗した:システムは「削除に失敗しました」画面を表示する。
end note
actor 利用者
boundary メニュー画面
boundary ユーザー一覧画面 as z
control "「ユーザー一覧画面」を表示する" as a
control ユーザーを削除する as d
control "削除に成功したか?" as i
control "「削除に失敗した」メッセージを表示する" as j #gray
control ユーザー一覧を取得する as k
control "ユーザーを選択する" as n
control "ユーザー情報を表示する" as o
control メニュー画面を表示する as p
boundary エラー画面 as y #gray
entity ユーザー
entity ユーザー一覧
利用者 --> メニュー画面
メニュー画面 --> a: 「ユーザー一覧」ボタンクリック
a -- k
k -- ユーザー一覧
a -- z
z -- n
n -- o
o -- ユーザー
z -- d: 「削除」ボタンをクリック
d -- ユーザー
d -- i
i -- j: いいえ
j -- y
i -- p: はい
p -- メニュー画面
@enduml
)
となりました。メニュー画面からユーザー一覧画面へ遷移する部分は共通化されたため、別ユースケースにするほうが良いかも。また、ユーザーが存在しない場合の代替コースは画面をまとめることにより異常系ではなくなりました。
ドメインを蒸留する際にあの図も含めるとより気付きやすくなると思いました。
改定ワイヤーフレーム
メニュー画面
lZRNj5swEIZ/jY9ZBQyBHBfysVLVS1O16tHgCVhrMGucQvrra4MhsBCp9QXPO2OPPfNghOOiPUtS5V8FBY7cLW0RPiDXdfDe0x+j3Hsl8IJeyCSjNughXNgfsOLWqjdGoZ4FKiG4YtVcTEVZQqpmGpFSNPOwq+DzrBXJYCFcUsKX6k9GVd6rfogf+huwLLeZPcc6EpK+Z1LcSpsOufjajd5dkGEre886J1Q0EwkfEY6lEKqfFW0M3JR2qFq/7vTEOx5bQqn+ZcEuCJIgCffe3nd8Z+9v7A6/Cb/BcIXuoOo+1KbJmYJLRVJjN7r/CEe5Kri2HD3tbg9m/622xgsag5MEeDSWKBZcSO0qRQkmVEnxDoOoK7ftxugZGmGSXBnnn5ZfRalOpGDcIPcDJCUlsbLly3GtvZaDcJaVWkt15UA7o1QULLXplmUd6gRSQTuRbJnPIApQ8q5DrHfo+H1uNhO6fKvlE7JwaEViic7GnR9t1RPb2fUu45rE5y8fdFPzJGS/vh3wCTbYX7b6iJFG/HVnJ1HcTVwUTRUPRSHSxzqGJvI1WACybNcEjxkQlNT5FJXK7FC0mXlUXpioX1h0U0qUa3R43Vh21P5vOEq6pd+h7Uo5IyH8hJBeRrsx1d3egQ++v/O1Y437BTVPsFiB5ykp3pwUb0mKg9dI+X9QtPl4ajrf5DnHx78=
)
動詞ではなく名詞にするのがポイントみたいです。
ユーザー一覧画面
7Vldb6M4FP01fkwFGAg8QgLd1exKo+1qV310wEnQEJwCmab99XttDMHgpF+06mjrSo19bWxzzrV9rkF4sTtel2S//ZOlNEeWkR4RXiLLMrFvww+3PDSWuT1vDJsyS2Wjk+Eme6TSaEjrIUtppTSsGcvrbK8aE1YUNKkVGylLdq82W7NcHXVPNnRkuElIPrb+m6X1trE6Hj7Zf6PZZitHtk1ZsSLJj03JDoUcDll4LVJTvSNtV/I9qy1J2X3PhCOEFyVjdZPbHRc059C2qDXPxWdqu2mXtKif84A7n6/mK8+3fcd0TN+ZyR5+kvxA21cQE60fWmzut1lNb/Yk4eV74B/hcFvvciiZkBVvT3n/BpS6F+SFnKxoHnYQLVjOSqgqWEF507pkP2hrBOQMkbqalgg+yDrL88Hja1bUMdllOXe5f2iZkoJIs/Qv05Jl3RgkzzYF2BJAjkJlmLBdlsjhxrC2ONGypseeScJ8TdmO1uUDNJG1LeMPavG+512OtG17noU9aSTSozddzydaISOZ1bOMK7K4/naXzqp85WW3fy1xTGctswrVbg7jhjVZAdngzaxMaQOUe3fgPhmap6wy+64ewLQcpVECk9mTNM2KjdLUVlqdHKw1ys4DqGx7NZq2LUCaqmbKs4TlOdlXtGnTlXoDuhv527zxisFWNTSW2nmd1jgfhjsSHwN8icwT37a6qaiV7TagzFO+wv7IB2I58CXa+t5qbZkXZrvlDiEd9tQsp+ta81CEEexbgSsz4UJkLBSeLL8v265X5XAwcC4+3ptm4CDfQN6SZzyfZybs20WBhwIfRT7yfT7Opb65cfSG53h+E0Vpa/G80I98Nzbs0LGXvhP4y8BcYsuxrXixWHiXkU/Pd4wiG4Uegg0CXh1o9KI3dDVHQYQCk2c4VeAaomfPudjDi+A8t2woWVspnmhldFOMLHPphHZkeSacblEQegFgHkVeHLsL04nfgBV43EJgNYD9+XzBf493Mhm202D2ekw+6MFP7G+/JnbcqDv6uL0RAa19IAJB9XB7T/eN5Fti8D+kirXTSYhDBuppnQt1yJugoXacQHVhR1Fdpq2RXZYzll3m+8ku+2mF3Ue1r59TUm37ynrP2++OGx6DXa0gaAAOyP6qLEVIFJZS9zo6dlKRLrBTgcIHyfYHP3ahD0FkT0vb6KSZxdE8ktbdCLqAYQJubVVRa6i1tIr63Zh1xsxqlM+0XHPow0Nds+LVhBv87wxNJa2gyy7U1cdCl/38aT57jNkXCCtpTurspxqhT8+ip2Hxgjoa0NkyBSNlIv4Ywj0Ians1vkhQAxynGVXWUiKSuuEOVp+6Xu3Bcp2P16crEpJh+XdWZXXG3WhZNtir/jj9ghWR22DFmrq92Hkvqn0N1WON9lKGqUj/S4ZN/MkoxppLjib6DZZtYIzbMBi3gXEXM491z/gq6lUbeMaqq6zbt0eOYos0JrQ7nFfi0b+FCFuqjuCNPXK89VtNBRwVjuuc2ftHN2JTbAG+6iDYHTuIa3/goY2x9tDmZ3UgrxQC+8sLJvYC47N5gUaUw1kfzvndEveCkB/6X14wqRdg67N5gU7AeyiMUdgI+AAFxpcXTOsFQ1X4kV5wd5vMy8fZ7eN1Rr/X3yo/mxXP+QKmXlM88T1M86lqxG4cy6DgDHoajM8DOrjywJorD1ujwbpvr5MjqvvQ9N6IcjzjeBpEB6K2Bbh/0eBr4lb/5aIWiqdvv6Ku930dR/8B
)
赤枠がユーザー一覧画面で赤枠がユーザーの閲覧用画面です。
あの図で記載したViewは必ずしも1画面1Viewでなくても問題ありません。
モバイルぐらいの画面サイズなら1画面1Viewで遷移させるのが良いかも。
画面サイズやデザインや利便性を考えて配置すれば良いはずです。
Viewの組み合わせについて考えられるのもあの図を作ったおかげです。
ユーザー追加編集画面
7Zddb5swFIZ/jS9bAYYELkM+OmmbNK3Tpl0acMCqwZlxlmS/frYxBMe03aqsmrS5F7XfY+NwntfHCYDL+njH0a56zwpMQeAVRwBXIAh8mITyn1JOnTIP551QclKYSWfhnvzARvSMuicFbq2JgjEqyM4Wc9Y0OBeWhjhnB3vallF71x0qsSPc54i66hdSiKpToxie9TeYlJXZOfRNIEP5Q8nZvjHbgQBudevCNeofZd6zrVDBDiMJrgFccsZE16uPS0xVavusdes2j0SHj81xI35lwWw+z+ZZnIRJ5Ed+Et2YJ3xHdI/7V9AfVJz63BwqIvD9DuVqfJD8AUwrUVM58mVXvz1Wz/fkaHhBNaAowzQdUrRklHEZaliD1VTB2QPuRZk5T7ch0oNQm2wJpRfLt6wRG1QTqiz3GfMCNcjIxl9+YMZTeyBKykZqucwclsE0ZzXJzXZuWvs8YS7wcSSZNN9hVmPBT3KKifbET/bwMHJXZLRq5CwYGxEZR5fDk89YZceQnaYMW7S8e/utuGlpFpOvH1dwg2+C8HnUI6wWyAK11RjxTs2vj6UqBreZdK8khna3nOuzmXIDIJqiXOh2wfR8buQKaTXSlO/wVuUk8i6ghiN4VM+5ZDzsMOXcK6ANbbShizaYRPvHyEYu2XUEEg/EK9WJE9W5MmuV+nQvBGteDNxTf49g4riVjxxq7vShfNrnz/McEQufAMYxRYJ8t6+K61OMJyjOwWINFr7qKJwzsI6BrBBx5ODsScmd5KWJ3XRfVNdRJNFNRiTjgmDrLOW62RX/4vTZ5zW8OK5z93zOdOvvhw+sJYIoG614l3vbj9c/sL7nnlg/cvn32vVRJxOoQ5BqtopwDBbL3yeMdfsnCfvwL0MMgwnEEMQBWKx0B4IFNJ0UmlCa9qHUpe98J3pRASesvSVD3XaMEurmAh0u50wv/YSPOoGWEWLXkW7pD7qAvCqiWfRI7Xe+ml2jBCS2QeDMNcgsfMVLG8LpGrABib60pU2S+L8LruwC79VcIIfnn3U6NvrpDNc/AQ==
)
保存ボタンだけにするか、追加と編集の2ボタンにするか、とかは検討事項です。
まとめ
ユースケース主体で設計していくと複数のユースケースをひとつの画面で行うという考えに至りづらかったです(ユースケースの抽出が悪いのかも)。
そこでOOUX(OOUI)という考え方を知ることができ、主要なオブジェクトが同じユースケースならば一つの画面にまとめることが可能である点に気付けるようになりました。
また画面から設計するにしても、画面の主役となる主要なオブジェクトを見つけるという作業がDDD(ICONIX(ロバストネス図))を介すと見つけやすいことに気付けました。
構造設計(バックエンド)だけではなく、画面設計(フロントエンド)においてもDDD(ドメイン。エンティティ(集約))は有用だと確認できました。
今度からGUIを見るたびにタスクベースかオブジェクトベースかチェックするようにします。
蛇足
上記紹介記事で自分にはなかった考え方で感動したので引用させていただきます。
アプリケーションの性格を特徴づけるのは、コレクションの形式です。コレクションがどのような表現でオブジェクトの一覧を提示するのかが、ユーザーにとってのアプリケーションの妥当性を決定します。
コレクションの形式には、例えば、カレンダー式、マップ式、一次元リスト式、タイル式などがあります。中略
OOUI では、コレクションとシングルの組み合わせによってオブジェクト同士の関係と情報粒度を定義しますが、オブジェクトの性質をアプリケーション固有の表現として反映するのは、コレクションのフォーマットなのです。
自分的にはコレクションといったら行列テーブルで画面に表示する、という考え方しかなかったので目から鱗でした。
マップにピンを立てて表示するのもコレクションですよね。言われてみれば。
情報を表示するだけならば名前と住所を列とした行列テーブルでも別に良いわけですし。
7ZjLcpswFIafRkt3AAEWS+RLOpN2JlN32slSBtloIpADcmzn6SthgcHISRdOJguzsKVzdIHz/UJHADjJ93cl2WQ/RUo58Jx0D+AUeJ4LI1/9acvhaBlH4dGwLllqGp0MC/ZKjdEx1i1LadVrKIXgkm36xkQUBU1kz0bKUuz6zVaC92fdkDUdGBYJ4UPrX5bK7GgNEDzZv1O2zszMvmscS5I8rUuxLcx0wIOr+jq6c9IMZZ6zykgqdh0TnAE4KYWQx1K+n1CuQ9tE7dhvfsHb3nZJC/k/HZ4fk3H5Onp8vWP0Qd5XERsVI8PuhfCtCQeYjUE8A7GrC5EDUAhmCCBVCMxzyEMTuvrpqR7fBRCTMjF0FVqIU1Jlra+SpXiiE8FFWXeFTn0pz4px3tgLUajueF2SlKmnOjPrAR+IlLQslBGpW1EkHLf+b2ZoCHr6fjhb65acrlSA8AstJVPYY2OWYqOnF4VcmCcyIdUN6f5ilN2WnVoSVORUlgfVxHTwDe1Dv7rrKKsRftZRlQuNkRg1r9uRT0hVwVC1Ew7H4+V4iSI/CtzAjYKRO6R7jnCXMUkXG5Lo+k6tcBWTTObccDsR1qxaCesKJ0vKcbsIzmBdBt4H5doloLHMSc64juMfWqakIA0tozHP1G1zNOgTRY0qJ05EzhIz3QWkFvAXKXt9yp6FcmChDNEVKMOKTO7un9NRxZeIPf6awjkdQc+ykCFAHoindQGCGJoChsaFcePCA10MKXVU0dNBu86NQjZ6hHy/1rvFNyaqbwxvpRSFTRR+fQ1BmhcpxMu662+6ryPYEwA6U47qltZX1+4dHXAaBGGgHDa5D8RyBYH4UV8hMBxKJPQtCvkwgUCLQAKAIoBiMItAFIHYv6ngyipwvpoK7Ps9Vls+qlWA9X5/U8FVVQC9r6aCwKICBPAc4Gn9UohB7NxUcF0VnGeGn6kCa+pv2xB8gOtcX70KVFqAZkMRGJrbnMeJ1FFu8+ofOh98EBWTTKOdLoUClV9OFLtQ7bl5R19iKzkrlFCaM6BjE89bh4or5PZne/o4GACElqQv/CiA4VsA1S8C8WQA8HZke+/I1n6Y+JQzm5UsspANNU19Kr8tzfeXpu3cfaW1qaqnbza1r/NdDM7+AQ==
)
というように表現しても良いわけです。(D&Dで棒人間移動)
権限の変更を主眼に置いたアプリケーションとして表現したいのであれば。
参考
ドメイン駆動設計とOOUXで迎える2019年
1年間ひたすらUI設計に関わって、情報に向き合った話と2018年振り返り
オブジェクトベースなUIデザインに取り組むための心構え