Статические и динамические suite

В архитектуре Vest ключевым строительным блоком является suite — набор правил валидации, объединённых в единый декларативный блок. Статический suite формируется один раз при объявлении и не зависит от внешних параметров выполнения. Его структура фиксирована и заранее известна до момента запуска валидации.

Статический suite характеризуется тем, что:

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

Типичный пример статического suite:

import { create, test, enforce } from 'vest';

const suite = create((data = {}) => {
  test('username', 'Имя пользователя обязательно', () => {
    enforce(data.username).isNotEmpty();
  });

  test('email', 'Некорректный email', () => {
    enforce(data.email).matches(/^[^\s@]+@[^\s@]+\.[^\s@]+$/);
  });
});

В этом примере структура проверки полностью фиксирована: всегда проверяются username и email, независимо от входных данных или внешнего состояния.

Статические suite особенно эффективны в сценариях:

  • формы с неизменным набором полей;
  • бизнес-логика с фиксированными правилами;
  • серверная валидация с предсказуемой структурой;
  • библиотеки и компоненты, где требуется стабильное поведение.

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


Динамические suite

Динамический suite представляет собой функцию, которая генерирует набор проверок в зависимости от входных параметров, состояния или контекста выполнения. В отличие от статического подхода, структура валидации формируется во время выполнения.

Основная идея динамического suite заключается в том, что набор test вызовов не фиксирован заранее, а зависит от условий.

Характерные признаки:

  • состав проверок определяется входными данными;
  • возможны условные блоки и ветвления;
  • структура может изменяться от вызова к вызову;
  • поддерживается адаптивная валидация.

Пример динамического suite:

import { create, test, enforce } from 'vest';

const suite = create((data = {}) => {
  test('username', 'Имя пользователя обязательно', () => {
    enforce(data.username).isNotEmpty();
  });

  if (data.type === 'business') {
    test('companyName', 'Название компании обязательно', () => {
      enforce(data.companyName).isNotEmpty();
    });
  }

  if (data.age < 18) {
    test('parentEmail', 'Требуется email родителя', () => {
      enforce(data.parentEmail).isNotEmpty();
    });
  }
});

В этом случае набор проверок зависит от значения type и age. Таким образом, suite становится адаптивным и формирует различные сценарии валидации без необходимости создания отдельных функций.

Динамические suite применяются в случаях:

  • формы с условными полями;
  • многошаговые сценарии ввода данных;
  • сложная бизнес-логика с ветвлением правил;
  • системы, где структура данных изменяется в зависимости от контекста пользователя.

Сравнение статических и динамических suite

Различие между подходами заключается не только в структуре, но и в модели исполнения.

Статические suite:

  • фиксированная структура;
  • предсказуемое поведение;
  • более высокая оптимизация исполнения;
  • проще анализировать и тестировать.

Динамические suite:

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

С точки зрения внутренней работы Vest, статические suite проще кэшировать и переиспользовать. Динамические требуют повторной оценки структуры при каждом вызове, поскольку условия могут изменять набор тестов.


Условная генерация тестов внутри suite

Одним из ключевых механизмов динамических suite является использование условий внутри тела функции. Это позволяет включать или исключать проверки без изменения общей структуры API.

Пример условной генерации:

const suite = create((data = {}) => {
  const isAdmin = data.role === 'admin';

  test('username', 'Обязательное поле', () => {
    enforce(data.username).isNotEmpty();
  });

  if (isAdmin) {
    test('accessLevel', 'Уровень доступа обязателен для администратора', () => {
      enforce(data.accessLevel).greaterThan(0);
    });
  }
});

Такой подход позволяет локализовать бизнес-логику внутри одного suite, избегая разбиения на множество отдельных функций.


Композиция статических suite

Статические suite хорошо подходят для композиции. Поскольку их структура фиксирована, их можно безопасно объединять без риска изменения поведения.

Пример композиции:

const baseSuite = create((data) => {
  test('username', 'Обязательно', () => {
    enforce(data.username).isNotEmpty();
  });
});

const emailSuite = create((data) => {
  test('email', 'Некорректный email', () => {
    enforce(data.email).matches(/.+@.+\..+/);
  });
});

const combinedSuite = create((data) => {
  baseSuite(data);
  emailSuite(data);
});

Композиция позволяет формировать модульную архитектуру валидации, где каждая часть отвечает за свою область ответственности.


Композиция динамических suite

Динамические suite также могут быть композиционными, однако их поведение становится менее предсказуемым из-за условий внутри каждого блока.

const roleSuite = (data) => {
  if (data.role === 'manager') {
    test('teamSize', 'Укажите размер команды', () => {
      enforce(data.teamSize).greaterThan(0);
    });
  }
};

const suite = create((data) => {
  test('username', 'Обязательно', () => {
    enforce(data.username).isNotEmpty();
  });

  roleSuite(data);
});

Здесь композиция выполняется на уровне функций, а не на уровне заранее определённой структуры.


Производительность и модель исполнения

Статические suite выигрывают за счёт:

  • отсутствия ветвлений;
  • возможности оптимизации графа тестов;
  • стабильного порядка выполнения;
  • упрощённого кеширования результатов частичных проверок.

Динамические suite требуют:

  • повторного анализа условий;
  • построения структуры тестов при каждом вызове;
  • учёта возможных различий между вызовами.

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


Частичные вычисления и повторное использование

В системе Vest важную роль играет возможность повторного использования результатов валидации. Статические suite позволяют эффективнее реализовать частичное кеширование, поскольку структура тестов остаётся неизменной.

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


Практическая организация архитектуры suite

В реальных приложениях часто используется гибридный подход:

  • базовая структура оформляется как статический suite;
  • условные проверки добавляются динамически;
  • общие правила выделяются в переиспользуемые модули.

Пример гибридной структуры:

const baseSuite = (data) => {
  test('username', 'Обязательно', () => {
    enforce(data.username).isNotEmpty();
  });
};

const suite = create((data) => {
  baseSuite(data);

  if (data.mode === 'extended') {
    test('bio', 'Описание слишком короткое', () => {
      enforce(data.bio).longerThan(10);
    });
  }
});

Такой подход позволяет балансировать между предсказуемостью и гибкостью, сохраняя управляемость логики валидации.