Устройство сервисов

Все backend сервисы однообразны:

  • именуются как tt_*;

  • устанавливаются и запускаются под собственным пользователем;

  • подключаются к отдельной базе;

  • общаются по API, описанному с помощью protocol buffers 3;

  • используют одинаковую структуру файлов исходного кода;

  • используют Django миграции для изменения схемы и данных в базе.

Сервисы, по возможности, не привязываются к логике игры и делаются реиспользуемыми.

Зависимости

Каждый сервис зависит от следующих компонентов:

  • tt_web - общий минифреймворк

  • tt_protocol - описание структур данных api в формате protocol buffers

Структура файлов

├── MANIFEST.in                # включаемые в Python пакет файлы
├── setup.py                   # описание Python пакета
├── tt_service                 # исходный код сервиса
│   ├── migrations             # Django миграции
│   ├── fixtures               # дополнительные данные для сервиса
│   ├── handlers.py            # обработчики HTTP API
│   ├── models.py              # модели Django
│   ├── objects.py             # внутренние структур данных
│   ├── logic.py               # внутренняя логики
│   ├── operations.py          # операции с базой данных и другими внешними сервисами
│   ├── protobuf.py            # конвертация из/в структур данных protocol buffers во внутренние структуры данных
│   ├── relations.py           # перечисления (enums)
│   ├── service.py             # код запуска сервиса
│   ├── settings.py            # настройки Django
│   ├── conf.py                # константы и прочие параметры
│   └── tests                  # тесты
│       ├── fixtures           # дополнительные данные для тестов
│       │   └── config.json    # конфигурация сервиса для тестов
│       ├── helpers.py         # вспомогательный код
│       └── test_something.py  # тесты

Если в одном из файлов образуется слишком много кода (например, в operations.py) он преобразуется в подмодуль (operations/…).

Архитектура

Код сервиса можно разделить на несколько слоёв:

  • интерфейс HTTP API: разбор запроса, проверка параметров, инициирование операции;

  • внутренняя логика: операции над внутренними структурами данных, без обращения к любым внешним сущностям;

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

Каждый из файлов, описанных ранее, можно явно отнести к одной из частей.

Тестирование

Весь код сервиса должен быть покрыть тестами (в отличии от кода сайта игры, который не всегда можно разумными усилиями качественно проверить).

Для каждой сущности (кроме тривиальных) внутренней и внешней логики пишутся тесты на каждый вариант поведения.

Код обработчиков HTTP API покрывается тестами:

  • для проверки верификации и преобразования данных (из запроса во внутренний формат и из них в формат ответа);

  • для проверки всей последовательности операций.

Покрывать тестами каждый вариант поведения обработчиков HTTP API не надо, так как в них не реализуется логика. Мы считаем, что логику проверяют тесты логики.