0 added
0 removed
Original
2026-01-01
Modified
2026-02-26
1
<p><em>Это перевод статьи Sandi Metz<a>The Wrong Abstraction</a>.</em></p>
1
<p><em>Это перевод статьи Sandi Metz<a>The Wrong Abstraction</a>.</em></p>
2
<p>Я размышляю о последствиях "неправильной абстракции". Мой доклад с RailsConf 2014 "<a>all the little things</a>" включал раздел, в котором я<a>высказала такое мнение</a>:</p>
2
<p>Я размышляю о последствиях "неправильной абстракции". Мой доклад с RailsConf 2014 "<a>all the little things</a>" включал раздел, в котором я<a>высказала такое мнение</a>:</p>
3
<blockquote><p><em>дублирование значительно дешевле, чем неправильная абстракция</em></p>
3
<blockquote><p><em>дублирование значительно дешевле, чем неправильная абстракция</em></p>
4
</blockquote><p>А заключение я<a>подытожила советом</a>:</p>
4
</blockquote><p>А заключение я<a>подытожила советом</a>:</p>
5
<blockquote><p><em>выбирайте дублирование вместо неправильной абстракции</em></p>
5
<blockquote><p><em>выбирайте дублирование вместо неправильной абстракции</em></p>
6
</blockquote><p>Эта небольшая часть довольно длинного доклада спровоцировала удивительно сильную реакцию. Несколько человек предположили, что я сошла с ума, но большинство выразило свои чувства примерно так:</p>
6
</blockquote><p>Эта небольшая часть довольно длинного доклада спровоцировала удивительно сильную реакцию. Несколько человек предположили, что я сошла с ума, но большинство выразило свои чувства примерно так:</p>
7
<blockquote><p>This, a million times this! “@BonzoESC: “Duplication is far cheaper than the wrong abstraction”<a>https://twitter.com/pims/status/442010383725760512</a></p>
7
<blockquote><p>This, a million times this! “@BonzoESC: “Duplication is far cheaper than the wrong abstraction”<a>https://twitter.com/pims/status/442010383725760512</a></p>
8
</blockquote><p>Сила эмоций заставила меня понять, насколько широко распространена и неразрешима проблема "неправильной абстракции". Я начала задавать вопросы и пришла к следующему шаблону:</p>
8
</blockquote><p>Сила эмоций заставила меня понять, насколько широко распространена и неразрешима проблема "неправильной абстракции". Я начала задавать вопросы и пришла к следующему шаблону:</p>
9
<ol><li><p>Программист A натыкается на дублирование.</p>
9
<ol><li><p>Программист A натыкается на дублирование.</p>
10
</li>
10
</li>
11
<li><p>Программист A извлекает дублирование и как-то его называет.</p>
11
<li><p>Программист A извлекает дублирование и как-то его называет.</p>
12
<p><em>Это создает новую абстракцию. Что-то вроде нового метода или, возможно, даже нового класса.</em></p>
12
<p><em>Это создает новую абстракцию. Что-то вроде нового метода или, возможно, даже нового класса.</em></p>
13
</li>
13
</li>
14
<li><p>Программист А заменяет дублирование новой абстракцией.</p>
14
<li><p>Программист А заменяет дублирование новой абстракцией.</p>
15
<p>Ах, код совершенен. Программист А довольно сваливает.</p>
15
<p>Ах, код совершенен. Программист А довольно сваливает.</p>
16
</li>
16
</li>
17
<li><p>Проходит время.</p>
17
<li><p>Проходит время.</p>
18
</li>
18
</li>
19
<li><p>Появляется новое требование, для которого текущая абстракция почти идеальна.</p>
19
<li><p>Появляется новое требование, для которого текущая абстракция почти идеальна.</p>
20
</li>
20
</li>
21
<li><p>Программисту B поручают реализовать это требование.</p>
21
<li><p>Программисту B поручают реализовать это требование.</p>
22
<p>Программист B чувствует почётное обязательство сохранить существующую абстракцию, но поскольку для каждого случая она - не совсем то же самое, чтобы принять параметр, код меняют, а затем добавляют логику, чтобы сделать всё правильно в соответствии с условными конструкциями и основываясь на значении этого параметра.</p>
22
<p>Программист B чувствует почётное обязательство сохранить существующую абстракцию, но поскольку для каждого случая она - не совсем то же самое, чтобы принять параметр, код меняют, а затем добавляют логику, чтобы сделать всё правильно в соответствии с условными конструкциями и основываясь на значении этого параметра.</p>
23
<p>То, что когда-то было универсальной абстракцией, теперь ведёт себя по-разному в разных случаях.</p>
23
<p>То, что когда-то было универсальной абстракцией, теперь ведёт себя по-разному в разных случаях.</p>
24
</li>
24
</li>
25
<li><p>Появляется ещё одно новое требование.</p>
25
<li><p>Появляется ещё одно новое требование.</p>
26
<p>Программист X. Ещё один дополнительный параметр. Ещё одна условная конструкция. Зацикливание до момента, пока код не станет слишком сложным для понимания.</p>
26
<p>Программист X. Ещё один дополнительный параметр. Ещё одна условная конструкция. Зацикливание до момента, пока код не станет слишком сложным для понимания.</p>
27
</li>
27
</li>
28
<li><p>Тут в истории появляетесь вы, и ваша жизнь резко делает драматический поворот в худшую сторону.</p>
28
<li><p>Тут в истории появляетесь вы, и ваша жизнь резко делает драматический поворот в худшую сторону.</p>
29
</li>
29
</li>
30
</ol><p>Существующий код оказывает сильное влияние. Само его наличие доказывает, что он правильный и необходимый. Мы знаем, что код - это приложенные усилия, и сильно мотивированы сохранить ценность этих усилий. К сожалению, печальная правда в том, что чем сложнее и непостижимей код, т. е. чем массивней вклад в его создание, тем больше мы чувствуем давление сохранять его ("<a>ложные выводы о необратимых затратах</a>"). Как будто наше бессознательное говорит нам: "Боже, тут всё так запутано - наверно, потребовалась вечность, чтобы сделать всё как надо. Конечно, это действительно очень, очень важно. Грех, если все эти усилия пропадут впустую."</p>
30
</ol><p>Существующий код оказывает сильное влияние. Само его наличие доказывает, что он правильный и необходимый. Мы знаем, что код - это приложенные усилия, и сильно мотивированы сохранить ценность этих усилий. К сожалению, печальная правда в том, что чем сложнее и непостижимей код, т. е. чем массивней вклад в его создание, тем больше мы чувствуем давление сохранять его ("<a>ложные выводы о необратимых затратах</a>"). Как будто наше бессознательное говорит нам: "Боже, тут всё так запутано - наверно, потребовалась вечность, чтобы сделать всё как надо. Конечно, это действительно очень, очень важно. Грех, если все эти усилия пропадут впустую."</p>
31
<p>Когда в этой истории появляетесь вы, как в пункте 8, давление может заставить вас продолжать, то есть реализовать новое требование, изменяя существующий код. Но это будет жестоко, скорее всего... Код больше - не единая общая абстракция, а нагруженная условиями процедура, которая чередует ряд неясно связанных идей. Его трудно понимать и легко сломать.</p>
31
<p>Когда в этой истории появляетесь вы, как в пункте 8, давление может заставить вас продолжать, то есть реализовать новое требование, изменяя существующий код. Но это будет жестоко, скорее всего... Код больше - не единая общая абстракция, а нагруженная условиями процедура, которая чередует ряд неясно связанных идей. Его трудно понимать и легко сломать.</p>
32
<p>Если вы окажетесь в такой ситуации, избегайте влияния необратимых затрат. Когда вы сталкиваетесь с неправильной абстракцией,<em>самый быстрый способ продвинуться дальше - вернуться</em>. Действуйте в такой последовательности:</p>
32
<p>Если вы окажетесь в такой ситуации, избегайте влияния необратимых затрат. Когда вы сталкиваетесь с неправильной абстракцией,<em>самый быстрый способ продвинуться дальше - вернуться</em>. Действуйте в такой последовательности:</p>
33
<ol><li>Восстановите дублирование, вернув абстрагированный код туда, где происходит вызов.</li>
33
<ol><li>Восстановите дублирование, вернув абстрагированный код туда, где происходит вызов.</li>
34
<li>Внутри каждого вызова, используйте передаваемые параметры, чтобы определить подмножество объединённого кода, который этот конкретный вызов исполняет.</li>
34
<li>Внутри каждого вызова, используйте передаваемые параметры, чтобы определить подмножество объединённого кода, который этот конкретный вызов исполняет.</li>
35
<li>Удалите части, которые не нужны для данного вызова.</li>
35
<li>Удалите части, которые не нужны для данного вызова.</li>
36
</ol><p>Это устранит и абстракцию,<em>и</em>условные конструкции, а также сократит каждый вызов и оставит в нём только необходимый код. Когда вы перематываете решения таким способом, обычно обнаруживается, что, хоть каждый вызов, вроде как и обращался к общей абстракции, выполняемый ими код, был довольно уникальным. Как только вы полностью удалите старую абстракцию, вы можете начать заново, повторно изолировать дублирование и повторно извлечь абстракции.</p>
36
</ol><p>Это устранит и абстракцию,<em>и</em>условные конструкции, а также сократит каждый вызов и оставит в нём только необходимый код. Когда вы перематываете решения таким способом, обычно обнаруживается, что, хоть каждый вызов, вроде как и обращался к общей абстракции, выполняемый ими код, был довольно уникальным. Как только вы полностью удалите старую абстракцию, вы можете начать заново, повторно изолировать дублирование и повторно извлечь абстракции.</p>
37
<p>Мне встречались случаи, когда люди пытались уверенно продолжать работать с неправильной абстракцией, но у них это слабо получалось. Добавление новых фич было невероятно сложным, а каждый положительный результат ещё больше усложнял код, что делало добавление следующей фичи ещё сложнее. Когда они поменяли свою точку зрения с "мне нужно сохранить своё вложение в этот код" на "этот код имел смысл какое-то время, но, мы, возможно, извлекли из него максимум пользы", и позволили себе переосмыслить свои абстракции, с точки зрения текущих требований, всё упростилось. После того, как они объединили код, стало очевидно куда двигаться дальше, а добавление новых фич стало быстрее и проще.</p>
37
<p>Мне встречались случаи, когда люди пытались уверенно продолжать работать с неправильной абстракцией, но у них это слабо получалось. Добавление новых фич было невероятно сложным, а каждый положительный результат ещё больше усложнял код, что делало добавление следующей фичи ещё сложнее. Когда они поменяли свою точку зрения с "мне нужно сохранить своё вложение в этот код" на "этот код имел смысл какое-то время, но, мы, возможно, извлекли из него максимум пользы", и позволили себе переосмыслить свои абстракции, с точки зрения текущих требований, всё упростилось. После того, как они объединили код, стало очевидно куда двигаться дальше, а добавление новых фич стало быстрее и проще.</p>
38
<p>Мораль этой истории? Не попадайте в ловушку ложных выводов о необратимых затратах. Если вы заметите, что передаёте параметры и добавляете условные пути через общий код, абстракция неверна. Возможно, было правильно с этого начинать, но тот день прошёл. Как только ошибочность абстракции доказана, лучшая стратегия - восстановить дублирование и оно покажет, что правильно. Хоть иногда и имеет смысл сохранить несколько условных конструкций, чтобы получить представление о том, что происходит, чем раньше вы откажетесь от неправильной абстракции, тем меньше вы пострадаете.</p>
38
<p>Мораль этой истории? Не попадайте в ловушку ложных выводов о необратимых затратах. Если вы заметите, что передаёте параметры и добавляете условные пути через общий код, абстракция неверна. Возможно, было правильно с этого начинать, но тот день прошёл. Как только ошибочность абстракции доказана, лучшая стратегия - восстановить дублирование и оно покажет, что правильно. Хоть иногда и имеет смысл сохранить несколько условных конструкций, чтобы получить представление о том, что происходит, чем раньше вы откажетесь от неправильной абстракции, тем меньше вы пострадаете.</p>
39
<p>Когда абстракция ошибочна, самый быстрый шаг вперёд - это возврат. Это не значит, что вы сдаётесь, это движение в сторону улучшения. Поступайте так. Вы сделаете лучше свою жизнь и жизнь всех, кто будет следовать вашему опыту.</p>
39
<p>Когда абстракция ошибочна, самый быстрый шаг вперёд - это возврат. Это не значит, что вы сдаётесь, это движение в сторону улучшения. Поступайте так. Вы сделаете лучше свою жизнь и жизнь всех, кто будет следовать вашему опыту.</p>