Контекст: webpack — популярний інструмент для JavaScript-розробників. Збирає всі твої JS-файли, CSS, картинки в один бандл для браузера. webpack-cli — його командний інтерфейс.
Розробники webpack-cli додали банер для донатів. Показувався тільки в понеділок:
if (now.getDay() === MONDAY) {
if (fileOwnerId === process.getuid()) // 💥
}process.getuid() — це Linux-функція. На Windows її немає. Баг з'являвся ТІЛЬКИ в понеділок, ТІЛЬКИ на Windows. Шість днів на тиждень — ідеально.Internet Explorer: DevTools як квантовий колапс
Контекст: DevTools — це інструменти розробника в браузері (F12). Там консоль, мережа, DOM-дерево.
console.log() — найпростіший спосіб дебажити JS: виводиш змінну в консоль і дивишся.У IE об'єкт
console не існував, поки не відкриєш DevTools. Код з console.log() падав у звичайних користувачів — бо в них DevTools закриті. Розробник відкривав DevTools подивитись — працює. Закривав — все ще працює.Чому? Бо об'єкт
console вже створився при відкритті. Акт спостереження змінив систему назавжди.Therac-25: коли Heisenbug вбиває (1985-1987)
Це вже не смішно.
Контекст: Therac-25 — медичний апарат для променевої терапії раку. Пацієнт лягає, апарат опромінює пухлину точною дозою радіації. Race condition — це коли два процеси "змагаються" за ресурс, і результат залежить від того, хто встигне першим. Непередбачувано.
Therac-25 мав race condition в софті. Іноді давав летальні дози радіації замість терапевтичних. Загинуло щонайменше троє людей.
Баг з'являвся тільки коли оператор друкував дуже швидко — потрібні були дні практики, щоб випадково натрапити. При стандартному тестуванні — все ідеально. Виробник місяцями не міг відтворити проблему.
Heisenbug, який ховався від спостереження. І вбивав.
———
Класифікація багів (для нердів)
Програмісти створили цілу "фізичну" таксономію:
Баг Фізик Що робить
**Bohrbug** Niels Bohr Стабільний, передбачуваний. Нудний, зате ловиться.
**Heisenbug** Werner Heisenberg Зникає, коли дивишся
**Mandelbug** Benoit Mandelbrot Фрактальний: чим глибше копаєш, тим більше знаходиш
**Schroedinbug** Erwin Schrödinger Код, що не мав би працювати, але працює — поки хтось не подивиться
———
Що з цього випливає
"Працює" — це не так чи ні
Програма не "працює" або "не працює". Вона працює за певних умов. Debug/release. Linux/Windows. Понеділок/вівторок. З логуванням/без. Змінив умови — змінив результат.
Debugger — не вікно. Це втручання.
Ти не "дивишся на програму". Ти створюєш нову систему: програма + debugger. А вона поводиться інакше.
"Працює на моїй машині" — не жарт
Memory layout різний. OS scheduler різний. Timing різний. Ти і твій колега буквально запускаєте різні програми. Обидва праві. Обидва ні.
Баг існує?
Залежить від того, хто дивиться. Як одночасність подій у теорії відносності — немає абсолютної відповіді.
———
Як ловити те, що тікає
Баг зник під debugger'ом? Це не проблема. Це підказка.
Ти щойно дізнався: баг чутливий до timing'у. Значить, шукай race conditions, memory ordering, timing-залежну логіку. Коло звузилось.