Share
Embed
"Simple Made Easy" Made Easier: Clojureに学ぶsimplicity
Rich Hickeyの有名なプレゼン"Simple Made Easy"をより踏み込んで解説します。
cf. 2019年版: https://speakerdeck.com/lagenorhynque/simple-made-easy-made-easy
Kent OHASHI
May 28, 2026
Transcript
52 slides
-
関数型プログラミング( 言語) の愛好者/ 実践者 特に , , がエレガントで好き の運営スタッフ( 座長のひとり)
主に(CfP を含む) メインコンテンツの準備を担当 のシニアエンジニア スタートアップと投資家のやり取りを効率化する データ管理プラットフォームを開発 ソフトウェア設計/ 開発とともに会計/ 財務/ 法務 について探求するのも好き lagénorhynque 🐬カマイルカ Clojure Haskell Flix 関数型まつり2026 株式会社スマートラウンド 2 -
[PR] 2026 年7 月の で登壇予定🐬 関数型まつり2026 速習FP in Scala with
Flix: Flix 言語で親しむ純粋関数型のコード設計 3 -
(2019 年7 月) での発表 Fun Fun Functional (2) 関数型言語 Lightning
Talks!! "Simple Made Easy" Made Easy: Clojure の設計思想を理解しよう [ 書き起こし記事] "simple" と"easy" はどう違う? Simple Made Easy を解説 Part1 5 -
今回のテーマ (-> (simple-made-easy-made-easy) revisit ; 「"Simple Made Easy" Made Easy
」をおさらい deepen ; 近年のClojure エコシステム/ コミュニティの進化を深掘り extend) ; Clojure の範囲に留まらないより一般的な示唆へと展開 6 -
1. simple と easy という言葉 2. "Simple Made Easy" とは
3. simple と easy の意味 4. simple と easy の関係 5. なぜ simplicity を重視するのか 6. どのように simple にするのか 7. Clojure に見る simplicity 8. simple と easy の区別のより抽象的( メタ) な示唆 7 -
Clojure コミュニティにおける simple 明確に定義された特別な意味がある easy と混同されやすいが概念的にまったく違う Clojure とは simple さ(simplicity)
を追求した言語 あらゆる場面で非常に重視されている概念 設計の良し悪しを図る指標のひとつ 9 -
(at 2011) Clojure 作者Rich Hickey による極めて有名な発表 コミュニティで simple の概念が浸透するきっかけ 日本ではタイトルも趣旨も(
特にClojurian 以外から) わりと誤解されているかも cf. (at 2012) Simple Made Easy Strange Loop Simplicity Matters RailsConf シンプルさの必要性 · eed3si9n 11 -
タイトル"Simple Made Easy" の意味 敢えて訳せば「simple 簡単解説」 例えば という本がある 英語の文法的には: X
makes Y easy. → Y is made easy [by X]. → Y made easy [by X] ( 簡単になったY) 本題の simple と easy を掛けた言葉遊びでもある simple を追求すると easy にもなる? 英語的にも内容的にもちょっと苦しい解釈 Word Power Made Easy 12 -
simple の意味 < simplex (= sim- + plex) ラテン語 simplex
原義: 「一折り」 「一編み」 「一捻り」 「単一の役割」 「単一の責務」 「単一の概念」 「単 一の次元」 ※ 「単一の実体/ 操作」 ではない 客観的な概念: 設計対象の構造の単純さ 対義語: (= com- + plex) 原義: 「絡まり合った」 「折り重なった」 「もつれ た」 simple complex 14 -
easy の意味 (= + -y) < aise/eise < adjacens ラテン語
adjacens (cf. 🇬🇧 adjacent) 原義: 「近くにある」 「隣接した」 「身近な」( 物理的に近い) 「親しみがある」( 自分 の理解に近い) 「易しい」( できることに近い) 主観的/ 相対的な概念: 利用者からの( 広義の) 近さ 対義語: 原義: 「強い」 「手ごわい」 ※ easy とは無関係 easy ease hard 15 -
simple と easy の二者択一ではない simple/complex, easy/hard の直交した2 つの評価軸 単純なトレードオフの関係にはない simple
AND easy も complex AND hard もある 「 easy よりも simple を選ぼう」 ではない complex になりうるものを避けて simple を追求 しようというのがRich Hickey の主張 選択するのは simple OR complex であって simple OR easy ではない simple AND easy は十分に実現可能 17 -
構図例: "easy but complex" vs "simple but hard" ease を優先し
complexity ( ↔ simplicity) を甘受する 短期: easy なため生産性が高く、 complex である ことも直ちに支障をきたさない 中長期: complex ゆえに生産性が急速に低下 構造的な限界により徐々に手に負えなくなる ⭐️ simplicity を優先し hardness ( ↔ ease) を甘受する 短期: hard ゆえに生産性が低く、 simple なもの を課題に適用するにはいくらか時間が掛かる 中長期: simple なため生産性が高い水準を維持 hard から easy へと習熟/ 環境整備も進む 18 -
よくある誤解/ 派生解釈と🐬の見解(1) 「 simple 簡単解説」というのが文字通りの解釈 simple と easy の峻別という本題に関わる最重要の キーワードが見事に組み込まれた表現
しかし、タイトル自体に何かを促すメッセージ性が あるとは読み取りがたい "Simple Made Easy" というRich Hickey による標語がある 19 -
よくある誤解/ 派生解釈と🐬の見解(2) simplicity と ease がもたらしうる実用的メリットを 分かりやすく伝えようという試みに感じられる しかし、 simplicity が客観的な構造の問題から主観
的な体験の問題に変質してしまう危うさがある 「覚えることが少ない」という体験はむしろ easy であることの例と位置付けるのが素直そう simple: 覚えることの少なさ重視 easy: 手数の少なさ重視 20 -
よくある誤解/ 派生解釈と🐬の見解(3) simple にすると ease が損なわれ、 easy にすると simplicity が損なわれるだろうか?
確かに、 simple but hard なもの、 easy but complex なものは両極端で分かりやすい対比 しかし、 「設計対象の構造の単純さ」と「利用者 からの( 広義の) 近さ」というまったく異なる性質 の間に不可避的な連動関係があるとは考えがたい simple と easy はトレードオフなので simple を選ぼう 21 -
誤解/ 派生解釈例に共通する傾向( 🐬のメタ読み) simplicity を分かりやすく(easy に) 理解しようとす るあまり、 simplicity が何かと
complect している 例1: ( 例えば) simple にすると easy になるという 論理関係が加わっている 例2: simplicity に主観的な要素が加わっている 例3: simple/complex, easy/hard という独立した 評価軸が単一軸の二項対立にまとまっている 22 -
simple にするメリット 構造的に( 必然的に) — simplicity の内在的性質 組み合わせやすい(composable) 独立性が高い(modular) 人間的に(
結果的に) — 派生的な ease への好影響 理解しやすい 変更しやすい デバッグしやすい 柔軟 あとから方針/ 決定を見直すことも容易 置き換えられる 25 -
simple なものを見極める complexity をもたらす( している) もの を避ける もともと simple なものを利用する
抽象化する( ) abstract の原義は「引き離す」(draw away) 詳細を覆い隠すことではない who, what, when, where, why, how をそれぞれ 検討することがヒントになるかも あらかじめ問題を simple にする( ) complect abstract simplify 27 -
すべて丸括弧ではなく複数の括弧を使い分ける 丸括弧が複数の役割を担って complect している as code: オペレーター呼び出し 束縛フォーム cond の節など、特殊形式/
マクロの要素 as data: コンスセル( によるリスト/alist/plist など) ;; Common Lisp: Clojure 以前からあるLisp の例 (defun fizzbuzz (n) (let ((fizzp (zerop (mod n 3))) (buzzp (zerop (mod n 5)))) (cond ((and fizzp buzzp) "Fizz Buzz") (buzzp "Buzz") (fizzp "Fizz") (t n)))) 29 -
括弧を役割ごとに使い分けたほうが simple ( ): オペレーター呼び出し(as code) 、リスト(as data) [ ]:
束縛フォーム(as code) 、ベクター(as data) { }: メタデータ(as code) 、マップ(as data) ℹ️ Common Lisp でもリーダーマクロによって括弧 の意味付けの変更は可能 ;; Clojure (defn fizzbuzz [n] (let [fizz? (zero? (mod n 3)) buzz? (zero? (mod n 5))] (cond (and fizz? buzz?) "Fizz Buzz" buzz? "Buzz" fizz? "Fizz" :else n))) 30 -
オブジェクトよりも値 オブジェクト( クラス) に以下が complect している 値(value): それ自体としては不変のデータ [ ミュータブルな場合]
状態(state): アイデンティ ティに紐付く値が時とともに変化するもの [ メソッドを持つ場合] 関数: オブジェクトの文脈 でのクロージャー 名前空間/ モジュール: 定義を束ねるもの // Scala: オブジェクト指向言語の例 case class Coffee(price: Double): def applyTax(rate: Double): Coffee = copy(price = price * (1 + rate)) 31 -
Clojure では構造的に分離されていて simple 値(value): ただの不変のデータ [ 状態(state) を扱いたい場合] 次節で紹介 💁♂️
関数: ただのトップレベル関数 名前空間/ モジュール: ns として独立 ℹ️ Scala の により( メソッドとしての) 関数の分離は部分的に可能 ;; Clojure ;; (require '[lagenorhynque.cafe.coffee :as-alias coffee]) (defn make-coffee [price] #::coffee{:price price}) (defn apply-tax [coffee rate] (update coffee ::coffee/price * (+ 1 rate))) 拡張メソッド 32 -
変数よりも管理された参照型 ( 可変の) 変数に以下が complect している アイデンティティ: 値が変化しても変わらない同 一の実体 値:
変数に紐付いているデータ 時間: 再代入のたびに生じるアイデンティティと 値の紐付き関係の遷移 // Scala: ( 可変の) 変数を持つ言語の例 def heavyCalculation(xs: List[Int]): Int = var result = 0 // 変数を宣言/ 初期化 for x <- xs do result += x * x // 変数に再代入 result // 変数を参照 33 -
参照型では構造的に分離されていて simple アイデンティティ: 参照型そのもの 値: 参照型が保持するデータ 時間: 更新操作のたびに生じるアイデンティティ と値の関係の遷移 ⚠️
並行処理向けには atom (CAS), ref (STM), etc. ℹ️ Scala のサードパーティライブラリには Ref など 参照型を提供するものがある ;; Clojure (defn heavy-calculation [xs] (let [result (volatile! 0)] ; 初期値を指定して参照型を導入 (doseq [x xs] (vswap! result + (* x x))) ; 参照型の値を更新( 差し替え) @result)) ; 参照型の値を参照 34 -
継承よりもアドホック多相的な仕組み サブタイピング( サブタイプ多相) により、継承関係 にある複数の型/ クラス同士が complect している // Scala:
( 継承を備えている) オブジェクト指向言語の例 // インターフェースの定義 trait Shape: def area: Double // クラス( 型) の定義とともにインターフェースの実装 class Rectangle(width: Double, height: Double) extends Shape: def area = width * height class Circle(radius: Double) extends Shape: def area = scala.math.Pi * radius * radius 35 -
Clojure の ではデータ型定義とインター フェース実装が分離可能で simple への解答例でもある ℹ️ Scala にも というアドホック多相機構が
ある ;; Clojure ;; インターフェースの定義 (defprotocol Shape (area [this])) ;; データ型の定義 (defrecord Rectangle [width height]) (defrecord Circle [radius]) ;; インターフェースの実装 (extend-protocol Shape Rectangle (area [{:keys [width height]}] (* width height)) Circle (area [{:keys [radius]}] (* Math/PI radius radius))) プロトコル Expression Problem 型クラス 36 -
パターンマッチングよりもアドホック多相的な仕組み パターンマッチングではパターン(who) と対応する 振る舞い(what) のペアが複数 complect している # Elixir: パターンマッチングを多用する言語の例
defmodule Geometry do # 関数定義とともに引数でパターンマッチ def area(%{type: :rectangle, width: w, height: h}), do: w * h def area(%{type: :circle, radius: r}), do: :math.pi() * r * r end 37 -
Clojure の ではディスパッチ関数 (who) とメソッド実装(what) が分かれていて simple ℹ️ Elixir にもClojure
類似の がある ;; Clojure ;; ディスパッチ関数 (defmulti area :type) ;; ディスパッチする値ごとのメソッド実装 (defmethod area :rectangle [{:keys [width height]}] (* width height)) (defmethod area :circle [{:keys [radius]}] (* Math/PI radius radius)) マルチメソッド プロトコル 38 -
アクターよりもキュー アクターではメッセージに対する振る舞い(what) と メッセージを送受信するプロセス(who) が complect している # Elixir: 並行処理機構にアクターモデルを採用する言語の例
# メッセージを受信するプロセス pid = spawn(fn -> receive do msg -> IO.puts(msg) end end) # プロセスへメッセージを送信 send(pid, "hello") 39 -
では軽量スレッドでの振る舞い(what) と 値を送受信するチャネル(who) が分かれていて simple ;; Clojure (require '[clojure.core.async :refer
[<! >! chan go]]) ;; チャネル/ ブロッキングキュー (def ch (chan)) ;; 軽量スレッドでチャネルへ値を送信 (go (>! ch "hello")) ;; 軽量スレッドでチャネルから値を受信 (go (println (<! ch))) core.async 40 -
型システムではなくデータ仕様記述ライブラリの追加 : データ仕様を述語で記述する一種の コントラクトシステム : データ駆動のスキーマライブラリ cf. : Clojure に型システムを追加する
ライブラリ 🐬< データとスキーマを分けて扱うアプローチが simple clojure.spec metosin/malli Typed Clojure 41 -
プラグインではなくデータ主体のCLI/ ビルドツール : deps.edn の中身はただのデータ : build.clj の中身はただの関数 cf. :
project.clj の中身は( マクロを含む) コード Java のMaven の系譜のビルドツール プラグイン拡張モデル 🐬< 設定( データ) とビルドロジック( 関数) が分かれて いて simple Clojure CLI tools.build Leiningen 42 -
破壊的変更を避けた積み重ねによる進化 Clojure エコシステム: 言語本体: 2009 年(v1.0) から2026 年(v1.12) 現在に 至るまで破壊的変更のない積み重ね
標準/ サードパーティライブラリ: 同様の安定進化 cf. Scala エコシステム: 破壊を伴うイノベーション 🐬< simple な構造を吟味しながら組み合わせて破壊 なく進化させていく文化 43 -
Clojure とScala のコードベースの変遷 (HOPL IV, 2020) で示される、 Clojure とScala のコードベースの進化の違い
🐬< A History of Clojure Rich Hickey も述べるように良し悪しは一概に 言えないが、コミュニティの価値観が表れている 44 -
改めて simple と easy の根本的な違いとは "Simple Made Easy" の核心: simple
≠ easy simple である(simplicity) 設計対象の構造の単純さ 客観的な概念 easy である(ease) 利用者からの( 広義の) 近さ 主観的/ 相対的な概念 ⇒ Clojure エコシステム/ コミュニティは simplicity を 追求して長期にわたり安定進化してきた 46 -
simplicity と ease の対比をさらに抽象化してみると simplicity → 対象/ 客体(object) ・モノの構造 ease
→ 主体(subject) ・ヒトの対象との関わり方 学習/ 経験や環境など、個人/ 社会の対象との向き 合い方 simplicity と ease を区別し simplicity を優先する → モノへの投資とヒトへの投資を区別する ヒトが移り変わっても残るモノには最初に意識的 に投資する 47 -
長く残るモノと移り変わるヒトから連想する古い格言 🇬🇧: Art is long, life is short/brief. 🇯🇵: 技芸は長く、人生は短い。
古希語( 原典): ὁ βίος βραχύς, ἡ δὲ τέχνη μακρή 原文での趣旨: 人生は短いのに対して( 医療) 技術の 道は長い( だから時間を無駄にせず学ばなければ) 。 後世の意味の変化: ( 芸術家の) 人生は短く儚いが、 芸術は長く残る。 ars longa, vita brevis 48 -
技芸(ars) を磨きながら人生(vita) を高める多様な道 言語/ エコシステムとコミュニティの選択 Clojure: simplicity を追求しながら ease を高める
他のLisp (e.g. Common Lisp) 他のJVM 言語(e.g. Scala) 他の関数型言語(e.g. Scala, Elixir) ソフトウェア開発者として、さらには人として いかなる技芸を学び磨き上げ、何を残せるだろう 自分と社会のより良い体験/ 人生に向けて、何が できるだろう 49 -
simplicity とは何かを知るために を一通り観てみる Clojure の背景を探ってみる: Clojure エコシステム/ コミュニティに触れてみる "Simple Made
Easy" A History of Clojure 50 -
user> (-> (simple-made-easy-made-easy) revisit deepen extend) "Simple Made Easy" Made
Easier ;; simplicity という長く続く価値を、皆さんにとってより身近に 51 -
Further Reading Simple Made Easy matthiasn/talk-transcripts > Hickey_Rich/SimpleMadeEasy.md Clojure と「Simple
Made Easy 」 - 紙箱 Simplicity Matters シンプルさの必要性 · eed3si9n A History of Clojure Rich Already Answered That! Clojurian が出会ったsimple 志向なJVM 関数型言語 Flix —— ファーストインプレッション 52