Разработка

Преждевременная оптимизация: абсолютное зло или иногда полезная практика?

Преждевременная оптимизация: абсолютное зло или иногда полезная практика? главное изображение

«Преждевременная оптимизация — корень всех зол». Эту цитату приписывают Дональду Кнуту, автору книги «Искусство программирования» и концепции грамотного программирования.

У медали всегда есть обратная сторона. Рэндал Хайд в статье The Fallacy of premature optimization говорит, что в некоторых ситуациях оптимизация сначала рассматривается как преждевременная, поэтому разработчики от неё отказываются. Но в какой-то момент оптимизировать программу уже невозможно.

Чтобы разобраться, мы обратились к опытным программистам и попросили ответить на один вопрос: «Дональд Кнут называл преждевременную оптимизацию корнем всех зол. Но некоторые специалисты считают её полезной. А как вы относитесь к преждевременной оптимизации?»

Игорь Камышев, разработчик веб-приложений и техлид в «Самокате». Автор телеграм-канала kamyshev.code

Игорь Камышев


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

Всё очень просто. Пример: бизнесу нужна программа, которая считает доход банка от ипотеки с конкретного гражданина и показывает результат сотруднику, который даёт или не даёт гражданину кредит. Программист А написал программу за один день, и она тратит 30 секунд на расчёт. Это медленно, но разработка такой программы стоила один день — пусть 10 000 рублей. А программист Б написал программу за один месяц, и она тратит 1 секунду на расчет. Отличный результат. Только вот на ее разработку было потрачено в 30 раз больше денег. Нужно ли бизнесу это ускорение? Из условий этой задачи непонятно.

Оптимизировать программы по любому параметру стоит только после того, как станет понятно, нужна ли эта оптимизация. Преждевременная оптимизация — зло.

Программист Р., захотел ответить на вопрос анонимно

анонимный программист

Неважно, что думал Дональд Кнут, преждевременной оптимизации сейчас практически нет.

На этапе разработки главное — архитектура проекта. Но при этом она зачастую неоптимизированная. А поиск проблем ложится на плечи конечного пользователя. Это есть и в играх, и в Windows.

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

Денис Инешин. Frontend-developer at Booking.com. Разработчик open source JavaScript-библиотек и фронтендер с огромным стажем работы

Денис Инешин


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

Возможно, некоторые проекты, например, какой-то особенный банковский софт, могут даже выиграть от этого.

Но, в большинстве случаев, конечно же это лишнее. Цикл разработки обычно выглядит так:

  1. Идея => MVP => провал.

  2. Новая идея => MVP => снова провал.

  3. Ещё новая идея => MVP => наконец-то не совсем провал, можно работать.

И даже здесь, пока продукт не встанет на рельсы, преждевременная оптимизация может все испортить.

То есть верно, что пока вы оптимизируете, ваш конкурент занимает вашу рыночную нишу.

Но также верно и то, что если не оптимизировать, то рано или поздно проект погрязнет в техническом долге и перестанет развиваться.

Поэтому разумным решением будет постепенное увеличение технического кредита по мере роста проекта.

К., опытный программист, ответил на вопрос на условиях анонимности

анонимный программист


О, это вопрос не на одну кружку пива.

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

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

Итого: сначала задача с допустимой долей оптимальности с поправкой на исполнителя, потом оптимизация.

Антон Назаров, iOS разработчик, член программного комитета конференций AppsConf и Moscow Python

Антон Назаров


Для начала определимся с терминами. С «оптимизацией» все ясно. Это набор действий, направленных на улучшение характеристик системы: скорости ответа, потребления памяти. Стоимость таких оптимизаций исчисляются временем разработки. Это часы, которые инженер потратит на нетривиальные приемы улучшения. Часто такие изменения приводят к усложнению проекта: код становится сложнее, набор инструментов шире. Позже новым инженерам предстоит считаться с этим, погружаться в тонкие особенности, поддерживать их. На это тоже уйдет время. И это не страшно, если оптимизация реально помогла улучшить метрики.

Но как понять, что она преждевременная? Когда же наступает то самое время? На мой взгляд, когда настроен полный мониторинг проекта. Причём не только на каком-то узком участке, скажем, взаимодействия с базой данных, но на всех уровнях проекта. Метрики позволяют определить «узкое горлышко» системы и начать работать над ним. Оптимизации в других местах не будут иметь никакого смысла. Например, пустой тратой времени будет улучшать двигатель автомобиля, имеющего квадратные колеса. О проблеме узкого горлышка с подробными примерами писал Том ДеМарко в книге «Дедлайн».

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

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

Павел Франков. Последние 13 лет занимаюсь фронтендом. Работал в крупных компаниях, нанимал разработчиков, мотивировал команды и внедрял процессы. Мой телеграм-канал помогает фронтендерам составлять отличные резюме и проходить собеседования

Павел Франков


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

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

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

Кстати, на собеседовании не стоит упоминать, что вы любите всё делать «сразу правильно»: преждевременная оптимизация — маркер начинающего специалиста.

Никита Липский, работает в исследовательском центре Хуавей над JVM, компиляторами и новыми языками программирования. Также известен как ключевая фигура в проекте Excelsior JET — виртуальная машина Java со статическим (AOT) компилятором

Никита Липский


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

Грубо говоря, когда я вижу алгоритм сложности O(n2), когда он очевидно переписывается в O(nlog(n)), и кода от этого больше не становится, я всегда выбираю O(n*log(n)), даже если этот код не предполагается часто вызывать.

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

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

Олег Бартунов, Co-Founder and Chief Executive Officer в Postgres Professional

Олег Бартунов


Преждевременная оптимизация по-определению не нужна, иначе она называлась бы своевременной :-)

Егор Петров, iOS разработчик в Британском стартапе Agora. В мобильной разработке уже более трех лет, за это время довелось работать от дейтинг-сервисов до финтех проектов и фоторедакторов. Люблю покопаться в разных технологиях, изучить новые подходы к разработке и ведению продукта

Егор Петров


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

Преждевременная оптимизация — инструмент, позволяющий при определенных навыках избежать проблем на длинной дистанции. Например, команда может заплатить цену сначала за внедрение и обучение коллег новым подходам, а затем ускорить разработку в N раз. И чем ближе к старту внедряется сложный подход, тем больше шансов, что после набора скорости у команды уже будет сформированное решение, достаточно гармонично интегрированное в проект.

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

Василий Васильков, CTO Ecwid

Василий Васильков


Есть выражение: «Если ты ни разу не работал с legacy-кодом — ты ни разу не работал в успешном проекте». Фраза настолько жизненна, что хоть татуировку делай. Чтобы проект стал успешным, он для начала должен выйти на рынок, а чтобы выйти на рынок, надо делать конкретную работу прямо сейчас, а не решать туманные проблемы «на перспективу».

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

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

Лично у меня есть эмпирическое правило — я никогда не проектирую код/систему на нагрузку больше 10-20x от текущей. У нас в Ecwid куча сервисов и, предположим, один из них начал тупить при работе со 100 тыс. пользователями. Ok, значит новая архитектура этого модуля будет спроектирована из расчета 2-3 млн клиентов. Каждый раз когда я нарушал это правило, получался какой-то нежизнеспособный архитектурный уродец, который в результате либо выбрасывали, либо переписывали еще раз.

В комментария поделитесь пожалуйста мнением о преждевременной оптимизации.

Аватар пользователя Дмитрий Дементий
Дмитрий Дементий 23 декабря 2019