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

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

Я создал репозиторий GitHub, чтобы вы могли получить доступ к коду, проанализировать его и понять, насколько он прост.

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

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

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

Я спрятал реализации метода для чистого чтения.

Внутри каждого метода я устанавливаю таймер со случайным интервалом от 100 до 1000 мс для имитации внешних подключений к другим сервисам, базам данных и т. д.

Итак, вы можете видеть здесь, что существует множество операторов if для проверки того, является ли appId мобильным устройством или веб-устройством, чтобы выполнить определенные проверки для каждого из них. Немного изменив порядок операторов if или даже расположение, я смог бы немного сократить время отклика, но это не то, что нам нужно; мы хотим производительности!

Итак, что, если бы мы могли выполнять только необходимую проверку для каждого appId, не блокируя наш eventLoop? Звучит интересно, правда? Давайте посмотрим, как мы можем добиться этого, используя Шаблон стратегии.

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

Здесь я определил свойство promises для хранения исполняемых обещаний (извините за опечатку в коде) и свойства промежуточного программного обеспечения, которые содержат каждую функцию проверки (эти методы в предыдущем подходе; следующее изображение покажет это), которые я назвал промежуточным программным обеспечением для не причина. Мой метод run выполнит каждое промежуточное ПО и поместит его неразрешенное значение в свойство обещания, а затем вернет материнский promise.all, ожидая завершения всех этих обещаний.

После этого я реализовал конкретные классы WebStrategy и MobileStrategy.

И теперь в моем классе AuditLoginIntent я реорганизую код, чтобы выбрать стратегию на основе значения appId из входных данных запроса и выполнить метод запуска стратегии.

Чтобы помочь мне проверить время отклика этих двух подходов, я создал файл run.sh для запуска curl в службе с полезной нагрузкой. Как вы можете видеть ниже, разница безумна. Мы не затрагиваем бизнес-логику какой-либо функции проверки; мы просто меняем блокирующий поток на неблокирующий. В этом сила цикла событий Node.js.

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

Использованная литература:

Репо: https://github.com/tenlisboa/decrease-response-time-strategy

Подробнее о стратегии: https://refactoring.guru/design-patterns/strategy