1. Зачем нужен release bundle
Если вы только начинаете, очень легко попасть в ловушку: кажется, что цель разработки — получить файл, который запускается. И это правда… примерно первые полчаса. А потом реальность начинает задавать вопросы, и все они звучат как разные варианты «а что это за штука и как ей пользоваться?». Пользователь (или вы через неделю) не обязан помнить, какие флаги есть у программы, какие команды поддерживаются, где посмотреть версию и что делать, если «оно не запускается на Windows».
Release bundle — это попытка быть вежливым инженером. Мы не просто отдаём «вот вам бинарник, удачи», а отдаём маленький набор артефактов, который отвечает на базовые вопросы: что это, как запустить, как проверить версию, где посмотреть примеры, какие изменения произошли. Это похоже на ситуацию, когда вы дарите человеку кофемолку: можно, конечно, вручить только мотор и провода, но инструкция и пара рецептов как-то повышают шанс, что вы останетесь друзьями.
Release bundle как контракт выдачи
Слово «контракт» здесь не юридическое, а инженерное. Мы фиксируем: любой, кто скачал нашу программу, должен иметь возможность без телепатии сделать несколько вещей. Во‑первых, понять, как запустить программу и где справка. Во‑вторых, понять, какой именно версии эта программа и под какую платформу она собрана. В‑третьих, увидеть короткие примеры типового использования. В‑четвёртых, понять, что изменилось по сравнению с прошлой версией (или хотя бы увидеть, что «изменения были»).
Важно, что этот контракт работает и для вас самих. Через месяц вы будете разбирать баг-репорт «у вас ничего не работает», и внезапно окажется, что самый полезный вопрос — «а покажите вывод todo --version». Если версия внутри бинарника не зашита и не выводится, вы начинаете играть в инженерную рулетку: «кажется, это был релиз… или не релиз… или это я собирал на прошлой неделе…».
Минимальный состав release bundle
В этой лекции мы не обсуждаем конкретные архиваторы, установщики и публикацию релизов на сервисах — это отдельный мир, где можно утонуть в кнопках. Нам нужна простая, понятная, переносимая идея: папка (или архив), внутри которой лежат предсказуемые файлы.
Удобно мыслить так: есть «сердце» (бинарник) и «обвязка», которая делает сердце пригодным для жизни вне вашего ноутбука.
Ниже — минимальный состав, который стоит держать в голове как дефолт.
| Элемент | Пример имени | Зачем нужен | Важная мысль |
|---|---|---|---|
| Бинарник | или |
То, что запускается | Имя должно отличать платформы и версию |
| README | или |
«Как пользоваться» + quickstart | README — это интерфейс проекта для человека |
| Examples | |
Готовые команды/сценарии | Примеры экономят больше времени, чем «описания» |
| Notes | / |
«Что изменилось» | Релизы принято сопровождать заметками |
Обратите внимание: это не список «чтобы было красиво», а минимальный набор, который превращает запуск в предсказуемое действие. И да, если вы думаете «мне и так всё понятно», то поздравляю — вы пока ещё не вы. Будущий вы оценит.
2. Как выглядит bundle для проекта todo
С этого момента будем говорить так, будто у нас есть учебное CLI-приложение todo (мы его строим весь курс): оно умеет создавать задачи, показывать список, отмечать выполненными, хранить данные и печатать всё это в stdout. Мы не будем расширять функциональность сейчас; мы будем «упаковывать» уже сделанное.
Представим, что мы подготовили релиз версии 1.3.0 для Linux amd64. Тогда release bundle можно мыслить как директорию:
todo_1.3.0_linux_amd64/
todo
README.md
RELEASE_NOTES.md
examples/
quickstart.txt
demo-session.txt
А для Windows:
todo_1.3.0_windows_amd64/
todo.exe
README.md
RELEASE_NOTES.md
examples/
quickstart.txt
demo-session.txt
Даже без архивов и «настоящего релизного процесса» уже видно главное: пользователь открыл папку и понял, куда смотреть.
5. Нейминг артефактов
Когда вы делаете один бинарник «для себя», можно назвать его хоть a.out, хоть final_final2_really. Но как только появляется больше одного артефакта, начинается путаница: какой из них для macOS, какой — для Linux, какой — новый, какой — старый, почему один не запускается (спойлер: потому что вы пытаетесь запустить бинарник под другую архитектуру).
Поэтому в релизах мы стремимся к скучной, но информативной схеме имени:
- имя приложения (todo)
- версия (1.3.0)
- целевая ОС (linux, windows, darwin)
- архитектура (amd64, arm64)
- расширение .exe для Windows
Это можно собрать строкой в Go (сама идея у нас уже была раньше), и полезно держать логику в одном месте, чтобы потом не искать по проекту 12 разных форматов.
Небольшой пример (мы не усложняем, просто показываем идею; это может жить в internal/buildinfo или рядом):
package buildinfo
import (
"fmt"
"runtime"
)
func ArtifactName(app, version string) string {
return fmt.Sprintf("%s_%s_%s_%s", app, version, runtime.GOOS, runtime.GOARCH)
}
Если вызвать это и распечатать, получится что-то вроде:
package main
import (
"fmt"
"example.com/todo/internal/buildinfo"
)
func main() {
fmt.Println(buildinfo.ArtifactName("todo", "1.3.0")) // todo_1.3.0_linux_amd64
}
Смысл не в том, чтобы прямо внутри приложения генерировать имена релизов (хотя иногда это полезно), а в том, чтобы привыкнуть к формату и перестать надеяться на память.
6. README: что в нём важно
README многие пишут по принципу «лишь бы был». Получается файл, где написано: «Это приложение todo. Оно делает todo.» Спасибо, конечно, но это как инструкция к микроволновке «Греет еду».
Хороший README для CLI — это короткая дорожная карта. У него есть одна главная цель: чтобы человек, который видит проект впервые, за 2–3 минуты смог:
- запустить бинарник,
- увидеть справку,
- выполнить один типовой сценарий,
- понять, где смотреть версию,
- понять, куда писать, если всё сломалось (или хотя бы что прикладывать к сообщению).
В README почти всегда полезны такие блоки:
- Что это такое (2–3 предложения, без романа).
- Быстрый старт: 3–6 команд, которые можно копировать.
- Справка: как увидеть --help и --version.
- Где лежат примеры: ссылка на папку examples/.
- Ограничения (если есть): например, «файл данных хранится там-то».
Чтобы это стало более осязаемо, вот «скелет» README (как текст, не как догма). Обратите внимание: это не «список требований», а минимальный сценарий общения с человеком.
# todo
Небольшой CLI-трекер задач: добавить задачу, показать список, отметить выполненной.
## Быстрый старт
1) Посмотрите версию:
todo --version
2) Посмотрите справку:
todo --help
3) Добавьте задачу:
todo add "купить молоко"
4) Покажите список:
todo list
В таком формате README реально работает: пользователь копирует команды, получает результат, начинает доверять инструменту. И да, «доверие» к CLI — это когда он не заставляет вас читать его исходники.
7. examples/: примеры использования
Папка examples/ звучит как что-то факультативное, пока вы не попробовали объяснить пользователю, как воспроизвести проблему. Примеры хороши тем, что они, во‑первых, являются «живой документацией», а во‑вторых, задают стандартный стиль использования вашей утилиты.
В нашем todo удобный пример — это «демо-сессия»: набор команд и ожидаемый вывод (хотя бы частично). Даже если пользователь не будет читать весь файл, он увидит шаблон: какие команды бывают и что они печатают.
Пример файла examples/quickstart.txt может выглядеть как обычный текст. Заметьте: это не код на Go, поэтому здесь мы не компилируем ничего — просто показываем «как пользоваться».
# Quickstart: todo
todo --version
todo --help
todo add "прочитать лекцию про release bundle"
todo list
todo done 1
todo list
Фишка в том, что такие примеры можно (при желании) использовать как основу для smoke-проверки вручную: вы открыли файл, пробежались по командам — и уже видите, что бинарник «жив». Даже если вы не строите CI и автотесты релизов, сама привычка иметь «сценарий запуска» в examples/ — очень инженерная.
8. Release notes: RELEASE_NOTES.md
«Release notes» звучат солидно, как будто у вас компания на тысячу человек и отдел маркетинга. На практике это просто честный ответ на вопрос: «Что поменялось?». Для Go-мира это нормальная культура: релизы сопровождаются заметками, и даже у самого языка Go в объявлениях релизов регулярно звучит «прочитайте release notes».
Для нашего todo релиз-ноты могут быть короткими. Важно не количество текста, а структура. Удобный формат — версия, дата (если вы её фиксируете) и несколько строк по смыслу.
Вот пример того, как может выглядеть RELEASE_NOTES.md:
# Release notes
## 1.3.0
Добавлено:
- флаг --version (показывает версию, коммит и дату сборки)
Исправлено:
- более аккуратные сообщения об ошибках при неверном id задачи
Изменено:
- вывод списка задач стал стабильнее (сортировка)
Если вы заметили, здесь есть пункты — да, иногда без них реально хуже: заметки про изменения легче читать «глазами по строкам». Внутри лекции мы в целом избегаем списков, но release-notes — как раз тот жанр, где короткие пункты уместны, потому что это не «объяснение», а «журнал изменений».
9. Что обязан уметь бинарник в составе bundle
Этот раздел важен, потому что он связывает «файлы рядом» и «поведение программы». С точки зрения пользователя, release bundle — это не только README. Это ещё и уверенность, что сам бинарник не ведёт себя как капризный кот: «сегодня запускаюсь, завтра — не хочу».
Поэтому у CLI почти всегда должны быть две «диагностические» ветки, которые не зависят от остальной логики:
- --help (или help как команда) — показывает usage.
- --version — показывает версию.
Мы уже делали --version. Осталось убедиться, что --help тоже дружелюбный, и что help/usage не скрывает важную информацию.
Вот маленький пример, как можно привязать flag.Usage к «About» из buildinfo. Это не «единственно правильный» вариант, но он хорошо показывает мысль: help — часть контракта.
package main
import (
"flag"
"fmt"
"os"
"example.com/todo/internal/buildinfo"
)
func main() {
flag.Usage = func() {
fmt.Fprintln(os.Stderr, buildinfo.About())
fmt.Fprintln(os.Stderr, "Usage: todo [flags] <cmd> [args]")
flag.PrintDefaults()
}
flag.Parse()
}
Пользователь вводит todo --help и видит не бездушное «Usage», а ещё и идентичность продукта. И если он потом присылает вам скриншот, у вас уже есть версия/коммит прямо в этом тексте.
Простая модель release bundle в голове инженера
Здесь полезно зафиксировать модель, чтобы не сваливаться обратно в «я просто собрал бинарник». Можно представить процесс как конвейер, даже если вы руками делаете его в три команды.
flowchart TD
A[Исходники + go.mod + зависимости] --> B[go build]
B --> C["Бинарник (target GOOS/GOARCH)"]
C --> D[Проверка: --version / --help]
D --> E[Папка релиза: бинарник + README + examples + notes]
Самое интересное здесь — шаг «проверка». Он психологически превращает бинарник в артефакт: вы не просто получили файл, вы убедились, что он сам себя описывает и что рядом лежит минимальная «карта местности».
10. Типичные ошибки при подготовке release bundle
Ошибка №1: считать, что релиз — это «выложить бинарник».
Такое обычно заканчивается тем, что пользователи пишут «не работает», а вы начинаете вытягивать из них информацию клещами: какая ОС, какая версия, как запускали. Release bundle нужен ровно затем, чтобы минимальные ответы были рядом: в README и в --version/--help.
Ошибка №2: не различать артефакты по платформам и архитектурам.
Когда рядом лежат todo для linux/amd64 и todo для darwin/arm64 с одинаковым именем, кто-то обязательно запустит «не то». И это будет тот самый человек, который потом скажет «ваш Go странный». Лечится скучным, но правильным неймингом: app_version_GOOS_GOARCH, и .exe для Windows.
Ошибка №3: делать README «про всё на свете», но без копируемого quickstart.
Парадоксально, но длинное описание хуже короткого набора команд. Пользователь хочет не философию, а «дай 3 команды, чтобы увидеть результат». Если quickstart отсутствует, человек чаще всего закрывает папку. Или открывает исходники. А потом уже не закрывает… потому что чинит ваш UX.
Ошибка №4: прятать примеры в тексте, вместо того чтобы дать examples/.
Когда примеры находятся только внутри README, их сложнее поддерживать и сложнее ссылаться на них в поддержке: «откройте examples/demo-session.txt и выполните команды». Папка examples/ создаёт ощущение, что проектом пользовались «не только авторы».
Ошибка №5: не иметь release notes и потом не помнить, что изменилось.
Это классика не только для пользователей, но и для автора. Вы сделали «небольшое исправление», выкатили новый файл, а через две недели не можете объяснить, чем 1.3.0 отличается от 1.2.9. Короткий RELEASE_NOTES.md дисциплинирует и вас, и проект.
ПЕРЕЙДИТЕ В ПОЛНУЮ ВЕРСИЮ