4.2 KiB
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
- Mỗi adapter chỉ giao tiếp với một dịch vụ bên ngoài
- Xử lý lỗi phù hợp và mapping sang domain errors
- Cung cấp logging và metrics cho mỗi adapter
- Retry mechanisms cho các dịch vụ không ổn định
- Circuit breaking để tránh cascading failures
- Feature toggles để dễ dàng chuyển đổi giữa các provider