97 Вещей, Которые Должен Знать Каждый Программист
87. Две Ошибки Могут «Исправить» Друг Друга (и Это Трудно Обнаружить)
Код никогда не лжёт, но может сам себе противоречить. Иногда такие противоречия могут заставить схватиться за голову и воскликнуть: «Как это вообще может работать?»
В своём интервью главный разработчик ПО лунного модуля Аполлона-11 Аллан Клумпп рассказал, что ПО управления двигателями, содержало ошибку, которая должна была сделать посадочный модуль нестабильным. Однако эта ошибка компенсировалась другой, и ПО использовалось как для посадки на Луну, так и для Аполлона-11, прежде чем была обнаружена или исправлена.
Рассмотрим функцию, возвращающую статус завершения задачи. Представьте, что она возвращает
false, когда должна возвращать true. Теперь представьте, что вызывающая функция не проверяет возвращаемое значение. Всё работает нормально, пока однажды кто-нибудь не заметит упущенную проверку и не добавит её.Или, например приложение, которое сериализует и сохраняет своё состояние для дальнейшего чтения и использования. Представьте, что одно из свойств неправильно названо как
TimeToLive, вместо TimeToDie, как указано в документации. Все выглядит нормально, пока код сериализации и код десериализации содержат одну и ту же ошибку. Но исправьте это в одном месте или добавьте новое приложение, читающее те же данные, и симметрия нарушится, как и работа кода.Когда два дефекта в коде создают одну видимую ошибку, стандартный подход к исправлению ошибок может потерпеть неудачу. Разработчик получает отчёт об ошибке, находит дефект, исправляет его и повторно тестирует. Однако неисправность всё равно проявляется, потому что работает второй дефект. В итоге первое исправление удаляется и код анализируется дальше, пока не будет обнаружен второй дефект. Он исправляется, но из-за отмены исправления первого дефекта ошибка всё ещё проявляется, поэтому и второе исправление откатывается. Процесс повторяется, но теперь разработчик отклонил два возможных исправления, и пытается найти третий дефект, которого в реальности не существует…
Взаимодействие между двумя дефектами кода, которые проявляются как одна видимая ошибка, не только затрудняет решение проблемы, но и ведёт разработчиков в тупик, в котором, при благоприятном исходе, они могут обнаружить, что они пробовали правильные решения на раннем этапе.
Это происходит не только в коде: проблема также существует в документации и требованиях. И она может вирусно распространяться из одного места в другое. Ошибка в коде может компенсировать ошибку в документации.
Это также может распространяться на людей: пользователи узнают, что когда приложение говорит: «Налево», - это означает «Направо», поэтому они корректируют своё поведение соответствующим образом. Они даже передают этот опыт новым пользователям: «Помните, когда в приложении говорится «нажмите стрелку влево», это на самом деле означает «стрелку вправо». Исправьте ошибку - и пользователям потребуется переобучение.
Одиночные ошибки можно легко обнаружить и легко исправить. Труднее решить проблемы со множеством причин, требующие множественных изменений. Отчасти это связано с тем, что простые проблемы так легко решаются, что люди склонны решать их относительно быстро, а более сложные проблемы откладывают на потом.
Не существует простых советов, как устранять недостатки, возникающие из-за множественных проблем. Необходимо осознавать вероятность такого случая, ясно мыслить и быть готовым рассмотреть все возможные варианты.
Источник: https://www.oreilly.com/library/view/97-things-every/9780596809515/
Автор оригинала – Allan Kelly