В процессе написания программ мы часто сталкиваемся с данными, для которых допустим только ограниченный набор значений. Например, возраст, который не может быть отрицательным или email, который может иметь только определенный формат строки. При использовании примитивных типов (Int
, String
) приходится писать различные валидаторы, поскольку такие типы:
- могут представлять все что угодно
- могут содержать все что угодно
Тут еще можно упомянуть антипаттерн Primitive Obsession.
Если у нас есть некоторая функция, которая принимает в аргументы имя, email и возраст, описанные примитивными типами:
Пользователь или мы сами можем случайно передать ей некорректные значения.
Добавление валидации в самом примитивном виде может выглядеть как то так.
Теперь функция foo
делает не только то, для чего она действительно была создана, но еще и ответственна за то, чтобы в ней производилась валидация (тем самым нарушая первый принцип SOLID).
Может помогут псевдонимы типов (Type alias
)?
Псевдонимы типов не помогут, поскольку они так же продолжают представлять примитивные типы.
И компилятор не сможет сообщить, что мы допустили ошибку, случайно поменяв email
и name
местами.
А value class-ы?
Обернув примитивные типы в кейс-классы (тем самым создав спец. типы), мы не можем просто так взять и подсунуть Name
вместо Email
.
Но эти типы все еще могут принимать любые значения.
Используем refined (уточненные) типы
Refined - это небольшая библиотека для Scala, позволяющая описать тип с помощью предикатов, ограничивающих набор значений, который может принимать этот тип.
Для использования refined-типов необходимо подключить библиотеку refined добавив следующую строчку в build.sbt
И сделать импорт там, где будет выполняться json-преобразование.
Собственно, если json будет содержать некорректные значения, то мы в результате получим Either
с ошибкой декодирования (DecodingFailure
).
Неполный список доступных расширений для интеграции различных библиотек с refined-типами приведен в документации.
И кстати, преобразование примитивных типов в refined-типы в рантайме происходит примерно следующим способом.
Вместо заключения
Целью этого небольшого поста ставил обозначить проблему, для решения которой были созданы refined-типы и продемонстрировать некоторые возможности библиотеки.
Более подробно с примерами и списком предикатов можно ознакомиться в гитхабе проекта.