Читать книгу Код. Культура, скомпилированная в байты - - Страница 8
ЧАСТЬ I: ФИЛОСОФИИ
Глава 1. Манифесты
1.3. Go Proverbs: простота как дисциплина
ОглавлениеВ ноябре 2015 года Роб Пайк выступил на Gopherfest в Сан-Франциско с докладом под названием «Go Proverbs». Он вышел на сцену не с презентацией, а со списком коротких фраз – пословиц, как он их назвал. Каждая описывала какой-то аспект того, как следует думать при программировании на Go.
«Don’t communicate by sharing memory, share memory by communicating» – «Не общайтесь через разделяемую память, разделяйте память через общение». «Clear is better than clever» – «Ясное лучше умного». «A little copying is better than a little dependency» – «Немного копирования лучше, чем немного зависимости». «The bigger the interface, the weaker the abstraction» – «Чем больше интерфейс, тем слабее абстракция». «Errors are values» – «Ошибки – это значения».
Пайк не изобрёл эти принципы для доклада. Они кристаллизовались за шесть лет развития Go – с момента, когда в 2007 году три инженера Google начали обсуждать, каким должен быть новый язык, и до 2015-го, когда Go уже использовался в критической инфраструктуре компании.
«Clear is better than clever» – «Ясное лучше умного».
Эта фраза могла бы стать эпиграфом всего проекта. Она напрямую противопоставлена культуре, в которой сложный код воспринимается как признак мастерства. Программист, написавший однострочник, непонятный коллегам, часто гордится собой. Go как язык не поощряет такую гордость. Если код нужно расшифровывать – он плохой, независимо от того, насколько он краток или элегантен.
Чтобы понять, почему Go проповедует такую дисциплину, нужно знать контекст его создания.
К 2007 году Google стал одной из крупнейших технологических компаний мира. Инфраструктура, на которой работали поиск, Gmail, YouTube, включала миллионы серверов и миллиарды строк кода. Значительная часть этого кода была написана на C++.
C++ – мощный язык. Он даёт программисту контроль над каждым байтом памяти, позволяет строить абстракции любой сложности, поддерживает десятки парадигм программирования. Но в масштабах Google эта мощность стала проблемой.
Компиляция крупных проектов занимала часы. Не минуты – часы. Инженеры запускали сборку и уходили обедать, надеясь, что к их возвращению она завершится. Новые сотрудники тратили недели, чтобы разобраться в хитросплетениях шаблонов и макросов. Код, написанный одной командой, был почти непонятен другой, хотя все использовали один язык.
Роберт Гриземер, Роб Пайк и Кен Томпсон – трое инженеров с легендарными послужными списками – начали обсуждать альтернативу. Пайк и Томпсон работали в Bell Labs и участвовали в создании Unix и Си. Гриземер работал над виртуальной машиной Java HotSpot. Они знали, как устроены языки программирования изнутри, и они устали от сложности.
«Complexity is multiplicative» – «Сложность мультипликативна», – говорил Пайк. Сложность не складывается, она умножается. Каждая новая возможность языка взаимодействует со всеми существующими, создавая комбинаторный взрыв краевых случаев. C++ начинался как простое расширение Си, но к 2007 году стал одним из самых сложных языков в истории.
Go был ответом на эту сложность. Не улучшением C++, а его антитезой. Команда задалась вопросом: какие возможности действительно необходимы для системного программирования? И систематически отказалась от всего остального.
В Go нет наследования классов. Нет generic-типов – они появились только в 2022 году, через тринадцать лет после первого релиза. Нет исключений. Нет перегрузки функций. Нет неявных преобразований типов. Каждое из этих «нет» – сознательное решение.
«A little copying is better than a little dependency» – «Немного копирования лучше, чем немного зависимости».
Этот принцип звучит как ересь для программиста, воспитанного на идее повторного использования кода. DRY – Don’t Repeat Yourself, «не повторяй себя» – стало мантрой индустрии. Но Пайк говорит: иногда лучше скопировать несколько строк, чем создавать зависимость от пакета, который потянет за собой другие зависимости, которые потянут ещё, и в итоге для вывода «Hello, world» понадобится десять мегабайт библиотек.
Go не против абстракций – он против абстракций ради абстракций. Каждая абстракция должна оправдывать себя. Если копирование проще и понятнее – копируй.
«Errors are values» – «Ошибки – это значения».
Обработка ошибок в Go – вероятно, самый спорный аспект языка. Там, где другие языки используют исключения или монады, Go предлагает простейший механизм: функция возвращает два значения – результат и ошибку. Если ошибка не nil, что-то пошло не так. Программист проверяет это условие после каждого вызова, который может завершиться неудачей. Паттерн «if err!= nil» повторяется в Go-программах десятки, сотни раз. Критики называют его многословным, уродливым, утомительным. Сторонники – честным.
Пайк объяснял эту философию так: «Errors are values. They can be programmed, not just handled» – «Ошибки – это значения. Их можно программировать, а не просто обрабатывать». Ошибка – не исключительная ситуация, выбивающая программу из нормального потока. Ошибка – обычное значение, с которым можно работать как с любым другим. Проверить, обернуть, агрегировать, отложить.
Это не просто технический выбор – это философский. Исключения предполагают, что ошибки редки и неожиданны: нормальный код делает нормальные вещи, а ошибки – нечто из ряда вон выходящее. Go говорит: нет, ошибки – часть жизни. Сеть отваливается, файлы не находятся, память кончается. Хороший код – тот, который это учитывает, а не притворяется, что всё всегда хорошо.
«Gofmt’s style is no one’s favorite, yet gofmt is everyone’s favorite» – «Стиль gofmt – ничей любимый, но сам gofmt – любимец всех».
gofmt – форматтер кода, встроенный в стандартную поставку Go. Он приводит любой код к единому стилю: определённые отступы, определённые переносы, определённое расположение скобок. Настроек почти нет. Код, пропущенный через gofmt, выглядит одинаково независимо от того, кто его написал.
Результат стиля gofmt никому не нравится полностью. Кто-то предпочитает другие отступы, кто-то – другое расположение скобок. Но сам инструмент нравится всем, потому что он прекращает споры. Не нужно обсуждать стиль на код-ревью. Не нужно писать style guide. Не нужно настраивать линтер. Вопрос закрыт: есть gofmt, всё остальное – шум.
Это воплощение философии Go в миниатюре. Язык не даёт свободу выбора там, где выбор не нужен. Он принимает решение за программиста – не потому, что программист глуп, а потому, что время программиста ценно. Пусть лучше думает о бизнес-логике, чем о том, ставить ли пробел перед скобкой.
Go Proverbs – не документ в традиционном смысле. Это выступление, ставшее легендой. Но в сообществе Go эти пословицы цитируют как священный текст. Они определяют, что значит писать идиоматичный Go – код, который не просто работает, но соответствует культуре языка.