Пронин
Назад к блогу

Как я, не-программист, собрал десктопный .exe за вечера

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

19 июн. 2026 г.
TL;DR

Я маркетолог, а не разработчик: код понимаю частично, потому что понимаю принципы ООП (точнее их базу), но сложные системы с нуля писать не в состоянии. Когда-то учился на геймдизайнера, и туда входил модуль по С#: переменные, циклы, методы и классы, полиморфизм и инкапсуляция — всё это я оооочень поверхностно прошёл, чтобы понимать, как писать скрипты под Unity или допиливать блюпринты для тогда нового UE4. Поэтому появление нейросетей, а потом и понятия вайбкодинга меня и цепануло. Частично закрылся гештальт, так сказать. Эта статья – мой путь погружения в нейронки, который начался с простого запроса: «смогу ли я сделать своё собственное веб- или десктоп-приложение без навыков разработчика?» А заканчивается она ссылками на бесплатный инструмент для маркетологов, который объединил в себе всё, что я мог пожелать для закрытия задач по UTM-разметке: базу данных, шаблоны, API с короткими ссылками и QR-коды.

Ключевая идея

Нейросети на старте начали строить своё УТП вокруг «замены разработчиков». Они и сейчас выстраивают одно из своих позиционирований вокруг этого — взять тот же Codex, Claude Code и подобные агентные системы.

Так со мной и вышло. Увидев их возможности (напомню, это был 2024 год), я полетел пробовать тогдашние ChatGPT и Gemini, собирая первые простенькие приложухи и лендинги. Очень быстро выкатился следующий сервис гугла — Firebase, который давал тот первый опыт вайбкодинга, когда он ещё не стал мейнстримом: прототипы по моим запросам, автокоммиты и пуши в гит, публикация на публичных доменах и возможность прикрутить базы данных в том же гугле.

И всё это дало толчок к известному русскому *«А чё будет…?».*

Откуда вообще взялась идея

Я много вожусь с UTM-метками — это рабочая рутина любого маркетолога. Если коротко, UTM — это хвостик, который цепляешь к ссылке, чтобы потом в аналитике видеть, откуда пришёл человек. Из рассылки, из поста, из рекламы. Без них в отчёте каша.

Но дело не только в конструкторе, коих куча в бесплатном доступе: та же Тильда, Roistat, Calltouch и ещё десятки сервисов сделали себе такие конструкторы, их принцип до боли простой.

Дело было именно в объединении нескольких моих болей:

  • Все мои шаблоны меток, с разбивками по категориям и кампаниям, всегда валялись в гугл-таблицах. Это норм, если ты не работаешь с множеством каналов коммуникации или вообще проектов, но когда тебе нужны теги, много разных меток по направлениям и с привязкой конкретной даты — страница быстро растёт.
  • Кроме того, таблицей могли пользоваться другие коллеги, постоянно пополняя этот нескончаемый список и превращая его в помойку.
  • Нет истории генерации меток, чтобы посмотреть их по датам или тем же названиям кампаний. Полезно, когда хочешь переиспользовать метку заново, поменяв там один пунктик или поле, или когда нужно найти конкретную ссылку и метку на конкретную дату — такой лог вести в таблице — доп. нагрузка.
  • Чтобы сократить ссылку, приходится идти в другой сервис — лезешь в тот же кликер Яндекса, снова усложнение пути.
  • Там же делаешь QR-код — тоже сторонний сервис, который не сохраняет коды в твоём гугл-доке.

Также хотелось нормального импорта и шеринга этими базами (кстати, это был первый пункт, из-за которого я на год забросил эту идею проекта). А главное — был исследовательский мотив: «я тот, кто всегда хотел разрабатывать игры, но не пошёл по этому пути», а тут открылась такая возможность.

*«А чё будет…?».* 😂

Первый заход, 2024

Первое, что стало получаться, - это простенький конструктор того самого хвоста, самой простой части проекта. Gemini тех лет справился гораздо лучше ChatGPT и даже помог мне сделать первый прототип. Тогда я узнал, что такое Flask и WebView, но упёрся в ТАКОЙ кривой и стрёмный нейрослоп-дизайн, что начал сомневаться в своей цели.

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

Firebase отлично помог мне в тот момент - у меня появился рабочий прототип, с хорошим дизайном, разделением по страницам и модулям, регулярными автокоммитами и агентной работой. На тот момент это была пушка!

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

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

Тогда я думал, что дело во мне - мозгов не хватило дожать. Сейчас-то понятно: дело было не во мне. Инструменты тех лет упирались в потолок ровно там, где начиналась моя задача. Модели не тянули проект целиком, а «серьёзное приложение» в моей голове ОБЯЗАНО было иметь облако. Обе эти стенки через полтора года просто испарились. Но тогда я, конечно, об этом не знал и честно похоронил идею.

Второй заход, 2026: и вот тут поперло

Вернулся я к проекту в начале 2026-го. История репозитория меня не обманет - первый коммит стоит 8 января. И в этот раз всё пошло иначе. Не потому что я поумнел (спойлер: не поумнел), а потому что инструменты стали другими.

Сначала за дело взялся Cursor - это редактор, где ИИ-агент видит весь проект целиком, а не по одному файлу за раз. Вот это «видит целиком» и было главным отличием от 2024-го. Агент держал в голове всю структуру приложения, не терял связи между файлами и собрал мне рабочий прототип, а потом и первые живые версии - то самое окно, которое уже открываешь и которым уже пользуешься. То, что в 2024-м рассыпалось на третьем экране, теперь собиралось и держалось.

И главное - я наконец плюнул на облако. Никакой базы в гугле. Обычный локальный файл рядом с приложением, и всё. Та самая «возня с базами», на которой я утонул в 2024-м, тут просто исчезла: данные лежат в одном файле на диске, ни правил доступа, ни синхронизаций. А ведь полтора года назад я был на сто процентов уверен, что взрослое приложение без облачного бэкенда - это не приложение. Оказалось - ещё какое приложение.

[screenshot placeholder] Главный экран UTMka: поле базового URL и пять полей UTM-параметров с подсказками по значениям
Конструктор UTM — всё в одном окне: URL, параметры, подсказки

А самую муторную, финальную часть я добивал уже с другим агентом - с Claude. И это было не «напиши мне функцию», а долгая нудная доводка до состояния «не стыдно людям отдать»: аккуратная работа с базой, сборки сразу под две платформы - Windows и macOS, автообновления. Версии, которые в итоге уехали в релизы, - 2.2.0 под Windows и 2.2.1 под macOS. Вот на этом этапе мой пет-проект и перестал быть «работает у меня на ноуте», превратившись в продукт с инсталлером и версиями.

Если сжать разницу между двумя заходами в одну фразу: в 2024-м я воевал С инструментами, а в 2026-м инструменты воевали ЗА меня. Сам я за это время программистом не стал. Как был маркетологом, читающим код, так и остался. Поменялось то, на что этот навык опирается.

Почему десктоп, а не свой сайт

Логичный вопрос: ты же маркетолог, ну подними веб-версию, это же проще. Но веб-версия - это снова сервер, снова домен, снова база где-то в облаке. То есть снова «данные не у меня» и снова платить за хостинг. А после танцев 2024-го желания опять лезть в серверную часть у меня, мягко говоря, поубавилось. Мне нужен был именно ЛИЧНЫЙ инструмент - чтобы данные физически лежали на моей машине и работали без интернета.

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

И тут - отдельный кайф для меня как для маркетолога. Интерфейс приложения - это обычная веб-страница. Те же HTML, CSS и немного JavaScript, что и на любом лендинге. Верстать веб я умею куда увереннее, чем городить нативные оконные приложения, и здесь это знание просто переиспользовалось. Не надо учить отдельный UI-фреймворк - хватает того, что уже умеешь. Порог входа в «десктоп» за счёт этого резко падает.

Что эта штука вообще умеет

Если коротко - закрывает весь мой UTM-цикл, чтобы не бегать по онлайн-сервисам. Ради «всё в одном окне» я в эту историю и влез, так что пройдусь по функциям чуть подробнее.

Базовый сценарий - конструктор. Вводишь URL, заполняешь поля параметров, видишь готовую ссылку, копируешь в один клик. Есть подсказки по значениям - чтобы в одной кампании не расплодить зоопарк из `fb`, `facebook` и `FB`. Звучит мелочью, но именно этот зоопарк потом превращает отчёт по источникам в кашу. Подсказки экономят больше нервов, чем кажется.

Поверх этого - сокращение ссылки (та самая единственная сетевая функция) и генерация QR-кода прямо в окне. QR рисуется на месте, без похода к чужому генератору - удобно, когда ссылку с UTM надо быстро увести в офлайн: на листовку, на стенд, на упаковку.

[screenshot placeholder] Экран сокращения UTM-ссылки одним кликом в UTMka
Сокращение длинной UTM-ссылки — единственная сетевая функция приложения

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

[screenshot placeholder] Сохранение набора UTM-параметров как шаблона: поле тега и выбор цветовой метки
Шаблон с тегом и цветной меткой — чтобы не вспоминать параметры каждый раз

История всех собранных ссылок сохраняется сама, её можно сортировать и фильтровать - спасает, когда через месяц надо вспомнить, какую метку ты вешал на конкретную рассылку. Хранится локально, до 500 записей, чтобы база не пухла до бесконечности. А чтобы данные не были заперты внутри приложения, шаблоны и историю можно выгрузить и загрузить обратно файлом. Это закрывает два сценария, которые для личного инструмента важнее, чем кажется: переезд на другую машину без потери накопленного - и передача готового набора шаблонов коллеге. Выгрузил файл, человек загрузил себе - и у него сразу те же заготовки, что у тебя. Ну и мелочи быта: переключение языка RU/EN и светлая/тёмная тема.

[screenshot placeholder] Список сохранённых шаблонов UTM с цветовыми метками и тегами
Несколько десятков шаблонов — и каждый находится поиском или по цвету

Ничего из этого по отдельности не впечатляет. Это нормальная утилита, и каждую функцию в отрыве делает десяток сервисов. Ценность ровно в том, что они собраны в одном окне, работают без интернета и хранят данные у меня. А самое интересное началось, когда я захотел не «запускать у себя из консоли», а отдать людям нормальный `.exe`, который ставится двойным кликом и сам обновляется.

Вот тут и проходит граница

По-моему, именно здесь граница между «скриптом для себя» и «продуктом». Скрипт запускается из консоли. Продукт - устанавливается, имеет версию, обновляется и не разваливается, когда этих версий становится пять.

Первое, что я сделал, - завёл одно-единственное место, где живёт номер версии. Одна строчка в одном файле. Звучит банально, но это, наверное, главное решение всей сборки. Потому что версия нужна не в одном месте, а сразу в трёх: в самом коде (чтобы проверять обновления), в скрипте инсталлера и в свойствах `.exe`-файла, которые Windows показывает в «Свойствах». Держишь её в трёх местах руками - рано или поздно соберёшь инсталлер одной версии поверх кода другой и потом полдня будешь искать, почему обновление «не видит само себя».

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

А дальше - буквально две команды, и из проекта получается дистрибутив. Первая собирает приложение в исполняемый файл, тянет за ним всё нужное - интерфейс, логотип, примеры шаблонов - и выкидывает лишнее, чтобы сборка не раздувалась. На выходе - папка с `.exe`, который уже запускается. Вторая команда собирает из этой папки нормальный Windows-инсталлер - тот самый `UTMka-Setup`, который ставит приложение, создаёт ярлыки, регистрирует его в системе. Итоговый установщик весит порядка 30 МБ - для приложения, которое несёт в себе целый Python внутри, вполне скромно.

Где меня поцарапало

Пути к файлам ломаются после упаковки

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

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

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

Оба случая - про одно и то же. Код пишется быстро. А «довести до продукта» - это вот эти мелкие, неочевидные стыки, которые всплывают только когда отдаёшь штуку наружу.

Автообновления - чтобы не рассылать .exe руками

Реальный баг рассинхрона версий

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

Поэтому я прикрутил автообновления. И работают они на удивление прямолинейно, без всякого своего сервера. При запуске приложение делает один запрос: какая там последняя опубликованная версия? Сравнивает со своей. Если новая больше - и под твою систему есть готовый установщик - показывает аккуратное окошко: вышла новая версия, обновить?

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

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

Бонусом - и под macOS

Неподписанное приложение под Windows и macOS

Раз уж зашла речь про две платформы, отдельно про Mac - потому что это был отдельный маленький квест.

Под Windows на выходе привычный `.exe`-инсталлер. Под macOS логика другая: приложение упаковывается в образ - отдельно под старые интеловские маки и отдельно под новые на Apple Silicon. Проверка обновлений работает так же. А вот финальный жест другой: вместо тихой установки приложение просто открывает скачанный образ, а дальше ты по маковской традиции перетаскиваешь иконку в «Программы».

И есть нюанс, на который наткнётся любой, кто раздаёт неподписанное приложение под Mac. Платного сертификата разработчика Apple у меня нет, поэтому система при первом запуске честно ругается: «от неустановленного разработчика», открыть нельзя. Лечится известным обходом: правый клик по приложению → «Открыть» → подтвердить один раз, дальше запускается как родное. Для личного инструмента - терпимо. Но в инструкцию для людей про этот шаг приходится писать прямым текстом, иначе человек упрётся в окно отказа и решит, что приложение сломано.

Что бы я сделал иначе

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

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

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

А в-третьих - главный урок, и он же ответ тому себе из 2024-го. Не лез бы я в облачную базу. Тогда мне казалось, что «серьёзное приложение» ОБЯЗАНО иметь облачный бэкенд, и именно эта установка меня и утопила. Локального файла хватало с самого начала - я просто не верил, что так можно. Для личного инструмента простое локальное решение почти всегда правильнее «взрослого» облачного, к которому тебя подталкивает насмотренность на чужие большие проекты.

Главное - вообще не про UTM

И вот теперь то, ради чего я, собственно, и сел писать.

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

Она про другое. И разница между двумя моими заходами говорит об этом лучше любых слов. В 2024-м у меня была ровно та же идея и примерно тот же я - но инструменты не дотягивали, и проект умер. В 2026-м идея и я не изменились - изменились агенты, и проект доехал до инсталлера с автообновлениями. Помнишь то самое русское *«А чё будет…?»*? Вот это и получилось - только на полтора года позже, чем задумывалось.

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

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

Что в итоге

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

И знаешь, что я из этого вынес? Да не то, что я стал круче. А то, что планка «собрать себе рабочую штуку» опустилась так низко, что под неё теперь пролезает куда больше народу, чем принято думать. Я просто оказался одним из них. Тот самый гештальт с несостоявшимся геймдизайнером - считай, закрыт. 😌

P.S.

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

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

© 2026 Александр Пронин · цены не офертаконфиденциальностьсоглашение
ЛентаFreeБизнесуКурс