Как расширять библиотеку валидации для добавления новых правил
Что проверяют
Умеете ли вы спроектировать API так, чтобы новое правило добавлялось без правки библиотеки, в том числе снаружи, в коде команды-клиента. Следом спрашивают, как вернуть причину ошибки и как сделать асинхронную проверку, например уникальность логина на сервере.
Как отвечать
Основа это протокол, а не перечисление правил. enum с кейсами закрыт: снаружи новое правило не добавить, а новый кейс ломает switch у всех пользователей библиотеки.
- протокол правила:
protocol ValidationRule<Value>сassociatedtype Valueи методомvalidate(_:) -> ValidationResult. Первичный ассоциированный тип (Swift 5.7) позволяет хранить правила как[any ValidationRule<String>]; - результат, а не Bool:
ValidationResultс кейсом.invalid(reason), где причина это ваш тип ошибки сLocalizedError, чтобы экран показал текст на языке пользователя; - короткий синтаксис: статические фабрики в расширении протокола с ограничением
where Self == MinLengthRule, тогда в generic-контексте вызов выглядит как.minLength(8). Клиент добавляет своё правило тем же способом, в своём модуле; - композиция:
Validatorсобирает правила и умеет останавливаться на первой ошибке или собирать все. Комбинаторыand,or,notстроятся из существующих правил, для декларативного описания подходит@resultBuilder; - асинхронные правила: отдельный протокол с
async-методом. В Swift 6 правила должны бытьSendable, иначе строгая проверка конкурентности не пропустит их между акторами; - тесты: каждое правило тестируется изолированно на граничных значениях, а библиотека может поставлять общий набор тестов, который клиент прогонит для своего правила.
Где спотыкаются
Возвращают Bool. Потом приходится дописывать отдельный механизм сообщений, и API ломается.
Делают правила наследниками общего базового класса. Вместо протокола получается иерархия, и изменение базового класса задевает все правила разом.
Забывают про правила, зависящие от нескольких полей, например подтверждение пароля. Если правило видит только одно значение, такой сценарий не выразить, нужен уровень валидации всей формы.