[Перевод] Перевод. Срезаем углы: почему rails может убить ruby
Вашему вниманию предлагается перевод статьи Piotr Solnica, опытного ruby разработчика и одного из авторов популярного Ruby Object Mapper. Переводчик в целом разделяет позицию автора.
Сегодня я опять устал и чувствую себя бесполезным. И это далеко не первый раз, когда такие эмоции меня посещают. Обычно я “спускаю пар” в twitter, теряю немного фоловверов, успокаиваюсь и продолжаю работать.
Но сегодня я хочу пережечь свои негативные эмоции во что-нибудь конструктивное — и, возможно, полезное другим разработчикам. Обычно я плачусь в twitter по поводу каких-нибудь аспектов экосистемы ruby и особенно моей неспособности сформулировать простые ответы на вопросы rails разработчиков. В основном из-за нехватки времени и потому, что twitter — не лучшее место для долгих бесед.
Эта статья — попытка сформулировать что не так с monkey-patch в частности и подходом к rails разработке в целом, который, по моему мнению, может в длительной перспективе просто прибить ruby.
Вчера я заметил pull request в ActiveSupport, который добавляет Enumerable#pluck — и он был принят. Почему бы и нет? Это полезная функциональность — давайте ее добавим. Тем более, такой метод есть у ActiveRecord — посему бы не добавить его во все Enumerable. Удобно же!
Разработчики rails не замечают, что применяя monkey-patch они делают примерно вот так:
Есть задача. Зачем искать и использовать сложное решение если можно просто применить синюю изоленту и решить задачу сейчас. Самолет приземлился, так что автор этого замечательного способа ремонта может смело утверждать что синяя изолента — великолепное решение его конкретной задачи (на самом деле там конечно не синяя изолента, а немного другая штука. Изображение приведено исключительно в иллюстративных целях).
Это именно то что мы делаем, используя monkey-patch: срезаем углы и убеждаем себя что это хорошее решение.
Использование monkey-patch в Ruby настолько просто, что язык даже не дает возможности остановиться на секунду и подумать. Зачем я это делаю? Какую задачу я пытаюсь решить? Какой тип задач решает конкретно этот monkey-patch? Является ли эта задача частью большой задачи, которая может быть решена корректным, хорошо всем понятным способом? Или это какая-то локальная задача, связанная с логикой моего приложения и решение которой не должно покидать области видимости моего приложения?
Enumerable#pluck возвращает коллекцию, содержащую значения, выбранные из исходной коллекции по указанному ключу — хорошая, полезная штука. Проблема в том, что этот метод сам по себе не решает никакой практической задачи. Вместо того, чтобы решить конкретную задачу по трансформации данных и изолировать сложность, monkey-patch выносит часть сложности выше по коду, отчего эта сложность потом начинает по этому коду расползаться: разработчики начинают использовать pluck где надо и где не надо.
Что, если появилась необходимость сделать нечто более сложное, нежели pluck? Первое, о чем думает зараженный Rails разработчик — это monkey-patch. Такие разработчики критикуют мой подход к трансформации данных в Ruby, утверждая, что правильно сделанный monkey-patch приведет к более элегантному коду.
Единственный способ борьбы со сложностью в наших проектах — это изолировать локальные задачи и решать их простыми способами. Использование monkey-patch запутывает разработчика и увеличивает связность (cohesion) кода.
Не надо. Так. Делать.
Я рассматриваю такое использование monkey-patch как наносящее огромный вред нашей экосистеме. Множество разработчиков, включая новичков, полностью убеждены что именно так нужно решать практические задачи разработки в Ruby.
Безусловно, это способ решать задачи. Но хороший ли это способ? Сомневаюсь. Нет, не так. Я знаю что это плохой способ. И это одна из основных причин, почему множество ruby библиотек так плохо написаны: использование monkey-patch понижает требования к качеству интерфейсов взаимодействия. Если можно использовать monkey-patch — зачем мне разрабатывать интерфейс для расширения моей библиотеки?
Мы не можем продолжать разрабатывать системы поверх той горы monkey patches, которую из себя представляет Rails. Это уменьшает нашу уверенность во вносимых изменениях, добавляет сложность в наш код, учит разработчиков порочной практике патчить код в рантайме, затрудняет понимание какие задачи на самом деле решает код — список можно продолжать и продолжать, включая такие специфичные кейсы как конфликты интерфейсов, трудности с дебагом из-за чужих изменений нашего кода в рантайме и так далее.
На прошлой неделе разработчики потеряли кучу времени из-за Object#with_options в ActiveSupport (Два разработчика, если быть более точным. И они просили моей помощи, потому что не могли понять что происоходит). Я получил “море удовольствия” отлаживая странное поведение своего кода, только чтобы обнаружить Object#try в ActiveSupport, который подменял мой собственный метод try с совершенно другой семантикой. А как насчет вот такой кучки monkey-patch которые добавляют методы NilClass#to_param и TrueClass#to_param только потому, что Rails использует эти методы в url_helper? Все эти штуки “делали мой день” далеко не единожды, и каждый раз это был вопрос многих часов отладки. И поверьте, я не один такой.
В 2009 году Дядюшка Боб (Роберт Мартин) выступил на Rails Conf с докладом “То, что убило Smalltalk может убить и Ruby”. Резюмируя: “Сделать беспорядок было слишком легко” (it was too easy to make a mess).
А теперь задумайтесь об этом. Rails — это большая куча того самого беспорядка, гора monkey-patch, фреймворк для изменения Ruby под свои нужды. Как сказал мой друг, “Rails считает, что является основной частью toolchain”. Очень метко подмечено. Результат — поврежденная экосистема и поколение разработчиков, обученные повреждать ее все больше и больше.
Горькая ирония заключаетсяв том, что 99% Ruby разработчиков стали Ruby разработчиками из-за Rails (я, правда, не совсем понимаю как это связано с обсуждаемым вопросом). Что нам теперь делать? Восхищаться Rails, несмотря на то, что многие из нас благодаря этому фреймворку стали разработчиками и теперь видят его недостатки?
Rails может убить Ruby так как многие хорошие разработчики прекращают или уже прекратили использовать Ruby. Я знаю многих из них и глубоко сожалею о потерях в нашем сообществе. Кто-то сказал мне в twitter что “ничего страшного не случится, если сбегут несколько экспертов”. Но если в технологии есть настолько серьезные недостатки, что эксперты прекращают ей пользоваться — то, возможно, в консерватории что-то не так?