Мета заняття: випустити версію 1.0 — поставити на неї незмінну позначку в git і дописати перелік змін — а потім показати робочий сервіс людям, які бачать його вперше й відкривають зі своїх телефонів.
Замість <логін> підставляєш свій
логін виду bohdan.g9: ім’я, крапка, номер групи. Кутові дужки не пишуться.
У прикладах на цій сторінці скрізь стоїть bohdan.g9 — читай це як свій логін
і виправляй у кожній команді, яку копіюєш. Кабінет — сторінка, де проти кожного критерію
стоїть відмітка, зарахований він чи ні.
<домен> — назва, яку ти записав у файл
~/app/project.yaml на занятті 10, розділ server, поле
url. Сабдомен (із заняття 10) — це частина адреси перед
доменом: в імені bohdan.g9.klub.example домен — klub.example,
а сабдомен — bohdan.g9. Саме цю адресу ти сьогодні даєш гостям, тому перевір
її першою справою.
Перші два рядки ведуть на одне й те саме: за обома адресами nginx віддає
файли з твоєї теки ~/www, а запити, в адресі яких є /api/,
передає твоїй службі. Різниця тільки в тому, як записана адреса самої служби: за
сабдоменом це /api/ping, а за адресою з цифрами —
/u/<логін>/api/ping. Сторінка звертається до служби за відносною
адресою (заняття 06), тому працює за обома.
Спершу ти доводиш проєкт до стану, який можна показувати: проганяєш тести, дописуєш
CHANGELOG.md щонайменше до восьми записів, ставиш у git тег v1.0
і оновлюєш сервіс на публічній адресі до цієї версії.
Далі — показ. По п’ять хвилин на людину: розповідаєш, для кого сервіс, показуєш три дії й одну історію про те, що в тебе зламалося і як ти це полагодив. Поки ти говориш, гості відкривають твою адресу на своїх телефонах і додають у сервіс справжні записи.
Наприкінці — голосування за три номінації: найкорисніший сервіс, найакуратніший, найстійкіший до злому.
Заняття довге, тому час розписаний наперед:
| Частина заняття | Час |
|---|---|
| Теорія: п’ять розділів і п’ять питань | 15 хв |
| Практика, кроки 1–10: підготовка релізу | 20 хв |
| Практика, кроки 11–12: підготовка до виступу | 8 хв |
| Крок 13: показ, дванадцять виступів по шість хвилин | 72 хв |
| Голосування й підсумок | 5 хв |
| Разом | 120 хв |
За три місяці в твоєму репозиторії накопичилося кількадесят комітів. Репозиторій
(із заняття 03) — це тека, у якій git зберігає всю історію проєкту: кожен збережений стан
файлів і порядок, у якому вони змінювалися. У тебе таких тек дві: ~/app, де ти
працюєш, і ~/repo.git, куди ти надсилаєш готове. Коміт
(теж із заняття 03) — це один збережений стан усіх файлів проєкту з підписом, що саме
змінилося. Коміти йдуть один за одним, і серед них є всякі: закінчена робота, половина роботи,
виправлення друкарської помилки в коментарі.
Сьогодні з цього ряду треба вибрати один коміт і сказати вголос: ось цей стан ми показуємо людям. Такий вибраний і названий стан називають релізом.
1.0. Номер потрібен, щоб можна було
назвати конкретний стан програми одним словом.Приклад із життя. Гра в тебе на телефоні пише «версія 2.14». Розробники за час між попереднім оновленням і цим зробили сотні змін у коді, але користувач бачить один номер і одне речення про те, що нового. Він не читає їхню історію змін по кроках — йому потрібен саме номер.
Навіщо це тобі сьогодні. Під час показу перед десятком людей може статися що завгодно: хтось надішле дивні дані, служба перезапуститься, ти сам випадково збережеш недописаний файл. Якщо в тебе є названий стан коду, повернутися до нього — одна команда. Якщо немає, ти шукатимеш потрібний коміт у списку з сорока рядків, поки гості дивляться.
Служба (із заняття 02) — це твоя програма, яку запускає і стежить за нею
сама операційна система: після перезавантаження сервера чи після помилки вона запускає
програму знову, і тобі не треба щоразу заходити на сервер і запускати її руками. Твоя служба
називається club-api — це ім’я їй дав викладач, коли створював тобі акаунт,
і воно однакове в усій групі. Керують службою командою systemctl, а прапорець
--user у ній означає «моя особиста служба, а не загальносерверна»: чужих служб ти
цією командою не бачиш і не чіпаєш.
FEEDBACK.md і виправ після демо. Правка «на одну хвилинку»
посеред демо-дня — найчастіша причина, чому сервіс перестає відповідати саме тоді, коли
до нього підійшли гості.
Номер версії складається з чисел, розділених крапками. У найпоширенішому порядку їх три:
1.4.2. Кожне число відповідає за свій розмір змін і рахується окремо від
сусідніх: після 1.9.0 йде 1.10.0, а не 2.0.0, бо
дев’ятка просто зростає до десяти.
| Число | Коли зростає | Приклад |
|---|---|---|
| перша | Змінилося так багато, що старі звички користувача більше не працюють | Був список справ, став календар з іншим виглядом сторінки: 1.4.2 →
2.0.0 |
| друга | З’явилося щось нове, але все старе працює як працювало | Додав кнопку «Поділитися посиланням»: 1.4.2 → 1.5.0 |
| третя | Тільки виправлення: нічого нового не з’явилося | Виправив дату, яка показувалася на день раніше: 1.4.2 →
1.4.3 |
Третє число часто не пишуть, поки його нема чим заповнювати. Тому сьогоднішній тег
називається v1.0, а не v1.0.0 — так коротше, і сенс той самий: перший
реліз, доповнень і виправлень після нього ще не було. Літера v на початку — від
слова version, вона нічого не змінює, але за нею одразу видно, що це номер версії, а не якесь
інше число.
Приклад із життя. Ти оновив додаток і бачиш «1.4.3, виправлено помилку, через яку додаток закривався сам при відкритті фото». Останнє число зросло на одиницю — можна очікувати, що все на місці й нічого переучувати не доведеться. Якщо ж номер став «2.0», варто прочитати, що там нового: там щось переробили помітно.
Ольга випустила версію 1.0. Наступного дня вона помітила, що в
повідомленні про помилку написано «Назва не може бути порожня.» замість «Назва не може бути
порожньою.», і виправила цей текст. Більше вона нічого не чіпала. Який номер поставити новій
версії?
У кожного коміта є ідентифікатор — рядок виду 9f3c1ab4e7d2... на сорок
символів, який git рахує сам. Скорочено пишуть перші сім: 9f3c1ab. Такий рядок
неможливо запам’ятати й незручно диктувати. Тому потрібному коміту дають ім’я.
git tag v1.0 усюди, де git
очікує ідентифікатор коміта, можна писати v1.0.Головна властивість тега — він не рухається. Порівняй із гілкою. Гілка —
це теж ім’я, прив’язане до коміта, але рухоме: у тебе гілка одна, вона називається
master і завжди показує на останній коміт. Щойно ти зробиш новий коміт, ім’я
master почне показувати вже на нього. Тег v1.0 показуватиме на той
самий коміт і завтра, і через рік, скільки б комітів ти не додав після нього. Через це тег і
годиться для релізу: за ним завжди знаходиться саме той стан коду, який бачили гості.
Теги бувають двох видів.
git tag v1.0 — тільки ім’я і нічого більше. Хто поставив і коли, git не
збереже.git tag -a v1.0 -m "текст" — окрім імені, git запише автора, дату й
повідомлення, яке ти дав після -m. Саме такий ми й ставимо: через півроку буде
видно, що це за версія і коли вона з’явилася.Три команди, які знадобляться на практиці:
git tag -a v1.0 -m "Реліз 1.0: перша версія, показана на демо-дні"
git tag -n
git show v1.0git tag -n друкує список тегів разом із першим рядком повідомлення.
git show v1.0 показує сам тег і коміт, на який він вказує: автора, дату, список
змінених файлів.
git push origin master надсилає у ~/repo.git коміти гілки
master, але теги лишає на місці. Щоб тег опинився й там, його надсилають окремою
командою: git push origin v1.0. Про це забувають частіше, ніж про будь-що інше
на цьому занятті, а критерій L12.1 перевіряє саме репозиторій
~/repo.git.
Слово origin у цих командах — не команда git і не гілка, а коротке ім’я, яким
твій репозиторій ~/app називає інший репозиторій, куди надсилає роботу. Ти задав
його на занятті 03, і показує воно на ~/repo.git. Побачити, куди саме
origin веде, можна командою git remote -v.
Богдан поставив тег v1.0, виконав git push origin
master і пішов на перерву. Автоперевірка написала, що тег v1.0 не
знайдено. Що сталося?
CHANGELOG (читається «ченджлог», від change log — запис змін) — файл, у
якому по версіях перелічено, що змінилося в програмі. Лежить у корені репозиторію й
називається CHANGELOG.md.
У тебе вже є git log — список усіх комітів. Різниця між ними у тому, для кого
вони написані. git log пише про кожен коміт словами того, хто цей код писав:
«поправив імпорт», «те саме, але без зайвого запиту». CHANGELOG пише про зміни, які помітив
би користувач, і словами, зрозумілими без коду.
Приклад із життя. У магазині додатків під кнопкою «Оновити» є короткий текст «що нового» — це і є CHANGELOG. Ніхто не показує там перелік комітів: він нічого не пояснить людині, яка просто хоче знати, чи полагодили те, що їй заважало.
Як виглядає запис. Кожен рядок — одна зміна, що починається з дієслова: «Додано»,
«Виправлено», «Прибрано», «Змінено». Порівняй два записи про одне й те саме. У правому
стовпці трапляються числа 500 і 422 — це коди відповіді, якими
сервер відповідає браузерові на кожен запит. Ти бачив їх на заняттях 05 і 08; коротко:
200 — усе гаразд, сторінку віддано; 404 — за такою адресою нічого
немає; 422 — запит дійшов, але дані в ньому не годяться, наприклад порожня
назва; 500 — у програмі на сервері сталася помилка, і вона не змогла
відповісти.
| Так не годиться | Так годиться |
|---|---|
| поправив main.py | Виправлено помилку 500 при порожній назві: тепер сервіс відповідає 422 й пояснює, що поле обов’язкове |
| зробив дизайн | Додано підписи до полів форми й напис «Поки що жодного запису» для порожнього списку |
| оптимізація | Зменшено вагу сторінки з 812 КБ до 176 КБ: картинки переведено у формат WebP |
Ліві записи неможливо прочитати через місяць: у них немає ні того, що змінилося, ні того, для кого це важливо. Праві читаються без коду й без пояснень автора.
Основні записи ти вже приніс із домашнього завдання заняття 11 — там треба було виписати щонайменше вісім змін, поки деталі ще свіжі в пам’яті. Сьогодні залишається перевірити їх, додати те, що ти зробив уже після здачі того завдання, і поставити зверху заголовок версії.
Іван відкрив CHANGELOG.md і побачив у себе рядок «Виправив баг у
db.py». Автоперевірка рахує записи і цей теж порахує. Чому цей рядок усе одно варто
переписати?
Демо — це коли ти показуєш працюючий сервіс людям, які його ще не бачили: батькам, друзям, молодшій групі. У тебе рівно п’ять хвилин і хвилина на те, щоб змінити доповідача. Дванадцять людей по шість хвилин — це сімдесят дві хвилини, тобто більша частина сьогоднішнього заняття.
Виступ складається з чотирьох частин у такому порядку.
| Частина | Час | Що сказати |
|---|---|---|
| Проблема | 1 хв | Для кого ти це зробив і що цій людині заважало. Одна конкретна людина з іменем, а не «усі підлітки». |
| Рішення | 1 хв | Що робить сервіс і чому саме так. Двома-трьома реченнями, без назв бібліотек. |
| Показ | 2 хв | Три дії на живій сторінці. Вирішені заздалегідь, а не «зараз щось спробуємо». |
| Історія поломки | 1 хв | Що в тебе зламалося за три місяці, як ти про це дізнався і що зробив. |
Кілька порад, які економлять час на показі.
main.py не
встигнеш, і гостям це нічого не пояснить. Якщо хтось спитає про код — покажеш після
виступу.Окрема річ, до якої треба підготуватися: гості користуються сервісом по-справжньому. Це означає, що десяток людей одночасно відкриють твою адресу й почнуть щось додавати. Такого не дасть жоден тест, який ти запускаєш у себе. Тому перед показом потрібні дві речі: свіжа копія бази (раптом хтось додасть двадцять порожніх записів і ти захочеш повернути список до попереднього стану) і відкритий журнал служби в сусідньому вікні терміналу, щоб одразу бачити помилки.
Журнал — це записи, які служба веде про свою роботу: коли запустилася, які
запити отримала, на чому зупинилася через помилку. Дивляться його командою
journalctl --user -u club-api: --user означає «моя особиста
служба», а -u club-api — «журнал саме цієї служби, а не всіх одразу».
Посеред виступу Марка сторінка перестала відкриватися: гості бачать помилку. До кінця його часу лишилося дві хвилини. З чого починати?
До початку демо лишилося десять хвилин. Софія бачить, що один із п’яти тестів
не проходить: test_delete_missing_gives_404. Що робити?
У прикладах — таблиця habit і адреси /api/habits із занять 04 і
05. Підставляй свої назви: вони записані у project.yaml у розділах
database і endpoints (розділи у цьому файлі названі англійською —
так їх читає програма перевірки, перекладати їхні назви не можна).
Три слова, які часто трапляються далі на цій сторінці.
/api/, віддають не оформлену сторінку, а самі дані. Звідси й ім’я
твоєї служби — club-api.project.yaml — розділ endpoints)GET /api/habits — віддай список, POST /api/habits — прийми новий
запис, DELETE /api/habits/{id} — видали запис із таким номером. Слово перед
адресою браузер надсилає разом із запитом, і сервіс за ним розрізняє, чого від нього
хочуть.GET /api/habits віддає твій список.v1.0.
ssh bohdan.g9@91.219.61.4
cd ~/app
git status --short
git log --oneline | head -5git status --short має відповісти порожнечею — це означає, що всі зміни
закомічені. Якщо там є рядки, закомить їх зараз:
git add -A
git commit -m "Останні правки перед релізом"git log --oneline | head -5 друкує п’ять останніх комітів по одному рядку:
скорочений ідентифікатор і повідомлення. Подивись на верхній рядок — саме на цей коміт стане
тег v1.0, якщо ти більше нічого не змінюватимеш.
cd ~/app
/opt/club/venv/bin/python -m pytest -q testsТут два слова потребують пояснення. /opt/club/venv — це спільна тека, у яку
адміністратор один раз установив python разом із бібліотеками курсу (FastAPI та інші).
Такий набір називають віртуальним середовищем, скорочено venv. Просто python
писати не можна: системний python цих бібліотек не бачить, і тести одразу зупиняться з
повідомленням ModuleNotFoundError. pytest — програма, яка знаходить
у теці tests усі функції-тести, виконує їх і звітує, які з них дали очікуваний
результат. Прапорець -q робить вивід коротким.
Очікуваний вивід — п’ять крапок і рядок про те, що все пройдено:
..... [100%]
5 passed in 0.71sЯкщо хоч один тест не проходить, зупинись тут і розберись. Це або справжня помилка в
коді, або тест, який більше не відповідає тому, як працює сервіс. В обох випадках ставити
тег зарано: ./deploy.sh усе одно зупиниться на тестах і не оновить сервіс.
Читай вивід pytest знизу вгору. Усередині тесту стоїть рядок зі словом
assert — це вимога «ось це має бути правдою»; якщо вона не справджується, тест
зупиняється саме на ній. Pytest друкує цей рядок і два значення поруч: чого тест чекав і що
отримав насправді.
У тебе є FEEDBACK.md — зауваження трьох людей із домашнього завдання
заняття 10. Відкрий його:
less ~/app/FEEDBACK.mdless показує файл посторінково: пробіл — далі,
q — вийти.
Вибери звідти щонайбільше дві правки, кожна з яких робиться за чотири хвилини:
перейменувати кнопку, дописати підказку під полем, поміняти порядок сортування. Усе інше
перенеси у файл PLANS.md — це список того, що робитимеш після курсу.
nano ~/app/PLANS.mdФайли з розширенням .md пишуться у форматі Markdown — той самий, що в
README.md із заняття 03. Правил тут потрібно два: рядок, який починається з
# і пробілу, стає заголовком, а рядок, який починається з - і
пробілу, стає пунктом списку.
# Що зробити після курсу
- Нагадування о 20:00 (просив брат, потрібна робота з часом).
- Сторінка статистики за тиждень.
- Можливість редагувати назву запису, а не тільки видаляти й додавати.Після кожної правки в коді — тести й коміт:
/opt/club/venv/bin/python -m pytest -q tests
git add -A
git commit -m "Кнопку перейменовано на «Додати до списку» за зауваженням із FEEDBACK"CHANGELOG.mdФайл ти почав у домашньому завданні заняття 11. Відкрий його й доведи до вигляду нижче: зверху заголовок версії з датою, під ним записи.
nano ~/app/CHANGELOG.md# Що змінилося
Проєкт: Трекер звичок. Автор: Богдан.
Номер версії: перше число — реліз, друге — нові можливості,
третє — виправлення.
## 1.0 — 13 вересня 2026
Перша версія, показана на демо-дні.
- Додано сторінку зі списком звичок і формою додавання.
- Додано збереження звичок у базу SQLite замість текстового файлу:
дані не зникають після перезапуску служби.
- Додано адресу GET /api/habits — список звичок у форматі JSON.
- Додано адресу POST /api/habits — додавання звички з форми.
- Додано адресу DELETE /api/habits/{id} — видалення звички.
- Додано вхід власника за паролем: дивитися список може будь-хто,
додавати й видаляти — тільки я.
- Виправлено помилку 500 при порожній назві звички: тепер відповідь 422
з поясненням, що поле обов’язкове.
- Виправлено видалення неіснуючої звички: замість помилки 500 приходить 404.
- Додано напис «Поки що жодної звички» замість порожньої сторінки.
- Додано підписи до полів форми, щоб було зрозуміло, що вводити.
- Зменшено вагу сторінки з 812 КБ до 176 КБ: картинки переведено у формат WebP.
- Додано щоденну копію бази й інструкцію RUNBOOK.md на випадок,
коли сервіс не відповідає.Розберемо розмітку. Один # на початку рядка — заголовок першого рівня, два
## — заголовок другого рівня, тобто підрозділ. Рядок, що починається з
-, стає пунктом списку. Порожній рядок між абзацами обов’язковий: без нього
Markdown вважатиме два сусідні рядки одним абзацом.
Дату пиши справжню — ту, коли проходить демо-день. Записів має бути щонайменше вісім, у прикладі їх дванадцять. Перечитай свої: якщо рядок не зрозумілий людині, яка не бачила твого коду, перепиши його за зразком із теорії.
cd ~/app
git add CHANGELOG.md PLANS.md
git commit -m "CHANGELOG: перелік змін від першого заняття до релізу 1.0"
git log --oneline | head -3Тепер верхній коміт у списку — це той стан, який стане версією 1.0. Далі до кінця показу нічого в коді не змінюємо.
v1.0git tag -a v1.0 -m "Реліз 1.0: перша версія, показана на демо-дні"Команда нічого не друкує — це нормально. -a означає анотований тег (git
збереже автора, дату й повідомлення), -m — саме повідомлення. Тег стає на той
коміт, який зараз верхній у гілці.
Перевір, що вийшло:
git tag -n
git show v1.0 --stat | head -20git tag -n покаже один рядок:
v1.0 Реліз 1.0: перша версія, показана на демо-дніgit show v1.0 --stat друкує спершу сам тег із твоїм іменем і датою, далі
коміт, на який він указує, і перелік файлів, змінених у цьому коміті.
| head -20 обрізає вивід до двадцяти рядків, щоб він не зайняв увесь
екран.
git tag -d v1.0 і ставиться заново. Це безпечно,
поки тег не надіслано в ~/repo.git. Після надсилання видаляти вже не варто:
краще поставити наступний номер.
~/repo.gitgit push origin master
git push origin v1.0Дві окремі команди, і друга не менш важлива за першу: push гілки надсилає
коміти, але теги лишає на місці. Саме тут найчастіше зупиняються.
Перевір, що тег з’явився в ~/repo.git:
git -C ~/repo.git tag
git -C ~/repo.git log --oneline | head -3git -C <тека> означає «виконати команду так, ніби ми в цій теці». Перша
команда має надрукувати v1.0, друга — ті самі коміти, що й у
~/app. Якщо тега в списку немає, повтори git push origin v1.0 і
прочитай, що git відповість: у відповіді буде причина.
cd ~/app
./deploy.sh
echo $?Скрипт із заняття 09 робить чотири кроки по черзі: забирає коміти з
~/repo.git, проганяє тести, перезапускає службу club-api і
перевіряє, що /api/ping відповідає кодом 200 («усе гаразд»).
echo $? друкує код виходу останньої команди. Нуль означає, що скрипт дійшов
до кінця. Будь-яке інше число — зупинився на якомусь кроці, і в його виводі написано, на
якому саме.
Останній рядок виводу має бути таким:
ГОТОВО: /api/ping відповів 200Спершу з сервера, через публічну адресу. Подивись, яку адресу ти записав у
project.yaml:
grep url ~/app/project.yaml url: "https://bohdan.g9.klub.example/"Тепер запиши цю адресу у змінну, щоб не набирати її щоразу. Без лапок і без
скісної риски в кінці — риску ми додамо самі в наступних рядках, а дві риски
поспіль (//) багато серверів вважають іншою адресою й відповідають
404:
MY=https://bohdan.g9.klub.example
curl -s -o /dev/null -w 'сторінка: %{http_code}\n' "$MY/"
curl -s -o /dev/null -w 'api/ping: %{http_code}\n' "$MY/api/ping"curl — програма, яка робить той самий запит, що й браузер, але з командного
рядка і без малювання сторінки. Прапорці означають:
-s — не показувати смужку завантаження;-o /dev/null — саму сторінку нікуди не зберігати. /dev/null —
спеціальний файл Linux, з якого нічого не читається, а все записане в нього просто
зникає. Нам потрібен лише код відповіді, а не текст сторінки;-w 'сторінка: %{http_code}\n' — надрукувати наприкінці свій рядок.
Замість %{http_code} curl підставить код відповіді, а \n —
це перехід на новий рядок.Обидві перевірки мають надрукувати 200 — «усе гаразд». Критерій
L12.2 перевіряє рівно це, тільки під час показу.
curl: (6) Could not resolve host означає, що в адресі помилка в написанні
або в полі url записано не те: перевір рядок посимвольно. Помилка зі словами
URL using bad/illegal format — ти лишив у змінній лапки з
project.yaml: набери адресу без них. Якщо приходить 404,
а служба працює, подивись, чи не потрапила
в змінну зайва скісна риска в кінці: echo "$MY" має надрукувати адресу, що
закінчується назвою домену.
Тепер найважливіше: відкрий адресу з телефона, вимкнувши Wi-Fi. Гості заходитимуть саме так — зі свого мобільного інтернету, а не з класної мережі. Пройди всі три дії, які показуватимеш, і подивись, чи вміщується сторінка в екран без горизонтальної прокрутки.
Попроси сусіда відкрити твою адресу зі свого телефона й додати один запис. Якщо в нього вийшло — адреса робоча для чужих людей, а не тільки для тебе.
На занятті 11 ти налаштував щоденну копію бази через crontab — особистий
розклад команд. Подивись, який саме скрипт там записано, і запусти його руками, щоб копія
була зроблена не вчора вночі, а щойно:
crontab -l
ls -lt ~/backups | head -3crontab -l друкує твій розклад: у рядку буде час і повний шлях до скрипта —
щось на зразок /home/bohdan.g9/app/backup.sh, тільки з твоїм логіном замість
bohdan.g9. Запусти цей скрипт і перевір, що з’явився новий файл:
~/app/backup.sh
ls -lt ~/backups | head -3ls -lt сортує за часом зміни, найновіше зверху. Верхній файл має бути
датований сьогоднішньою хвилиною. Якщо в тебе скрипт називається інакше — підстав своє ім’я
з виводу crontab -l.
Навіщо це зараз: під час показу десяток людей додасть у твій сервіс справжні записи, і
серед них можуть трапитися випадкові або порожні. Зі свіжою копією ти повернеш список до
того стану, який був до демо, однією командою з RUNBOOK.md.
План потрібен на папері або у відкритому файлі на телефоні. Тримати його в голові перед десятком незнайомих людей не виходить майже ні в кого.
nano ~/DEMO.mdЦей файл лежить у домашній теці ~, а не в ~/app, як
FEEDBACK.md, PLANS.md і CHANGELOG.md. Причина проста:
DEMO.md — твоя особиста нотатка, а не частина проєкту, і в репозиторій вона не
потрапляє. До того ж після кроку 6 у теці ~/app ми до кінця показу нічого не
змінюємо.
# План виступу — 5 хвилин
## Проблема (1 хв)
Для кого: мій молодший брат, 11 років.
Що заважало: забуває, що вже зробив, і о десятій вечора з’ясовує,
що не зробив нічого.
## Рішення (1 хв)
Що робить сервіс: показує список справ на день, кожну можна
відмітити одним дотиком.
Чому саме так: телефон завжди під рукою, зошит — ні.
## Показ (2 хв) — рівно три дії
1. Відкрити сторінку, показати список із чотирьох записів.
2. Додати справу «Вивчити вірш» — вона з’являється зверху одразу.
3. Відмітити її — лічильник унизу змінюється з 2 на 3.
## Історія поломки (1 хв)
Що зламалося: після надсилання порожньої форми сторінка показувала
помилку 500.
Як дізнався: сусід на занятті 08 надіслав порожню назву, і сервіс
відповів помилкою 500.
Що зробив: додав перевірку, тепер приходить 422 і текст
«Назва не може бути порожньою».
## Якщо не відкриється
Запасна адреса: http://91.219.61.4/u/bohdan.g9/
Поки перезапускаю службу, розповідаю, як влаштована база.Останній розділ — про запасний варіант. Твоя сторінка доступна за двома адресами: за
сабдоменом і за адресою з цифрами. Обидві обслуговує той самий nginx, який звертається до тієї самої теки
~/www і до тієї самої служби, тому сторінка за ними однакова. Якщо одна не
відкриється, ти назвеш другу, не втрачаючи часу на роздуми. Перевір запасну адресу зараз,
разом із основною: відкрий її й пройди ті самі три дії.
Прочитай план уголос із секундоміром. Якщо не вкладаєшся в п’ять хвилин, скорочуй розділ «Рішення»: саме там зазвичай з’являються зайві подробиці.
Три речі, зроблені до того, як тебе викличуть.
http://91.219.61.4/k/bohdan.g9/ — там
видно зараховані критерії, якщо хтось спитає.journalctl --user -u club-api -f-f (від follow) означає «показувати нові рядки, поки не зупиню». Рядки
з’являтимуться самі, коли гості заходитимуть на твою сторінку. Вийти —
Ctrl+C: журнал закриється, служба
працюватиме далі.
Дивись на це вікно краєм ока під час показу. Рядок зі словом Traceback або
500 означає, що в коді сталася помилка на чиємусь запиті. Це не привід
зупиняти виступ — це матеріал для розмови після нього.
Порядок виступів називає викладач. Поки говорить хтось інший:
Голосування наприкінці займає п’ять хвилин: три номінації, у кожній називаєш одну людину, крім себе:
| Номінація | За що |
|---|---|
| Найкорисніший | Сервісом хочеться користуватися далі, а не тільки подивитися |
| Найакуратніший | Зрозуміло з першого погляду, що робити на сторінці; на телефоні все вміщується в екран без горизонтальної прокрутки |
| Найстійкіший до злому | Ти пробував зламати й не зміг: порожні поля, чужі запити, довгі назви |
Після голосування — останні дві дії на сервері: зберегти зауваження гостей і зробити ще одну копію бази, тепер уже з даними, які додали під час показу.
nano ~/app/FEEDBACK.md
~/app/backup.sh
ls -lt ~/backups | head -2П’ять критеріїв заняття 12. Чотири з них перевіряє програма, п’ятий — L12.5 —
оцінює викладач під час показу. Перевірка запускається за розкладом, тому відмітка в кабінеті
з’являється не в ту саму секунду, коли ти виконав команду. Публічну адресу програма бере з
~/app/project.yaml, розділ server, поле url.
| Код | Критерій | Що це означає | Не зараховано — що робити |
|---|---|---|---|
| L12.1 | тег v1.0 існує в репозиторії | Позначка з іменем v1.0 має бути в ~/repo.git — у тому
репозиторії, куди ти надсилаєш коміти. За нею потім знаходять саме той стан коду, який
показували на демо, скільки б комітів не з’явилося пізніше. |
Перевір, що бачить сам репозиторій: git -C ~/repo.git tag. Порожній
вивід означає, що тег лишився тільки в ~/app — надішли його окремою
командою git push origin v1.0. Якщо тега немає й у
~/app (git tag -n мовчить), постав його заново: крок 6
практики. Перевір ім’я посимвольно: V1.0 з великою літерою або
v.1.0 зайвою крапкою — це інші імена. |
| L12.2 | сервіс відповідає 200 під час демо | Програма звертається до твоєї публічної адреси в час показу й чекає код відповіді
200 — «сторінка віддана». Перевіряються головна сторінка й
/api/ping. |
Подивись стан служби: systemctl --user status club-api. Рядок
active (running) — служба працює. Якщо там failed, читай
причину: journalctl --user -u club-api -n 30. Найчастіші причини за три
місяці — друкарська помилка в коді, який зберегли перед самим показом, і незакінчена
правка. Запустити службу заново:
systemctl --user restart club-api. Якщо служба працює, а адреса не
відкривається, перевір поле url у project.yaml: там має бути
твоя адреса, а не чужий логін. |
| L12.3 | CHANGELOG.md містить ≥8 записів | Програма читає ~/app/CHANGELOG.md і рахує рядки-пункти списку — ті, що
починаються з -. Їх має бути щонайменше вісім. Файл має бути закомічений і
надісланий: те, чого немає в репозиторії, для перевірки не існує. |
Порахуй сам: grep -c '^- ' ~/app/CHANGELOG.md — -c друкує
кількість рядків, що підійшли. Якщо число менше восьми, дописуй: за три місяці змін
точно більше, дивись git log --oneline і переписуй коміти словами,
зрозумілими користувачеві. Якщо число вісім і більше, а критерій не зарахований, перевір
git status --short і зроби git add CHANGELOG.md,
git commit, git push origin master. |
| L12.4 | усі тести проходять | Програма запускає твої тести з теки ~/app/tests і дивиться, що жоден із
них не завершився помилкою. Ті самі п’ять тестів із заняття 09: список повертається,
запис додається, погані дані відхиляються, сторонній не видаляє, неіснуюче дає 404. |
Запусти в себе: cd ~/app && /opt/club/venv/bin/python -m pytest -q
tests. Читай вивід із рядків, де стоїть assert: там видно, чого тест
чекав і що прийшло насправді. Якщо тести зупиняються з повідомленням
ModuleNotFoundError, ти запустив не той python — потрібен саме
/opt/club/venv/bin/python. Якщо в тебе на сервері тести проходять, а
перевірка каже інакше, значить у ~/repo.git лежить не та версія:
git status --short і git push origin master. |
| L12.5 | демо проведено (оцінює викладач) | Виступ на п’ять хвилин: проблема, рішення, показ на живій сторінці й історія про те, що зламалося і як ти це полагодив. Гості при цьому користуються твоїм сервісом зі своїх телефонів. | Цей критерій не має другої спроби в той самий день, тому підготовка з кроків 11 і 12 важить більше за все інше. Якщо ти пропустив демо-день з поважної причини, час показу призначає викладач окремо. |
Курс закінчився, але сервер працює далі: акаунт лишається щонайменше на три місяці, і твоя адреса відкривається так само, як сьогодні. Це завдання — про те, щоб вона такою й лишилася.
Перше. Зауваження гостей — у файл. Поки пам’ятаєш, допиши
FEEDBACK.md: що люди питали, де зупинялися, що не змогли знайти. Формат той
самий, що після заняття 10, з рядком «сказав дослівно». Потім познач у
PLANS.md, які з цих зауважень ти справді збираєшся зробити.
Друге. Випустити версію 1.1 або 1.0.1. Зроби одну правку зі свого списку й повтори весь порядок дій релізу — тепер уже самостійно, без сторінки з підказками:
cd ~/app
# правка в коді
/opt/club/venv/bin/python -m pytest -q tests
nano CHANGELOG.md # новий розділ ## 1.0.1 із датою
git add -A
git commit -m "Виправлено сортування списку: найновіші записи зверху"
git tag -a v1.0.1 -m "Виправлення після демо-дня"
git push origin master
git push origin v1.0.1
./deploy.shНомер вибирай за таблицею з теорії: додав щось нове — v1.1, тільки виправив
— v1.0.1. Рядок, що починається з #, у командному рядку — це
коментар, він не виконується.
Третє. Раз на тиждень перевіряти, що сервіс живий. Одна команда з
телефона чи комп’ютера — відкрити свою адресу. Якщо сторінка не відкрилася, у тебе є
RUNBOOK.md із заняття 11: там записано, які команди виконати й куди
дивитися.
Четверте. Перечитати README.md очима людини, яка бачить проєкт
уперше. Розділи «Що це» і «Як запустити» ти писав на занятті 03, і за три місяці
проєкт змінився. Перевір, що команди в README справді працюють, якщо виконати їх по
порядку. Через півроку ти сам будеш тією людиною, яка бачить цей код уперше.
Тег із таким іменем уже поставлений — можливо, ти виконав команду двічі. Подивись, на якому він коміті:
git show v1.0 --stat | head -12
git log --oneline | head -3Якщо тег стоїть на правильному коміті (тому ж, що зверху в git log), нічого
робити не треба — переходь до git push origin v1.0. Якщо тег стоїть на старому
коміті, а після нього ти зробив ще кілька, видали й постав заново:
git tag -d v1.0
git tag -a v1.0 -m "Реліз 1.0: перша версія, показана на демо-дні"
git tag -n-d (delete) прибирає тільки позначку, самі коміти лишаються на місці. Але це
безпечно, поки тег не надіслано в ~/repo.git. Якщо він уже там, не видаляй його:
постав наступний номер v1.0.1. Переставляти вже опублікований тег — спосіб
отримати два різні стани коду з однією назвою.
~/app, а в кабінеті критерій не зарахованийПеревір, що бачить сам репозиторій:
git tag -n
git -C ~/repo.git tagПерша команда друкує тег, друга мовчить — тег не надісланий. Надішли:
git push origin v1.0Якщо git відповідає Everything up-to-date, а тега в
git -C ~/repo.git tag усе одно немає, подивись, чи туди ти надсилаєш:
git remote -vВивід — два рядки: git окремо показує, звідки він забирає коміти (fetch) і
куди надсилає (push). Між іменем і шляхом стоїть символ табуляції, тому пробіл
там може виглядати ширшим:
origin /home/bohdan.g9/repo.git (fetch)
origin /home/bohdan.g9/repo.git (push)Шлях має бути твій — із твоїм логіном. Чужий логін або інший шлях означає, що коміти надсилаються не в той репозиторій: покажи цей вивід викладачеві.
Найчастіше вивід виглядає так:
==> 1/4 забираємо коміти з ~/repo.git
fatal: Not possible to fast-forward, aborting.Це означає, що в ~/repo.git є коміти, яких немає в ~/app, і
навпаки: історії розійшлися. Скрипт свідомо не намагається їх поєднати сам. Подивись, чим
відрізняються:
git fetch origin
git log --oneline HEAD..origin/master
git log --oneline origin/master..HEADgit fetch забирає інформацію про чужі коміти, нічого не змінюючи в твоїх
файлах. Далі два нових слова. HEAD — так git називає коміт, на якому ти зараз
стоїш, тобто верхній у твоєму ~/app. origin/master — верхній коміт
гілки master у репозиторії ~/repo.git, яким git його запам’ятав під
час fetch. Запис A..B між ними читається так: покажи коміти, які є
в B і яких немає в A.
Тому перша команда покаже коміти, які є тільки в репозиторії, друга — які є тільки в тебе.
Якщо перший список порожній, просто надішли своє: git push origin master. Якщо в
обох списках щось є — це та ситуація, яку сьогодні не розв’язують поспіхом перед показом,
клич викладача.
Три команди по черзі, у цьому порядку:
systemctl --user status club-api
journalctl --user -u club-api -n 30
systemctl --user restart club-apiПерша каже, у якому стані служба. active (running) — працює,
failed — служба зупинилася через помилку і не змогла запуститися знову. Друга
друкує тридцять останніх рядків журналу: читай знизу вгору, останній рядок із
Error або Traceback і є причиною. Третя перезапускає службу.
Після перезапуску перевір сервіс прямо на сервері, не через публічну адресу. Для цього
потрібен номер твого порту. Порт — число, за яким на одній машині
розрізняють програми, що приймають запити з мережі: у тебе такий номер свій, у сусіда інший,
тому ваші служби не заважають одна одній. Твій номер записаний у файлі служби, у рядку
ExecStart:
grep ExecStart ~/.config/systemd/user/club-api.serviceExecStart=/opt/club/venv/bin/uvicorn main:app --host 127.0.0.1 --port 9536У твоєму файлі число після --port буде інше — воно твоє на весь курс
(заняття 02). Підстав його в команду нижче замість 9536:
curl -s -o /dev/null -w '%{http_code}\n' http://127.0.0.1:9536/api/ping127.0.0.1 — це адреса «ця сама машина»: запит нікуди не виходить у мережу й
не проходить через nginx. Якщо тут 200, а ззовні сторінка не відкривається,
справа не в твоєму коді — скажи викладачеві.
Якщо служба зупиняється одразу після запуску, поверни код до стану релізу:
cd ~/app
git stash
git checkout v1.0
systemctl --user restart club-apigit stash прибирає незбережені зміни вбік, щоб вони не заважали;
git checkout v1.0 перемикає файли на той стан, який ти позначив тегом.
You are in 'detached HEAD' state і займає рядків
десять. Нічого не зламалося. Так git каже, що ти зараз стоїш не на гілці, а на окремому
коміті: ім’я master лишилося там, де було, а файли перед тобою — з тега
v1.0. У цьому стані не роби комітів: вони не потраплять у жодну гілку, і
після git checkout master знайти їх буде важко. Дочекайся кінця показу.
Після демо повернешся на гілку командою git checkout master — і попередження
зникне, — а відкладені зміни дістанеш через git stash pop.
Спочатку з’ясуй, у скількох людей так. Якщо не відкривається в одного, а в решти працює,
річ у його телефоні чи мережі. Дай другу адресу — ту, що з цифрами:
http://91.219.61.4/u/bohdan.g9/. Вона веде на ту саму теку й ту саму службу, але
в ній немає імені, яке треба перетворювати на число: якщо мережа його оператора ще не знає,
який IP відповідає твоєму сабдомену, адреса з цифрами відкриється однаково.
Якщо не відкривається в усіх, перевір сервіс командами з попереднього пункту. Коли служба
працює й curl на сервері віддає 200, продиктуй адресу ще раз по літерах: у
довгому імені легко почути одне замість іншого.
Окремий випадок — гість бачить сторінку, але додати запис не може. Це нормально: додавання й видалення на занятті 07 закриті паролем, і роблять їх тільки з твого входу. Скажи це вголос, інакше гість вирішить, що сервіс зламався.
Спокійно допрацюй виступ до кінця — на пів хвилини це не вплине. Після демо подивись, що там:
ls -lt ~/backups | head -3
sqlite3 ~/data/app.db "SELECT id, title FROM habit ORDER BY id DESC LIMIT 10;"sqlite3 — програма, яка відкриває файл бази й виконує запит, написаний після
неї в лапках. Тут запит просить показати номер і назву десяти останніх записів таблиці
habit: ORDER BY id DESC — від найбільшого номера до найменшого,
LIMIT 10 — не більше десяти рядків. Підстав назву своєї таблиці й своїх полів
із project.yaml.
Якщо зайвих записів кілька, видали їх через свою ж сторінку — це швидше й безпечніше за
роботу з базою напряму. Якщо їх десятки, відновлюй базу з копії за інструкцією з
RUNBOOK.md: саме для цього ти робив свіжу копію на кроці 10. Зверни увагу, що
разом із випадковими зникнуть і справжні записи, додані під час показу.