От мышления архитектора программного обеспечения к мышлению архитектора решений (и обратно)

От мышления архитектора программного обеспечения к мышлению архитектора решений (и обратно)

23 февраля 2023 г.

Нужная функция в нужном месте

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

  1. Вы отлично знаете программные библиотеки
  2. Вы плохо знаете компоненты инфраструктуры

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

Конкретный пример

Представьте себе приложение API. Он работает на JVM и написан в «реактивном» стиле с помощью фреймворка Spring Boot.

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

С моей шляпой архитектора программного обеспечения я буду искать библиотеку JVM, которая делает это. Поскольку у меня есть небольшой опыт, я знаю отличную библиотеку Bucket4J:

<цитата>

Java-библиотека ограничения скорости на основе алгоритма token-bucket

Bucket4J

Это всего лишь вопрос интеграции библиотеки в мой код:

val beans = beans {
    bean {
        val props = ref<BucketProperties>()                  (1)
        BucketFactory().create(                              (2)
            props.size,
            props.refresh.tokens,
            props.refresh.duration
        )
    }
    bean {
        coRouter {
            val handler = HelloHandler(ref())                (3)
            GET("/hello") { handler.hello(it) }
            GET("/hello/{who}") { handler.helloWho(it) }
        }
    }
}

class HelloHandler(private val bucket: Bucket) {             (3)

    private suspend fun rateLimit(                           (4)
        req: ServerRequest,
        f: suspend (ServerRequest) -> ServerResponse
    ) = if (bucket.tryConsume(1))
            f.invoke(req)
        else
            ServerResponse.status(429).buildAndAwait()

    suspend fun hello(req: ServerRequest) = rateLimit(req) { (5)
        ServerResponse.ok().bodyValueAndAwait("Hello World!")
    }
}

  1. Получить свойства конфигурации из класса с аннотацией @ConfigurationProperties
  2. Создайте правильно настроенный сегмент.
  3. Передать ведро обработчику
  4. Создайте многократно используемую оболочку ограничения скорости на основе сегмента.
  5. Перенести вызов

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

  1. Включите Spring Security для аутентификации пользователей (или напишите собственный механизм аутентификации)
  2. Создайте сегмент для каждого пользователя
  3. Сохраните корзину на стороне сервера и привяжите ее к сеансу пользователя.

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

Золотой кейс для шлюзов API

<цитата>

Всему свое место, все на своем месте.

Эта цитата связана с Сэмюэлем Смайлсом, миссис Изабеллой Битон и Бенджамином Франклином.

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

Вот как это сделать с помощью Apache APISIX.

consumers:
  - username: joe
    plugins:
      key-auth:                               (1)
        key: joe
  - username: jane
    plugins:
      key-auth:                               (1)
        key: jane
routes:
  - uri: /hello*
    upstream:
      type: roundrobin
      nodes:
        "resilient-boot:8080": 1
    plugins:
      limit-req:                              (2)
        rate: 1
        burst: 0
        key: consumer_name                    (3)
        rejected_code: 429
      key-auth: ~                             (1)
  1. Мы используем простой HTTP-заголовок для аутентификации в демонстрационных целях. В реальных приложениях будет использоваться OAuth2.0 или OpenID Connect, но принцип тот же.
  2. Плагин ограничения скорости
  3. Настройте сегмент для каждого потребителя

Обсуждение: что где?

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

<цитата>

Основной тезис книги — дихотомия двух способов мышления: «Система 1» — быстрая, инстинктивная и эмоциональная; «Система 2» медленнее, более продуманна и логична.

Кроме того, Система 2 потребляет гораздо больше энергии. Поскольку мы ленивы, мы предпочитаем Систему 1 — быструю и инстинктивную. Следовательно, как архитекторы, мы обычно отдаем предпочтение следующему:

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

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

Во-первых, вам нужно классифицировать, является ли функция чисто технической. Например, классическое ограничение скорости для предотвращения DDoS носит чисто технический характер. Такие технические особенности принадлежат инфраструктуре: каждый достойный обратный прокси-сервер имеет такое ограничение скорости.

Чем больше функция связана с бизнесом, тем ближе она должна быть к приложению. Наш вариант использования немного связан с бизнесом, потому что ограничение скорости для каждого пользователя. Тем не менее шлюз API предоставляет эту функцию по умолчанию.

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

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

Также нужно подумать о конфигурации. Если вам нужно настроить каждый компонент библиотеки для каждого экземпляра, это огромный красный флаг; предпочитаю инфраструктурный компонент. Некоторые библиотеки предлагают решение для централизованной настройки, например,, Spring Cloud Config. Тщательно оцените дополнительную сложность такого компонента и частоту его отказов по сравнению с другими выделенными компонентами инфраструктуры.

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

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

Заключение

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

Дальше:


Полный исходный код для этого сообщения можно найти на GitHub. Первоначально опубликовано на сайте A Java Geek 19 февраля 2023 г.

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


Оригинал
PREVIOUS ARTICLE
NEXT ARTICLE