Мы все видели и использовали поля типа boolean
в базах данных как часть структуры данных.
На первый взгляд это удобно: два значения — «да» или «нет», просто и понятно.
Например, у пользователя может быть флаг is_active
, который показывает, включён аккаунт или нет, или поле is_deleted
, которое используется как мягкое удаление. Такие поля встречаются повсюду.
Но на практике хранение boolean
в базе данных как элемента модели часто приводит к проблемам.
В этой статье разберёмся, почему boolean может быть плохим выбором, и что использовать вместо него, чтобы избежать ошибок в будущем.
Что такое boolean и для чего его используют
Boolean — это примитивный тип данных, у которого всего два значения: true
или false
. В программировании это одна из базовых концепций: на boolean
значениях строятся условия, branching
и логика выполнения кода.
Но по какой-то причине мы решили, что хранить boolean в структуре данных — это нормально. Ведь так удобно: добавил поле is_active
, и теперь легко писать запросы вроде:
SELECT * FROM users WHERE is_active = true;
Просто, быстро и кажется идеальным решением.
Но удобство здесь обманчиво: boolean хорошо решает задачу только на первый взгляд, а в долгосрочной перспективе может сильно ограничить модель данных.
Почему boolean не надо использовать как часть структуры
На первый взгляд boolean кажется идеальным инструментом для хранения состояния.
Но если посмотреть глубже, почти всегда он оборачивается проблемами при развитии проекта.
Давайте разберём это на примерах:
export interface User {
id: string;
email: string;
isDeleted: boolean;
}
На первый взгляд здесь нет ничего плохого: всего лишь простой флаг, который показывает, удалён ли пользователь.
Но именно здесь и кроется подвох.
Скорее всего в будущем нам понадобится не только знать, удалён ли пользователь, но и:
активен ли он сейчас;
был ли когда-то отключён;
существует ли просто как запись, но никогда не использовался;
может ли он войти в систему прямо сейчас.
Один флаг isDeleted
не отвечает на эти вопросы и не позволяет различать разные жизненные состояния пользователя.
Тогда как же правильно, спросите вы?
Мы хотим и можем сделать так:
export interface User {
id: string;
email: string;
status: "active" | "inactive" | "deleted";
}
Такой подход уже лучше, потому что у нас появляется несколько осмысленных состояний, а не просто «да/нет».
А можно пойти ещё дальше:
export interface User {
id: string;
email: string;
status: {
state: "active" | "inactive" | "deleted";
updatedAt: Date;
}
}
И это решение не просто избавляет нас от дублирования разных булевых флагов под каждый статус.
Оно даёт дополнительные преимущества:
Контроль и валидация состояний — нельзя случайно оказаться одновременно в
isDeleted = true
иisActive = true
. Есть одно поле, и оно всегда содержит валидное значение.Историчность (в расширенном варианте с
updatedAt
) — мы понимаем, когда именно изменилось состояние.Простая аналитика — легко посчитать, сколько пользователей сейчас «inactive», как часто они переходят в «locked» и т.д.
Таким образом, вместо разрозненных флагов у нас появляется цельная модель жизненного цикла пользователя.
Итоги
Этот пример, на мой взгляд, достаточно показателен.
Можно добавить, что использование boolean на старте проекта вполне приемлемо.
И здесь нам в помощь приходят принципы YAGNI («You Aren’t Gonna Need It») и RUG («Repeat Until Good»): не стоит усложнять модель раньше времени, если вам реально нужен только простой флаг.
Но важно помнить: проект развивается, и вместе с ним эволюционируют данные.
Как разработчики, мы должны смотреть чуть дальше «сегодняшнего удобства».
Мы всегда стремимся к единообразию в проекте — будь то стиль кода, архитектурные подходы или правила работы с данными.
Именно структура данных является фундаментом, который задаёт тон всей системе: от неё зависит не только то, насколько легко будет развивать проект завтра, но и то, как сами разработчики будут о нём мыслить.
Хорошо спроектированная модель данных формирует правильное мышление и привычки.
Плохая же — заставляет придумывать хаки, вводит двусмысленности и тормозит развитие.
В итоге правили простые:
Чем меньше boolean
-флагов мы храним в структуре данных — тем лучше.
А в идеале от них стоит вовсе отказаться.
Вместо boolean
-полей:
используйте enums или явные статусы, если существует вероятность эволюции состояния;
используйте timestamp, если важно знать не только факт («да/нет»), но и момент времени. Это особенно полезно для аналитики и отладки.
Такой подход позволяет построить модель данных, которая не ломается при развитии системы, проще валидируется и помогает разработчикам мыслить о бизнес-логике правильно.