タスクベースUIとCQRS


この記事は 弁護士ドットコム Advent Calendar 2020 19日目の記事です。12月19日の午前2時を過ぎて苛立ちがドアを叩くころです。

今年は上野学さんの単著『オブジェクト指向UIデザイン 使いやすいソフトウェアの原理』が発売され、OOUIという言葉が盛り上がっていますね。昨日のアドベントカレンダーの記事を書いた @shirauix さんともOOUIの話で盛り上がり、彼が主催で社内読書会も行われました。

さて、世間的にも社内的にもOOUIが盛り上がって読書会も開催されるなか、わたしは社内でひっそりと「タスクベースUI」の勉強会をやったのでした。

タスクベースUI?

「タスクベースUI」という言葉は、先程の上野さんが盛んに言及することで最近有名になった言葉な気がします。

『オブジェクト指向UIデザイン』から引用します。

GUIのようにオブジェクトを起点として設計された操作モデルを「オブジェクト指向UI」と呼ぶのに対し、CLIのように、動詞を起点として設計された操作モデルを、動詞=やることを指向しているという意味で「タスク指向UI」と呼ぶことにします。

このようにも書かれています。

現代のデザインの多くは、タスク指向のベクトルで発達してきたと言えます。それはつまり、デザインというものを、顕在化した課題に対する即物的な解消手順として狭く捉えること。

上野さんの言う「タスク指向」なデザインとは、問題解決指向のデザインのことで、現代のデザインの多くがタスク指向で発達してきたとの指摘の通り、通常のデザインのことです(「デザインは問題解決だ」という物言いは聞いたことがあるのではないでしょうか?)。上野語のなかでも独特のイデオロギー色の濃い言葉で、批判的な文脈で使われます。

わたしは「タスク指向UI」という言葉は上野さんの造語なのだと考えていたのですが、CQRSのテキストを読んでいたら、Task-Based UI という章があり、驚いてしまいました。

ごん、お前だったのかタスクベースUIを支えていたのは。

CQRS

CQRS(Command Query Responsibility Segregation, コマンドクエリ責務分離)とは Greg Young さんという方が考えたデザインパターンです。原典はこちら(pdf)から読めます。

CQRSについてはいろいろ意見がありますが、ご本人の記事によると、コマンド(=状態を変更するメソッド)とクエリ(=値を返すメソッド)をもった一つのオブジェクトを、コマンドのみのオブジェクトとクエリのみのオブジェクトに分離しようというだけのパターンです。

以下は上記リンクの擬似コード例です。

CustomerService
void MakeCustomerPreferred(CustomerId)
Customer GetCustomer(CustomerId)
CustomerSet GetCustomersWithName(Name)
CustomerSet GetPreferredCustomers()
void ChangeCustomerLocale(CustomerId, NewLocale)
void CreateCustomer(Customer)
void EditCustomerDetails(CustomerDetails)

このクラスをもとにして、以下の2つのクラスに分割するのがCQRSパターンです。

CustomerWriteService
void MakeCustomerPreferred(CustomerId)
void ChangeCustomerLocale(CustomerId, NewLocale)
void CreateCustomer(Customer)
void EditCustomerDetails(CustomerDetails)
CustomerReadService
Customer GetCustomer(CustomerId)
CustomerSet GetCustomersWithName(Name)
CustomerSet GetPreferredCustomers()

CQRSというパターン自体は基本的にはここまでで、先の本人記事にあるとおり、アーキテクチャでもなければストレージの読み書きとも無関係である。ただ、このように状態の変更を伴う操作と値を返却する操作が一つだったものをそれぞれ分割することだけを指す。

さて、ここまではとても単純な話です。というか、もともとバートランド・メイヤーが言っているCQSとそんなに変わらないみたいなのですが、グレッグさんはこのパターンになかなか深い洞察を持っています。

いったいUIとなんの関係が...?という前に、CQRSを考える前提をおさらいしましょう。

CRUD UI

グレッグ・ヤングさんがCQRSを引き合いにだして批判する対象がCRUD UIです。CRUDとは、Create, Read, Update, Deleteの頭文字をとったものですが、"同一の対象"にたいする4種類の操作をまとめてCRUDと呼びます1
CRUD UIをプログラムに直訳してしまうと、あるオブジェクトに対する状態変更もできるし、同じオブジェクトから値を取得できることになります。データベースのテーブル上の行とプログラムのオブジェクトをマッピングするActiveRecordが近いのではないでしょうか。また、先程の CustomerService は「状態変更と値の読み取り」がセットになったオブジェクトで、CRUD的な思考からでてきたデザインだと、グレッグさんは考えているわけです。

CRUDを批判するに際して、おそらくグレッグさんの念頭にあったのは "REST" API2 だと思われます。先程の CustomerService を、一つのエンドポイントにたいして GET/POST/PUT/DELETE していると考えたときに、システムは指示されたとおりに処理をしているだけで、意味を理解していない。そこにあるのはただのデータ操作であり、そういうものは意味を失った「貧血オブジェクト」だというのが、グレッグさんのCRUDに対する主な批判です(そういえば最近サーバーサイドエンジニアはたまにjson返すだけおじさん扱いされたりしますね)。

さて、これがグレッグ的CQRSの前提です。つまりグレッグ的なCQRSとは、CRUDの単一なオブジェクトをコマンドとクエリに分割することです。
そしてようやくタスクベースUIが登場します。

Task-Based UI

グレッグさんのテキストを読むまで知らなかったのですが、タスクベースUIは Microsoft が提案した概念で、別名 Inductive User Interface と呼ばれ、Windows XP などのデザインのベースになったもののようです。グレッグさんのTask-Based UIには2001年の Microsoft の記事にリンクが貼られています。

グレッグさんの記事は Microsoft の記事の要約になっており、なかなか面白いとおもいます。グレッグさんがこのUIパターンに興味をもつ主な視点は、紛れもなく「CRUDベースUIからコマンドの切り出し」にあります。つまり、デザインは以下のようにリファクタリングされます。

これがCRUDパターンのUIです。Inventory Item がなにかわかりませんが、このアイテムをdeactivate(非活性化)するにはステータス列の値を変化させる必要があるUIになっています。

これを以下のように直します。Deactivate がリンクです。


↓deactivate

ここで興味深いのは、ページ分割が行われていることでしょう。パラメータ表示と更新処理が別ページで表現されています(CRUD UIはこれが一体だった)。タスクベースUIの主な手法として、このように明確にページ分割をすることが先の Microsoft のUIガイドラインにも記載されています。

グレッグさんが興味を持っているのは、どうみても「タスク」です。もとの CRUD UI では、アイテムの非活性化は status パラメータを変えることでしたが、タスクベースUIのなかでは deactivate という操作が切り出されています。おわかりかとおもいますが、タスクを実現する手段がコマンドなのです。CQRSは「クエリとコマンドを分離する」と言われますが、グレッグさんの本質的な関心はあきらかにコマンドのほうなのです。CQRSとタスクベースUIは直接の関係はないと言ったあと、グレッグさんはこのようにいいます。

There is however one thing that does really require a task based UI… That is Domain Driven Design.
しかし、タスクベースUIを本当に必要としているものが1つあります。ドメイン駆動設計です。

またでかい言葉でてきちゃったよ...。手を広げすぎてどう収拾つければ...。

いかがでしたか?

いかがでしたか?じゃないんですよ。もう朝の5時です。なぜ深夜からこんなめんどくさそうな話に手を出したのか、自分でもまったく理解できません。お布団に呼ばれている気がするのでまとめさせてください。まとまらないことはわかっているんですけど。

オブジェクト指向UIデザインの一節を思い出してみましょう。

動詞=やることを指向しているという意味で「タスク指向UI」と呼ぶ

グレッグさんの関心事の「コマンド」は、上野さんの考える「タスク」とじつにぴたり一致しているのです。

そして、グレッグさんは「ドメイン駆動設計にはタスクベースUIが必要だ」と言います。
なぜDDDはタスクベースUIを必要とするのか?それは、操作が意味づけられている必要があるからです。言葉を変えるなら、ユーザーは事前に意味づけられた操作の中を動き回らなければならない。まさにグレッグさんはこのように主張します。

The Application Service Layer in Domain Driven Design represents the tasks the system can perform.
ドメイン駆動設計のアプリケーションサービス層は、システムが実行可能なタスクを表します。

グレッグさんにとってDDDは、タスクの集合です。DDD下手するとタスク指向になるよねみたいなことを去年書いたような...。

さて、ややこしい記事を書いた挙げ句、なにもまとまっていないのですが、「ユーザーは事前に意味づけられた操作の中を動き回らなければならない」と書いてみて、最近読んだ記事を思い出したのでした。

排除アートと過防備都市の誕生。不寛容をめぐるアートとデザイン

排除アートの問題は、じつは都市におけるデザインから単一の意味以外排除されていくというトレンドだと思います。ベンチから「座る」という意味以外を排除することが排除アートにおける「デザイン」なのです。

こんなことを以前つぶやいたのでした。

グレッグさんが考えるシステムが、直接こういった不寛容だとはまったく思っていないのですが、DDDなりCQRSなりが洗練された不寛容につながらないようにするには「ユーザーにどうさせたいか」だけではなく、「ユーザーがどうやったら楽しいか」みたいな視点が必要かなと愚行する次第です。


追記
@Naoki_Tsuchiya さんがタスクベースUIのREST的な面からの解説を書いてくれました。まるで続きものみたいになっているのでこちらもぜひお読みください。
https://qiita.com/NaokiTsuchiya/items/fe5622639d5f57c172d3


  1. わざわざ引用符でくくったのは、CREATEとUPDATEは「同一の対象」に対する操作ではないことは明らかなのにCRUDとまとめられている根拠がよくわからないからです。 

  2. ここも"REST"に引用符をつけていますが、REST=CRUDというのがよくある誤解です。以前はグレッグさんがRESTをCRUDだと考えて批判していたのですが、あるときから「正しいRESTはCQRSになる」と主張するようになりました。