Найти в Дзене

Golang + транзакции, что и куда передавать | Repository и Unit of Work

Вот раньше хорошо было, один монолит, одна БД. Транзациями рулит база данных реализуя ACID, тебе только важно не забывать транзакцию в коде передавать к вызову SQL. А сейчас, в эпоху микросервисов вызовы к бд чередуются с обращением к внешнему API, а внешнему апи всё равно какая там у тебя транзакция в бд. И вот чтобы это всё хорошо организовать в коде, разделить по слоям, не перемешивать вызовы SQL и HTTP существуют паттерны Repository и Unit of Work. Без них красиво построить 2PC и Саги не получиться (Если интересно почему, жду вопрос в комментарии). Примеры будут на моей любимой гошке Паттерн Repository (репозиторий) — это архитектурный паттерн, который предоставляет абстракцию для доступа к данным. Он отделяет логику работы с данными от бизнес-логики приложения, что упрощает тестирование и поддержку кода. Основные идеи паттерна Repository: Короче простыми словами - не должно быть в слое репозитория бизнес-логики! Сделали круды на таблицы - норм вообще, дальше просто на уровне серв
Оглавление

Вот раньше хорошо было, один монолит, одна БД. Транзациями рулит база данных реализуя ACID, тебе только важно не забывать транзакцию в коде передавать к вызову SQL. А сейчас, в эпоху микросервисов вызовы к бд чередуются с обращением к внешнему API, а внешнему апи всё равно какая там у тебя транзакция в бд.

И вот чтобы это всё хорошо организовать в коде, разделить по слоям, не перемешивать вызовы SQL и HTTP существуют паттерны Repository и Unit of Work. Без них красиво построить 2PC и Саги не получиться (Если интересно почему, жду вопрос в комментарии).

Примеры будут на моей любимой гошке

Паттерн Repository

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

Основные идеи паттерна Repository:

  1. Абстракция доступа к данным: Репозиторий предоставляет интерфейс для выполнения операций с данными, таких как создание, чтение, обновление и удаление (CRUD). Это скрывает детали реализации, такие как SQL-запросы или взаимодействие с ORM.
  2. Инкапсуляция логики запросов: Репозиторий инкапсулирует логику построения запросов к базе данных, что позволяет избежать дублирования кода и упрощает его изменение.
  3. Упрощение тестирования: Благодаря абстракции доступа к данным, можно легко подменять реализацию репозитория на заглушки или моки, что упрощает написание модульных тестов.

Короче простыми словами - не должно быть в слое репозитория бизнес-логики! Сделали круды на таблицы - норм вообще, дальше просто на уровне сервиса будете объединять обращения к таблицам.

Пример использования паттерна Repository на языке Go:

-2

Как правильно описывать методы для Репозитория

При проектировании методов для репозитория важно соблюдать баланс между универсальностью и специфичностью. Вот несколько рекомендаций:

  1. Избегайте слишком узконаправленных функций: Например, функции, которые выполняют очень специфичные задачи, могут привести к избыточности кода. Вместо этого старайтесь делать функции более универсальными.
  2. Избегайте сложной бизнес-логики в репозитории: Репозиторий должен быть простым и не содержать сложной бизнес-логики. Это делает код более управляемым и тестируемым.
  3. Управление транзакциями: Репозиторий не должен управлять транзакциями напрямую. Это задача Unit of Work, который координирует работу нескольких репозиториев.
  4. Связь полей SQL и сущностей приложения: Используйте метки для полей структур, чтобы связать их с полями в базе данных. Это упрощает создание запросов и внесение изменений.
  5. Заполнение полей сущности: Избегайте заполнения полей сущности внутри методов репозитория. Это может привести к размытию ответственности между слоями.

Паттерн Unit of Work

Unit of Work (единица работы) — это паттерн, который управляет транзакциями и координирует изменения, которые должны быть сохранены в базе данных. Он отслеживает изменения в объектах и гарантирует, что все изменения будут применены в рамках одной транзакции.

Основные идеи паттерна Unit of Work:

  1. Управление транзакциями: Unit of Work координирует работу нескольких репозиториев и управляет транзакциями.
  2. Отслеживание изменений: Он отслеживает изменения в объектах и гарантирует, что только измененные объекты будут сохранены.
  3. Тестируемость: Обеспечивает единый интерфейс для управления транзакциями, что упрощает тестирование.

Короче простыми словами - создаёшь и управляешь ты транзакцией не на уровне репозитория, а на уровне сервиса. Так ты сможешь вызвать CRUD запросы к БД передавая туда транзацию, а также делать http вызовы. За счет того что это всё будет на уровне сервиса - бизнес логика будет только там, код будет отгранизован хорошо

Пример использования Unit of Work:

-3

Заключение

Заключение я хочу сделать в формате диалога, чтобы точно была понятна суть статьи

Ты: Ну что, как ты думаешь, как эти паттерны Repository и Unit of Work помогают в разработке?

Я: О, это как когда ты строишь дом. Repository — это как фундамент, который отделяет работу с кирпичами и бетоном от всей архитектуры дома. Он скрывает сложности работы с базой данных, так что ты можешь сосредоточиться на том, чтобы дом был красивым и функциональным.

Ты: Интересно! А Unit of Work?

Я: Unit of Work — это как главный строитель, который координирует все работы. Он следит за тем, чтобы все изменения в доме были сделаны правильно и в одной транзакции. Если что-то пошло не так, он может откатить изменения, чтобы все осталось в порядке.

Ты: Звучит удобно! Так что же это значит для нашей разработки?

Я: Это значит, что мы можем строить сложные системы, как микросервисы, без хаоса. Repository упрощает работу с данными, а Unit of Work управляет транзакциями. В итоге, код становится чище, легче тестировать и поддерживать. И это особенно важно, когда у нас есть много разных сервисов и баз данных.

Ты: Понятно! Спасибо за объяснение!

Давай заключим сделку, я продолжаю писать - ты подписываешься на мою телегу https://t.me/timofey_yakunin. Win-Win подход.