Когда DRY не работает, попробуйте WET

2
410
views

Перевод статьи «When DRY Doesn’t Work, Go WET».

От редакции Techrocks. Мы выбрали эту статью для перевода, потому что затронутая тема достаточно интересна, в оригинале она привлекла внимание многих людей. Вместе с тем в разделе комментариев разгорелась жаркая дискуссия относительно советов из статьи. Мы хотели дать возможность русскоязычным читателям ознакомиться с точкой зрения автора статьи. Если вы опытный программист и у вас есть, что сказать по теме, — приглашаем поделиться в комментариях.

Примечание переводчика. В названии присутствует игра слов. Принцип DRY расшифровывается как «Don’t repeat yourself» и переводится как «не повторяйся». При этом само слово «dry» переводится как «сухой». Принципу DRY противопоставляется WET (расшифровка будет в статье). Само слово «wet» переводится как «мокрый». В общем, название можно перевести как «Если сухость не работает — намочите».


Я и сам совершал подобные ошибки, и многократно замечал их у других. Когда вы впервые читаете про принцип DRY, вы, скорее всего, понимаете его превратно.

В вашей голове складывается примерно такая картина:

Википедия: DRY предполагает, что вы не повторяете один и тот же код дважды.
Вы: Хмм, окей, я заменю все свои дубликаты абстракциями.

Это кажется удачным решением, но на самом деле им не является. Ваша абстракция зачастую ошибочна, и вот почему:

  1. Вы видите дублирование.
  2. Вычленяете дублирование в новую абстракцию (метод, класс).
  3. Заменяете дубликат новой абстракцией.
  4. Думаете, что ваш код идеален.
  5. Проходит время.
  6. У менеджера продукта появляются новые требования. Ваша абстракция практически полностью подходит для них.
  7. Вы начинаете реализовывать новые требования.
  8. Но есть одно маленькое «но»: ваша абстракция подходит практически полностью, но не абсолютно. Почему? Только 95% вашего кода, выделенного в абстракцию, соответствуют новым требованиям. И вместо того чтобы создать новую абстракцию из скопированных 95% кода уже существующей, вы решаете изменить код имеющейся у вас абстракции. Например, добавляете блоки if...else и передаете параметр, чтобы ваша абстракция могла осуществлять разные действия для разных решений.
  9. Теперь ваша абстракция в разных случаях ведет себя по-разному.
  10. Поступает еще одно новое требование. Еще один дополнительный параметр. Еще одно условие. (Цикл повторяется, пока код не становится слишком сложным для чтения и поддержки).
  11. Поздравляю, вы создали неверную абстракцию.

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

Это бесконечный цикл.

Что же делать?

Пишите все дважды.

Photo by Oliver Hihn on Unsplash

WET

Концепция WET (англ. Write Everything Twice — «Пиши все дважды», или «We enjoy typing» — «Нам нравится печатать») является противоположностью DRY. Когда вы приступаете к созданию новой системы, вы не знаете, какими будут будущие требования. Поэтому не спешите с абстракциями.

Не забывайте: дублирование кода намного дешевле, чем плохая абстракция.

Допустим, вы создаете веб-приложение и на данный момент у вас нет на руках дизайна всех его страниц. Но в том, что вы уже видите, много кнопок, и на каждой странице они весьма похожи. Вы решаете выделить их в компонент под именем Button и использовать на каждой странице. Пока все логично.

И тут поступает дизайн еще одной страницы. Вы просматриваете его и обнаруживаете внизу страницы необычную, причудливую кнопку.

Эта кнопка вроде бы выглядит так же, как и остальные, но имеет «изюминку». Для реализации этой изюминки вам нужно переписать 10% вашего компонента Button, а также добавить условия и новые параметры.

Вы стоите перед дилеммой:

  1. Изменить Button, переписав 10% абстрагированного кода (добавить логические условия для поддержки логики новой кнопки).
  2. Создать две абстракции, скопировав 90% кода из Button в FancyButton.

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

Но горькая правда в том, что таки создадите (если вы, конечно, не опытный программист, который точно знает, что и зачем он делает).

Скопируйте этот код. Не бойтесь.

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

Если уже слишком поздно

Допустим, вы поняли, что уже слишком поздно что-то делать с неверной абстракцией. В таком случае лучше всего будет вернуться назад.

Сделайте следующее:

  1. Верните назад абстрагированный код.
  2. Удалите неиспользуемый параметр, который передавали в абстракцию для осуществления разных действий в разных сценариях.
  3. Удалите неиспользуемую логику.

Таким образом вы удалите абстракцию и условия для каждого вызова.

Напоследок…

Если вы понимаете, что передаете параметры и вставляете дополнительные условия в общий код, ваша абстракция ошибочна.

Дублирование кода лучше ошибочной абстракции, так что лучше продублировать.

2 КОММЕНТАРИИ

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

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

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

ОСТАВЬТЕ ОТВЕТ

Please enter your comment!
Please enter your name here