Убедително и грешно
В урок 29 асистентът ви даде код. Кодът се компилира, работи на примера, има хубави имена и коментари. Това е и проблемът: изглежда като верен код. Моделът е обучен да произвежда най-вероятното продължение — а най-вероятното е код, който прилича на правилното решение. Дали покрива и случая, за който не сте питали, е друг въпрос.
- Асистентът не е пуснал кода. Той го е написал по образец.
- Примерът, който сте дали, е „удобен“ — обикновено малък и без особености.
- Грешката най-често е на ръба: първи и последен елемент, нула, празен вход.
- Хубавите коментари не правят кода верен — те също са предсказан текст.
Граничните случаи
Граничен случай
Вход на ръба на допустимото — най-малкият, най-големият, празният, нулата, единственият елемент. Точно там се крият повечето грешки.
| Граничен случай | Пример | Типична грешка |
|---|---|---|
| Празен вход | 0 числа в редицата | деление на нула, цикъл, който не се изпълнява |
| Нула | N = 0, стойност 0 | 0 се бърка с „няма стойност“ |
| Отрицателни | всички числа под нулата | начална стойност 0 за максимум |
| Единичен елемент | редица от едно число | цикъл, който започва от втория |
| Максимум / много голямо | N = 1000000 | препълване на int |
| Точно на границата | N = 3 при „кратни на 3“ | < вместо <= (грешка с единица) |
| Еднакви стойности | 4, 4, 4 | „по-голямо“ вместо „по-голямо или равно“ |
Грешка с единица (off-by-one) е най-честата от всички: цикълът започва от 1 вместо от 0, или спира на < n вместо на <= n. Резултатът е почти верен — с един елемент по-малко. Точно затова се открива само с тест на границата.
Тестовата таблица
Тестова таблица
Списък от входове с предварително пресметнат очакван изход. Програмата се пуска с всеки ред и полученото се сравнява с очакваното.
Пример за задачата „най-голямо от три числа“:
| Вход | Очакван изход | Какво проверява |
|---|---|---|
| 1 2 3 | 3 | обикновен случай, най-голямото е последно |
| 3 2 1 | 3 | най-голямото е първо |
| -5 -2 -9 | -2 | всички отрицателни |
| 4 4 4 | 4 | еднакви стойности |
| 0 0 1 | 1 | нули |
- Прочетете условието и изпишете граничните случаи от таблицата по-горе, които са възможни за тази задача.
- За всеки вход пресметнете очаквания изход на ръка — ПРЕДИ да пуснете програмата. Иначе ще повярвате на това, което тя изведе.
- Пуснете програмата с всеки ред и запишете полученото.
- Отбележете ✓ или ✗. Всяко ✗ е грешка — в програмата или в очакването ви. Проверете и двете.
Когато откриете грешка
- Опишете я точно: вход, очакван изход, получен изход. Без „не работи“.
- Намерете реда, който я причинява. Проследете стойностите на променливите на ръка за този вход.
- Поправете сами или върнете на асистента точното описание от стъпка 1. Той поправя много по-добре „при вход 1 7 извежда 0, а трябва 7“, отколкото „грешно е“.
- Пуснете ЦЯЛАТА таблица отново — не само падналия тест. Поправка на едно място често чупи друго.
- Добавете нов ред в таблицата за случая, който сте открили. Така грешката няма да се върне.
Отговорността на програмиста
Никой не пита откъде е дошъл кодът, когато той сгреши. Пита се кой го е пуснал. Асистентът не носи отговорност — не може. Отговорността е на човека, който е решил, че кодът е готов.
Какво трябва да запомниш
- Кодът от асистента изглежда верен, защото е предсказан по образец — не защото е пуснат и проверен.
- Грешките се крият на ръба: празен вход, нула, отрицателни, единичен елемент, точно на границата.
- Тестовата таблица е вход → очакван изход, а очакваното се пресмята преди пускането.
- Грешката се описва с вход, очаквано и получено — така се поправя и от човек, и от асистент.
- След поправка се пуска цялата таблица, не само падналият тест.
- Кодът е твой, когато го пуснеш — отговорността не се делегира.