[{"data":1,"prerenderedAt":-1},["ShallowReactive",2],{"question-arkhitektura-prilozheniy-chto-takoe-geksagonalnaya-arkhitektura-ports-and-adapters":3},{"id":4,"slug":5,"topicId":6,"topicSlug":7,"topicName":8,"topicEmoji":9,"question":10,"answer":11,"codeLang":12,"codeSrc":12,"important":12,"commonMistakes":12,"modernUsage":12,"difficulty":13,"tags":14,"related":19,"progress":20,"seo":21},120,"chto-takoe-geksagonalnaya-arkhitektura-ports-and-adapters",3,"arkhitektura-prilozheniy","Архитектура приложений","🏗️","Что такое гексагональная архитектура (Ports and Adapters)","Гексагональная архитектура (Hexagonal Architecture), также известная как Ports and Adapters, — это архитектурный стиль, предложенный Алистером Кокберном, основная идея которого — изолировать ядро приложения (бизнес-логику) от внешнего мира с помощью портов (интерфейсов) и адаптеров (реализаций). Представьте розетку и вилку: розетка (порт) задаёт стандарт, а вилка (адаптер) может быть любой — главное, чтобы она подходила к розетке.\n\n### Структура\n\n```\n                    ┌──── Адаптеры (Driving \u002F Входящие) ────┐\n                    │                                        │\n              ┌───────────┐                          ┌───────────┐\n              │  REST API │                          │   CLI     │\n              │ Controller│                          │  Adapter  │\n              └─────┬─────┘                          └─────┬─────┘\n                    │                                      │\n                    ▼                                      ▼\n              ┌─────────────────────────────────────────────────┐\n              │              Входящие порты                     │\n              │         (интерфейсы Use Case)                   │\n              │  ┌─────────────────────────────────────────┐    │\n              │  │                                         │    │\n              │  │         Ядро приложения                  │    │\n              │  │     (Domain Model + Use Cases)          │    │\n              │  │                                         │    │\n              │  └─────────────────────────────────────────┘    │\n              │              Исходящие порты                    │\n              │         (интерфейсы репозиториев,               │\n              │          внешних сервисов)                      │\n              └──────────────┬──────────────┬───────────────────┘\n                             │              │\n                             ▼              ▼\n                       ┌──────────┐  ┌────────────┐\n                       │ JPA      │  │  Kafka     │\n                       │ Adapter  │  │  Adapter   │\n                       └──────────┘  └────────────┘\n                    └──── Адаптеры (Driven \u002F Исходящие) ────┘\n```\n\n### Порты и адаптеры\n\n**Порт** — это интерфейс, определяющий контракт взаимодействия:\n\n- **Входящий (driving) порт** — интерфейс, через который внешний мир обращается к приложению (Use Case).\n- **Исходящий (driven) порт** — интерфейс, через который приложение обращается к внешнему миру (БД, очередь сообщений, внешний API).\n\n**Адаптер** — конкретная реализация порта:\n\n- **Входящий адаптер** — REST-контроллер, gRPC-сервис, обработчик очереди.\n- **Исходящий адаптер** — JPA-репозиторий, HTTP-клиент, Kafka-продюсер.\n\n### Пример на Java\n\n\u003Cdetails>\u003Csummary>Пример кода\u003C\u002Fsummary>\n\n```java\n\u002F\u002F Входящий порт (Use Case)\npublic interface TransferMoneyUseCase {\n    void transfer(TransferCommand command);\n}\n\n\u002F\u002F Доменная модель\npublic class Account {\n    private AccountId id;\n    private Money balance;\n\n    public void withdraw(Money amount) {\n        if (balance.isLessThan(amount)) {\n            throw new InsufficientFundsException(id, amount);\n        }\n        balance = balance.minus(amount);\n    }\n\n    public void deposit(Money amount) {\n        balance = balance.plus(amount);\n    }\n}\n\n\u002F\u002F Исходящий порт\npublic interface AccountRepository {\n    Account findById(AccountId id);\n    void save(Account account);\n}\n\n\u002F\u002F Реализация Use Case (Application Service)\n@Service\npublic class TransferMoneyService implements TransferMoneyUseCase {\n\n    private final AccountRepository accountRepository;\n\n    public TransferMoneyService(AccountRepository accountRepository) {\n        this.accountRepository = accountRepository;\n    }\n\n    @Override\n    @Transactional\n    public void transfer(TransferCommand command) {\n        Account from = accountRepository.findById(command.getSourceId());\n        Account to = accountRepository.findById(command.getTargetId());\n        from.withdraw(command.getAmount());\n        to.deposit(command.getAmount());\n        accountRepository.save(from);\n        accountRepository.save(to);\n    }\n}\n\n\u002F\u002F Входящий адаптер (REST)\n@RestController\npublic class AccountController {\n\n    private final TransferMoneyUseCase transferMoney;\n\n    @PostMapping(\"\u002Ftransfer\")\n    public ResponseEntity\u003CVoid> transfer(@RequestBody TransferRequest request) {\n        transferMoney.transfer(new TransferCommand(\n            new AccountId(request.getFromId()),\n            new AccountId(request.getToId()),\n            Money.of(request.getAmount())\n        ));\n        return ResponseEntity.ok().build();\n    }\n}\n\n\u002F\u002F Исходящий адаптер (JPA)\n@Component\npublic class JpaAccountRepository implements AccountRepository {\n\n    private final AccountJpaRepository jpaRepository;\n\n    @Override\n    public Account findById(AccountId id) {\n        AccountEntity entity = jpaRepository.findById(id.getValue())\n            .orElseThrow(() -> new AccountNotFoundException(id));\n        return AccountMapper.toDomain(entity);\n    }\n\n    @Override\n    public void save(Account account) {\n        jpaRepository.save(AccountMapper.toEntity(account));\n    }\n}\n```\n\n\u003C\u002Fdetails>\n\n### Плюсы\n\n- Бизнес-логика полностью изолирована от инфраструктуры.\n- Легко подменять адаптеры (например, заменить PostgreSQL на MongoDB).\n- Отличная тестируемость — можно тестировать ядро без БД и сети.\n- Соответствует принципу инверсии зависимостей (DIP из SOLID).\n\n### Минусы\n\n- Больше кода (интерфейсы, маппинг между слоями).\n- Сложнее для небольших CRUD-приложений.\n- Требует дисциплины от команды.\n\n> **На собеседовании:** Ключевое, что хотят услышать — это разницу между входящими и исходящими портами и понимание инверсии зависимостей. Частая ошибка — описывать гексагональную архитектуру как «просто layered с интерфейсами», упуская суть направления зависимостей.","","middle",[15,16,17,18],"clean-code","ports-and-adapters","hexagonal","architecture",[],null,{"title":22,"description":23,"ogTitle":22,"ogDescription":24,"keywords":25,"schemaAnswer":32,"featuredSnippetReady":33},"Гексагональная архитектура (Ports and Adapters) — Gymterview","Гексагональная архитектура изолирует бизнес-логику от внешнего мира через порты (интерфейсы) и адаптеры (реализации). Примеры на Java и Spring.","Гексагональная архитектура изолирует бизнес-логику от внешнего мира через порты и адаптеры. Примеры на Java.",[26,27,28,29,30,31],"гексагональная архитектура","Ports and Adapters","Hexagonal Architecture","порты и адаптеры","Алистер Кокберн","Java архитектура","Гексагональная архитектура (Hexagonal Architecture), предложенная Алистером Кокберном, изолирует ядро приложения (бизнес-логику) от внешнего мира с помощью портов (интерфейсов) и адаптеров (реализаций). Входящие порты определяют Use Case-интерфейсы, исходящие — интерфейсы для БД и внешних сервисов. Адаптеры — конкретные реализации: REST-контроллеры, JPA-репозитории, Kafka-продюсеры. Это обеспечивает отличную тестируемость и возможность замены инфраструктурных компонентов.",true]