Дневник разработки · День 7

Шестнадцать способов задать восемь вещей

Перерыв вышел длиной в понедельник.

Что сделано вчера? Там и считать нечего: ни одного коммита, ни одного открытого проекта.

А сегодня я вытащил себя за шиворот.

🎸 Весна объявляется досрочно

Я в этом месте уже был. Не в этом проекте — в жизни.

Семнадцать лет назад у меня развалились первые длинные отношения. Больше двух лет. Я дошёл до точки, где стало ясно: сделать я тут уже ничего не могу, и дальше мне будет хреново.

Такой момент ни с чем не спутаешь. Усилия бесполезны, и остаётся только прожить его — боль, зиму, всё это. А потом настанет весна, и жизнь потечёт каким-то новым чередом.

И ровно под это осознание меня ещё и уволили. В декабре.

Отличный расклад, чтобы лечь и не вставать до марта.

А потом я подумал вот что.

Весна сегодня не наступит. Но давайте представим, что я уже отныл эти пару месяцев. Что в сухом остатке?

В сухом остатке — второго января мне не надо на работу. Откуда-то взялось невменяемое количество свободного времени. И денег: зарплату выдали на месяц вперёд.

То есть на руках у меня оказался ресурс, которого не было много лет.

В тот год весна была объявлена двадцать седьмого декабря.

Накрывало ли меня после этого? Накрывало, врать не буду. Но именно тогда я купил свою первую гитару и провёл пару крайне неплохих месяцев.

Приблизить настоящую весну у меня, конечно, не вышло. Зато началась глава, которая иначе спокойно провисела бы до лета.

Здесь то же самое.

Задача большая, делать её сложно и некогда. Значит, берёмся за неё с самого удобного края и тянем — в сторону, противоположную той, где лежит заброшенный репозиторий.

Ту книжку я так и не дочитал. Но название работает.

Screw it, let's do it.

🗂 Канбан без тикетов

Системного подхода у меня не было — и, если честно, в этом половина причины, по которой я вчера встал из-за стола.

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

Поэтому стратегия на сегодня простая, и она не из книжки.

Встаю и начинаю переделывать то, что мне не нравится.

В случайном порядке. Без списка, без приоритетов, без оценок в часах.

Правило ровно одно: проблема должна быть либо решена, либо закрыта.

Закрыта — значит решена хоть как-нибудь, лишь бы перестала висеть. Вернусь к ней потом, когда уйдут те, что портят впечатление сильнее.

Обычный канбан, только без тикетов. Две колонки: «мне не нравится» и «чиним». Карточки — мои собственные раздражения.

К вечеру список выглядит так:

  • 🟡 вывеска — закрыта, не решена
  • ✅ блок при перетаскивании больше не дрожит
  • ✅ своя палитра вместо системной
  • ✅ три регрессии, которые она за собой притащила
  • ✅ настройки: одна панель вместо двух
  • ✅ новая шапка окна
  • 🟡 три ошибки в сейфе — закрыты, не решены

Пять галочек и два жёлтых. Жёлтое — это не «не успел». Это «решено ровно настолько, чтобы перестало висеть».

Перебирать весь список подряд смысла нет. Расскажу про то, что оказалось интереснее прочего, — и начну с того, что видно раньше всего.

🪧 Вывеска

Собрал. Запустил.

И в доке появился серый прямоугольник без картинки.

Иконки не было вообще. Ни одной, ни для одного размера — в проекте лежал пустой набор, и система подставляла в док стандартную пустышку.

Справедливости ради: у прототипа вывеска тоже заглушка. Два прямоугольника и курсор — ровно столько, чтобы док не пустовал.

Тащить её сюда смысла не было. Это вывеска не того дома.

Это довольно точная метафора всего, что происходило до сих пор.

Внутри — вкладки, сейфы, шифрование, зелёный прогон тестов. Снаружи — дом без вывески.

Сегодня вывеска появилась. Полный набор для Mac, все размеры, светлый и тёмный варианты.

Видеть в доке иконку собственного проекта — приятно, врать не буду.

Хочется только, чтобы там стояла не заглушка, а что-то осмысленное.

А она мне не нравится.

Я честно попробовал. Накидал вариантов, порисовал руками, перевёл в вектор. Всё бьёт не туда — это видно сразу, хотя объяснить, куда надо, я пока не могу.

Тратить на это день сегодня — плохая затея. Вывеска не мешает ничему из того, что внутри, а внутри ещё некуда войти.

Поэтому решение такое: берём нейтральное. Пусть просто будет.

Слева — вывеска прототипа, справа — то, что с сегодняшнего дня стоит в доке. Ниже — семь вариантов, которые не подошли.
Слева — вывеска прототипа, справа — то, что с сегодняшнего дня стоит в доке. Ниже — семь вариантов, которые не подошли.

И в ней есть ляп, который я уже не развижу.

У буквы «p» срезан хвост. Ровно и плоско, будто картинку обрезали по линейке и промахнулись на миллиметр.

Внутренний перфекционист от этого воет.

Хоть какая-то вывеска лучше, чем её отсутствие.

Пустая заглушка не раздражает — она никакая, её взгляд не цепляет. А эта будет попадаться мне на глаза при каждом запуске и каждый раз напоминать, что вопрос не закрыт.

Пусть бесит. Как напоминание это работает лучше, чем строчка в списке задач.

И отдельно — набор для iOS.

(Зачем iOS-иконка приложению для Mac, я сегодня объяснять не буду. В том числе себе.)

🪤 Блок, который мерил себя собой

А теперь лучший баг за всю историю проекта.

Холст масштабируется. Значит всё, что на нём лежит, нарисовано с коэффициентом — и координаты внутри него живут не в пикселях экрана, а в своих.

Блок, который тянут мышкой, считал своё новое положение относительно себя самого. Относительно собственной рамки — той, которая в этот момент уже поехала.

Получается петля.

Блок смещается. Рамка смещается вместе с ним. Следующее измерение берётся от уже смещённой рамки. Смещение вычитается из самого себя.

Снаружи это выглядит так: блок ползёт за курсором вдвое медленнее, чем надо, и дрожит.

Вдвое — потому что половину каждого движения он съедал сам.

Лечится переносом точки отсчёта: мерить не от своей рамки, а от неподвижного контейнера под холстом.

И мораль, которая мне тут нравится: предмет не может быть точкой отсчёта для собственного движения.

Ни на холсте, ни где-либо ещё.

🎨 Палитра, которая ломала соседей

У блока выбирается цвет. Рядом с готовыми кружками стоял системный выбор цвета — родной, от Apple, рисовать ничего не надо.

Он не работал. И не сам по себе — он ломал соседей.

Внутри у него нативный элемент, и одно его присутствие в ряду отключало нажатия всем остальным кружкам. Кружки рисовались. Кружки подсвечивались. Кружки не нажимались.

А когда системную палитру всё-таки удавалось открыть, она приезжала отдельным системным окном поверх нашего. А наше устроено так, что фокус не забирает — иначе оно перехватывало бы у вас работу каждый раз, когда вы им пользуетесь.

Два окна с разными представлениями о том, кто здесь главный.

Так приложение выглядело утром — и так выглядел выбор цвета. Чтобы покрасить одну карточку, приезжало системное окно поверх нашего. А пока оно стояло в ряду, соседние кружки переставали нажиматься.
Так приложение выглядело утром — и так выглядел выбор цвета. Чтобы покрасить одну карточку, приезжало системное окно поверх нашего. А пока оно стояло в ряду, соседние кружки переставали нажиматься.

Убрал. И дальше было то, что я люблю больше всего в этой работе: возня с вариантами.

Сначала получилась просто полоска нынешнего цвета прямо на блоке. Потом мы догадались сделать саму полоску выбиралкой — ткнул в неё, и цвет меняется там же, где ты его видишь.

Путь проб и ошибок до момента, когда результат перестаёт раздражать. Без попытки решить всё и навсегда: поле выбора цвета в настройках осталось кривоватым, и я в него сегодня не полез. Нет смысла лезть в дебри до того, как дойдёшь до полировки настроек.

И это первый раз, когда «взять родное» вышло дороже, чем сделать самому. Замороженное решение — только родные фреймворки, никаких сторонних библиотек — я при этом не нарушил. Полоска нарисована теми же родными средствами. Просто не готовым контролом.

Разница, которую я до сегодняшнего дня не различал.

🧹 Настройки без дна

А это моя собственная нерешённая задача, притащенная сюда из прототипа.

Там настройки лежали одним файлом на всё приложение. И меня давно напрягало, что у всех вкладок одинаковый фон: вкладки-то про разное, а выглядят одинаково. Как это правильно устроить, я не знал.

Здесь у меня наконец появилась возможность попробовать. Я попробовал.

Панелей настроек стало две. Настройки приложения и настройки вкладки.

В каждой — одни и те же восемь параметров внешнего вида. Глобально, и отдельно для каждой вкладки. И к каждому переопределению свой тумблер.

Восемь настроек, два места, восемь выключателей сверху.

Шестнадцать способов задать восемь вещей.

Вот от этого настройки и казались бездонными. Не от количества — количество как раз небольшое. От того, что каждая настройка лежала в двух местах, а между ними стоял переключатель, который решал, какое из двух сейчас правда.

Возможность настраивать давать надо. Только не превращая это в пульт от старого телевизора — тот, где кнопок столько, что не вспомнить, какая за что отвечает.

Я как раз собрал пульт.

Сегодня осталась одна панель, поделённая на две части: доска и приложение. Один контроль на одну настройку. Понятия «переопределить» в интерфейсе больше нет.

Я не добавил ни одной возможности. Я убрал один концепт.

Это уже второй раз. Первый был, когда я выкинул детектор столкновений и написал, что иногда правильная оптимизация — это удаление.

Слева — как было: те же восемь настроек в двух местах, и восемь переключателей, решающих, какое из двух сейчас правда. Справа — как стало.
Слева — как было: те же восемь настроек в двух местах, и восемь переключателей, решающих, какое из двух сейчас правда. Справа — как стало.

И второй раз это оказалось лучшим изменением дня.

🔌 Engineer honesty moment

Три ошибки в сейфе. И ни одну из них я не искал.

Сейф меня сегодня вообще мало заботил: я разбирал настройки, а он просто лежал по дороге. Хотелось убрать очевидное, не залезая внутрь. Всерьёз я его ещё не тестировал — вот когда сяду тестировать, тогда и захочется доделать.

Первая. Сервис сейфа не сообщал о себе наружу. Доску заперли — а экран об этом не узнал, и запертая доска продолжала показывать содержимое, пока что-нибудь постороннее не заставит её перерисоваться.

Третий случай подряд, если считать.

Сейф без шифрования. Тумблер, который ничего не переключает. Замок, который заперт, но выглядит открытым.

Вторая. Форма для пароля открывалась изнутри всплывающего окна. А macOS закрывает такие вместе с хозяином — то есть ровно посреди настройки пароля.

Третья, и самая неприятная. Вкладка переключалась в режим сейфа до того, как пароль вообще появлялся. Нажал «отмена» — и остался с доской, чей замок принимает любой ввод.

И вот что я про это думаю, раз уж день был про то, чтобы каждую проблему либо решить, либо закрыть.

Все три — закрыты. Ни одна не решена.

Я убрал то, что видно снаружи, и не трогал то, что под ним. Потому что сегодня я не проверял сейф — я мимо него шёл.

Так что список «мне не нравится» за сегодня не стал короче. Он просто стал честнее.

🎤 Между делом

Сегодня у меня была презентация. Не по этому проекту — по основной работе.

И чтобы под рукой лежало всё, что понадобится, я завёл себе ещё одну вкладку и накидал туда с десяток сниппетов.

Десяток строк, которые иначе пришлось бы держать в голове или искать ровно в тот момент, когда на тебя смотрят.

Когнитивная нагрузка упала сразу. Не «стало удобнее» — именно упала.

И вот здесь неловкий момент.

Выручил меня прототип. Тот самый, браузерный, из говна и палок.

А то, на что ушло двести часов, сегодня не выручило бы никого. В него до сих пор нельзя нормально положить текст.

Прототип пока лучше того, что я строю. По всем статьям.

И это, если смотреть трезво, нормально для этой стадии. Он старше, он прошёл два месяца ежедневного использования, и его правили руками. Здесь я руками не правлю ничего: всё идёт через прокси, и прокси зовут ИИ.

Но дело даже не в этом.

Прототип был табуреткой из говна и палок. Сколоченной за неделю, работающей, и мне её хватало.

А в эту идёт весь опыт человечества по металлургии и сопромату — чтобы табуретка, оставаясь табуреткой, была надёжной, безопасной и служила долго.

Ни подлокотников, ни подсветки, ни семнадцати регулировок. Одна вещь, которая делает одну вещь. Просто сделанная так, чтобы не сложиться под тем, кто на неё сядет.

Вот за это и платится разница.

То, что вчера выглядело перерасходом, — это не перерасход. Это цена.

Не обойти. Не оптимизировать. Принять.

И ровно поэтому бросать нельзя. Вещь, которая каждый день снимает с меня нагрузку, уже существует. Остался вопрос, доведу ли я её до состояния, в котором ею смогут пользоваться не только я.

А это вечер того же дня. Тот же блок, один ряд вместо двух — и своя полоска цвета вместо системного окна.
А это вечер того же дня. Тот же блок, один ряд вместо двух — и своя полоска цвета вместо системного окна.

Таков путь.

💬 Вопрос

Сколько ваших проектов дожили до состояния, в котором их не стыдно показать?

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

Так что вчерашнее «брошу или не брошу» — для меня не драма. Это штатная ситуация, и она случается со всеми, кто вообще что-нибудь начинает.

Вопрос не в том, как в неё не попадать. Вопрос в том, что делать, когда уже попал.

У меня сегодня ответ такой: взяться с самого удобного края и что-нибудь закрыть.

Расскажите, как у вас 👇

Следующим в списке — цена. Завтра сажусь за экран покупки.

Придумать её мне почему-то страшнее, чем написать 😉