Skip to content

Latest commit

 

History

History
76 lines (58 loc) · 5.32 KB

File metadata and controls

76 lines (58 loc) · 5.32 KB

Проектирование API транзакционного слоя

Время выполнения

На выполнение задания отводится 2 часа:

  • Первый час — реализация основного решения задачи
  • Второй час — полировка и доведение кода до препродакшен состояния: тесты, дефекты, чистка кода (НЕ настройка CI/CD, автоматизации сборки или деплоя)
  • Важно: Не забудьте ответить на вопросы в конце задания.

Цель задания

Разработать backend-прототип на TypeScript с акцентом на проектирование и реализацию расширяемого и удобного API работы с транзакциями БД, используя Kysely. Важна не только корректность, но и архитектурная продуманность, масштабируемость при росте кодовой базы и читаемость.

Задачи:

  1. Создать макет TypeScript-приложения.
  • Можно использовать готовые шаблоны. Структура проекта и его организация должны отражать зрелый подход к проектированию backend-приложений. Предполагается, что в будущем кодовая база приложения значительно вырастет.
  • Реализовать два HTTP-эндпоинта:
    • Создание сообщения
    • Получение списка сообщений
  • При создании сообщения нужно также создавать запись в логах.
  1. Реализовать универсальную функцию withTransaction, которая:
  • При первом вызове — запускает новую БД транзакцию (выполняет переданную функцию fn внутри неё).
  • При повторном вызове в рамках уже начатой транзакции — переиспользует её.
  • Передает транзакцию автоматически между асинхронными вызовами.
  • Покрыта тестами.
  1. Продумать возможные расширения API, которые сделают его удобным и масштабируемым в большом TypeScript-проекте.
  • Внутри проекта основная бизнес-логика реализована через классы.
  • Методы классов вызывают друг друга, и не передают транзакцию явно.
  • Разработчики хотят оборачивать методы в транзакции "автоматически", без потери читаемости или предсказуемости поведения.
  • Если хватает времени, реализуйте придуманные расширения.

Пример возможного использования (упрощенный, API проектируете вы, важно предоставить хороший DX):

class MessageService {
  constructor(private logService: LogService) {}

  async createMessage(content: string) {
    return withTransaction(async (trx) => {
      await trx.insertInto('messages').values({ content }).execute()

      // вызываем LogService, он не знает о текущей транзакции напрямую
      await this.logService.log('Создано сообщение')
    })
  }
}

class LogService {
  async log(message: string) {
    return withTransaction(async (trx) => {
      await trx.insertInto('logs').values({ message }).execute()
    })
  }
}

Ожидаемые минимальные технологии

  • TypeScript
  • Kysely
  • Любой HTTP-сервер (Express, Fastify и др.)
  • Любая БД (SQLite, Postgres и т.п.)
  • Любая другая на ваш выбор.

Вопросы на которые стоит ответить в конце записи видео или во время выполнения задачи.

  • Сталкивались ли вы с подобным раньше? Напоминает ли что-то такой подход из других тех. стэков?
  • Как улучшить текущую реализацию проекта?

Требования к сдаче

  • Ссылка на репозиторий или архив с решением
  • Скринкаст с демонстрацией работы и объяснением решения (обязательно со звуком, проверьте доступ к видео перед отправкой)
  • В репозитории должны быть только файлы, относящиеся к решению (удалите лишние файлы и мусор)