Я выпустил 102 версии macOS-приложения за два месяца. Это не продуктивность, я просто быстро ошибался

Я просто хотел, чтобы переключатель раскладки не воровал буфер обмена. Через два месяца у проекта было 102 релиза, у меня - два ИИ по $200 и новое понимание фразы «быстро войти в айти».

Из видеопроизводства обратно в IT. Потом всё слегка вышло из-под контроля.
Из видеопроизводства обратно в IT. Потом всё слегка вышло из-под контроля.

Вообще-то я не собирался выпускать 102 версии приложения за два месяца, строить вокруг него маленький зоопарк и отдавать по $200 в месяц двум разным искусственным интеллектам. Я просто хотел, чтобы одна программа на Mac исправляла ghbdtn на «привет» и при этом не рылась в буфере обмена грязными лапами.

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

Через два месяца в Keyboop было около 25 тысяч строк Swift, 102 опубликованные версии и журнал разработки на 8337 строк. Само приложение осталось бесплатным. Если вы сейчас подумали, что я нашёл какую-то удивительную схему сверхпродуктивности, не торопитесь: значительная часть релизов появилась потому, что предыдущий релиз очень хотел познакомиться со следующим.

Я просто хотел не ломать буфер обмена

Многие утилиты исправляют раскладку с помощью старого фокуса: кладут исправленный текст в буфер, вызывают вставку, а потом пытаются вернуть то, что лежало там раньше. На демонстрации всё красиво. В живой системе между «положить» и «вернуть» человек, менеджер буфера или другое приложение успевает скопировать что-нибудь новое, после чего автоматизация торжественно возвращает прошлое и затирает настоящее. Небольшая бытовая машина времени, только вместо динозавров у вас пропадает важная ссылка.

Я решил, что основной путь Keyboop вообще не будет трогать буфер: приложение удаляет неверно набранный фрагмент через Backspace и печатает исправленный текст напрямую. Для редких случаев, где без запасного механизма не обойтись, оно сначала проверяет, не менялся ли буфер; если менялся, отступает и не изображает хозяина компьютера.

Звучит как маленькая инженерная деталь, и таковой она оставалась примерно минут пятнадцать. Потом выяснилось, что разные приложения по-разному работают с выделением, событиями клавиатуры и доступностью, браузеры живут по своим законам, а у macOS на каждую очевидную вещь есть несколько API, два из которых устарели, один документирован наполовину, а последний просто смотрит на тебя и молчит.

Так 4 июня появился первый прототип Keyboop - бесплатного open-source приложения для macOS, которое исправляет неверную раскладку, умеет локально распознавать речь, хранить сниппеты и живёт в строке меню. Телеметрии в нём нет, поэтому приложение ничего не знает о людях, а я ничего не знаю о красивых продуктовых графиках. Пока это честный обмен.

Я выпустил 102 версии macOS-приложения за два месяца. Это не продуктивность, я просто быстро ошибался

Как оператора снова затянуло в IT

Тут, наверное, стоит объяснить, каким образом оператор, режиссёр и монтажёр вообще оказался ночью в Xcode и почему никто вовремя не отобрал у него клавиатуру.

У меня техническое образование по IT и ещё одно - по рекламе. Когда-то я увлёкся съёмкой, она меня очень сильно поглотила, и много лет я занимался видеопроизводством: снимал, режиссировал, монтировал. До этого жизнь успела занести меня в интернет-маркетинг и обувное производство, так что если собрать всё в одну строку, будет похоже, будто у резюме сломалась автосортировка.

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

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

До разработки я в основном смотрел на мир через камеру. Теперь чаще смотрю в Xcode - объектив хотя бы не просил $200 в месяц за токены. 
До разработки я в основном смотрел на мир через камеру. Теперь чаще смотрю в Xcode - объектив хотя бы не просил $200 в месяц за токены. 

В команде теперь трое. Платит по-прежнему один

Keyboop я начал писать вместе с Claude Code и прямо указал Claude соавтором кода в README. Он помогает разбирать системные фреймворки, читать логи, собирать тестовые стенды и предлагать решения; я формулирую задачу, задаю ограничения, проверяю поведение на живой системе и принимаю финальные решения. Иногда он уверенно предлагает ерунду, иногда я с не меньшей уверенностью её одобряю - в этом смысле командная культура сложилась удивительно быстро.

Потом мне стало мало одного инструмента, и рядом появился Codex. Теперь максимальный тариф Claude Code обходится примерно в $200 в месяц, ещё около $200 - Codex, плюс $99 в год стоит программа разработчика Apple и отдельно живёт сервер. Я настолько втянулся в разработку, исследования и проверку новых идей, что даже самых больших тарифов периодически не хватает. Очень приятное ощущение: раньше я покупал объективы, теперь покупаю токены, а спина болит почему-то всё равно.

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

Зато скорость, с которой можно проверить идею, стала почти опасной. Раньше между «а что, если» и рабочим прототипом оставалось время образумиться, сходить погулять и забыть затею. Теперь можно придумать функцию ночью, к утру получить сборку, а днём уже выяснить, почему человечеству было полезнее прожить без неё.

102 релиза - это не 102 приступа гениальности

Номера версий легко принять за медали: вот, смотрите, человек так быстро работает. На деле они скорее похожи на следы в снегу вокруг одного и того же места. Нашёл проблему, измерил, исправил, собрал приложение, подписал Developer ID, отправил на нотаризацию Apple, обновил канал Sparkle, проверил публичный код - и иногда через час понял, что круг надо пройти ещё раз.

Каждый из 102 релизов был настоящей сборкой, а не заменой цифры на сайте. Многие содержали небольшие исправления, несколько выходили в один день. Я не вижу смысла складывать их в один большой «идеальный» релиз раз в месяц, если человек уже сегодня упирается в конкретную проблему; с другой стороны, частые обновления отлично воспитывают скромность, потому что changelog хранит всю твою эволюцию от «кажется, готово» до «ладно, теперь точно кажется».

Чтобы не наступать на одни и те же грабли с азартом первооткрывателя, я веду журнал разработки. Сейчас в нём 8337 строк: причины решений, результаты измерений, удачные ходы и довольно большое кладбище красивых гипотез. Последние особенно ценны - без записей через неделю можно снова придумать ту же ерунду, дать ей новое имя и получить удовольствие от повторного знакомства.

Не 102 правки номера на сайте. Каждая точка означает отдельную подписанную и нотарифицированную сборку.
Не 102 правки номера на сайте. Каждая точка означает отдельную подписанную и нотарифицированную сборку.

Обновление, которое терпеливо ждало вечность

Самая ироничная поломка обнаружилась в механизме обновления. Люди писали, что новая версия вроде бы находится, но автоматически не устанавливается, и в итоге приложение приходится скачивать с сайта руками - прекрасная функция для программы, которая должна экономить лишние действия.

Keyboop использует Sparkle, стандартную библиотеку обновлений для macOS. В одном месте наш код сообщал ей: скачанную версию установим при выходе из приложения, дальше я сам. Sparkle вежливо соглашался, останавливал текущий цикл и ждал.

Проблема в том, что Keyboop живёт в строке меню, запускается вместе с системой и закрывать его обычно незачем. Получался идеальный тупик: обновление ждёт выхода, приложение не выходит, пользователь нажимает «Проверить сейчас», а кнопка находится внутри уже припаркованного цикла и демонстрирует очень здоровые личные границы.

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

Скачанное обновление ждало выхода из приложения. Приложение почти никто не закрывал.
Скачанное обновление ждало выхода из приложения. Приложение почти никто не закрывал.

Чуть раньше мы несколько недель пытались ускорить переключение раскладки клавишей Globe. Перебирали события, настройки и способы перехвата, успели создать несколько новых проблем, а потом выяснили, что паузу держит сама macOS: система ждёт, не станет ли нажатие началом комбинации или жеста диктовки. Мы ничего не ускорили, зато перестали оптимизировать чужую задержку своими багами - тоже, если подумать, результат.

Сначала друзья кивнули. Потом пришли 250 тысяч просмотров

Сначала я рассказал о Keyboop нескольким друзьям. Они отнеслись к этому без особого энтузиазма - примерно как друзья и должны относиться к очередному приложению знакомого, иначе через год им придётся тестировать умный чайник на блокчейне. Но понемногу начали пользоваться, втянулись и довольно быстро сказали, что теперь уже не представляют без него работу за компьютером.

Через месяц или полтора я решил снять короткий ролик для Instagram. Тут пригодилась старая профессия: если уж объяснять переключатель раскладки за несколько секунд, то хотя бы с нормальным светом. Ролик неожиданно посмотрели около 250 тысяч человек, под ним появились тысячи реакций и комментариев, а мне написало гораздо больше людей, чем я ожидал.

252 тысячи просмотров ролика и около 3 тысяч скачиваний Keyboop для macOS. Первое - охват, второе - уже ближе к потенциальным пользователям, но ни одно не равно числу активной аудитории.
252 тысячи просмотров ролика и около 3 тысяч скачиваний Keyboop для macOS. Первое - охват, второе - уже ближе к потенциальным пользователям, но ни одно не равно числу активной аудитории.

Сразу оставлю табличку для отдела аналитики в комментариях: просмотры ролика не равны установкам, установки не равны активным пользователям, а лайки не надо пересчитывать в оценку бизнеса по курсу на вторник. Но этот отклик показал главное - проблема существует не только у меня и нескольких вежливых друзей.

Сам дистрибутив Keyboop для macOS за это время скачали около 3 тысяч раз. Вот это уже намного ближе к числу потенциальных пользователей, хотя скачивание всё равно не равно человеку: кто-то мог загрузить файл повторно, кто-то - не установить, а кто-то - открыть и решить, что прежняя жизнь была вполне терпимой.

В самом приложении аналитики нет, оно ничего не высылает, поэтому сколько людей действительно пользуются Keyboop, я не знаю и пока не уверен, нужно ли вообще пытаться посчитать это любой ценой. На GitHub сейчас 109 звёзд и 16 форков, через форму внутри приложения пришло 117 сообщений - тоже не аудитория, но вместе с тремя тысячами скачиваний это уже приятный признак, что приложение людям пригодилось. Мой главный дашборд пока выглядит старомодно: люди просто пишут словами, что у них не работает и чего не хватает.

Почему я продолжаю это делать

Сейчас Keyboop бесплатный, с открытым исходным кодом и без рекламы. Для меня это одновременно полезный инструмент и большая учебная работа, на которой я заново осваиваю разработку и проверяю, насколько далеко можно зайти с современными инструментами. Возможно, это не самая передовая бизнес-модель, зато от неё не хочется закрыть баннер с cookies.

Больше всего меня радуют даже не цифры, а сообщения от людей, которые сначала отнеслись к приложению без особого энтузиазма, а потом написали, что уже не представляют без него работу за компьютером. Приятно делать вещь, которая кому-то пригодилась, даже если мой главный продуктовый дашборд по-прежнему состоит из человеческих сообщений и нескольких скриншотов.

У нового увлечения обнаружился только один системный баг. На съёмках я постоянно двигался, таскал технику, менял локации, а за компьютером очень быстро почувствовал, насколько иначе тело относится к восьми, а то и шестнадцати часам почти без движения. На себе я отлично заметил, как спорт влияет на здоровье и самочувствие, поэтому короткая пропаганда полезного: заниматься спортом - полезно, нормально питаться - полезно, вставать, ходить и вообще давать мышцам вспомнить, зачем они существуют, - тоже очень полезно. Если после установки Keyboop вы сэкономите несколько секунд на раскладке, потратьте их на то, чтобы хотя бы встать со стула. Берегите себя: это самая полезная функция, которую я пока не сумел автоматизировать.

Текущая ветка называется Pika, следующая будет Axolotl, а версия 1.0 когда-нибудь станет Capybara. Аксолотль умеет восстанавливаться после повреждений, поэтому для проекта, в котором исправления иногда требуют исправлений, это уже не маскот, а техническое задание.

Проект называется Keyboop. А мне интересно другое: если вас жизнь тоже перебрасывала между профессиями, к чему вы в итоге неожиданно вернулись - и в какой момент поняли, что это уже не временное увлечение?

...

ВОПРОС К ЧИТАТЕЛЯМ

Если вас жизнь тоже перебрасывала между профессиями, к чему вы в итоге неожиданно вернулись - и когда поняли, что это уже всерьёз?

4