Go: с нуля до своего блога
Пятьдесят уроков плюс анонс и предисловие. В конце ваш собственный блог работает в интернете на вашем домене. Все уроки открыты: бесплатно и без регистрации.
·
Все уроки открыты: регистрация для чтения не нужна.
-
Бесплатный курс программирования на казахском: Go с нуля
Курс из 50 уроков: от «как работает интернет» до собственного блога на Go, живущего в интернете на вашем домене. Курс написан целиком, читать можно без регистрации и без оплаты. Казахский первым, русский и английский рядом. Внутри — что получится в конце, почему Go и кто на нём пишет.
-
Прежде чем начать: что нужно для курса, а что нет
Предисловие к курсу по Go. Что нужно на самом деле — компьютер, право ставить программы и полчаса в день, — и чего не нужно: английского, математики и мощной машины. Какой у вас терминал и почему это важно, что делать, если установка программ запрещена, и во сколько всё это обойдётся.
-
Как работает интернет: HTTP, запрос и ответ за 15 минут
Первый урок курса по Go. Что браузер спрашивает у сервера и что считается ответом: клиент и сервер, домен, IP и порт, метод и путь, заголовки и коды 200, 404, 500. Одна строка в терминале покажет вам настоящий HTTP-ответ раньше, чем вы о нём прочитаете. Школьная программа этого не даёт.
-
Как установить Go и настроить VS Code: рабочее место с нуля
Второй урок курса по Go. Что поставить до первой строки кода: сам Go 1.27, редактор VS Code с расширением Go, папка проекта и команда go mod init. Разбираем, кто за что отвечает: язык, редактор, расширение и терминал. В конце ваша первая программа здоровается с миром в терминале.
-
Первая программа на Go: веб-сервер на net/http за 20 минут
Третий урок курса по Go. Первая программа на Go и работающий веб-сервер: package main, func main, http.HandleFunc, http.ListenAndServe и порт 8080. Откройте localhost:8080 в браузере и увидите ответ своей программы раньше, чем выучите хоть одно правило языка. И что делать, если порт занят.
-
Переменные и типы в Go: string, int, float64 и bool
Четвёртый урок курса по Go. Что такое переменная и зачем языку типы: string, int, float64 и bool, объявление через := и var, нулевые значения и почему тип выбирается один раз. Разбираем ошибку declared and not used, которую вы увидите в первый же день, и правила именования.
-
Функции в Go: параметры, return и два значения сразу
Пятый урок курса по Go. Как объявить функцию и что такое параметр, аргумент и return. Главное в уроке: функция в Go возвращает два значения сразу — результат и признак, получилось ли. Отсюда и отсутствие исключений в языке. Разбираем приём result, ok := и подчёркивание.
-
Ветвление и цикл в Go: if, else и единственный for
Шестой урок курса по Go. Как программа выбирает между двумя путями: if, else if и else, сравнения и логические И, ИЛИ, НЕ. И цикл — в Go он ровно один, слово for, зато в трёх формах: со счётчиком, по условию и без условия с break. Ни while, ни do-while, ни foreach в языке нет.
-
Строки и руны в Go: почему казахская буква — два байта
Седьмой урок курса по Go. Почему len("шаңырақ") возвращает 14, а не 7, чем байт отличается от буквы и что такое руна. Обход строки через range, честный подсчёт букв через utf8.RuneCountInString и главная ловушка: обрезка строки по байтам разрубает казахскую букву пополам.
-
Массивы и срезы в Go: список, который растёт, append, len и cap
Восьмой урок курса по Go. Массив, из которого сделан срез, и сам срез — список, который растёт: []string, append и почему результат присваивают обратно. Чем массив отличается от среза при присваивании, чем длина от ёмкости и главная ловушка: кусок смотрит в ту же память, что и оригинал.
-
Словарь (map) в Go: ключ и значение
Девятый урок курса по Go. Словарь, он же map: пара «ключ — значение», по которой находят сразу, а не перебором. Как записать и прочитать, почему отсутствующий ключ отдаёт ноль, а не ошибку, что такое запятая-ok, зачем Go меняет порядок обхода и чем nil-словарь опаснее nil-среза.
-
Первый тест в Go: go test и файл _test.go
Десятый урок курса по Go. Проверка, которая остаётся: файл _test.go рядом с кодом, функция TestXxx и команда go test. Как читать провал — имя теста, файл, строка, «получили» и «ждали», — чем t.Errorf отличается от t.Fatalf и почему проверять надо края списка, а не его середину.
-
Структура в Go: свой тип вместо пяти переменных
Одиннадцатый урок курса по Go. Структура — свой тип: type Article struct вместо трёх словарей, которые держали в согласии вручную. Поля и точка, литерал с именами и без, нулевая структура, срез структур и главная ловушка: структура передаётся копией, и правка внутри range пропадает.
-
Указатели и методы в Go: почему правка не сохранялась
Двенадцатый урок курса по Go. Ответ на ловушку прошлого урока: указатель — это адрес значения, а не его копия. Как работают & и *, чем метод отличается от функции, когда приёмник берут указателем, а когда значением, и почему for i := range чинит то, что for _, a := range ломает.
-
Интерфейс в Go: договор по умению, а не по устройству
Тринадцатый урок курса по Go. Интерфейс — список умений: одна функция работает с любым хранилищем, если оно умеет то, что записано в договоре. Почему реализация не объявляется, а получается сама, как проверить её при сборке и почему подменное хранилище делает тесты возможными без базы.
-
Ошибки в Go: не исключение, а обычное значение
Четырнадцатый урок курса по Go. Ошибка здесь не прерывает программу, а возвращается вторым значением, и проверяют её первой. error как интерфейс с одним методом, errors.New и fmt.Errorf, обёртка через %w и errors.Is, своя ошибка как значение — и почему panic для этого не нужен.
-
Пакеты и модули в Go: go mod и заглавная буква
Пятнадцатый урок курса по Go. Пакет — это папка, а заглавная буква в имени — дверь наружу. Как разложить программу по папкам, что записано в go.mod и go.sum, как подключить чужой пакет командой go get, зачем нужна папка internal и почему go mod tidy запускают перед отправкой кода.
-
Git: история вашего кода и путь назад
Шестнадцатый урок курса по Go. Git хранит не последнюю версию файла, а все состояния, к которым можно вернуться. git init, три места — папка, индекс и история, — git status как самая частая команда, что писать в сообщении, зачем нужен .gitignore и как достать вчерашний файл.
-
GitHub: код, который видно
Семнадцатый урок курса по Go. GitHub — не резервная копия, а та же история, видимая другим. Аккаунт и первый репозиторий, git remote и git push, почему пароль там больше не принимают и чем его заменили, README как первое, что читает человек, и что нельзя выкладывать никогда.
-
Сборка: блокнот в консоли из всего, что вы уже знаете
Восемнадцатый урок курса по Go и конец модуля о языке. Одна законченная программа из знакомых деталей: структура, срез, словарь, методы с указателем, ошибки, свой пакет и тесты. Ничего нового, кроме чтения команд с клавиатуры: собрать выученное в работающую вещь — отдельное умение.
-
HTTP по-настоящему: метод, путь, заголовки и код ответа
Девятнадцатый урок курса по Go и начало модуля о вебе. Запрос — это структура, которую можно прочитать: метод, путь, заголовки, параметры. Ответ уходит в одну сторону: заголовки, код, тело — и в этом порядке. Почему 404 и 405 разные и что значит superfluous WriteHeader.
-
Маршруты в Go: кто обрабатывает какой адрес
Двадцатый урок курса по Go. ServeMux разводит запросы по обработчикам: метод и путь пишутся одной строкой, {slug} вынимает кусок адреса, {$} не даёт главной странице ловить всё подряд. Ошибки 404 и 405 маршрутизатор берёт на себя, а конфликт двух образцов ловит при запуске.
-
Обработчик и middleware: одна обёртка на все маршруты
Двадцать первый урок курса по Go. Обёртка вокруг маршрутизатора делает одно и то же для каждого запроса: журнал, время ответа, проверка. Что такое http.Handler, почему обёртка берёт обработчик и возвращает обработчик, и как узнать код ответа, которого ResponseWriter не хранит.
-
Шаблоны в Go: html/template и страница вместо строк
Двадцать второй урок курса по Go. HTML переезжает из кода в отдельный файл: точка как имя данных, range по срезу, if и else. Почему html/template сам обезвреживает чужой текст, зачем шаблоны разбирают один раз при старте и почему страницу собирают в буфер, а не сразу в ответ.
-
Формы в Go: принять то, что прислал читатель
Двадцать третий урок курса по Go. Данные впервые идут в обратную сторону — от читателя к серверу. Метод и имена полей, r.FormValue, почему проверка в браузере не защита, и почему обработчик, который что-то изменил, отвечает редиректом, а не страницей: иначе F5 создаст вторую статью.
-
Статика в Go: CSS, шрифты и картинки
Двадцать четвёртый урок курса по Go. Сайт начинает выглядеть, а не только работать. http.FileServerFS, почему для файлов с диска нужен StripPrefix, а для встроенных нет, откуда берётся Content-Type, почему папка static видна целиком и почему встроенный файл браузер качает заново.
-
Ошибки и журнал в Go: увидеть, что сломалось
Двадцать пятый урок курса по Go. Паника в обработчике не роняет сервер — она роняет ответ, и читатель не получает вообще ничего. recover одной прослойкой, номер обращения в странице и в журнале, log/slog вместо печати в консоль и почему после уже ушедшего ответа спасать поздно.
-
Конфигурация в Go: флаги, переменные окружения и пароль вне кода
Двадцать шестой урок курса по Go. Адрес, файл базы и ключ подписи уезжают из кода. Пакет flag и что даёт -h, почему переменную окружения удобно делать значением флага по умолчанию, чем пустая переменная отличается от незаданной и почему без обязательной настройки надо падать при старте.
-
SQL: первая таблица, INSERT и SELECT
Двадцать седьмой урок курса по Go. Статьи наконец переживут перезапуск. Почему в курсе SQLite, а не Postgres, как создать таблицу и положить в неё строку: insert с returning, select с where и order by, update, у которого забыли where, и разница между = null и is null.
-
SQL: две таблицы, JOIN и внешние ключи
Двадцать восьмой урок курса по Go. У статьи появляются комментарии, и они не помещаются внутрь неё. Вторая таблица и ключ между ними, join против left join, каскадное удаление и ловушка SQLite, из-за которой внешние ключи молчат и оставляют строки сиротами.
-
SQLite и database/sql: первая строка из базы, а не из среза
Двадцать девятый урок курса по Go. Блог наконец читает статьи из файла базы. Пакет и драйвер, почему sql.Open ничего не открывает, что такое пул соединений и почему прагму про внешние ключи пишут в строку подключения, а не отдельным запросом. Плюс ErrNoRows и проверка ошибки после цикла.
-
CRUD: четыре действия над статьёй и жизнь без среза
Тридцатый урок курса по Go. Статьи переезжают из среза в базу и переживают перезапуск. Тип Store, который прячет базу от остального кода, четыре действия над статьёй и одна неочевидная вещь, стоящая целого раздела: обновить то, чего нет, — не ошибка, и узнать об этом можно только по RowsAffected.
-
Миграции: история базы, а не `create table if not exists`
Тридцать первый урок курса по Go. Схему перестаёт создавать программа при старте: появляются нумерованные файлы миграций, журнал применённого и правило «каждая ровно один раз». Плюс измеренная ловушка: колонку not null без значения по умолчанию пустая база примет, а рабочая откажется менять.
-
Транзакции и SQL-инъекции: запрос — не строка, которую склеивают
Тридцать второй урок курса по Go. Два правила, на которых держится база. Данные не склеивают с текстом запроса: подстроенный адрес возвращает три строки вместо одной, а через параметр — ноль. Что должно случиться вместе — в транзакцию: без неё счётчик вырос за переезд, которого не было.
-
Теги: третья таблица, которой не видно на странице
Тридцать третий урок курса по Go. У статьи много тегов, у тега много статей — и хранится это отдельной таблицей, а не списком в колонке. Составной ключ, on conflict ради id, каскад при удалении. И обещанный способ спросить у ошибки её код вместо того, чтобы читать её текст.
-
Поиск: FTS5, и почему параметр спасает не от всего
Тридцать четвёртый урок курса по Go. Работающий поиск по блогу: виртуальная таблица FTS5, три триггера, ранжирование и подсветка найденного. И измеренный сюрприз: параметр защищает от инъекции, но не от того, что человек напечатал в строку поиска слово OR.
-
Макет: одна рамка на все страницы
Тридцать пятый урок курса по Go. Семь шаблонов блога держат семь копий одного и того же начала страницы. Сегодня остаётся одна рамка: base с блоками, папки pages и partials, семантическая разметка — и измеренная ловушка, из-за которой у людей все страницы вдруг показывают одну и ту же.
-
Регистрация: что хранить вместо пароля
Тридцать шестой урок курса по Go. Пароль в базе не хранят — хранят bcrypt-хеш, у которого соль внутри, а стоимость снаружи. Измерено: sha256 даёт девять миллионов хешей в секунду, bcrypt десять. Плюс предел в 72 байта, о который казахский пароль спотыкается уже на тридцать седьмой букве.
-
Сессии и cookie: как сервер помнит, кто вошёл
Тридцать седьмой урок курса по Go. HTTP не помнит ничего: каждый запрос приходит от незнакомца. Печенье с номером пользователя подделывается за секунду. Поэтому в браузер уходит случайный токен, а в базу его хеш, и всё закрывается тремя словами: HttpOnly, Secure, SameSite.
-
Права: кто что может менять
Тридцать восьмой урок курса по Go. Спрятать кнопку — не защита: измерено, как чужой человек правит вашу статью прямым запросом, пока кнопки он не видит. Проверка живёт в обработчике и в одном месте, а отказы отвечают по-разному: гостю — на вход, чужому — 403, несуществующему — 404.
-
CSRF и XSS: три защиты, которые ставят всем
Тридцать девятый урок курса по Go. Чужой скрипт на вашей странице и чужой сайт, отправляющий форму от имени вашего читателя. Измерено, как html/template экранирует по месту — в тексте, в ссылке и внутри script, — и как жетон отличает вашу форму от чужой.
-
Загрузка изображений: чужой файл на вашем диске
Сороковой урок курса по Go. Форма, в которой едет файл, и четыре вещи, которые проверяют до того, как он ляжет на диск: размер, тип по содержимому, собственное имя вместо присланного и место, куда его класть. Заодно приводим /static в порядок: brand, css, images, js, uploads.
-
Тесты: узнать, что сломалось при правке
Сорок первый урок курса по Go. Обещанная в уроке 10 таблица: случаи складывают в список, `t.Run` даёт каждому имя, и провал сразу говорит, какой именно случай сломался. Плюс проверка обработчика без запуска сервера и честный разговор о том, что показывает `-cover`.
-
Горутины и каналы: зачем они вебу
Сорок второй урок курса по Go. Сервер конкурентен с урока про HTTP, и вы этого не выбирали: каждый запрос — своя горутина. Измерено, как счётчик без замка сначала теряет один просмотр из пятисот, а потом роняет весь сервер, и как go test -race находит это заранее.
-
`context`: вовремя остановить запрос
Сорок третий урок курса по Go. Читатель закрыл вкладку — и обработчик узнаёт об этом сам: измерено, как он бросает работу через двести миллисекунд. Срок на запрос к базе, ключ своего типа вместо строки и обещанный переезд вошедшего человека в контекст запроса.
-
JSON и своё API: блог читают не только браузером
Сорок четвёртый урок курса по Go. Теги структуры решают, как поле называется снаружи и что скрыто совсем; лишнее поле в чужом JSON молчит, если не попросить обратного; число без типа становится float64. И ответ обработчика, у которого ошибка — тоже JSON.
-
Свой логотип, своё имя, своя иконка: блог становится вашим
Сорок пятый урок курса по Go. Блог носит чужое имя, чужой знак и чужие цвета — до этого урока. Имя переезжает из одиннадцати шаблонов в одну настройку, логотип становится вашим файлом, палитра — девятью строками, а иконка — вашей. Заодно посчитан контраст, и две наши ошибки исправлены.
-
Блог туда, где его откроют: бесплатный хостинг
Сорок шестой урок курса по Go. Хостинг решает за вас три вещи: порт приходит в переменной PORT, слушать надо все адреса машины, а не себя одного, и диск бесплатного тарифа исчезает при каждом деплое — измерено: вход тем же паролем даёт 303 до и 401 после. Плюс сборка в один статический файл.
-
Свой домен и HTTPS: чтобы блог открывали по имени
Сорок седьмой урок курса по Go. Домен — это одна запись в DNS, которая ведёт на ваш адрес, а HTTPS — не галочка, а необходимость: измерено, что в открытом канале пароль читателя виден целиком, все 222 байта, а в TLS его в этих байтах нет. Плюс прокси спереди и заголовок, которому нельзя верить.
-
Служба, которая переживёт перезагрузку: systemd и аккуратная остановка
Сорок восьмой урок курса по Go. Программу останавливают не кнопкой, а сигналом, и разница измерена: при обрыве читатель получает EOF, при аккуратной остановке — ответ 200 через 270 мс. Плюс файл службы, который проверил настоящий systemd, автозапуск после перезагрузки.
-
Перед запуском: чек-лист, а не надежда
Сорок девятый урок курса по Go. Сервер без таймаутов держит соединение бесконечно — измерено: медленный клиент занял его, и первыми сдались мы. Плюс копия базы, снятая на работающем блоге, описание страниц для поиска и список из тринадцати пунктов перед тем, как дать ссылку людям.
-
Куда дальше: дженерики и дорога после курса
Пятидесятый, последний урок курса по Go. Дженерики — одна функция вместо трёх, и условие на тип проверяет компилятор: измерено, что `string` не проходит до запуска. Измерено и чем они лучше `any`: 534 наносекунды против 1801. А ещё — куда идти дальше и что теперь умеет ваш блог.