Blog Dla Programistów C#/.NET

środa, 31 grudnia 2025

W świecie .NET rośnie zainteresowanie architekturą heksagonalną (ang. hexagonal architecture, zwana też Ports and Adapters). Jej celem jest wyraźne oddzielenie logiki biznesowej (domeny) od wszelkich szczegółów technologicznych, takich jak bazy danych, interfejsy użytkownika czy zewnętrzne serwisy. Dzięki temu serce aplikacji (rdzeń biznesowy) pozostaje niezależne i łatwiejsze w testowaniu. W praktyce oznacza to, że zamiast mieć zależności "od góry w dół" (jak w tradycyjnej architekturze warstwowej), komponenty zewnętrzne komunikują się z rdzeniem aplikacji za pomocą określonych interfejsów - portów, a konkretne implementacje tych portów to adaptery.

Architektura Heksagonalna w .NET - Separacja Logiki Biznesowej Od Detali Technicznych

Kluczowe elementy architektury heksagonalnej


Architektura heksagonalna skupia się na trzech głównych składnikach, które wspólnie izolują logikę biznesową od reszty systemu:
   
Domena (Core) - to rdzeń aplikacji, zawierający całą logikę biznesową i przypadki użycia. Nie zna on szczegółów technicznych, definiuje tylko abstrakcyjne interfejsy (porty) wymaganych operacji.
    
Porty (interfejsy) - definiują punkty wejścia/wyjścia do domeny. Mogą to być porty wejściowe (np. przyjmujące komendy lub zapytania HTTP z UI czy API) albo wyjściowe (np. dostęp do bazy danych, systemu płatności czy kolejki komunikatów). Porty mówią "co" aplikacja może zrobić, nie określając jednak "jak" to zostanie zrealizowane.
   
Adaptery - to konkretne implementacje portów w wybranych technologiach. Adapter pobiera dane z zewnątrz, mapuje je na modele domenowe (i odwrotnie) i wywołuje serwisy domeny poprzez porty. Można je wymieniać, dodawać lub modyfikować bez zmiany samej logiki biznesowej. Na przykład adapter może zaimplementować port dostępu do bazy danych (np. SqlOrderRepository : IOrderRepository) lub port integracji z zewnętrznym API (np. StripePaymentAdapter : IPaymentGateway).

Taki podział sprawia, że domena "nie widzi" konkretnej bazy danych, frontendu czy serwisu płatności, a zależności są odwrócone, to adaptery zależą od interfejsów domenowych, a nie odwrotnie. Dzięki takiej organizacji aplikacja staje się bardziej elastyczna.


Zalety architektury heksagonalnej


Izolacja logiki biznesowej: Kluczową korzyścią jest wyraźne oddzielenie logiki domeny od szczegółów implementacyjnych. Zmiany w technologii (np. inna baza danych czy UI) nie wymagają modyfikacji kodu biznesowego.
    
Modułowość i łatwa wymienialność: Dzięki portom i adapterom można łatwo podmieniać technologie. Przykładowo, jeśli dziś korzystasz z jednej implementacji repozytorium bazy danych, możesz jutro wprowadzić inny system (np. z SQL na NoSQL) tylko poprzez zmianę adaptera, bez ingerencji w logikę biznesową.
    
Łatwość testowania: Logika biznesowa jest testowana w izolacji, testy mogą symulować adaptery (np. mock lub stub) bez potrzeby uruchamiania prawdziwej bazy czy serwisu. Taki modularny charakter architektury znacząco ułatwia pisanie testów jednostkowych.
   
Niezależność od frameworków: Kod domenowy nie zawiera zależności do konkretnych bibliotek czy frameworków. W .NET można na przykład trzymać modele domenowe i interfejsy w osobnej bibliotece klasy, co pozwala na jej ponowne użycie w innych kontekstach. Ten wzorzec dobrze wspiera podejście DDD (Domain-Driven Design) i zasady SOLID (szczególnie Dependency Inversion).

W praktyce architektura heksagonalna prowadzi do bardziej odpornych na zmiany aplikacji, łatwiej je rozwijać i utrzymywać w dłuższym czasie.


Przykład prostego rozwiązania w .NET


Wyobraźmy sobie usługę zamówień w ASP.NET Core. W serwisie domenowym możemy mieć np. interfejs portu:

public interface IOrderRepository 
{
void SaveOrder(Order order);
}

oraz jego adapter do bazy danych:

public class SqlOrderRepository : IOrderRepository 
{
public void SaveOrder(Order order)
{
/* zapis do SQL Server (np. Entity Framework) */
}
}

W klasie serwisu domenowego korzystamy z tego portu:

public class OrderService 
{
private readonly IOrderRepository _orderRepository;

public OrderService(IOrderRepository orderRepository)
{
_orderRepository = orderRepository;
}

public void PlaceOrder(Order order)
{
/* logika biznesowa (np. sprawdzenie stanu magazynu) */
_orderRepository.SaveOrder(order);
}
}

W powyższym przykładzie OrderService (logika biznesowa) nie wie nic o tym, jak zamówienie jest zapisywane. W warstwie infrastruktury rejestrujemy implementację portu w kontenerze DI:

services.AddTransient<IOrderRepository, SqlOrderRepository>();

Dzięki temu w runtime ASP.NET Core wstrzykuje do OrderService konkretny adapter. W przyszłości można łatwo stworzyć inny adapter (np. MongoOrderRepository) i podmienić go w konfiguracji bez zmiany samej klasy OrderService. Takie podejście doskonale ilustruje zasadę "forma programu wynika z architektury", gdzie rdzeń domenowy pozostaje maksymalnie niezależny od środowiska.


Podsumowanie


Architektura heksagonalna to sprawdzony sposób na budowę elastycznych i łatwych w utrzymaniu aplikacji .NET. Dzięki rozdzieleniu logiki biznesowej od szczegółów technicznych aplikacje są bardziej odporne na zmiany technologii i prostsze do testowania. Wiele projektów ASP.NET Core korzysta z podobnych idei (nazywanych też "clean architecture" lub "onion architecture"), wykorzystując wbudowany mechanizm wstrzykiwania zależności do łączenia portów z adapterami.

Jeśli temat architektury i dobrych praktyk w .NET Cię zainteresował, zachęcam do zapoznania się z moim szkoleniem online "Szkoła ASP.NET Core", pokazuję w nim, jak tworzyć zaawansowane aplikacje ASP.NET Core MVC i Web API z zastosowaniem najlepszych wzorców projektowych.

Autor artykułu:
Kazimierz Szpin
Kazimierz Szpin
CTO & Founder - FindSolution.pl
Programista C#/.NET. Specjalizuje się w Blazor, ASP.NET Core, ASP.NET MVC, ASP.NET Web API, WPF oraz Windows Forms.
Autor bloga ModestProgrammer.pl
Dodaj komentarz

Wyszukiwarka

© Copyright 2026 modestprogrammer.pl | Sztuczna Inteligencja | Regulamin | Polityka prywatności. Design by Kazimierz Szpin. Wszelkie prawa zastrzeżone.