Оптимизация алгоритма изменения порядка элементов в системе курсов

Рассмотрим задачу управления порядком отображения элементов (например, модулей) внутри курса. Имеется сущность курс (course), связанная отношением OneToMany с сущностью модуль (module). У каждого модуля есть поле order (порядок), которое определяет его позицию в списке. Значение этого поля начинается с 1. При создании нового модуля ему автоматически присваивается значение MAX(order) + 1. При удалении модуля все элементы, следующие за ним, смещаются на одну позицию вверх (их порядковые номера уменьшаются на 1).

Постановка задачи

Предположим, существует курс с ID=1, содержащий модули с порядковыми номерами 1, 2, 3, 4. Система получает запрос на изменение порядка конкретного модуля. Например:

  • Запрос 1: { moduleId: 2, newOrder: 3 }
    Ожидаемый результат: модуль с ID=2 получает порядок 3, а модуль, который был на позиции 3 (с порядком 3), смещается на позицию 2.
  • Запрос 2: { moduleId: 2, newOrder: 4 }
    Ожидаемый результат: модуль с ID=2 получает порядок 4, а модули с порядками 3 и 4 смещаются на позиции 2 и 3 соответственно.

Критерии решения

Требуется разработать логику, которая будет соответствовать следующим критериям:

  1. Экономичность по запросам к БД: минимизировать количество операций обновления.
  2. Оптимизированность: алгоритм должен быть эффективным по времени выполнения.
  3. Устранение ошибок конкурентного доступа (race condition): необходимо предусмотреть ситуацию, когда несколько запросов (например, создание нового модуля и изменение порядка) выполняются одновременно. Решением может быть использование транзакций с подходящим уровнем изоляции или блокировок (например, SELECT ... FOR UPDATE).
  4. Расширяемость архитектуры: как корректно организовать систему, если внутри курса могут находиться не только модули, но и другие сущности (например, тесты), у которых также должен быть свой порядок отображения?

Проблемы текущей реализации и возможные пути

В текущей реализации используются два независимых отношения OneToMany от курса к модулям и тестам. Это приводит к следующим сложностям:

  • Смешение порядков: Порядковые номера назначаются в рамках каждой отдельной таблицы, что неудобно для обработки, если требуется единая последовательность элементов разного типа.
  • Нарушение целостности: В системе уже возникали ситуации, когда появлялись объекты с одинаковыми порядковыми номерами или порядки "слетали".

Архитектурное предложение: Для решения проблемы расширяемости можно создать единую абстрактную сущность (например, CourseItem), которая будет представлять любой элемент внутри курса. Эта сущность будет содержать:

  • Ссылку на курс.
  • Поле type (например, module, test), определяющее тип элемента.
  • Поле order для порядка сортировки в рамках конкретного курса.
  • Ссылку на конкретные данные (через внешний ключ или полиморфную связь).

Это позволит управлять порядком всех элементов курса в рамках одной таблицы и одной логики, исключив смешение и дублирование порядков.

Запрос на рекомендации

Существуют ли общепринятые паттерны или лучшие практики (must-have) для реализации подобной функциональности изменения порядка с учетом конкурентности? Буду благодарен за рекомендации в виде описания алгоритма, псевдокода или концепции. Готов рассмотреть решение как на уровне кода, так и на уровне архитектуры базы данных.