mnemo_cards/mnemo_cards_backend/docs/SHOULD_EXTRACT_DATABASE.md
2026-01-03 16:14:27 +03:00

11 KiB
Raw Blame History

📦 Стоит ли выносить Database (Drift + DAO) в отдельный пакет?

🤔 Краткий ответ

Для текущего проекта: НЕТ, выносить не нужно.

Но давайте разберем, когда это имеет смысл, а когда нет.


Когда выносить имеет смысл

1. Множественное использование в разных проектах

Если database используется в нескольких независимых проектах:

mnemo_cards_database/        ← Отдельный пакет
  ├── lib/
  │   ├── database.dart
  │   ├── tables/
  │   └── daos/
  └── pubspec.yaml

mnemo_cards_backend/         ← Использует database
  └── pubspec.yaml
    dependencies:
      mnemo_cards_database:
        path: ../mnemo_cards_database

mnemo_cards_admin_tool/      ← Тоже использует database
  └── pubspec.yaml
    dependencies:
      mnemo_cards_database:
        path: ../mnemo_cards_database

mnemo_cards_analytics/       ← И это тоже
  └── pubspec.yaml
    dependencies:
      mnemo_cards_database:
        path: ../mnemo_cards_database

Плюсы:

  • Переиспользование в нескольких проектах
  • Централизованное управление схемой БД
  • Общие миграции для всех проектов
  • Избежание дублирования кода

Когда это нужно:

  • У вас несколько backend сервисов (микросервисы)
  • Есть отдельные инструменты (admin panel, analytics, migration tools)
  • Разные команды работают с одной БД

2. Публикация как библиотека

Если вы хотите опубликовать database layer как отдельную библиотеку:

# mnemo_cards_database/pubspec.yaml
name: mnemo_cards_database
version: 1.0.0
publish_to: pub.dev  # Публикуется для всех

Плюсы:

  • Можно использовать в других проектах
  • Версионирование отдельно от backend
  • Переиспользование в открытых проектах

3. Тестирование изолированно

Если нужно тестировать database layer отдельно:

mnemo_cards_database/
  ├── lib/
  └── test/
      └── database_test.dart  # Тесты только для database

mnemo_cards_backend/
  └── test/
      └── integration_test.dart  # Интеграционные тесты

Плюсы:

  • Изолированное тестирование database layer
  • Можно тестировать без запуска всего backend

Но: Обычно этого можно достичь и без вынесения в отдельный пакет.


Когда выносить НЕ нужно (ваш случай)

1. Один проект использует database

Текущая ситуация:

mnemo_cards_backend/
  ├── lib/
  │   ├── database/          ← Используется ТОЛЬКО здесь
  │   │   ├── database.dart
  │   │   ├── tables/
  │   │   └── daos/
  │   ├── api/               ← Использует database
  │   ├── user/              ← Использует database
  │   └── packs/             ← Использует database
  └── pubspec.yaml

Почему не нужно выносить:

  • Нет переиспользования (только один потребитель)
  • Усложняет структуру проекта без выгоды
  • Больше файлов для навигации
  • Дополнительные настройки pubspec.yaml
  • Усложняет рефакторинг (нужно менять два пакета)

2. Тесная связанность с бизнес-логикой

В вашем проекте database тесно связана с backend:

// database используется ВЕЗДЕ в backend
lib/api/v2/users_api_v2.dart        database
lib/user/user_manager.dart          database
lib/packs/pack_manager.dart         database
lib/api/purchase/payment_manager.dart  database
lib/cron/*.dart                     database

Проблемы при выносе:

  1. Циклические зависимости:

    mnemo_cards_database/
      └── нужно что-то из mnemo_cards_backend (конвертеры, хелперы)
    
    mnemo_cards_backend/
      └── зависит от mnemo_cards_database
    
  2. Конвертеры и extensions:

    // Где должны быть эти extensions?
    extension UserToUserModel on User { ... }  // В database или backend?
    extension CardPackToCardPackModel on CardPack { ... }
    
  3. Зависимости:

    // database.dart использует converters.dart
    // converters.dart может использовать что-то из backend
    

3. Database специфична для backend

В вашем проекте:

  • Database структура создана специально для backend логики
  • Таблицы отражают бизнес-логику backend
  • DAO методы оптимизированы под нужды backend
  • Нет планов использовать в других проектах

Если database специфична для одного проекта - выносить не стоит.


📊 Сравнение: Ваш проект vs Когда нужно выносить

Критерий Ваш проект Когда нужно выносить
Количество потребителей 1 (только backend) 3+ проекта
Микросервисы Нет Да, несколько сервисов
Общая БД Одна БД для backend Одна БД для многих сервисов
Переиспользование Нет Да, используется в разных местах
Независимая разработка Нет Да, разные команды
Версионирование Одно с backend Отдельное версионирование

🎯 Альтернативы вынесению

1. Модульная структура внутри проекта

Вместо отдельного пакета, используйте модульную структуру:

mnemo_cards_backend/
  ├── lib/
  │   ├── database/           ← Database модуль (НЕ отдельный пакет)
  │   │   ├── database.dart
  │   │   ├── tables/
  │   │   └── daos/
  │   ├── api/                ← API модуль
  │   ├── user/               ← User модуль
  │   └── packs/              ← Packs модуль

Плюсы:

  • Четкое разделение ответственности
  • Легко навигироваться
  • Нет проблем с зависимостями
  • Можно вынести позже, если понадобится

2. Barrel exports для изоляции

Создайте единую точку входа для database:

// lib/database/database.dart
export 'database_impl.dart';
export 'daos/user_dao.dart';
export 'daos/pack_dao.dart';
// ...

// Использование:
import 'package:mnemo_cards_backend/database/database.dart';

Плюсы:

  • Чистые импорты
  • Легко рефакторить (меняем только один файл)
  • Можно вынести позже (меняем только exports)

🔮 Когда стоит пересмотреть решение

Если появятся:

  1. Второй backend сервис:

    mnemo_cards_backend_api/      ← Основной API
    mnemo_cards_backend_admin/    ← Admin API
    

    → Тогда имеет смысл вынести общую database

  2. Отдельные инструменты:

    mnemo_cards_migration_tool/   ← Миграции
    mnemo_cards_analytics/        ← Аналитика
    

    → Тогда имеет смысл вынести database

  3. Публикация как библиотека:

    • Если планируется публикация на pub.dev → Тогда нужно вынести в отдельный пакет

💡 Рекомендации для вашего проекта

Что делать СЕЙЧАС:

  1. Оставить database внутри backend:

    mnemo_cards_backend/
      └── lib/
          └── database/  ← Остается здесь
    
  2. Использовать модульную структуру:

    • Четко разделять database, api, user, packs модули
    • Использовать barrel exports для чистоты импортов
  3. Документировать архитектуру:

    • Описать модульную структуру
    • Объяснить, когда и как выносить в отдельный пакет

Что НЕ делать:

  1. Не выносить database в отдельный пакет без необходимости
  2. Не усложнять структуру без реальной выгоды
  3. Не создавать лишние абстракции

📝 Вывод

Для вашего проекта: НЕ ВЫНОСИТЬ

Причины:

  1. Database используется только в одном проекте (backend)
  2. Тесная связанность с бизнес-логикой backend
  3. Нет планов на переиспользование
  4. Вынос усложнит структуру без выгоды

Когда пересмотреть решение:

  1. 🔄 Появится второй сервис, использующий ту же БД
  2. 🔄 Появится отдельный инструмент (admin, analytics)
  3. 🔄 Планируется публикация database как библиотеки
  4. 🔄 Разные команды будут работать с database независимо

Альтернатива:

Используйте модульную структуру внутри проекта:

  • Четкое разделение модулей
  • Barrel exports для изоляции
  • Легко вынести позже, если понадобится

Итог: Ваша текущая структура правильная для проекта с одним backend. Выносить database в отдельный пакет стоит только когда появится реальная необходимость (несколько потребителей, переиспользование).