tasks.json. Сьогодні буде roadmap.htmlТема 6, урок 2 з 2. Онлайн-дошки та управління проєктами. 120 хвилин
Минулого разу ти зібрав tasks.json — беклог із дієсловами,
дедлайнами й критеріями готовності. Сьогодні з цього самого файлу сторінка
roadmap.html намалює дошку в три колонки.
Різниця між «у мене є список задач» і «у мене є процес» — не в кількості задач. У списку бракує трьох речей. Сьогодні ти додаси всі три.
Перше — обмеження. Це число: скільки задач тобі дозволено тримати в роботі одночасно. Більше не береш, поки не закриєш одну зі старих.
Друге — критерій завершення. Це список умов, за яких задачу можна назвати зробленою. Поки хоч одна умова не виконана, картка лишається на місці.
Третє — горизонт. Це поділ задач на три купки: що ти робиш зараз, що відкладено на потім і що не робитимеш ніколи. Третя купка потрібна не менше за перші дві.
done, — по пунктах, а не «на око»;roadmap.html, у якій жодної назви задачі
не вписано руками — усе читається з tasks.json;Слова WIP-ліміт, Definition of Done і burndown поки нічого не означають — розберемо кожне тоді, коли воно знадобиться.
| Етап | Хв | Що ти зробиш |
|---|---|---|
| Вхідний зріз беклогу | 10 | Порівняєш свій tasks.json із класом: скільки задач, епіків, який розподіл пріоритетів |
| Канбан і WIP-ліміт | 20 | Побачиш на числах, чому пʼять задач одночасно повільніше, ніж по одній |
| Канбан на даних | 15 | Вставиш свій JSON у тренажер, потягаєш картки й упрешся у власний WIP-ліміт |
| Definition of Done і віхи | 15 | Напишеш, що означає «готово», і позначиш три віхи запуску |
Практика: roadmap.html | 35 | Зверстаєш сторінку, у якій немає жодної назви задачі — усе приходить із JSON |
| Симулятор спринту | 20 | Прокрутиш 10 робочих днів свого беклогу з подіями з реального життя |
| Автоперевірка | 5 | Запустиш check11 6 — і закриєш тему 6 повністю |
~/www/roadmap.html: дошка в три колонки плюс блок віх.
Усі назви задач сторінка забирає з tasks.json сама.
Другий файл — оновлений tasks.json зі справжніми статусами задач.
Перевірка підмінить назву однієї задачі в JSON і подивиться, чи змінилася
сторінка.Найчастіша помилка першої дошки — колонки «Понеділок / Вівторок / Середа»
Слово канбан (看板) японською означає «сигнальна картка». На заводах Toyota така картка була дозволом на роботу. Ділянка не бралася за нову деталь, поки не отримувала картку далі по конвеєру.
Картка приходила тоді, коли на наступній ділянці звільнялося місце. Тобто правило звучало не «роби скільки встигнеш», а «роби стільки, скільки сусід здатен узяти». Сучасна канбан-дошка — та сама ідея, тільки для розумової праці.
Звідси головне правило колонок. Колонка описує стан, у якому зараз перебуває задача. Кожен перехід між колонками означає, що з задачею щось сталося. А от тиждень, людину чи розділ проєкту колонкою робити не можна. Тоді картка ніколи нікуди не рухається, і дошка стає кольоровим списком.
| Колонка | Це стан? | Чому |
|---|---|---|
todo · doing · done | Так | Задача справді переходить із одного в інший, і перехід видно |
| «Беклог → В роботі → На перевірці → Готово» | Так | Те саме, але з окремим станом очікування чужої дії |
| «Понеділок / Вівторок / Середа» | Ні | Це календар. Задача не «переходить у середу» — вона просто там лежить |
| «Ваня / Оля / Максим» | Ні | Це список виконавців. Виконавець — поле картки, а не колонка |
| «Лендинг / Форма / Аналітика» | Ні | Це епіки. У тебе вони вже є полем epic у tasks.json |
Одинадцятикласник зробив дошку з колонками «Дизайн», «Код», «Тексти», «Публікація» і розклав по них усі 12 задач свого стартапу. За тиждень жодна картка не переїхала. Що з дошкою?
Головна ідея уроку, і вона рахується на пальцях
WIP — work in progress, робота в процесі: усе, що почато, але ще не закінчено. WIP-ліміт — число, яке ти сам собі призначаєш: «у колонці “в роботі” не більше трьох карток». Виглядає як зайва бюрократія. Насправді це єдина річ на дошці, яка змушує закінчувати, а не тільки починати.
Уяви пʼять задач, кожна на два дні роботи. Разом — десять днів праці. Розкласти їх можна двома способами, і сумарна праця в обох однакова.
Тепер додай те, чого на схемі немає. Ти повернувся до задачі після перерви — і кілька хвилин просто згадуєш. Де лежав той файл? Що ти вже пробував? Чому відмовився від першого варіанта?
Ці хвилини звуться перемиканням контексту. Голова щоразу робить дві речі: наводиться на нову ціль і піднімає з памʼяті все, що ти знав про задачу.
Рубінштейн, Меєр і Еванс виміряли ці втрати 2001 року. У їхніх дослідах перемикання зʼїдало до 40 % робочого часу. Досліди були лабораторні, не про верстку лендинга. Тому бери 40 % як порядок величини, а не як точне число для себе.
Однокласник каже: «Яка різниця, як робити, — усі пʼять задач усе одно займуть десять днів, роботи ж однаково». Що ти відповіси, щоб це був аргумент, а не думка?
Ліміт нічого не прискорює. Він робить проблему видимою — і це його робота
Без ліміту дошка виглядає добре: у «todo» порожньо, у «doing» тісно, усі зайняті. Саме тому вона й небезпечна — відчуття зайнятості і результат перестають бути одним і тим самим. Задача, яка тиждень стоїть у «в роботі», нікому нічого не дала. Її не можна показати, не можна перевірити, не можна викинути. Вона просто займає голову.
Є формула, яку не треба вигадувати: WIP = пропускна здатність × час проходження. Математик Джон Літтл довів її 1961 року для черг.
Формула працює скрізь, де щось заходить і виходить рівним потоком. Каса в супермаркеті, приймальне відділення лікарні, канбан-дошка — правило те саме.
Перевернемо її: час проходження = WIP ÷ пропускна здатність. Ти закриваєш дві задачі на тиждень. Отже:
| Карток у «в роботі» | Закриваєш на тиждень | Скільки живе задача |
|---|---|---|
| 10 | 2 | 10 ÷ 2 = 5 тижнів від старту до готовності |
| 6 | 2 | 6 ÷ 2 = 3 тижні |
| 3 | 2 | 3 ÷ 2 = 1,5 тижня |
Зверни увагу: пропускна здатність у трьох рядках однакова. Ти не став працювати швидше — ти просто менше почав. А час очікування впав утричі. Це і є вся математика WIP-ліміту.
У вашій колонці «в роботі» сім карток і жодної в «готово» вже тиждень. Що відбувається і з чого почати?
Ти закриваєш 3 задачі на тиждень і тримаєш у «в роботі» 12 карток. Однокласник питає, коли буде готова задача, яку ти щойно почав. Яка чесна відповідь?
Встав свій tasks.json — сторінка збере з нього дошку,
стежитиме за WIP-лімітом і поверне змінений JSON назад
Це той самий механізм, який за півгодини ти зробиш у
roadmap.html. Беремо масив обʼєктів, групуємо за полем
status, малюємо три колонки. Тут він уже готовий — щоб ти
спершу зрозумів поведінку, а вже потім писав код.
done_criteria← і → на картці.
Тренажер працює у твоєму браузері й нікуди нічого не надсилає. Демо-беклог складено автором сторінки за схемою з уроку 9: 12 задач, 4 епіки, дедлайни в жовтні–листопаді. Твої числа будуть свої.
check11 6 вимагає не більше 3 задач у doing
і щонайменше 40 % у done. Обидва числа тренажер показує
згори. Якщо колонка «в роботі» червона — червоним буде й критерій.Ти перетягнув четверту картку в «в роботі», колонка почервоніла. Спокуса — підняти ліміт із 3 до 4, і червоне зникне. Коли так робити чесно, а коли це самообман?
Один перелік умов, однаковий для всіх задач, написаний до роботи
Слово «готово» — найдорожче слово в проєкті, бо кожен розуміє його по-своєму. Ти вважаєш задачу готовою, коли код працює в тебе на ноутбуці. Вчитель — коли сторінка відкривається з сабдомену. Однокласник, який робить наступну задачу, — коли він може на неї спертися. Три різні «готово» на одну картку — і картка їздить із «done» назад у «doing» третій раз.
Тому «готово» домовляються заздалегідь і записують. Такий запис зветься Definition of Done, скорочено DoD. Це один перелік умов, спільний для всіх задач проєкту, а не опис окремої картки.
У Scrum Guide 2020 правило суворе. Робота, яка не відповідає DoD, не випускається й навіть не показується — вона повертається в беклог.
Якщо перелік умов зʼявляється після того, як робота зроблена, він завжди підганяється під результат: «ну, задокументувати можна й потім». Написаний до старту, DoD виконує три функції одразу:
| Функція | Що це дає на практиці |
|---|---|
| Оцінка | Ти рахуєш час на всі пʼять пунктів, а не лише на код. Тому оцінки перестають бути втричі оптимістичними |
| Суперечка | Питання «це готово чи ні» вирішується списком, а не тим, хто гучніше |
| Ліміт | Задача звільняє місце в «в роботі» тільки коли справді закрита — інакше WIP-ліміт нічого не обмежує |
done_criteria — це різні речі
У твоєму tasks.json кожна задача має власний
done_criteria: що саме має запрацювати в цій конкретній
задачі. DoD — спільний для всіх: у якому стані будь-яка задача
вважається завершеною. Картка готова, коли виконано і своє
done_criteria, і загальний DoD.Однокласник переносить картку в «готово» зі словами: «я дописав, вдома доллю». Ти відповідаєш за цей проєкт. Що не так із цим переносом із погляду процесу, а не дисципліни?
Команда закінчила спринт і аж тоді сіла писати Definition of Done — «щоб зафіксувати, як ми працювали». Що з таким DoD не так?
Беклог відповідає «що»; карта відповідає «коли й навіщо»
Беклог — усе, що спало на думку, відсортоване за пріоритетом. Дорожня карта — інший документ: вона показує, які проблеми ти берешся розвʼязати найближчим часом і в якому порядку. Тому в карті не 40 рядків, а 6–8, і кожен має причину, а не тільки назву.
Найпоширеніший формат карти сьогодні — три горизонти Зараз / Далі / Колись (now / next / later). Його ввела Джанна Бастоу з ProdPad.
До того карти малювали з точними датами. Дати обіцяли те, чого команда не могла гарантувати, і кожен перенос виглядав як провал. Горизонти чесніші: вони показують не дату, а наскільки ти впевнений.
Кожен рядок карти спирався б на оцінку часу. А оцінка часу — це прогноз
людини, яка ще не робила цієї задачі. У тебе на модуль 14 уроків, між ними
тиждень. І саме в цей тиждень трапляється контрольна з хімії. Тому дата в
due — це орієнтир і сигнал, а не обіцянка.
Сигнал читається так. Один перенос — буває. А коли дата зсувається вдруге, справа вже не в тому, що ти не встиг. Це означає, що задача більша, ніж здавалося, і її треба розбити.
roadmap.html.Ти показуєш учителю сторінку, де під заголовком «Дорожня карта» йде список із 34 пунктів, відсортований за датою створення. Він каже: «Це не карта». Чого саме тут бракує?
Одне джерело правди. Правка в одному місці, а не в двох
Спокуса зробити roadmap.html просто гарною сторінкою
з написаними руками картками величезна: так швидше й видно результат
одразу. Проблема зʼявиться через тиждень, коли ти закриєш задачу.
Тепер її треба виправити в tasks.json і в
roadmap.html. Один із двох файлів рано чи пізно відстане —
і сторінка почне брехати.
| Написано руками в HTML | Відрендерено з JSON | |
|---|---|---|
| Змінити статус задачі | Правити у двох файлах | Правити в одному |
| Додати задачу | Скопіювати блок розмітки й не забути класи | Дописати обʼєкт у масив |
| Порахувати «скільки в роботі» | Порахувати очима | filter().length |
| Автоперевірка | Не може відрізнити правду від верстки | Підмінює JSON і дивиться, чи змінилася сторінка |
| Ціна помилки | Сторінка показує неправду й ніхто не помічає | Сторінка показує помилку розбору |
Це той самий принцип, що й дизайн-токени в brand.css з уроку 5.
Там колір записаний один раз у змінній, а не двадцять разів у розмітці.
Тут — те саме, тільки для даних.
roadmap.htmlНижче — скелет, від якого ти відштовхуєшся. У ньому навмисно немає
жодної назви задачі: усе, що бачить користувач, приходить із
fetch.
<link rel="stylesheet" href="brand.css">
<h1>Дорожня карта</h1>
<p id="err" hidden></p>
<div class="board">
<section><h2>До роботи <span data-cnt="todo"></span></h2>
<div data-col="todo"></div></section>
<section><h2>В роботі <span data-cnt="doing"></span></h2>
<div data-col="doing"></div></section>
<section><h2>Готово <span data-cnt="done"></span></h2>
<div data-col="done"></div></section>
</div>
// нижче — усередині <script>
fetch('tasks.json')
.then(r => { // 404 не кидає виняток — перевіряємо самі
if(!r.ok) throw new Error('tasks.json не знайдено: ' + r.status);
return r.json(); // зламаний JSON кине тут
})
.then(draw)
.catch(e => { // порожній екран — найгірша помилка
const p = document.getElementById('err');
p.hidden = false;
p.textContent = 'Дошку не побудовано. ' + e.message;
});
function draw(tasks){
['todo','doing','done'].forEach(st => {
const box = document.querySelector('[data-col="' + st + '"]');
const list = tasks.filter(t => t.status === st);
document.querySelector('[data-cnt="' + st + '"]').textContent = list.length;
box.textContent = '';
list.forEach(t => {
const card = document.createElement('article');
const h = document.createElement('b');
h.textContent = t.title; // textContent, а не innerHTML
const m = document.createElement('small');
m.textContent = t.epic + ' · ' + t.priority + ' · до ' + t.due;
card.append(h, m);
box.appendChild(card);
});
});
}
roadmap.html подвійним кліком, адреса буде
file:///…, і fetch отримає помилку CORS.
Браузери вважають локальні файли різними джерелами й дозволяють
fetch тільки по http і https.
Перевіряй сторінку на сабдомені або підніми локальний сервер:
python3 -m http.server 8000 у теці з файлами і далі
http://localhost:8000/roadmap.html.-Encoding utf8 дописує на початок файлу
три невидимі байти — їх звуть BOM. Ти їх не бачиш, а r.json()
на них падає з повідомленням Unexpected token.
Зберігай ось так:# PowerShell 5.1 — єдиний надійний спосіб [IO.File]::WriteAllText("$HOME\tasks.json", $text, (New-Object Text.UTF8Encoding $false)) # Git Bash, macOS, Linux cat > tasks.json # перевірити, що файл валідний, перед заливкою # Git Bash, macOS, Linux — тут && працює python3 -m json.tool tasks.json > /dev/null && echo "JSON ok" # PowerShell 5.1 && не розуміє — тільки окремими командами python -m json.tool tasks.json | Out-Null; if ($?) { "JSON ok" }
Учитель відкрив твій roadmap.html, змінив у
tasks.json назву однієї задачі на «ТЕСТ-123» і перезавантажив
сторінку. Назва не змінилася, хоча дошка виглядає ідеально. Що він
зараз запише в перевірку і чому це справедливо?
Одна діаграма, яка відповідає на питання «ми встигаємо чи ні»
Burndown (буквально «згоряння») показує одне число щодня: скільки роботи ще лишилося. Не скільки зроблено — скільки лишилося. Пряма похила лінія — це план. У спринті 10 днів і 30 одиниць роботи, отже щодня має «згоряти» по 3. Ламана — реальність.
Лінія рідко буває прямою, і причина проста. Пряма означала б, що ти знав обсяг роботи наперед і нічого не змінилося. Так не буває.
Тому графік читають не на «збігається чи ні», а на форму. Рівна полиця — задачі стоять, проблема з WIP. Різкий стрибок угору — роботи додалося, проблема з обсягом. Обрив у самому кінці — усе закрили поспіхом, проблема з якістю.
Тепер найцікавіше. Візьми свій беклог (або демо) і пообіцяй, скільки берешся зробити за 10 днів. Потім прокрути ці 10 днів. Кожні кілька днів трапляється те, чого не було в жодному плані. Твоя справа — вирішити, чим за це платити.
Модель симулятора спрощена й оголошена повністю: швидкість 3 одиниці на день, спринт — 10 робочих днів, отже ємність 30 одиниць. Кожна подія додає роботу, якої не було в плані. Чотири рішення платять за неї по-різному.
Перекинути — робота росте, ємність та сама. Розбити — робота не росте, зате обіцяний обсяг меншає на ту саму величину. Відмовитися від could — робота не росте й MVP цілий, але could-задач у плані стає менше. Тому кнопка працює, лише поки такі задачі там ще лишилися. Зірвати дедлайн — робота росте, зате додається робочий день, тобто +3 до ємності.
Події, їхній порядок і ціни склав автор сторінки. Це навчальна модель, а не вимір реальної команди.
На вашому burndown лінія перші чотири дні йшла майже горизонтально, а потім за два дні впала до нуля. Обсяг зробили повністю. Що ця форма насправді розповідає про спринт?
Ти рахуєш: 10 днів × 3 одиниці = 30 одиниць ємності. У беклозі рівно 30 одиниць роботи. Скільки брати на спринт?
roadmap.htmlВиконуй по черзі. Галочки зберігаються — сторінку можна закрити.
roadmap.html ти пишеш у себе в редакторі. Перевіряєш його
на локальному сервері: python3 -m http.server 8000. Просто
відкрити файл подвійним кліком не вийде — через file:///
fetch не працює. По FTP у
~/upload/ → ~/www/ їдуть два легкі текстові файли:
roadmap.html і оновлений tasks.json. Скриншоти
дошки й результати симулятора на сервер не завантажуються — їх учитель
дивиться очно на твоєму екрані.check11 6Перевірка зробить реальний запит на твій сабдомен, прочитає
tasks.json і навмисно підмінить у ньому назву задачі, щоб
переконатися, що дошка жива. Спроби не обмежені.
Демонстраційний режим: результат згенеровано для показу.
На сервері ця кнопка запускає check11 6 від імені учня
і читає ~/.progress/11-6.json.
wip блокує оцінку, бо дисципліна WIP — головна навичка цього
уроку: сім карток у doing означають, що процесу немає.
no_media діє наскрізно весь модуль. У ~/www/
і ~/upload/ не має бути відео й звуку: .mp4 .mov .avi
.mkv .webm .mp3 .wav .flac. Файлів понад 2 МБ там теж бути
не повинно.tasks.json зі статусом 200 — дошка
справді тягне дані;Це те, що бачить учитель, коли виставляє оцінку.
| Складник | Вага | Результат |
|---|
done ще дві задачі — за done_criteria
і за своїм DoD, а не оптом. Переконайся, що канбан оновився
без жодної правки roadmap.html.~/www/kb/ нотатку dod.md із front-matter
і пʼятьма пунктами свого Definition of Done — вона підхопиться
базою знань із уроків 7–8.CHANGELOG.md один рядок про сьогоднішній день:
який WIP-ліміт ти собі поставив і яку задачу довелося повернути
з «готово» назад.~/data/responses.csv.
Цей файл лежатиме поза теками, які видно з інтернету, бо в ньому будуть
імена живих людей. А задача «Зробити форму відгуку», яка сьогодні висить
у тебе в doing, там і закриється.Кожне твердження, яке можна перевірити, має посилання. Перевіряти дозволено й корисно.
fetch не працює з file:///: браузери
вважають локальні файли непрозорими джерелами, CORS-запит дозволений
тільки для http і https — MDN.
developer.mozilla.org · CORS request not HTTPfetch не кидає виняток на HTTP-помилках 404 і 500 —
статус треба перевіряти самому через response.ok — MDN.
developer.mozilla.org · Window.fetch()Ілюстративні числа, за які автор сторінки відповідає окремо:
«дві доби на задачу» у схемі паралельно/послідовно, сім карток у заторі,
форма ламаної на burndown, демо-беклог із 12 задач і всі ціни подій
у симуляторі спринту. Вони підібрані так, щоб арифметика сходилася
на очах, і не є виміром реальної команди. Модель симулятора
(3 одиниці на день, 10 днів, ціни всіх чотирьох рішень) оголошена
прямо на сторінці під самим симулятором. Повний список джерел із поясненнями —
у файлі urok-10-джерела.md поруч із цією сторінкою.