starter-kit/docs/adapter.md
2025-05-21 12:39:40 +07:00

4.2 KiB

Adapter Layer

Tổng quan

Adapter là lớp giao tiếp giữa ứng dụng và các hệ thống bên ngoài. Layer này cung cấp khả năng tích hợp với bên thứ ba và sự độc lập của core business logic.

Nguyên tắc thiết kế

  • Tách biệt domain logic với chi tiết triển khai bên ngoài
  • Dễ dàng thay thế các implementation mà không ảnh hưởng tới business logic
  • Dependency inversion - core logic không phụ thuộc vào chi tiết triển khai
  • Interface-driven design cho các external services

Cấu trúc thư mục

internal/adapter/
  │── persistence/       # Database adapters
  │   │── postgres/      # PostgreSQL implementation
  │   │── mysql/         # MySQL implementation (optional)
  │   └── sqlite/        # SQLite implementation (optional)
  │── messaging/        # Messaging system adapters
  │── storage/          # File storage adapters
  │── externalapi/      # Third-party service adapters
  │── notification/     # Notification service adapters
  └── cache/            # Cache adapters

Database Adapter

Adapter database được triển khai với tính năng:

  • Kết nối tự động với PostgreSQL
  • Cấu hình connection pool
  • Xử lý migration tự động
  • Triển khai repository pattern

Cấu hình

Cấu hình database được định nghĩa trong file configs/config.yaml:

database:
  driver: "postgres"
  host: "localhost" 
  port: 5432
  username: "postgres"
  password: "postgres"
  database: "ulflow"
  ssl_mode: "disable"
  max_open_conns: 25
  max_idle_conns: 5
  conn_max_lifetime: 300
  migration_path: "migrations"

Triển khai adapter

1. Định nghĩa interface

// pkg/adapter/payment/interface.go
package payment

type PaymentProvider interface {
    ProcessPayment(amount float64, currency string, metadata map[string]string) (string, error)
    RefundPayment(paymentId string, amount float64) error
    GetPaymentStatus(paymentId string) (string, error)
}

2. Triển khai cụ thể

// pkg/adapter/payment/stripe/stripe.go
package stripe

import "github.com/your-project/pkg/adapter/payment"

type StripeAdapter struct {
    apiKey string
    client *stripe.Client
}

func NewStripeAdapter(apiKey string) *StripeAdapter {
    return &StripeAdapter{
        apiKey: apiKey,
        client: stripe.NewClient(apiKey),
    }
}

func (s *StripeAdapter) ProcessPayment(amount float64, currency string, metadata map[string]string) (string, error) {
    // Triển khai với Stripe API
}

// Triển khai các phương thức khác...

3. Sử dụng mock để test

// pkg/adapter/payment/mock/mock.go
package mock

import "github.com/your-project/pkg/adapter/payment"

type MockPaymentAdapter struct {
    // Fields to store test data
}

func (m *MockPaymentAdapter) ProcessPayment(amount float64, currency string, metadata map[string]string) (string, error) {
    // Mock implementation for testing
}

// Triển khai các phương thức khác...

Dependency Injection

Sử dụng dependency injection để đưa adapter vào business logic:

// pkg/transaction/order/service.go
package order

type OrderService struct {
    paymentProvider payment.PaymentProvider
    // Other dependencies...
}

func NewOrderService(paymentProvider payment.PaymentProvider) *OrderService {
    return &OrderService{
        paymentProvider: paymentProvider,
    }
}

func (s *OrderService) PlaceOrder(order *resource.Order) error {
    // Sử dụng payment provider thông qua interface
    paymentId, err := s.paymentProvider.ProcessPayment(
        order.TotalAmount, 
        order.Currency,
        map[string]string{"orderId": order.ID},
    )
    // Xử lý kết quả...
}

Best Practices

  1. Mỗi adapter chỉ giao tiếp với một dịch vụ bên ngoài
  2. Xử lý lỗi phù hợp và mapping sang domain errors
  3. Cung cấp logging và metrics cho mỗi adapter
  4. Retry mechanisms cho các dịch vụ không ổn định
  5. Circuit breaking để tránh cascading failures
  6. Feature toggles để dễ dàng chuyển đổi giữa các provider