← Back to Blog
MIMARI

Hexagonal Mimari Nedir?

F. Çağrı BilgehanFebruary 12, 202611 min read
hexagonalmimariports adaptersclean architecture

Hexagonal Mimari Nedir? Ports & Adapters Rehberi

Veritabanını değiştirmek tüm uygulamayı mı etkiliyor? Framework'e kilitlenmiş misiniz? Hexagonal Architecture ile iş mantığınızı dış dünyadan izole edin, test edilebilir ve değiştirilebilir hale getirin.

Hexagonal Mimari Tanımı

Hexagonal Architecture (Altıgen Mimari), Alistair Cockburn tarafından 2005'te tanımlanan bir mimari desendir. Ports & Adapters olarak da bilinir. Temel fikir: İş mantığını (domain) merkeze koyun, dış bağımlılıkları (DB, API, UI) çevre adaptörlerine taşıyın.

          ┌──────────────────────┐
          │     Adapters          │
          │  ┌────────────────┐  │
          │  │   Ports         │  │
          │  │  ┌──────────┐  │  │
 Input ──►│  │  │  Domain   │  │  │──► Output
          │  │  │  (Core)   │  │  │
          │  │  └──────────┘  │  │
          │  └────────────────┘  │
          └──────────────────────┘

Neden Hexagonal?

Geleneksel Katmanlı Mimari Sorunları

Controller → Service → Repository → Database
     ↓           ↓          ↓
  Framework   Business   DB Logic
  kilitli     karışık    bağımlı

Hexagonal Çözümü

HTTP Adapter → [Port] → Domain Logic → [Port] → DB Adapter
REST/GraphQL                                    PostgreSQL/MongoDB
  • Domain katmanı hiçbir dış bağımlılığa sahip değildir
  • Adaptörler değiştirilebilir (PostgreSQL → MongoDB, REST → GraphQL)
  • Test edilmesi kolay — domain'i izole test edin

Temel Kavramlar

Domain (Core)

İş kurallarınız. Hiçbir framework, DB veya HTTP kavramı içermez.

Port

Domain'in dış dünya ile iletişim kurmak için tanımladığı arayüz (interface).

Adapter

Port arayüzünü gerçekleştiren somut uygulama.

Pratik Örnek: Sipariş Sistemi

Port (Interface)

// domain/ports/OrderRepository.ts
interface OrderRepository {
  save(order: Order): Promise<void>;
  findById(id: string): Promise<Order | null>;
  findByCustomer(customerId: string): Promise<Order[]>;
}

// domain/ports/PaymentGateway.ts
interface PaymentGateway {
  charge(amount: number, token: string): Promise<PaymentResult>;
}

// domain/ports/NotificationService.ts
interface NotificationService {
  sendOrderConfirmation(order: Order): Promise<void>;
}

Domain (Core Logic)

// domain/services/OrderService.ts
class OrderService {
  constructor(
    private orderRepo: OrderRepository,
    private payment: PaymentGateway,
    private notification: NotificationService
  ) {}

  async createOrder(items: Item[], paymentToken: string): Promise<Order> {
    const order = Order.create(items);
    
    const result = await this.payment.charge(order.total, paymentToken);
    if (!result.success) throw new PaymentError(result.error);
    
    order.markAsPaid(result.transactionId);
    await this.orderRepo.save(order);
    await this.notification.sendOrderConfirmation(order);
    
    return order;
  }
}

Adapter (Infrastructure)

// adapters/PostgresOrderRepository.ts
class PostgresOrderRepository implements OrderRepository {
  async save(order: Order): Promise<void> {
    await db.query('INSERT INTO orders ...', [order.id, order.total]);
  }
  
  async findById(id: string): Promise<Order | null> {
    const row = await db.query('SELECT * FROM orders WHERE id = $1', [id]);
    return row ? Order.fromRow(row) : null;
  }
}

// adapters/StripePaymentGateway.ts
class StripePaymentGateway implements PaymentGateway {
  async charge(amount: number, token: string): Promise<PaymentResult> {
    const result = await stripe.charges.create({ amount, source: token });
    return { success: true, transactionId: result.id };
  }
}

Hexagonal vs Diğer Mimariler

| Özellik | Katmanlı | Hexagonal | Clean Architecture | |---------|----------|-----------|-------------------| | Domain izolasyonu | Zayıf | Güçlü | Güçlü | | Test edilebilirlik | Orta | Yüksek | Yüksek | | Karmaşıklık | Düşük | Orta | Yüksek | | DB bağımsızlığı | Düşük | Yüksek | Yüksek | | Öğrenme eğrisi | Düşük | Orta | Yüksek |

Best Practices

  1. Dependency Rule — Bağımlılık her zaman dıştan içe doğru olmalı
  2. Domain'de framework kullanmayın — Saf TypeScript/Java/Python
  3. Port'ları küçük tutun — Interface Segregation prensibini uygulayın
  4. Adapter'ları kolayca değiştirilebilir yapın — Dependency Injection kullanın
  5. Domain event'leri kullanın — Yan etkileri decouple edin

Sonuç

Hexagonal Architecture, iş mantığınızı teknik detaylardan izole ederek sürdürülebilir, test edilebilir ve esnek bir mimari sunar. Karmaşıklık maliyeti vardır, ama orta-büyük projeler için uzun vadede karşılığını fazlasıyla verir.

Hexagonal mimariyi LabLudus platformunda interaktif görevlerle öğrenin.

Related Posts

Message Queue Nedir?

Message Queue nedir ve neden kullanılır?

Yazılım Mimarisi Nedir? Temelden İleri Seviyeye Kapsamlı Rehber

Yazılım mimarisi nedir, neden önemlidir ve nasıl öğrenilir?