Что такое паттерн Anti-Corruption Layer (ACL)?

Ответ

Паттерн Anti-Corruption Layer (ACL) — это архитектурный паттерн, который используется при интеграции двух или более систем с разными моделями данных или технологиями. ACL выступает в роли изолирующего слоя-переводчика между ними.

Основная задача — защитить модель данных новой (или основной) системы от влияния и "загрязнения" со стороны устаревшей (legacy) или внешней системы. ACL преобразует данные из формата одной системы в формат, понятный другой.

Ключевые компоненты ACL:

  • Адаптер (Adapter): Получает данные из внешней системы.
  • Транслятор (Translator): Преобразует модели данных.
  • Фасад (Facade): Предоставляет упрощенный и понятный интерфейс для основной системы.

Пример на Go:

Представим, что наша новая система работает с пользователями (User), а legacy-система отдает их в другом формате (LegacyUser).

package main

import "strconv"

// Модель данных в legacy-системе
type LegacyUser struct {
    UserID   int
    FullName string
    IsActive bool
}

// Модель данных в нашей новой системе
type User struct {
    ID     string
    Name   string
    Status string
}

// ACL: Слой-адаптер для преобразования данных

// Интерфейс для нашей системы
type UserRepository interface {
    FindByID(id string) (User, error)
}

// Реализация, которая ходит в legacy-систему через ACL
type LegacyUserAdapter struct {
    // здесь может быть клиент для legacy API
}

// Функция-транслятор внутри ACL
func (a *LegacyUserAdapter) translate(legacyUser LegacyUser) User {
    status := "inactive"
    if legacyUser.IsActive {
        status = "active"
    }
    return User{
        ID:     strconv.Itoa(legacyUser.UserID),
        Name:   legacyUser.FullName,
        Status: status,
    }
}

// Метод, который будет вызываться нашей системой
func (a *LegacyUserAdapter) FindByID(id string) (User, error) {
    // 1. Сходить в legacy-систему за данными (симуляция)
    legacyID, _ := strconv.Atoi(id)
    legacyUser := LegacyUser{UserID: legacyID, FullName: "John Doe", IsActive: true}

    // 2. Преобразовать данные с помощью транслятора
    user := a.translate(legacyUser)
    return user, nil
}

Преимущества:

  • Изоляция: Новая система не зависит от сложностей и странностей legacy-кода.
  • Независимое развитие: Команды могут работать над своими системами параллельно.
  • Чистая доменная модель: Модель данных основной системы остается чистой и неискаженной.
  • Упрощение рефакторинга: Позволяет постепенно заменять устаревшую систему, не ломая всё сразу.