Философия простоты Рича Хикки
Разбираем главную идею Clojure: «простое» — не то же самое, что «лёгкое».
Простое (simple) — то, что не переплетено с другими вещами; лёгкое (easy) — то, что близко и привычно. Это разные оси.
Знаменитый доклад «Simple Made Easy»
В 2011 году Рич Хикки прочитал доклад, который изменил то, как многие думают о коде. Его тезис: индустрия путает простоту с удобством. Слово «simple» происходит от латинского «simplex» — «один плетёный слой». Противоположность — «complex», «много слоёв, сплетённых вместе». Простое не значит «маленькое» или «знакомое». Простое — значит несвязанное с другими вещами.
«Лёгкое» (easy) — другое: это то, что рядом, что мы уже умеем, что не требует усилий прямо сейчас. Изменяемая переменная кажется лёгкой — она привычна. Но она сложна (complex), потому что переплетает значение, время и идентичность в один комок.
Зачем это нужно на практике
Хикки утверждает: лёгкие, но сложные решения копят технический долг. Сначала всё быстро, но через год систему невозможно понять, потому что всё переплетено. Простые решения требуют чуть больше мысли в начале, зато потом каждую часть можно понять и поменять отдельно.
Clojure воплощает эту идею в конкретных решениях:
| Привычное (лёгкое, но сложное) | Решение Clojure (простое) |
| изменяемая переменная | неизменяемое значение + явная ссылка (atom/ref) |
| класс с методами и полями | отдельно данные (map) и отдельно функции |
| наследование | композиция функций, протоколы |
| ORM, скрывающий SQL | данные как данные, явные запросы |
Разделять значение, время и идентичность
Главный пример простоты в Clojure — обращение со состоянием. В обычном языке переменная x — это и имя, и текущее значение, и точка во времени одновременно. В Clojure эти три понятия разведены:
- Значение — неизменяемый факт, например число 42 или вектор [1 2 3];
- Идентичность — ссылка, которая со временем указывает на разные значения (atom);
- Время — момент, в который мы смотрим на идентичность.
; Значение - просто факт, его нельзя изменить
[1 2 3]
; Идентичность - ссылка, способная со временем менять значение
(def счётчик (atom 0))
; В каждый момент времени мы читаем текущее значение
@счётчик ; => 0Как работает под капотом
Чтобы неизменяемость не была медленной, Clojure использует персистентные структуры данных со структурным разделением (structural sharing). Когда вы «добавляете» элемент в вектор, старый вектор не копируется целиком — новый делит большую часть памяти со старым и хранит только различие. Об этом будет отдельный урок; пока запомните: неизменяемость в Clojure — это не «копировать всё», а «делиться неизменным».
Частые ошибки
- Путать «простое» и «лёгкое». Знакомое решение часто оказывается сложным, если оно переплетает несколько забот.
- Бояться, что неизменяемость медленная. Персистентные структуры дают почти ту же скорость, что и изменяемые, без рисков гонок.
- Тащить ООП-привычки. В Clojure данные отдельно, поведение отдельно — не нужно склеивать их в классы.
Итоги
- Простое (несвязанное) и лёгкое (привычное) — разные вещи; цель Clojure — простое.
- Сложность копит технический долг; простота требует усилия вперёд, но окупается.
- Clojure разделяет значение, идентичность и время — это фундамент модели состояния.
- Неизменяемость быстра благодаря структурному разделению.