Недавно я наткнулся на Bubble Tea — терминальный UI-фреймворк для Go, и буквально влюбился в то, как он отрисовывает интерфейсы в консоли. В репозитории есть множество примеров — и выглядят они действительно красиво.

Я никак не связан с разработчиками — просто захотел поделиться личным опытом.
Первое открытие: низкоуровневое управление и архитектура ELM
С первого взгляда Bubble Tea выглядит как высокоуровневый фреймворк с красивой абстракцией. Но под капотом он довольно низкоуровневый в плане контроля, и построен на архитектуре, вдохновлённой ELM.
Она основана на трёх основных концепциях:
Model — структура, содержащая всё состояние приложения (например, позицию курсора, список элементов, ввод пользователя и т. д.).
Update(msg) — функция, в которой можно изменять модель. Принимает сообщение (пользовательское действие или внутреннее событие), возвращает обновлённую модель и (опционально) команду.
View(model) — рендеринг интерфейса на основе текущей модели.
Что такое команды?
Команды — это события, которые мы можем генерировать и отправлять сами. Это может быть как пользовательское действие (например, нажатие клавиши), так и произвольная внутренняя структура. В Update
они обрабатываются через type switch
.
Пример: бесконечный спиннер загрузки
Допустим, нам нужен спиннер с тремя кадрами, которые циклично меняются каждую секунду. Вот как это реализуется в Bubble Tea:
В модели храним текущий индекс кадра и список кадров.
Объявляем кастомную команду
type nextFrame struct {}
.При инициализации модели вызываем первую команду
nextFrame
.В
Update
, при получении командыnextFrame
, увеличиваем индекс и планируем следующую команду с задержкой в 1 секунду (с помощью утилит из фреймворка).Фреймворк сам вызывает
View
при изменениях, а мы вView
просто показываем нужный кадр по индексу.
В результате — плавно анимированный спиннер, без явных таймеров и горутин.
Второе открытие: простая параллельность через команды
Команды оказались удивительно мощным инструментом. Например, предположим, нам нужно загрузить 10 изображений с помощью 3 воркеров. В обычном Go мы бы использовали каналы и горутины, но в Bubble Tea можно обойтись всего одной командой:
Команда проверяет: есть ли ещё изображения в очереди. Если да — загружает, сохраняет результат, вызывает себя снова.
При старте запускаем 3 таких команды — и получаем 3 параллельно работающих воркера.
Когда очередь заканчивается, команды просто перестают запускаться.
Это не "классическая" конкурентность Go, но она естественно вписывается в архитектуру UI-приложения, и позволяет сохранять отзывчивость интерфейса.
Третье открытие: вся архитектура — это ELM, и с этим надо смириться
Как только вы начнёте писать что-то чуть сложнее Hello World, всё ваше приложение станет ELM-подобным. Другого пути нет: либо вы принимаете архитектуру, либо постоянно боретесь с ней. Вот что помогло мне на этом пути:
Не полагайтесь на нейросети для генерации кода. Большинство LLM плохо справляются с архитектурой Bubble Tea. Код получается нечитаемым. Лучше продумать архитектуру, модель и структуру проекта самостоятельно, а LLM подключать точечно — например, для генерации вспомогательных функций или отладки.
Разделяйте ответственность. Выносите
View
,Update
иModel
в отдельные файлы. Даже официальные примеры временами тяжело читать без этого.Следите за читаемостью
Update
. Он быстро может превратиться в 300 строк кода. Используйте вспомогательные методы и выносите обработку отдельных команд.Выносите стили в отдельный файл. Цвета, отступы, рамки — всё это лучше оформить централизованно.
Обязательно проводите рефакторинг. Написали рабочую реализацию — сделайте её читаемой. Иначе завтра вы сами себя не поймёте.
Эти советы в целом универсальны, но именно в Bubble Tea их игнорирование быстро делает поддержку невозможной.
Что я сделал на Bubble Tea
Я реализовал визуальный менеджер зависимостей для go.mod
, который сканирует зависимости и показывает, какие можно и нужно обновить. Это может быть полезно, потому что стандартный go get -u
просто обновляет всё подряд, и часто приводит к тому, что проект перестаёт собираться.
Проект здесь: chaindead/modup
Если у вас был опыт с Bubble Tea — расскажите, как оно? Какие архитектурные приёмы вам помогли?