Злоупотребление повторным использованием кода: Размышления о микросервисах


Отказ от ответственности

Этот пост — скорее мои личные размышления, в которых я попытался представить пример того, что может пойти не так при разработке микросервисов. Моя цель — не просто поделиться своими мыслями, но и попытаться принять другие мнения, которые могут отличаться от того, что я собираюсь изложить здесь, как часть моего процесса обучения. Итак, прежде всего, большое спасибо, что прочитали мой пост и оставили свои комментарии (если таковые имеются) 🙂 🙂 .

Вступление

Как часть того, что мы изучали в университете или даже для людей, которые начинают изучать разработку программного обеспечения, нас учили повторному использованию кода, и это одна из причин, по которой мы создаем функцию. Не только это, такие термины как «не изобретайте колесо» или принцип DRY говорят нам об этом. Но вопрос в том, являются ли они абсолютной вещью? Я считаю, что все должно быть в контексте.

Проблема

Вот один из примеров, которым я хотел бы поделиться, и который «на мой взгляд» не следует применять повторно.

Рассмотрим следующую ситуацию, когда сервис A вызывает сервис B, а сервис B вызывает сервис C, как описано на диаграмме ниже:

Проблема возникает, если модель ответа, перечисление, объект или DTO из C «повторно используется» в B, а затем передается в A — см. фрагмент ниже:

interface ResponseC {
    prop1: string
    prop2: string
}

const endpointC: Promise<ResponseC> = async() => {
  ...

  return { prop1, prop2 }
}
Вход в полноэкранный режим Выход из полноэкранного режима
import { ResponseC } from 'path-to-c-or-common'

const endpointB: Promise<ResponseC> = async () => {
  ...
  const { prop1, prop2 } = await serviceC.endpointC()

  return { prop1, prop2 }
}

Войти в полноэкранный режим Выход из полноэкранного режима
import { ResponseC } from 'path-to-c-or-common'

const endpointA: Promise<Omit<ResponseC, "prop2">> = () => {
  ...
  const { prop1, prop2 } = await serviceB.endpointB()

  return { prop1 }
}
Войти в полноэкранный режим Выход из полноэкранного режима

Так в чем же проблема?

Приведенный выше случай повторного использования противоречит самой идее микросервиса.

Одна из основных идей микросервисов — разделение ответственности / свободное соединение (вы можете сами прочитать об этом на странице https://microservices.io).

Аргумент №1

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

НО наличие этой «дополнительной» работы делает нашу систему «развязанной» и даст нам больше гибкости в будущем (и скорости в будущем, если можно так выразиться).

Подумайте, когда требуется изменить форму общей модели на сервисе C, это повлияет не только на сервис B, но и на сервис A. Изменения внезапно становятся трудными, потому что существует множество неправильных зависимостей, и сложность выполнения изменений будет возрастать тем больше, чем больше сервисов используют один и тот же общий объект. Я использую слово «ненужные зависимости» для обозначения любого сервиса «второго уровня».

Модель данных/объект должен потребляться только на следующий уровень, который должен быть отображен на этот объект данных внутреннего уровня. Если в сервисе C произойдет какое-либо изменение, оно должно повлиять только на сервис B (примечание: я не говорю здесь об отказоустойчивости, просто на всякий случай).

Давайте теперь представим другую иллюстрацию, если эти вышеуказанные сервисы фактически управляются разными компаниями, где A является клиентом/потребителем B, а B является клиентом C — Если вы являетесь владельцем C, вам нужно будет информировать только своих клиентов о любом обновлении вашего API (в данном случае B), и не нужно будет думать о клиенте вашего клиента (A).

Аргумент №2

Эй, но мы можем использовать союзы или любые другие типы в typescript, будь то Omit, Pick, Partial, etc.

Теперь тот факт, что вам все еще нужно «перенастраивать» эти типы в зависимости от изменений на C, говорит о том, что вы все еще связываете свои сервисы.

Аргумент №3

Хорошо, а как насчет совместного использования enums? Допустим, в сервисе payment-service есть перечисление CreditCardType, которое мне нужно повторно использовать в другом сервисе. Разве тип кредитной карты не будет одинаковым в любом случае?

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

Ваш сервис должен быть агностичен к другому сервису (или иметь четкое разделение ответственности с другим сервисом), если нет, то, вероятно, он должен принадлежать к тому же микросервису.

Заключение

code-reuse, если не использовать его в правильном контексте, замедлит разработку, увеличит усилия по координации и помешает прогрессу, так как сделает микросервисы более не независимыми.

Некоторые ссылки на мудрость кода

«Предпочитайте дублирование неправильной абстракции».

мудрость кодирования

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

Заблуждение относительно повторного использования

«Вы хотите подождать, пока возможность повторного использования станет очевидной.

Преждевременное повторное использование кода

Примечание
Я постараюсь продолжать обновлять эту страницу с новыми аргументами, с которыми я столкнулся. Не стесняйтесь оставлять свои комментарии, мне интересно узнать другие точки зрения 🙂 .

Оцените статью
devanswers.ru
Добавить комментарий