Харипрабу Сенгоден Кандасами, главный архитектор ICE/NISE, приводит на портале ITPro Today лучшие стратегии для снижения долга по производительности (performance debt) при разработке ПО, а также объясняет, когда их лучше применять для достижения максимальной эффективности.

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

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

Что такое долг по производительности?

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

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

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

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

Как уменьшить долг по производительности путем раннего тестирования

В области инженерии производительности существуют инструменты и фреймворки, которые могут помочь уменьшить долг по производительности. Лучшей стратегией является раннее и непрерывное тестирование. Интегрируйте инструменты тестирования производительности непосредственно в конвейер CI/CD. Почти все основные инструменты тестирования нагрузки (JMeter, LoadRunner, Gatling и т. д.) можно интегрировать в процесс CI/CD.

Для критически важных приложений тестирование производительности и бенчмаркинг следует выполнять как можно раньше, используя такие фреймворки, как JMH (Java Microbenchmark Harness) для Java и BenchmarkDotNet для приложений .NET. Чтобы обеспечить наилучший сценарий использования, это тестирование должно быть тщательно спланировано и выполнено. Успешное внедрение этих инструментов и фреймворков в конвейер CI/CD гарантирует, что тесты производительности будут запускаться автоматически при каждом внесении изменений, что позволит обнаруживать проблемы производительности на ранней стадии.

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

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

Дополнительные стратегии снижения долга по производительности

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

  • Планируйте заранее. Четко определите цели по производительности и убедитесь, что архитектура масштабируема и соответствует требуемым параметрам ресурсов. Кроме того, перед началом разработки сделайте акцент на выборе правильных технологий, структур данных и алгоритмов. Если в архитектуру внедряются новые технологии/фреймворки, убедитесь, что получены достоверные доказательства верности концепций для обеспечения достижения целей по производительности.
  • Сосредоточьтесь на качестве кода. Стремитесь писать чистый и эффективный код, используя правильные паттерны проектирования для решения задач, и введите регулярный процесс обзора кода. Создайте документ о лучших практиках с шаблонами производительности, которые следует использовать, и антипаттернами, которых следует избегать.
  • Рефакторинг кода. Периодически проводите рефакторинг кода, чтобы повысить его качество и эффективность и обеспечить возможность адаптации к новым требованиям. Кроме того, обновляйте технологический стек, чтобы использовать преимущества повышения производительности, заложенные в новых версиях.
  • Усердно мониторьте. Инвестируйте правильные инструменты наблюдаемости на критических этапах разработки. Определите ключевые показатели эффективности (KPI) и обеспечьте их мониторинг, сбор и отчетность. Любые аномалии должны быть исследованы и сразу же устранены.

Начинайте тестирование как можно раньше

В сфере разработки ПО процветает философия «создай сейчас, исправь потом», но в условиях современного технологически подкованного рынка она может быстро поставить компанию в невыгодное положение. То, что Уорд Каннингем однажды сказал о техническом долге, можно применить и к долгу по производительности: «Отправить первый вариант кода — все равно что влезть в долги. Небольшой долг ускоряет разработку, если он быстро возвращается с помощью переписывания. Опасность возникает, когда долг не возвращается. Каждая минута, потраченная на не совсем правильный код, считается процентами по этому долгу. Целые инженерные организации могут остановиться под тяжестью долгов».

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