🎛️

エアコンで理解する「宣言的」と「命令的」

に公開

「宣言的プログラミング/命令的プログラミング」や「宣言的 UI/命令的 UI」という言葉で登場する「宣言的」「命令的」という概念があります。
この違いを理解するためにわかりやすい題材として、エアコンのリモコン操作を見つけたので、これを使って説明します。

さっそく 2 種類の異なるリモコンを見てみましょう。

2種類のエアコンのリモコン

命令的なリモコン

以下は我が家に存在する(比較的古い)エアコンのリモコンの写真です。
ここで注目してほしいのは、「運転/停止」ボタンと「運転切替」ボタンです。

命令的な設計のリモコン

このリモコンでは次のように操作します。

  • 運転/停止」ボタンを押して、運転のオンオフを切り替える
  • 運転切替」ボタンを押して、モードを切り替える
    • 押すたびに 4 つのモードが順繰りに切り替わる(「自動」→「冷房」→「ドライ(除湿)」→「暖房」→「自動」→...)
    • 現在のモードはリモコン上部の液晶に表示される

例えば、冷房をつけたいときは、以下のように操作します。

  1. (エアコンが停止している状態で)「運転/停止」ボタンを押して、エアコンの運転をオンにする
  2. (現在のモードが「自動」になっている場合)「運転切替」ボタンを 1 回押して、モードを「冷房」に切り替える

このリモコンは「命令的」な設計といえます。
運転オンオフの切り替え、モードの切り替えという「どう操作するか?」という手順を意識する必要があります。
ちなみに、「命令的」は「手続き的」と呼ぶこともあります。

以降は、このリモコンを「命令的なリモコン」と呼ぶことにします。

宣言的なリモコン

一方、我が家の別の部屋にある、(比較的新しい)エアコンのリモコンは以下のようになっています。

宣言的な設計のリモコン

こちらのリモコンには「運転切替」ボタンはありません。また、「運転」ボタンもありません。
代わりに、次のようなボタンがあります。

  • 「冷房」ボタン
  • 「暖房」ボタン
  • 「除湿切換」ボタン
  • 「自動」ボタン
  • 「停止」ボタン

それぞれの機能は読んで字のごとくです。
例えば、冷房をつけたいときは「冷房」ボタンを押すだけです。
止めたいときは「停止」ボタンを押すだけです。

このように、どうやって切り替えるか?を意識する必要がなく、「何をしたいか」を直接指定できる設計は「宣言的」といえます。

以降は、このリモコンを「宣言的なリモコン」と呼ぶことにします。

この 2 つの例をベースに、宣言的と命令的の違いとしてわかることを整理していきましょう。

命令的と宣言的の違い

前提:できることは同じ

前述のどちらのリモコンでも、同じ機能を実現しています。
冷房をつけることができるし、暖房をつけることもできるし、除湿もできます。

しかし、実現したいことに対して、すべきボタン操作は違っています。
あくまで「考え方」「アプローチ」が違うだけなのです。
そしてこの考え方・アプローチの違いにより、扱いやすさが変わってくるのです。

ポイント1:「どうやって」の命令的 vs 「何を」の宣言的

どうやって (How)」を意識するのが命令的なアプローチの特徴です。
命令的なリモコンでは、冷房をつけたいな、と思ったときに、何をすべきかを考える必要があります。エアコンが起動しているかどうかを確認し、停止しているなら運転をオンにします。そして次にモードを確認し、冷房になっていないなら冷房にするまでに「運転切換」ボタンを押せばいいか計算し、必要回数ボタンを押して切り替えます。
切り換えという命令(手順)を意識する必要があるのです。

一方、宣言的なアプローチでは「何を (What)」を意識します。
冷房をつけたいな、と思ったときには「冷房」ボタンを押すだけです。何をしたいかを直接指定できる設計になっています。

ポイント2:「状態」を気にする命令的 vs 気にしない宣言的

命令的な設計では「状態」の存在が切り離せません。
エアコンの例では、エアコンが現在「運転中」か「停止中」か、そして現在のモード(冷房・暖房・除湿・自動)がエアコンの持つ状態です。
例えば、冷房をつけたいとき、現在の状態が「自動運転」なら運転切換ボタンを 1 回だけ押す必要がありますし、現在の状態が「ドライ(除湿)」なら運転切換ボタンを 3 回押す必要があります。
このように、現在の状態によって行うべき操作が変わってきます。
今の状態を常に意識してなきゃいけないのは大変ですよね。
現在の状態を間違って認識していると、冷房にするつもりが暖房にしてしまった、みたいな意図しない結果になることもあります。

一方、宣言的なら現在の状態を気にしなくてよいです(※当然、エアコンの内部には状態があるのですが、ユーザーはそれを意識しなくてよいということです)。
例えば、冷房をつけたいときは「冷房」ボタンを押すだけです。現在の状態が何であれ(停止中であろうが、他のモードで運転中であろうが)、同じ操作で同じ結果になります。

ポイント3:「冪等性」を持たない命令的 vs 持つ宣言的

冪等性(べきとうせい)」とは、同じ操作を何度繰り返しても結果が変わらない性質のことです。

命令的な設計の場合、冪等性は保証されません。これは、前述の「状態」と関係しています。
命令的なリモコンでは、例えばエアコンをつけようと思って「運転/停止」ボタンを押したとき、間違って「運転/停止」ボタンを 2 回押してしまうとエアコンは停止してしまいます。
なぜなら、「運転/停止」ボタンの機能は状態によって変わるからです。

  • 命令的なリモコンの「運転/停止」ボタンの機能は…
    • 停止中なら:オンにする
    • 運転中なら:オフにする

宣言的な設計なら、冪等性を持ちます
例えば宣言的なリモコンでは、冷房をつけようと思って「冷房」ボタンを押したとき、間違って「冷房」ボタンを 2 回押してしまっても、エアコンは冷房のままです。
なぜなら、「冷房」ボタンの機能は状態に依存せず、常に同じだからです。

  • 宣言的なリモコンの「冷房」ボタンの機能は…
    • 常に冷房にする

おわりに

エアコンのリモコンを例に、命令的と宣言的の違いを説明しました。
ここまでの例から、宣言的なアプローチの方が扱いやすいことが感じられたのではないでしょうか。
実際、近年のソフトウェア開発では、宣言的なアプローチが好まれる傾向にあります。
例えば、React や Vue.js などのモダンなフロントエンドフレームワークは、宣言的な UI 開発を実現しており、旧来の命令的な DOM 操作を記述するアプローチに比べて、コードの可読性や保守性が向上しています。
宣言的なアプローチは、何をしたいのかが表現できるわかりやすさ、そして状態を意識する必要がないことからコードの可読性や保守性を向上させ、冪等性の性質からバグの発生を減少させる効果があります。

エアコンのリモコンについても、昔は命令的な設計のリモコンが多かった気がしますが、最近の機種では宣言的な設計のリモコンが多いようです。操作が直感的でわかりやすいからでしょうね。

理解の助けになれば幸いです。

関連・参考記事

https://zenn.dev/miyamonz/articles/3318bc87cf14cb

https://speakerdeck.com/uenitty/why-declarative-ui-is-less-fragile

GitHubで編集を提案

Discussion