Мапери, або як написати багато коду заради чистої архітетури

Однією зі спорних тем в Clean Architecture як на мене це мапери. Сьогодні ми подивимось чому вони необхідні(або ні). Та реалізуємо простий мапер.

Що це і для чого

Почнемо з далека. Clean Architecture пропонує розділяти наш додаток на різні шари. І ці шари повинні бути максимально незалежні один від одного. Настільки незалежні що мають різні сущності для одних і тих самих обєктів в різних шарах.

Тобто якщо в нас є два шари, перший data layer а другий service layer. То в кожного з них буде окремий об’єкт для роботи

interface IServiceUser {
  id: string;
  name: string;
}

interface IDataUser {
  _id: string;
  name: string;
}

І ось тут ми вже бачимо проблеми. Як бути якщо поля в різних шарах у об’єкта повинні бути різні. Наприклад ми хочемо щоб данні зберігались в іншому вигляді ніж ми з ними працюємо.

Мапери

Ось тут ми і зустрічаємось з концепцією маперів. Мапер - це клас який надає дві функції для трансформації з одної форми в іншу.

Ось як би виглядав мапер для наших інтерфейсів

class UserMapper {

  from(entity: IServiceUser): IDataUser {
    return {
      _id: entity.id,
      name: entity.name
    }
  }

  to(entity: IDataUser): IServiceUser {
    return {
      id: entity._id,
      name: entity.name
    }
  }

}

Ніби все просто? Так воно і є. Концепт не є дуже складним. Тепер ми можемо використовувати цей клас для того щоб не турбуватись і однією функцією перетворювати об’єкт в нужний інтерфейс

Які проблеми?

Перше, очевидно такий підхід змущує нас писати додатковий код. Якщо ми пишемо не величкий додаток то це достатньо вагомо. А також якщо ми розділяємо різними інтерфейсами кожен з шарів то в звичайному Clean Architecture додатку який має 3 шара, ми будемо мати 3 інтерфейса і 2 мапера…..

…які треба підтримувати. По друге, важкість підтримування. Вам потрібно завжди тримати в голові що якщо ви змінюєте якись з інтерфейсів вам потрібно перевірити коректність роботи маперів.

Так а нашо вони потрібні якщо стільки мінусів?

Складне питання. Питання чи варто вводити мапери доволі хитке і залежить від ситуації. Моя рекомендація: якщо можно уникнути маперів, їх треба уникати. Але якщо для вашого сервісу важливо не залежити від жодних змін зовні і зберігати незалежність то варто їх додати.

Хто повинен викликати мапери?

Мапери повинен викликати той сервіс який залежить від другого. Тобто якщо сервіс А залежить від сервісу Б, то на його відповідальності перетворити обєкти через мапер на прийнятні для сервісу Б і передати їх. А потім відповідь знов ж таки перетворити за допомогою маперів на прийнятні для себе

class A {

  constructor(private B: Service, private mapper: Mapper) {}

  func(user: IUser) {
    const dataUser = this.mapper.to(user)
    const resultUser = this.B.someFunction(dataUser)
    const serviceUser = this.mapper.from(resultUser)
  }

}

Висновки

Висновки як завжди прозаічні. Мапери це той достатньо простий концепт який можно використовувати для відділення сущностей різних шарів один від одного. Я би радив уникати їх використання коли це можливо. Але знати як їх використовувати корисно

Поділись своїми ідеями в новій публікації.
Ми чекаємо саме на твій довгочит!
Владислав Лєсной
Владислав Лєсной@unnsin

621Прочитань
4Автори
17Читачі
На Друкарні з 15 квітня

Більше від автора

  • Clear Architecture для бекенда на JS

    Кожен хто займається розробкою певний час приходить до слова архітектура. Сьогодні ми подивимось на одну з парадигм проектування архітектури через призму типового JS бекенду.

    Теми цього довгочиту:

    Clean Architecture
  • Паттерн “Репозиторій“ в JS

    В попередній статті ми розібрались з паттерном Специфікація Сьогодні ми поговоримо про логічне продовження паттерн репозиторій.

    Теми цього довгочиту:

    Js
  • Паттерн “Специфікація“ в JS чи потрібен він?

    Одним з найскладніших для мене був паттерн специфікація. Сьогодні я вам пояснити для чого він. І запропонувати свою версію реалізацію

    Теми цього довгочиту:

    Js

Вам також сподобається

  • NVM або чому у тебе має бути декілька версій NodeJS

    Одна і певно найвагоміша причина, чому вам потрібно мати декілька версій NodeJS — підтримка декількох проєктів. Розберемось, як встановити NVM та додати декілька версій NodeJS на твою робочу машину

    Теми цього довгочиту:

    Nodejs
  • λanguage: Як реалізувати мову програмування на JavaScript

    Це посібник з реалізації мови програмування. Якщо ви вже писали інтерпретатор, то, ймовірно, тут немає нічого нового для вас. Але якщо ви використовуєте регулярні вирази для "розбору" чогось, що схоже на мову програмування, прочитайте хоча б розділ про синтаксичний аналіз.

    Теми цього довгочиту:

    Мова Программування
  • λanguage: Написання парсера

    Написання парсера - це досить складне завдання. У сутності, він повинен перетворити фрагмент коду у "абстрактне синтаксичне дерево". Це структуроване представлення програми в пам'яті, воно абстрактне в тому сенсі, що не має значення, з яких саме символів складається вихідний код.

    Теми цього довгочиту:

    Парсер

Коментарі (3)

Цікаво, дякую!

dovgochyt request:

Що робити коли ти отримав об’єкт типу User і тепер хочеш цьому юзеру додати новий філд. Наприклад age:32

У юзера такого поля немає, але є інтерфейс умовно UserWIthAge;

Як з юзера зробити тепер UserWIthAge. Може я тупий, але я роблю щось типу:

Вам також сподобається

  • NVM або чому у тебе має бути декілька версій NodeJS

    Одна і певно найвагоміша причина, чому вам потрібно мати декілька версій NodeJS — підтримка декількох проєктів. Розберемось, як встановити NVM та додати декілька версій NodeJS на твою робочу машину

    Теми цього довгочиту:

    Nodejs
  • λanguage: Як реалізувати мову програмування на JavaScript

    Це посібник з реалізації мови програмування. Якщо ви вже писали інтерпретатор, то, ймовірно, тут немає нічого нового для вас. Але якщо ви використовуєте регулярні вирази для "розбору" чогось, що схоже на мову програмування, прочитайте хоча б розділ про синтаксичний аналіз.

    Теми цього довгочиту:

    Мова Программування
  • λanguage: Написання парсера

    Написання парсера - це досить складне завдання. У сутності, він повинен перетворити фрагмент коду у "абстрактне синтаксичне дерево". Це структуроване представлення програми в пам'яті, воно абстрактне в тому сенсі, що не має значення, з яких саме символів складається вихідний код.

    Теми цього довгочиту:

    Парсер