[Перевод] Остерегайтесь эффекта Makefile

98bbb8e143db2eeb00d6bf3d9f51bdcf

Существует специфический «эффект Makefile», напоминающий такие феномены как карго-культы, нормализация отклонений,  «нечитабельный язык» и т.д. В этой статье я берусь утверждать, что Makefile — явление того же порядка, с той оговоркой, что он немного отличается от вышеперечисленных феноменов. Makefile не является по сути своей неэффективным или плохим и сказывается на результатах проектирования лишь в некоторых ситуациях.

Не могу подобрать идеального названия для этого явления, так что буду называть его просто «эффект Makefile». Эффект Makefile не назовёшь однозначно порочным — просто нужно иметь его в виду при проектировании инструментов и систем.

Суть эффекта Makefile сводится к следующему:

Если некоторый инструмент достигает определённого уровня сложности, или работа с ним строится слишком непривычно, то этот инструмент не запускают с чистого листа, а копируют и вставляют по образцу уже имеющихся готовых и хорошо зарекомендовавших себя конфигураций, после чего слегка адаптируют под новую ситуацию.

На это падки технари всех мастей, независимо от их навыков и уровня профессионализма, и в качестве наиболее красноречивого примера такого рода можно привести работу с Make:

  1. Требуется выполнить (понятную в общих чертах) задачу. Ранее вы уже решали очень похожую или даже идентичную задачу.

  2. Make (или другой инструмент, которому присущ такой эффект) считается верным или «наилучшим» из себе подобных (учитывая практическую целесообразность, зависимости пути, пр.) для решения данной задачи.

  3. Инженер не пишет новый Makefile, а копирует более ранний (зачастую очень большой и переусложнённый) Makefile из ранее решённой задачи, после чего адаптирует этот материал до тех пор, пока он не станет работать в новом контексте. Мне доводилось слышать, как некоторые технари получали Makefile «в наследство» т.e., эти Makefile они брали у своих начальников, преподавателей и т.д. В результате складывается так, что и эти «предковые» Makefile также с незапамятных времён передавались из поколения в поколение с косметическими изменениями. 

Make — просто пример, а не универсалия. Складываются разные профессиональные группы, члены которых осваивают разные инструменты. Есть и более обширное наблюдение: существуют целые классы инструментов/систем, (более) подверженных этому эффекту и (относительно) менее подверженные.

При некотором приближении это просто отличный (даже идеальный) инженерный механизм реагирования с точки зрения проектирования: зачастую наиболее рационально применить известный рабочий вариант. (Теоретически) так мы снижаем риск привнести в код баги, поскольку большая часть сделанного остаётся без изменений.

Но именно с точки зрения проектирования это выдаёт ущербность инструмента. Она может заключаться в том, как инструмент устроен или как применяется, но суть такова: инструмент (система) слишком сложны или раздражают, чтобы использовать их с нуля. Пользователь избегает применять инструмент с каждой задачей заново, а раз за разом копирует известное хорошее решение, в котором со временем накапливаются изменения.

Как только вы заметите этот эффект, вы также убедитесь, что он встречается повсюду. Кроме Make:

  • Конфигурации CI/CD (непрерывной интеграции и доставки) в таких инструментах как GitHub Actions и GitLab CI/CD, где пользователь копирует лохматую YAML-разметку из последней работавшей конфигурации и доводит её до ума, пока она снова не заработает (зачастую её для этого требуется не раз перезапустить);

  • Конфигурации линтеров и инструментов форматирования, где из проекта в проект копируется базовый набор правил, которые затем ужесточаются или смягчаются в зависимости от конкретных условий;

  • Сборочные системы как таковые, которые во всех нетривиальных деталях начинают напоминать предковую сборочную систему.

Важно ли это?

Зачастую, пожалуй, нет. Но я думаю, что об этой проблеме стоит задумываться, в особенности при проектировании инструментов и систем:

  • Инструменты и системы, в которых проявляется такой паттерн, часто оставляют желать лучшего в области поддержки при диагностике или отладке. Пользователю приходится раз за разом гонять инструмент (то и дело с длительными задержками), по крупицам выуживая информацию. Представьте себе конфигурации CI/CD, где всё скопировано и вставлено, и отладку такого конвейера приходится делать «в стиле дампа». При этом работа идёт по сети через промежуточный уровень, опосредующий оркестрацию VM. Смешно же!

  • Инструменты, в которых проявляется такой паттерн, зачастую не располагают к ознакомлению с собой: найдутся считанные спецы, которые настолько хорошо разбираются в инструменте, что способны его сконфигурировать. Все остальные будут просто копировать, а их знаний хватит ровно на то, чтобы точечно поменять настройки. Иногда это неизбежно, но не всегда. Графы зависимостей по определению сложны, как и описываемые ими сборочные системы. Но что стоит выучить разницу между $< и $^ в Make?

  • Инструменты, в которых проявляется такой паттерн не располагают к безопасному использованию: для обеспечения безопасности обычно требуется глубоко понимать,  почему некоторое поведение устроено так, а не иначе. В системах, подверженных эффекту Makefile, также зачастую наблюдается спутанность между кодом и данными (или, в более общем случае, любая передача сигналов внутри полосы), в основном потому, что рабочие решения не всегда безопасны. Вспомните, например, об инъекции шаблона в GitHub Actions.

В целом я думаю, что в хорошо спроектированных инструментах (и системах) такой эффект должен минимизироваться. Наверное, это сложно обеспечить всегда, но вот о чём я задумываюсь при проектировании нового инструмента:

  • Должен ли он быть конфигурируемым?

  • Нужен ли ему собственный синтаксис?

  • Распространяется ли мой подход к работе с этим инструментом через копипаст? Если да, то насколько вероятно, что другие захотят повторить за мной?

Сложные инструменты — это необходимость и, можно даже сказать, неизбежность. Но, если эффект Makefile проявляется в простом приложении, это подсказывает, что данный инструмент переусложнён для решаемой им задачи. 

© Habrahabr.ru