К каким областям Clean Architecture относятся интерфейсы шлюзов и их реализации?

К каким областям Clean Architecture относятся интерфейсы шлюзов и их реализации?
К каким областям Clean Architecture относятся интерфейсы шлюзов и их реализации?

Говоря о шлюзах из Чистой архитектуры, необходимо различать:

  • Интерфейсы
  • Реализацию этих интерфейсов

Пример на TypeScript:

// === Interface ======================================
interface UsersGateway {
 
  retrieveSelection: (requiestParameters: UsersGateway.SelectionRetireving.RequestParameters) => 
       Promise<UsersGateway.SelectionRetireving.ResponseData>;

}

namespace UsersGateway {
  export namespace SelectionRetireving {

    export type RequestParameters = Readonly<{
      paginationPageNumber: number;
      itemsCountPerPaginationPage: number;
      fullOrPartialName? string;  
    }>;

    export type ResponseData = Readonly<{
      totalItemsCount: number;
      filteredItemsCount: number;
      itemsForCurrentPaginationPage: ReadonlyArray<User>;
    }>;
  }
}


// === Implementation =======================================
class UserMySQL_Gateway implements UserGateway {
  retrieveSelection(
    requiestParameters: UsersGateway.SelectionRetireving.RequestParameters
  ):  Promise<UsersGateway.SelectionRetireving.ResponseData> {
    // Implementation including SQL code here
  }
}

Теперь вопрос: на приведенном ниже изображении из книги Clean Architecture, "шлюзы" в зеленом кольце являются интерфейсами их реализаций? Если один из них, то есть и другой?

Мои предположения

Хотя фреймворки должны быть во внешнем (синем) кольце и, я не видел ранее независимых от фреймворка контроллеров и/или презентеров. Таким образом, "шлюзы" в зеленом кольце могут быть реализациями, которые зависят от какого-то фреймворка или СУБД (что соответствует концепции адаптера интерфейса).

Если да, то есть ли интерфейсы шлюза? Оглавление главы 20 Правила ведения бизнеса:

  • Сущности
  • Примеры использования
  • Модели запросов и ответов
  • Заключение

Являются ли перечисленные выше модели запроса и ответа интерфейсами шлюза?

Не видя больше кода, чем то, что вы предоставили в своем примере Typescript, невозможно быть уверенным на 100%, но я бы поспорил, что следующее примерно правильно (если нет, просто мысленно сдвиньте его на один слой).

Модели запроса и ответа — это только ваши RequestParameters и ResponseData. Ваш интерфейс UsersGateway, RequestParameters и ResponseData принадлежат красному слою вариантов использования (они «принадлежат» или служат потребностям какого-то Interactor — что предположительно имеет какое-то отношение к пользователям). Интерфейс UsersGateway подобен выходному порту (изображен на вставке) в том смысле, что он вызывается Interactor, за исключением того, что вместо этого он используется для извлечения данных (Interactor решает, когда инициировать извлечение; напротив, входной порт является вызывается вещами в следующем слое). Конструктор Interactor будет полиморфно принимать конкретный шлюз в качестве параметра UsersGateway.

Типы RequestParameters и ResponseData связаны с UsersGateway, поэтому в некотором смысле они вместе определяют более широкий интерфейс (или API) для шлюза (то есть класс, реализующий UsersGateway, также должен использовать эти типы запросов и ответов). Вот почему все они перечислены в разделе «Интерфейс» во фрагменте кода.

Реализация UserMySQL_Gateway находится на зеленом уровне интерфейсных адаптеров — она «адаптирует» интерфейс UsersGateway, требуемый Interactor, и подключает его к интерфейсу (API), предоставляемому любой библиотекой доступа к данным, которую вы используете. Вы должны ввести экземпляр UserMySQL_Gateway в качестве вышеупомянутого параметра UsersGateway. Тот факт, что интерфейс UsersGateway сам по себе определен внутри внутреннего слоя (и для конкретных нужд Interactor), приводит к инверсии зависимостей.

Теперь Чистая Архитектура не требует точного количества слоев — вы можете использовать больше или меньше, чем показано, в зависимости от ваших потребностей. В вашем примере с TypeScript UserMySQL_Gateway напрямую зависит от фреймворка/библиотеки; это нормально, потому что сам Interactor отвязан через интерфейс UsersGateway. Таким образом, в некотором смысле правило зависимости нарушается на самом внешнем уровне, но это всегда будет происходить на самом внешнем уровне - в какой-то момент вам придется вызывать свои фреймворки/библиотеки. В качестве альтернативы вы можете думать о том, что синий слой Framework & Drivers объединяется с зеленым, сохраняя правило зависимости глобально. В принципе, вы можете решить отделить UserMySQL_Gateway, применяя инверсию зависимостей аналогичным образом, если логика особенно сложна, и вы хотите ввести принадлежащий UserMySQL_Gateway интерфейс, который (1) поможет упростить код и сделать его более читабельным, и (2) позволить вам провести модульное тестирование шлюза.


См. также мой ответ на этот вопрос — в нем обсуждается, как кто-то, кто более знаком с написанием процедурного и/или CRUD-кода, может прийти к дизайну, похожему на чистую архитектуру.


LetsCodeIt, 4 января 2023 г., 17:29