Где брать перф? 🙈
Я прошел много стадий развития отношения к производительности моего кода: начиная от мамкиного оптимизатора "знающего наизусть все хаки и трюки ускорения кода" и считающего, что любой код нужно писать настолько быстро, насколько это можно (спойлер, конечно же на деле было не так). Затем плавно переходя в "базированность" с идеальной структурой под задачу и алгоритмом. Ну а закончил все предсказуемым этапом "если проблем нет, то и нечего улучшать" и "преждевременная оптимизация - корень всех зол". Сейчас для меня кажется куда более важным вопрос архитектуры, поддержки, документации и тестов в конце концов.
Но с другой стороны, такое вот легкомысленное отношение может привести нас к недопустимой деградации производительности: в начале у нас все было в рамках допустимого, а затем со временем мы незаметно для себя "поднабрали" и бегать нам стало тяжело. Как раз с такой ситуаций сейчас и столкнулся на работе и усиленно сражаюсь с ней последние недели.
На самом деле ситуация очень типичная и в неё может попасть кто угодно. Думаю, вы сами не раз замечали, как изначально быстрое ПО со временем становится медленней и медленней, а в какой-то момент это начинает уже мешать. Измениться могут и ограничения к вашему ПО. Например, вы изначально разрабатывали приложение под мобильные устройства и все вроде было ок, а потом вам стало нужным портировать его под умный телевизор. И в новом окружение начинаются проблемы...
В общем к чему я все это веду. Прежде чем бежать что-то оптимизировать, нам надо сначала определиться с критерием нормальности. Например, вот ваше приложение 2-х летней давности и оно работает на одном и том же устройстве лучше, чем последняя версия. Причем настолько лучше, что это становиться заметно на "радарах": продуктовые метрики, UX пользователя и т.д. Значит, ваша задача сделать как минимум также, как и было.
А вот дальше мы уже вооружаемся профайлером, логами и пристальным взглядом. Процесс профилирования достаточно рутинная история. Мы раз за разом смотрим под лупой на сценарии работы приложения и сравнивая его с эталоном, а затем пытаясь понять, что же пошло не так. Хорошо, если причиной замедления является "дурацкий валенок", который лежит на поверхности. Но чаще бывает иначе: за время развития приложения реализовывались новые фичи, что-то рефакторилось. Короче говоря, писался код, который сам по себе достаточно безвредный, но скопившись за несколько лет разработки привел к значимым ухудшениям.
А бывает еще забавнее. Вот взять пример с работы: у нас раньше текла память, но текла по-тихому. Обычный пользователь мог начать испытывать проблемы, только если долго пользовался приложением. Затем мы это нашли и поправили, но оказалось, что это привело к появлению лонг-тасок на очистке. Пришлось прикрутить инкрементальную очистку.
Или другой пример. У нас был ряд здоровенных классов, которые было сложно поддерживать. Мы разбили их на подмодули, но это стало причиной просадки времени инициализации приложения. Пришлось прикручивать механизмы ленивости и мемоизации, чтобы поправить.
Повторюсь, с такими вот изменениями проблемы не видны сразу. Отдельно взятый рефакторинг может ухудшить на 1-2%. Вы не заметите этого на продуктовых метриках, как и не заметите при ручном тестировании. Как то это автоматизировать тоже достаточно сложно. Но мы сейчас пытаемся найти компромиссное решение.
Одним словом, засада. И судя по крупным релизам других продуктов проблема актуальна для всех.
Всем базы! 💪
Я прошел много стадий развития отношения к производительности моего кода: начиная от мамкиного оптимизатора "знающего наизусть все хаки и трюки ускорения кода" и считающего, что любой код нужно писать настолько быстро, насколько это можно (спойлер, конечно же на деле было не так). Затем плавно переходя в "базированность" с идеальной структурой под задачу и алгоритмом. Ну а закончил все предсказуемым этапом "если проблем нет, то и нечего улучшать" и "преждевременная оптимизация - корень всех зол". Сейчас для меня кажется куда более важным вопрос архитектуры, поддержки, документации и тестов в конце концов.
Но с другой стороны, такое вот легкомысленное отношение может привести нас к недопустимой деградации производительности: в начале у нас все было в рамках допустимого, а затем со временем мы незаметно для себя "поднабрали" и бегать нам стало тяжело. Как раз с такой ситуаций сейчас и столкнулся на работе и усиленно сражаюсь с ней последние недели.
На самом деле ситуация очень типичная и в неё может попасть кто угодно. Думаю, вы сами не раз замечали, как изначально быстрое ПО со временем становится медленней и медленней, а в какой-то момент это начинает уже мешать. Измениться могут и ограничения к вашему ПО. Например, вы изначально разрабатывали приложение под мобильные устройства и все вроде было ок, а потом вам стало нужным портировать его под умный телевизор. И в новом окружение начинаются проблемы...
В общем к чему я все это веду. Прежде чем бежать что-то оптимизировать, нам надо сначала определиться с критерием нормальности. Например, вот ваше приложение 2-х летней давности и оно работает на одном и том же устройстве лучше, чем последняя версия. Причем настолько лучше, что это становиться заметно на "радарах": продуктовые метрики, UX пользователя и т.д. Значит, ваша задача сделать как минимум также, как и было.
А вот дальше мы уже вооружаемся профайлером, логами и пристальным взглядом. Процесс профилирования достаточно рутинная история. Мы раз за разом смотрим под лупой на сценарии работы приложения и сравнивая его с эталоном, а затем пытаясь понять, что же пошло не так. Хорошо, если причиной замедления является "дурацкий валенок", который лежит на поверхности. Но чаще бывает иначе: за время развития приложения реализовывались новые фичи, что-то рефакторилось. Короче говоря, писался код, который сам по себе достаточно безвредный, но скопившись за несколько лет разработки привел к значимым ухудшениям.
А бывает еще забавнее. Вот взять пример с работы: у нас раньше текла память, но текла по-тихому. Обычный пользователь мог начать испытывать проблемы, только если долго пользовался приложением. Затем мы это нашли и поправили, но оказалось, что это привело к появлению лонг-тасок на очистке. Пришлось прикрутить инкрементальную очистку.
Или другой пример. У нас был ряд здоровенных классов, которые было сложно поддерживать. Мы разбили их на подмодули, но это стало причиной просадки времени инициализации приложения. Пришлось прикручивать механизмы ленивости и мемоизации, чтобы поправить.
Повторюсь, с такими вот изменениями проблемы не видны сразу. Отдельно взятый рефакторинг может ухудшить на 1-2%. Вы не заметите этого на продуктовых метриках, как и не заметите при ручном тестировании. Как то это автоматизировать тоже достаточно сложно. Но мы сейчас пытаемся найти компромиссное решение.
Одним словом, засада. И судя по крупным релизам других продуктов проблема актуальна для всех.
Всем базы! 💪