# Дефект

## Що це таке

Дефект — це щось неправильне всередині результату роботи, через що той поводиться не так, як
задумано, або не робить частини того, що мав робити. Програмісти здебільшого кажуть «баг», у розмові
можна почути «вада» чи просто «помилка», а в стандартах і підручниках із тестування трапляються ще
англійські fault і flaw.

Головне слово тут — _результат роботи_. Дефект може сидіти у вихідному коді, але так само у вимозі,
що суперечить іншій вимозі, в архітектурі, яка не витримує навантаження, під яке її проєктували, у
файлі конфігурації, у тесті, що очікує хибне значення, чи в інструкції, яка описує кнопку, прибрану
з продукту два релізи тому. Хоч би де він був, дефект належить самій речі й існує незалежно від
того, помітив його хтось чи ні.

Тестування розрізняє три речі, які в побутовій мові злипаються в одну «помилку». Людина помиляється
(error): хибно прочитала специфікацію, зробила неправильне припущення, натиснула не ту клавішу. Ця
помилка залишає дефект у тому, що людина створила. Коли дефектна частина виконується за умов, які
його оголюють, продукт поводиться неправильно, і саме цю видиму неправильну поведінку називають
відмовою (failure). Ланцюжок рухається тільки в один бік і може обірватися на будь-якій ланці.
Дефект у гілці коду, до якої виконання ніколи не доходить, або такий, що потребує вхідних даних,
яких ніхто не надсилає, може роками лежати в кодовій базі, так і не спричинивши жодної відмови.

Що вважати неправильним, залежить від того, чого чекали, а очікування сягають далі за написану
специфікацію. Модель якості продукту в ISO/IEC 25010 описує функціональну придатність (functional
suitability) як ступінь, до якого продукт надає функції, що задовольняють заявлені й неявні потреби
під час використання за визначених умов. Цю характеристику поділено на повноту (чи охоплюють функції
визначені завдання й цілі користувачів), коректність (чи точні результати) і доцільність (чи
допомагають функції виконати завдання). Хибна сума — проблема коректності; звіт, який неможливо
експортувати, — проблема повноти. Надійність у моделі стоїть окремою характеристикою, і серед її
складників є безвідмовність, доступність (availability), стійкість до відмов і відновлюваність, тож
продукт, який рахує правильно, а потім двічі на день падає, однаково має дефекти.

Регресія — це дефект з історією: щось працювало, а пізніша зміна його зламала. Окрему назву вона
отримала тому, що несе підказку, якої бракує первинному дефекту, а саме останню версію, про яку
відомо, що вона була справною.

## Чому це важливо

Ціна дефекту найбільше залежить від того, де його знайшли. Якщо його впіймав сам автор коду, це
коштує хвилину й не лишає сліду. На рев'ю він коштує одну розмову. Якщо ж його знайшов клієнт,
рахунок охоплює саму відмову, звернення до підтримки, розслідування, виправлення й частину довіри, а
коли дефект завдав реальної шкоди, він уже став частиною інциденту. Системи типів, лінтери, тести й
рев'ю коду працюють на одному відтинку: вони намагаються наблизити момент виявлення до моменту, коли
дефект з'явився в коді.

Дефекти ще й ходять родинами. У помилки, яка породила один, зазвичай є родичі: той самий неправильно
зрозумілий інтерфейс, однаково викликаний у шести місцях, та сама плутанина з одиницями виміру,
скопійована в кожен новий модуль, те саме неперевірене припущення в кожному обробнику запитів. Після
дефекту корисніше питати не стільки, де стоїть хибний рядок, скільки що зробило цей рядок легким для
написання і де ще сталося те саме.

І дефекти повертаються. Код змінюється постійно, і виправлений дефект може прийти знову через
рефакторинг, злиття гілок чи оновлення залежності. Тест, написаний так, щоб падати на дефекті й
проходити на виправленні, перетворює виправлення на тривку властивість збірки. Якщо регресія
все-таки з'являється, історія версій стає простором пошуку: `git bisect` виконує двійковий пошук
серед комітів між відомою справною і відомою зламаною версією, тож діапазон із 1 000 комітів
звужується до того, що вніс баг, приблизно за десять запусків тестів.

Деякі дефекти водночас є проблемами безпеки. Common Weakness Enumeration, перелік, який веде MITRE,
каталогізує слабкі місця (weaknesses), а проєкт описує їх як стани компонента програмного
забезпечення, мікропрограми, апаратури чи сервісу, що за певних обставин можуть сприяти появі
вразливостей. Чимало пунктів цього переліку — звичайні дефекти, для яких зловмисник знайшов
застосування: пропущена перевірка меж, введення користувача, передане в запит без екранування, крок
авторизації, пропущений на одному маршруті.

## Як це виглядає на практиці

Найдорожчими дефектами на цьому сайті виявилися ті, які кожен автоматичний сигнал вважав
нормальними. Під час аудиту знайшлося
[одинадцять дефектів доступності, які автоматичні правила пропустили](/uk/portfolio/fixed-11-accessibility-defects-the-browser-called-healthy-131/),
бо кожен проявлявся у відображеній сторінці, а в HTML-розмітці його не було видно. Два з них сиділи
в самих перевірках. Кожне вікно, яке відкривала перевірка розкладки, мало висоту 900 пікселів, тому
телефон, повернутий горизонтально, 852 × 393, із сімома пікселями між двома елементами, жодного разу
не потрапив у поле зору; а рушій правил виконував 70 зі своїх 105 правил. Кожен дефект записано в
реєстр поруч із правилом, яке він породив, тож робота усуває цілу категорію помилок, а не один її
прояв. Щойно саму перевірку розкладки полагодили, вона провалилася 128 разів на сторінках трьома
мовами.

Другий дефект не мав жодного симптому. За замовчуванням сайт показує темну тему, а світлу — читачам,
чия система про неї просить, і повносторінкове тло в темній темі складається з трьох шарів. Невелика
структурна перевірка, що рахує шари, які малює кожна тема,
[виявила, що світла тема малює лише два](/uk/portfolio/found-the-light-theme-missing-an-overlay-layer-134/),
і зробила це вже під час першого запуску. Накладки бракувало відтоді, як написали світлу тему. Ніщо
не кидало помилки, кожна сторінка відображалася, а тло з одним шаром менше легко прийняти за
свідомий вибір, тож місяцями ніхто не мав причини придивитися. На виправлення пішло одне правило, а
виправленим його тримає саме перевірка.

Утримувати виправлення на місці — завдання системи запобіжників репозиторію, де одне правило
пов'язує кожне виправлення бага з доказом:
[коміт-виправлення має приносити тест, що провалюється без цього виправлення](/uk/portfolio/built-the-repository-s-guard-engine-of-268-checks-95/).
Самі запобіжники мають ще 146 власних тестів, бо запобіжник із дефектом пропускає кожен коміт і
зовні нічим не відрізняється від справного.

## Де виникають проблеми

**Випадок виправлено, а клас лишився відкритим.** Рядок зі звіту виправляють, заявку закривають, а
три родичі тієї самої помилки чекають в інших місцях коду. Після кожного виправлення шукайте шаблон,
що його породив, а там, де машина здатна розпізнати шаблон, перетворіть пошук на перевірку.

**Виправлений баг повертається.** Через пів року рефакторинг відновлює стару поведінку, бо ніде не
записано, від чого захищало виправлення. Пишіть тест до виправлення, переконайтеся, що на старому
коді він падає, і залиште його в наборі тестів назавжди.

**Дефект сидить у самій перевірці.** Набір правил, що мовчки завантажує лише частину своїх правил,
список тестових вікон однакової висоти, твердження (assertion), яке перевіряє, що код робить, а не
що мав би робити: кожне з них звітує про успіх, поки дефект лежить на видноті. Дайте перевіркам
власні тести й з'ясовуйте з виводу самого інструмента, які правила справді виконалися.

**Покриття підміняє коректність.** Набір тестів може пройти кожен рядок і все одно прийняти хибний
результат, якщо жодне твердження не дивиться на підсумок, а код, що виконує свою письмову
специфікацію, може однаково схибити щодо неявної потреби. Використовуйте покриття, щоб знаходити
код, який ніщо не тестує, а цінність тесту оцінюйте за дефектами, які він здатен упіймати.

**«Працює як задумано» закриває справжній звіт.** Поведінка збігається зі специфікацією, звіт
відхиляють, а дефектним результатом роботи весь цей час була сама специфікація. Коли проблема живе у
вимозі чи в архітектурі, реєструйте дефект саме там, щоб виправлення відбулося біля джерела.

## Що почитати далі

- [Defect](https://glossary.istqb.org/en_US/term/defect) — визначення ISTQB, прийняте в тестуванні
  програмного забезпечення, із синонімами та пов'язаними термінами error і failure.
- [ISO/IEC 25010](https://iso25000.com/index.php/en/iso-25000-standards/iso-25010) — огляд моделі
  якості продукту й підхарактеристик кожної характеристики, серед них функціональна придатність і
  надійність.
- [git-bisect](https://git-scm.com/docs/git-bisect) — посібник Git із двійкового пошуку коміту, що
  вніс баг, зокрема з автоматичними запусками тестового скрипту.
- [About CWE](https://cwe.mitre.org/about/index.html) — що таке Common Weakness Enumeration, як
  упорядковано її перелік слабких місць у програмах і апаратурі та хто його веде.

<https://engineer.company/uk/glossary/defect/>
