← Back to list

Hexagonal Architecture: Ports & Adapters — Overview (Part 1)

Bu seride, hexagonal (ports & adapters) yaklaşımını, geliştirmiş olduğum demo projem ile payment-service mikroservisi üzerinden uçtan uca…

Tarık Gören · 2026-07-03 18:01 · 0 claps · 4.2 min read
#hexagonal-architecture #ports-and-adapters
Open on Medium ↗
Wiki topics: FIN · Fintech & Banking 🏛️ · Architecture

Hexagonal Architecture: Ports & Adapters — Overview (Part 1)

Bu seride, hexagonal (ports & adapters) yaklaşımını, geliştirmiş olduğum demo projem ile payment-service mikroservisi üzerinden uçtan uca özetliyor olacağım.

Sonraki bölümlerde aynı çerçevede outbox + inbox ve saga konularına da değineceğim. Ancak burada özellikle demo projedeki saga/mikroservis karmaşasına girmeden, hexagonal mimariyi daha sade anlatabileceğim bir kesit seçtim.

Neden böyle bir mimariye ihtiyaç duyuyoruz?

Çoğumuz backend geliştirmeye klasik layered architecture ile başlıyoruz:

Controller → Service → Repository → Database

İlk bakışta oldukça temiz ve anlaşılır bir yapı gibi görünüyor ancak sistem büyüdükçe işler yavaş yavaş karışmaya başlıyor.

Özellikle domain karmaşası arttıkça aşağıdaki durumlar sıkça karşımıza çıkıyor:

  • Service katmanı hem business logic hem de infrastructure detaylarını taşımaya başlıyor
  • JPA entity’ler zamanla domain model yerine geçiyor
  • Controller → Service → Repository akışı içinde iş kuralları katmanlar arasında dağılıyor, yani business kodu olmaması gereken katmanda karşımıza çıkabiliyor
  • Basit bir senaryoyu test etmek için database, Spring context, hatta messaging tool’larını bile ayağa kaldırmak gerekiyor

Bir süre sonra şu sorular kaçınılmaz oluyor:

“Business logic tam olarak nerede?” “Bu iş kuralını neden izole test edemiyorum?” “Neden küçük bir değişiklik her katmanı etkiliyor?”

Buradaki kırılmanın asıl sebebi: Dependency Inversion ihlali

Bu problem aslında doğrudan SOLID prensiplerinin D harfine karşılık gelen Dependency Inversion Principle (DIP) ile ilgilidir.

DIP şunu söyler:

Üst seviye modüller (business logic), alt seviye modüllere (database, framework, external sistemler) bağımlı olmamalıdır. Her ikisi de abstraction’a bağımlı olmalıdır.

Layered architecture’da ise genelde şu yapıda olur:

Service → Repository → Database

Yani:

  • Business logic (service), doğrudan repository’ye bağımlıdır
  • Repository de database’e bağımlıdır

Bu da şu anlama gelir:

Business logic, doğrudan teknik detaylara bağımlı hale gelir.

Görsel 1 — DIP Yönünden Mimari Karşılaştırma

Görsel 1 — DIP Yönünden Mimari Karşılaştırma

Hexagonal Architecture neyi değiştiriyor?

Hexagonal Architecture (Ports & Adapters), uygulamanın iş mantığını (core / domain) dış dünyadan (database, external API, UI, messaging vs.) izole etmeyi amaçlayan bir mimari yaklaşımdır. Bu yaklaşım Alistair Cockburn tarafından ortaya atılmıştır.

Bu mimariyi konuşurken pratikte sık duyduğumuz iki kavram vardır:

  • port → dış dünya ile konuşmak için tanımlanan contract (interface)
  • adapter → bu contract’ın somut teknoloji ile implement edilmesi (JPA, Kafka client, Redis, REST controller…)

Application core, dış dünyaya doğrudan bağımlı değildir.

Bağımlılık yönü nasıl değişiyor?

Klasik yapı:

Service → Repository → Database

Hexagonal yaklaşım:

Domain → Port ← Adapter ← Infrastructure

Hexagonal yaklaşım ile artık:

  • Domain sadece abstraction’ları (port) tanımlar
  • Infrastructure bu abstraction’ları implement eder

Yani:

Bağımlılık yönü tersine çevrilir (DIP uygulanır).

Görsel 2 — Hexagonal Mimariye Genel Bakış

Görsel 2 — Hexagonal Mimariye Genel Bakış

Ortadaki yapıyı parça parça okuyalım

Yukarıdaki Görsel 2 aslında her şeyi tek seferde anlatıyor ama ilk bakışta göze biraz kalabalık gelebilir.

O yüzden gelin bunu daha basit bir şekilde düşünelim: Bir istek sisteme geliyor ve içeride adım adım ilerliyor.

1. Driving side (Primary Adapters) — “İstek nereden geliyor?”

Her şeyin başladığı yer burasıdır.

Görsel 3 — Primary Adapters

Görsel 3 — Primary Adapters

Buradaki bileşenlerin ortak özelliği şu:

Sistemi tetikleyen taraf burası.

Bu bir:

  • HTTP request olabilir
  • Queue’dan gelen bir mesaj olabilir
  • Ya da CLI / UI üzerinden gelen bir aksiyon olabilir

Hexagonal terminolojide buraya driving (primary) adapter deniyor.

Ama daha sade düşünürsek:

“Bu use case’i kim başlattı?” sorusunun cevabı burası.

2. Use Case / Application Service — “Ne yapmak istiyoruz?”

İstek içeri girdiğinde ilk durduğu yer burasıdır:

Görsel 4 — Use Case

Görsel 4 — Use Case

Burayı şöyle düşünebilirsin:

“Bu sistemden ne istiyorum?”

Örneğin:

  • kullanıcı oluştur
  • ödeme başlat
  • sipariş tamamla vb.

Bu katman:

  • İş akışını yönetir
  • Gerekirse birden fazla domain objesini koordine eder
  • Ama kendisi “iş kuralı” yazmaz

Yani orchestration yapar, domain’e delegasyon yapar.

3. Domain Layer — “Gerçek business logic burada”

Bir adım daha içeri girdiğimizde domain’e geliyoruz:

Görsel 5— Domain Layer

Görsel 5— Domain Layer

Burası işin en kritik kısmı.

Sistemin gerçek davranışı burada tanımlı.

Örneğin:

  • “bir kullanıcı şu şartlarda oluşturulabilir”
  • “bir ödeme şu durumda başarısız sayılır”

Bu katman için önemli olan şey şu:

  • JPA yok
  • Kafka yok
  • REST yok

Sadece iş kuralları var.

4. Port Interfaces — “Dışarıdan neye ihtiyacım var?”

Domain tek başına çalışmaz. Bir noktada dış dünyaya ihtiyaç duyar.

İşte o ihtiyaçların tanımlandığı yer:

Görsel 6 — Ports

Görsel 6 — Ports

Burada kritik bir bakış açısı vardır:

Domain “nasıl yapılacağını” değil, “neye ihtiyacı olduğunu” söyler.

Örneğin:

  • “kullanıcıyı kaydetmem lazım” → persistence port
  • “başka bir servise istek atmam lazım” → external API port
  • “bir event publish etmem lazım” → event publisher port

Ama domain şunu bilmez:

  • JPA mı kullanılacak?
  • Atılacak istek REST mi, SOAP mı?
  • Bu iş Kafka ile mi yapılacak?

Özetle bunlar domain’in problemi değil.

5. Driven side (Secondary Adapters) — “Bunu teknik olarak nasıl yaptım?”

En dış katmana geldiğimizde artık tamamen teknoloji konuşuyoruz:

Görsel 7 — Secondary Adapters

Görsel 7 — Secondary Adapters

Buradaki adapter’ların görevi çok net:

Domain’in tanımladığı port’ları implement etmek.

Örneğin:

  • Persistence port → JPA ile implement edilir
  • External API port → Feign / REST client ile implement edilir
  • Event publisher port → Kafka ile implement edilir

Ve en önemli nokta:

Domain bu detayların hiçbirini bilmez.

Özetle

Tüm akışı tek cümlede şöyle düşünebilirsin:

İstek dış dünyadan gelir → use case’e ulaşır → domain’de işlenir → ihtiyaçlar port üzerinden tanımlanır → adapter’lar port’larda tanımlı abstract contract’ları implement eder ve somut hale getirir.

Bu noktadan sonra artık teorik kısmı bırakıp, bunu gerçek bir servis üzerinde görmek çok daha anlamlı oluyor.

Bir sonraki bölümde aynı akışı demo projede payment-service üzerinden uçtan uca inceleyeceğiz.

[embed]Hexagonal Architecture: Ports & Adapters — Spring Boot Implementation (Part 2) Part 1’de hexagonal mimariyi kavramsal olarak konuştuk.medium.com


메타데이터
post_id
2b39b7dda74a
slug
hexagonal-architecture-ports-adapters-overview-part-1-2b39b7dda74a
url
https://medium.com/@tarikgoren58/hexagonal-architecture-ports-adapters-overview-part-1-2b39b7dda74a
canonical_url
https://medium.com/@tarikgoren58/hexagonal-architecture-ports-adapters-overview-part-1-2b39b7dda74a
author_url
https://medium.com/@tarikgoren58
status
ok
fetched_at
2026-07-30 02:57:19