Всем привет, пикабушники! Наверно этот поток сознание уместнее смотрелся бы на хабре, но эта площадка мне нравится решительно больше. Хочу поделиться историей своего просветления. Я адепт старой школы, лет семь назад я писал на Java под Android и свято верил в святость enum'ов и священные ритуалы проверок if (state != null && state == STATE_LOADING && !error). Я не работаю программистом и разработка для меня - хобби. Некоторые крестиком шьют, а я вот буквы в код складываю. Так вот, писал я когда-то на Java и казалось, что я владею миром, пока не сел изучать Kotlin. Ну а что, синтаксис похож, лямбды есть — за неделю освоусь, думал я.
Сегодня я натыкаюсь на одну статью на mobilab про sealed class. Начинаю читать и чувствую, как мое самолюбие джависта начинает медленно и верно трещать по швам. Оказывается, я не просто писал код. Я строил хрупкие карточные домики из boolean-флагов и надеялся, что их не сдует ветром нового требования от продукт-менеджера. Раньше я жил в аду ловли состояний. Мой типичный код управления состоянием экрана аутентификации выглядел как памятник человеческой глупости:
var isLoading: Boolean = false
var errorMessage: String? = null
var isTwoFactorRequired: Boolean = false
var authToken: String? = null
И где-то в глубине onCreateView сидел монстр на 100 строк с вложенными if/else, который пытался угадать, что же сейчас нужно показать пользователю. Добавляем двухфакторку? Легко. Просто добавляем еще один флаг и на 20% увеличиваем энтропию этого блока. Уверен, вы знаете, чем это заканчивается: «Ой, а почему у нас при ошибке показывается индикатор загрузки?».
И теперь, когда я узнал про sealed class, мир перевернулся.
В статье показали, как эта проблема решается элегантно и с невозмутимым спокойствием. Вместо этого зоопарка флагов ты объявляешь одно понятное состояние:
sealed class AuthState {
object Idle : AuthState()
object Loading : AuthState()
data class Success(val token: String) : AuthState()
data class Error(val message: String) : AuthState()
data class TwoFactorRequired(val sessionId: String) : AuthState()
}
И как же это гениально просто. Состояние может быть только одно. Не может быть Success и Error одновременно. Компилятор физически не даст. Это как если бы раньше твоя машина могла быть одновременно и красной, и синей, а теперь ты просто выбираешь один цвет. И все.
Самое волшебное это when.
Когда в коде UI у тебя появляется when (state), компилятор Kotlin превращается в строгого, но заботливого наставника. Он тебя заставляет обработать все возможные варианты. Добавил TwoFactorRequired в sealed class? Поздравляю, проект не соберётся, пока ты не добавишь ветку для его отображения в этом самом when. Это не «ой, надо бы не забыть». Это «забудь и умри (в смысле, не запустишь приложение)». После лет надежд на свою память и на тестировщиков это ощущение будто тебе выдали бронежилет.
Теперь, когда я возвращаюсь к своему старому Java-коду, то смотрю на него с тихой грустью и мысленно прошу у него прощения. Kotlin с его sealed class — это не просто «более приятная Java». Это другой уровень мышления. Это переход от тактики «надеюсь, я ничего не упустил» к стратегии «я не могу это упустить по определению».
P.S. А самый большой кайф это писать unit-тест для такой логики. Подсовываешь Idle и действие Login, получаешь Loading. Подтверждаешь двухфакторку - получаешь Success. Красота, которая даже мне, закоренелому цинику, приносит эстетическое удовольствие.