Hexagonal Architecture (Altıgen Mimari): Portlar, Adaptörler ve Bağımsız Domain Tasarımının Derin Rehberi
1. GİRİŞ
Hexagonal Architecture (Altıgen Mimari), Alistair Cockburn tarafından popülerleştirilen ve uygulama çekirdeğini (domain) çevresel bağımlılıklardan izole eden bir mimari yaklaşımdır. Bu desenin temel amacı, uygulamanın iş mantığını dış altyapıdan (UI, veritabanı, mesajlaşma, dış API'ler) bağımsız hale getirmek; böylece test edilebilirliği, esnekliği ve bakımı kolaylaştırmaktır. Modern bulut‑native, mikroservis ve event‑driven uygulamalarda altıgen yapı, değişen teknoloji tercihlerine karşı dayanıklılığı artırır.
Bu neden bugün önemli?
- Teknoloji yığını hızlı değişiyor: veritabanı, mesajlaşma servisleri, client framework'leri sık güncelleniyor.
- Test edilebilirlik ve otomasyon öncelikli: domain'i izole etmek birim ve entegrasyon testi maliyetini düşürür.
- Mikroservisleşme ve dağıtık ekipler, bağımlılık sınırlarının net olmasını gerektiriyor.
Kimler için önemli?
- Yazılım mimarları ve sistem tasarımcıları
- Backend geliştiriciler, platform mühendisleri ve SRE ekipleri
- Üretim odaklı, uzun ömürlü sistemler inşa eden ekipler
Hangi problemleri çözüyor?
- Domain kodunun framework veya infrastructure değişimlerinden etkilenmesini engeller
- Test senaryolarını kolaylaştırır (unit tests, port mocks)
- Entegrasyon ve deployment esnekliği sağlar — ör. veritabanını değiştirmek, UI'yi yenilemek kolaylaşır
2. KAVRAMSAL TEMELLER
2.1 Hexagonal Architecture nedir — net tanım
Hexagonal Architecture, uygulamayı merkezde bir çekirdek (domain) ve çevresinde portlar (interfaces) ile adaptörler (implementations) şeklinde organize eder. İç çekirdek dış dünya ile yalnızca portlar aracılığıyla konuşur. Adaptörler bu portları kullanarak dış sistemlerle etkileşime girer. Bu yapı çoğu zaman bir altıgen diyagramla gösterilir; fakat şekil sembolik olup esas fikir bağımlılıkların tersine çevrilmesidir.
2.2 Temel bileşenler ve terminoloji
- Domain / Application Core: İş kuralları, aggregate'lar, servisler — bağımsız kod.
- Port: Domain'in beklentisini tanımlayan soyutlama (interface). İncoming (driving) ve outgoing (driven) port olarak iki tip olabilir.
- Adapter (Adapter/Driver): Port'un gerçek dünya implementasyonu; ör. REST controller, JDBC repository, AMQP consumer.
- Driving adapter: Kullanıcının veya başka bir sistemin domain'i tetiklediği adaptör (örn. UI, testsimulated client).
- Driven adapter: Domain'in dışa bağımlı olarak çağırdığı adaptör (örn. DB, email service).
2.3 Ports and Adapters vs Clean Architecture vs Hexagonal
Hexagonal Architecture genelde Ports & Adapters olarak da adlandırılır ve Clean Architecture ile birçok ortak prensip paylaşır (bağımlılığın içe doğru olması, domain izolasyonu). Farklar çoğunlukla terminolojide ve şematik sunumdur; pratikte bu yaklaşımların hepsi bağımlılıkları sınırlandırıp domain'i merkez alır.
3. NASIL ÇALIŞIR? — TEKNİK MİMARİ VE AKIŞ
3.1 Sistem mimarisi — portların rolü
Portlar domain'in dış dünya ile iletişim kurma sözleşmeleridir. Incoming (ör. CommandHandler) port'lar uygulamayı tetiklerken, outgoing (ör. Repository) port'lar dış sistemlerle veri alışverişi yapar. Domain sadece portlara bağımlıdır; portların implementasyonları dış katmanlarda bulunur. Bu sayede port'u mock'layarak domain'i izole edilmiş olarak test edebilirsiniz.
3.2 Veri akışı — örnek senaryo
- HTTP isteği bir Driving Adapter (Controller) tarafından alınır.
- Controller isteği uygun port (ör. CreateOrderPort) üzerinden application core'a iletir.
- Core işlem yapar; ihtiyacı varsa Driven Port (OrderRepository) aracılığıyla veri depolar.
- Driven Adapter (JPA/ORM implementasyonu) repository çağrısını veritabanına çevirir.
- Sonuç geri döner; Controller uygun HTTP yanıtını üretir.
3.3 Test stratejileri
Hexagonal mimari testleri basitleştirir:
- Birim test (Unit): Port'lar mocklanarak application core izole şekilde test edilir.
- Adaptör testi (Adapter tests): Adapter'ların dış sistemlerle doğru konuştuğu doğrulanır (örn. repository implementasyonunun DB ile davranışı).
- Entegrasyon testi: Tam akışın (driving -> core -> driven) doğru çalışması test edilir; test container veya in‑memory DB kullanılabilir.
3.4 Bağımlılıkların tersine çevrilmesi
Domain, port interface'lerini tanımlar. Concrete implementasyonlar domain'den bağımsız olarak dış katmanda geliştirilir ve başlangıçta (composition root) core'a enjekte edilir. Böylece dependency inversion principle (DIP) gerçekleştirilmiş olur.
4. GERÇEK DÜNYA KULLANIMLARI
4.1 Örnek: E‑ticaret sipariş iş akışı
Sipariş sistemi domain çekirdeğinde order creation, validation ve pricing kuralları bulunur (application core). Repository, payment gateway ve notification service port'ları tanımlar. Bu port'ların adaptörleri (SQL repository, Stripe adapter, Email adapter) dış katmanda yer alır. Böylece ödeme sağlayıcısını değiştirmek core'u etkilemez.
4.2 Netflix, Amazon gibi şirket uygulamaları
Büyük ölçekli platformlar bağımsız deploy ve teknoloji değişikliklerine ihtiyaç duyar. Hexagonal yapı, farklı adaptörlerle (kendi message bus'ları, farklı veri depoları, çeşitli client türleri) çalışmayı kolaylaştırır. Örneğin bir servis önce RDBMS üzerinde çalışıp daha sonra bir NoSQL çözümüne taşındığında domain aynı kalır.
4.3 Startuplar ve MVP'ler
Startuplar çabuk iterasyon ister; hexagonal mimari küçük adımlarla uygulanabilir. İlk evrede port'lara basit adaptörler yazılır, sonra ihtiyaç büyüdükçe adaptörler geliştirilebilir veya değiştirilebilir.
5. AVANTAJLAR VE SINIRLAMALAR
Avantajlar
- Domain izolasyonu: iş kuralları altyapıdan bağımsızdır.
- Test edilebilirlik: unit test'ler kolaydır çünkü port'lar mocklanır.
- Esneklik ve replaceability: dış bağımlılıklar değiştirilebilir.
- Net sınırlar: adaptörler ve port'lar aracılığıyla sorumluluklar açıkça ayrılır.
Sınırlamalar
- Başlangıç maliyeti: küçük projelerde fazla soyutlama olabilir.
- Yapı karmaşıklığı: çok sayıda interface, DTO ve mapping gerektirebilir.
- Pratik uygulamada hatalı uygulama (interface sızıntıları, adapter'ların domain'e bağımlılığı) faydayı azaltır.
6. ALTERNATİFLER VE KARŞILAŞTIRMA
| Yaklaşım | Avantaj | Dezavantaj |
|---|---|---|
| Monolitik katmanlı (Layered) | Basit, hızlı geliştirilebilir başlangıç | Domain ve altyapı karışabilir; test zorlaşabilir |
| Clean Architecture | Domain izolasyonu, test edilebilirlik | Benzer faydalar; farklı terminoloji |
| Onion Architecture | Bağımlılıkların içe doğru olması, domain merkezli | Yapısal benzerlik — seçim çoğunlukla terminolojiye bağlı |
7. EN İYİ PRATİKLER
Production kullanımı
- Port ve adapter sınırlarını net belirleyin: interface tek sorumluluk ilkesine uygun olsun.
- Composition root (uygulama başlangıcı) tek yerde olsun ve test edilebilir şekilde tasarlayın.
- Mapping kodunu merkezi bir yerde yönetin; DTO ve domain dönüşümleri açık ve testlenebilir olsun.
Performans optimizasyonu
- Adapter'larda gereksiz mapping ve kopyalamaları azaltın; lazy loading ve streaming kullanımı düşünün.
- Hot path'leri profil edin; domain katmanında gereksiz IO çağrıları olup olmadığını kontrol edin.
Güvenlik
- Authentication/Authorization genelde adaptör seviyesinde uygulanır; domain sadece yetki bilgisini kullanarak karar versin.
- Input validation çift katmanlı olmalı: transport‑level ve domain‑level validasyon.
Observability
- Port çağrı zamanlarını ve adaptör hatalarını loglayın; correlation id ile izleme sağlayın.
- Adaptörlerin bulunduğu katmanda metrik toplayın: DB latency, external API errors, queue length vb.
8. SIK YAPILAN HATALAR
- Port interface'lerini altyapı terminolojisiyle yazmak — domain'e özgü ve intention revealing olmalı.
- Adapter'larda domain logic koymak — iş kuralları core'da kalmalı.
- Composition root'un dağınık olması — bağımlılık enjeksiyonunu merkezi yönetmeyi bırakmamak gerekir.
- Fazla soyutlama: küçük projelerde developer hızını düşürebilir; pragmatik denge şarttır.
9. GELECEK TRENDLER
- Interface‑first geliştirme: API ve port sözleşmeleri önce tasarlanıp, adaptörler sonradan implement edilecek.
- AI destekli adaptör jenerasyonu: Telemetry'e dayalı olarak adapter implementasyonları için kod önerileri ve mapping jenerasyonu daha yaygın olacak.
- Domain‑centric tooling: Domain modellerinden otomatik port/interface ve test scaffold'ları üreten araçlar artacak.
EK BÖLÜMLER
Sık Sorulan Sorular (FAQ)
- 1. Hexagonal Architecture her projede uygulanmalı mı?
Hayır. Küçük, kısa ömürlü projelerde gereksiz soyutlama olabilir. Uzun ömürlü, değişime açık veya ekip büyüme beklentisi varsa tercih edilir.
- 2. Port ile interface arasında fark var mı?
Port genelde domain'in dış dünya ile iletişim sözleşmesini ifade eden interface'tir; terminolojik fark yok, port konseptsel, interface ise teknik birleşimdir.
- 3. Adapter'larda hangi sorumluluklar olmalı?
Adapter'lar veri dönüşümü, transport/IO işlemleri ve hata eşleme (error mapping) ile sınırlı olmalıdır; iş kuralları domain'de kalmalıdır.
- 4. Hexagonal Architecture ile CQRS/ES birlikte kullanılabilir mi?
Evet. Hexagonal mimari port ve adapter düzeni sağlar; CQRS/ES ise read/write ayrımı ve event store konularını ele alır; birlikte güçlü bir kombinasyon oluşturur.
- 5. Mapping işleri nerede olmalı?
Mapping genelde adapter katmanında yapılır; domain DTO'ları veya domain modelleri adapter tarafından oluşturulmalıdır. Mapping kodu test edilebilir olmalıdır.
- 6. Monolitik projede nasıl başlarım?
Küçük adımlarla: önce domain paketini oluşturun ve bağımlılık kurallarını uygulayın; daha sonra adaptörleri ayırın. Strangler Fig pattern yardımcı olur.
- 7. Hexagonal Architecture testleri nasıl kolaylaştırır?
Domain sadece port'lara bağlı olduğu için port'lar mocklanır ve core unit test'leri izolasyon sağlar. Adapter'lar ayrı testlerle doğrulanır.
- 8. Hangi metrikleri izlemeliyim?
Port çağrı latencyn, adapter error rate, DB query latency, external API success rate, unit/integration test coverage gibi metrikler kritik öneme sahiptir.
Anahtar Kavramlar
- Port
- Domain'in dış dünya ile iletişim sözleşmesi; interface.
- Adapter
- Port'un gerçek dünya implementasyonu; transport ve persistence detaylarını içerir.
- Driving / Driven Adapter
- Driving adapter uygulamayı tetikler (UI, tests); driven adapter dış sistemleri çağırır (DB, mail).
- Composition Root
- Bağımlılıkların bağlandığı tek nokta; uygulama başlangıcında adaptörlerin core'a enjekte edildiği yer.
- Dependency Inversion
- Yüksek seviye modüllerin düşük seviye modüllere bağlı olmaması ilkesi; port/adapters ile sağlanır.
Öğrenme Yol Haritası
- 0–1 ay: Ports & Adapters temel kavramlarını öğrenin; küçük bir domain modeli oluşturup port/interface'leri tasarlayın.
- 1–3 ay: Adapter implementasyonları yazın: HTTP controller, repository, messaging consumer; unit ve adapter testlerini ekleyin.
- 3–6 ay: Composition root, DI container ve entegrasyon testlerini uygulayın; Strangler Fig ile legacy entegrasyonu deneyin.
- 6–12 ay: CQRS/ES entegrasyonu, multi‑adapter scalabilité ve observability pratiklerini hayata geçirin.