diff --git a/case-study.md b/case-study.md new file mode 100755 index 0000000..c7b1ae1 --- /dev/null +++ b/case-study.md @@ -0,0 +1,126 @@ +# Задание № 8 + +### Общая информация о проекте + +Приветствую! + +Я не работаю программистом и у меня нет опыта ни в одном коммерческом проекте, вместо этого я занимаюсь своим, как это модно сейчас говорить, стартапом. +Это будет развивающая онлайн-платформа по теме культуры, истории. +Логика работы простейшая - пользователи выбирают определенный курс, смотрят скринкасты к урокам, потом проходят тесты по данным урокам. +Также будет присутствовать геймификация, например при прохождении тестов будут предложены подсказки ("Право на ошибку", "50/50" и т.д.), а также система набора опыта пользователями. +Мое приложение достаточно тяжеловесное, там много видео и фотографий. Используются сервисы Google maps, Cloudinary, Vimeo. +Web-сервер NGINX, сервер приложения Passenger. + +Начал я его делать с января 2021 г, а сейчас ноябрь 2021, соответственно почти уже год. +Работал над проектом почти каждый день как минимум 2-4 часа (в выходные больше). +Опытный программист конечно уже бы давно закончил его, но в моем случае он сделан на 80 %. +Осталось реализовать оплату курсов (пока не знаю как, но разберусь), авторизацию через соц. сети и систему опыта игрока. + +### Используемые инструменты в оптимизации + +В своей оптимизации я использовал следующие инструменты: + * New Relic + * Pghero + * Rack Mini Profiler + * Lighhouse + +Я не смог использовать WebPageTest и SiteSpeed.io, потому что у меня есть аутентификация и главная страница закрыта ею, соответственно они тестировали страницу логин-пароля. + +### Определение главной точки роста + +Конечно все что я изучил на этом курсе по оптимизации мне пригодилось в своем проекте! +Если бы я был на том состязании на Хакатоне Google по оптимизации, мой проект бы точно боролся за призовое место, потому что разница между тем что было ДО и стало ПОСЛЕ, просто ОГРОМНАЯ! + +Итак, тестировал проект с таким количеством данных. + +Users: 16 +Courses: 8 +Topics: 8 +Lessons: 16 +Tests: 16 +Questions: 128 +Answers: 256 + +Получается в одном Курсе 8 Тем, в каждой теме по 16 Уроков с Тестами к эти урокам, в каждом Тесте по 8 Вопросов и в каждом Вопросе по 2 Ответа. + +New Relic определил, что главной точкой роста является главная страница courses#index, а именно паршал `'_course.html.erb'` + +### Формирование бюджета +Главная страница courses#index изначально загружается за 10_000 ms. +Хочу чтобы она загружалась за 1000 ms + +` +courses#index +10790ms (Views: 5486.2ms | ActiveRecord: 3936.1ms | Allocations: 2632450) + GET http://localhost:3000/ 129.7 +0.0 11 sql 25.2 + Executing action: index 380.3 +124.0 14 sql 17.5 + Rendering: courses/_marker_course.html.slim 527.7 +256.3 + Rendering: courses/_marker_course.html.slim 2.1 +783.9 + Rendering: courses/_marker_course.html.slim 2.3 +786.7 + Rendering: courses/_marker_course.html.slim 2.3 +789.7 + Rendering: courses/_marker_course.html.slim 7.1 +792.9 + Rendering: courses/_marker_course.html.slim 21.8 +800.2 + Rendering: courses/index.html.erb 8826.7 +855.3 1664 sql 649.1 + Rendering: shared/_flash.html.slim 3.3 +9893.7 + Rendering: shared/_footer.html.slim 16.9 +9897.1 +` + +### Итерация 1 + + * С помощью Bullet убрал ненужные запросы + * С помощью Pghero удалил 5 неиспоьзуемых индексов + * Пересмотрел ассоциации полиморфной модели Photo (она была связана и с Course и с Topic и с Lesson). Оставил ее только у Lesson, а у Course и Topic Сделал атрибуты image с помощью active_storage (has_many_attached) + * На главной странице изменил вызов partial, добавив туда атрибут collection + * Добавил кэширование Курсов на главной + * Где нужно, изменил .count на load.size + +После данной итерации загрузка страницы стала в 2 раза быстрее + +` +5298ms (Views: 2556.5ms | ActiveRecord: 2071.6ms | Allocations: 1870971) + GET http://localhost:3000/courses 100.1 +0.0 11 sql 12.5 + Executing action: index 414.4 +95.0 20 sql 31.4 + Rendering: courses/_marker_course.html.slim 513.9 +302.1 + Rendering: courses/index.html.erb 4343.7 +827.3 888 sql 381.3 + Rendering: shared/_flash.html.slim 3.1 +5373.9 + Rendering: shared/_footer.html.slim 15.4 +5377.6 +` + +### Итерация 2 + +Я понял в чем основная проблема: у каждой панельки с курсом был прогресс бар и прогресс этот высчитывался отдельным методом, каждый раз для каждого курса сервер лез в БД. +Я поразмыслил и сделал отдельное поле для всех этих вычислений и значение сохранял в него после завершения теста. + +Также убрал ненужную информацию о количестве уроков у курса. + +После данной итерации загрузка страницы умениьшилась почти в 5 раз + +`` +1223ms (Views: 822.6ms | ActiveRecord: 121.3ms | Allocations: 862606) + GET http://localhost:3000/courses 101.0 +0.0 11 sql 13.0 + Executing action: index 447.9 +95.0 20 sql 40.7 + Rendering: courses/_marker_course.html.slim 22.6 +331.4 + Rendering: courses/_marker_course.html.slim 482.2 +353.8 + Rendering: courses/index.html.erb 198.7 +847.3 17 sql 17.9 + Rendering: shared/_flash.html.slim 8.8 +1250.2 + Rendering: shared/_footer.html.slim 57.1 +1260.9 +`` + +### Итерация 3 + +Также у каждого курса в информации был его статус. +Высчитывался он опять же отдельным методом в модели, где каждый раз когда его дергали, сервер лез в БД для того чтобы узнать прошел ли данный курс пользователь или какой у него прогресс. +Я решил результат этой логики запихнуть в поле модели User. Назвал я его progress_course... + +` +860ms (Views: 686.1ms | ActiveRecord: 40.5ms | Allocations: 647574) + GET http://localhost:3000/courses 135.4 +0.0 11 sql 10.3 + Executing action: index 446.7 +133.0 17 sql 17.3 + Rendering: courses/index.html.erb 388.5 +310.5 + Rendering: shared/_footer.html.slim 25.1 +966.9 +` + +В итоге получилось сократить время запроса больше чем в 10 раз! + +На проде удалось уменьшить время ответа с 100 ms до 25-30ms, т.е. около 3 раз +