среда, февраля 24, 2010

Bug theory - Redundant expectations

Redundant expectations

Симптомы:

В определенных условиях система делает не то, что ожидается. Баг проявляется только в частных случаях, все остальное время система работает нормально. При воспроизведении бага могут возникнуть проблемы, но если воспроизводить тестовый сценарий в точности баг всегда проявляется.

Критические места: любые межмодульные взаимодействия, особенно слабо изученными сторонними модулями.

Это типичный баг "на границе". В определенных условиях сторонний модуль ведет себя не так, как ожидалось. Чаще всего это происходит когда документация на интерфейс была прочитана невнимательно или изначально была неполна. Хороший пример, это NullPointerException при нарушении принципа Деметры.

person.getLeftHand().getRingFinger();

Для большинства людей это сработает, но на первом же одноруком мы получим NullPointerException.

Профилактика:

Внимательно изучать документацию на межмодульный интерфейсы, писать интеграционный тесты захватывая крайние случаи, не верить документации и самостоятельно изучать код сторонних модулей, проектировать интерфейсы, которые ведут себя одинаково вне зависимости от условий, использовать контрактное программирование.

среда, февраля 17, 2010

Bug theory - TODO: Implement

TODO: Implement

Симптомы:

Не происходит то, что ожидалось. Выбрасывается NullPointerException, OperationNotSupportedException, InvalidArgumentException или любое другое похожее исключение. Такие баги легко обнаруживаются и легко воспроизводятся. При анализе в коде обнаруживается комментарий "TODO: Implement" или просто отсутствие необходимого кода.

Критические места:

Код после рефакторинга, новые фичи, реализации интерфейсов.

Тоже простой и очевидный баг, который появляется когда разработчик по какой-то причине оставляет часть контракта нереализованной. Это может происходить по разным причинам. Лень заниматься пустой работой, противоречивый или слишком детальный интерфейс, отсутствие времени.

Профилактика:

Избегать противоречивых и слишком сложных интерфейсов. После рефакторинга обязательно проверять появившиеся TODO/FIXME.

вторник, февраля 16, 2010

Bug theory

bugzilla logo

Каждый день программисты делают баги. Большинство из них почти сразу же исправляются, но бывают и те, которые так никогда и не были обнаружены. Большую часть багов никто не замечает, иногда они приводят к смерти людей и крупным техногенным катастрофам. Многие баги легко исправить, но некоторые годами кочуют из версии в версию. В нескольких книгах я встречал главы, посвященные разбору классических ошибок, но какой-то общей классификации мне не попадалось. Чтобы исправить это упущение, я собираюсь написать несколько постов, посвященных ошибкам.

Ну и для затравки:

Misprints

Симптомы:

Что-то происходит не так, как ожидается. Выбрасываются неожиданные исключения, возвращаются не те данные. Будучи обнаруженным, такой баг легко воспроизводится. Почти всегда опечатка легко обнаруживается и легко исправляется, но в тяжелых случаях она может прятаться годами.

Критические места:

Любая математика, обилие копипсаста, любая не очевидная логика, похожие по звучанию идентификаторы отличающиеся лишь несколькими буквами.

Опечатки это самые простые и известные ошибки. Сложно найти программиста, который ни разу с ними не сталкивался. Особенно такие баги любят гнездиться в математике. Стройная на бумаге формула превращается в коде в жуткую кашу в которой очень легко ошибиться.

Профилактика:

Использовать строгую типизацию там, где это возможно. Избегать магических чисел. Избегать арифметики, а если избежать не удалось, изолировать ее и покрывать юнит-тестами. Писать сложные алгоритмы в стиле literate programming. Избегать похожих имен функций и переменных в одном контексте.