Разработчику — любому из нас! — часто бывает трудно признать, что его код не работает. Это кажется настолько неправдоподобным, что мы скорее готовы допустить наличие ошибки в компиляторе.
В действительности, очень и очень редко код оказывается неработоспособным из-за ошибки в компиляторе, интерпретаторе, операционной системе, сервере приложений, базе данных, менеджере памяти или любом другом элементе системного программного обеспечения. Да, там встречаются ошибки, но гораздо реже, чем нам хотелось бы думать.
Однажды я действительно столкнулся с ошибкой в компиляторе (удаление переменной цикла при оптимизации), но во всех остальных случаях мои претензии к компилятору или операционной системе оказывались беспочвенными. Я тратил массу своего времени, времени службы поддержки и времени начальства, а в результате оказывался в неловком положении, когда обнаруживалось, что ошибка — моя собственная.
Когда применяемые в проекте средства разработки проверены временем, широко используются и входят в многочисленные технологические цепочки, нет особых оснований сомневаться в их качестве. Конечно, если это одна из ранних версий инструмента, или им пользуются лишь несколько человек в мире, или это редко загружаемый проект с открытым исходным кодом и номером версии 0.1, вполне можно заподозрить этот инструмент. (Точно так же можно с подозрением отнестись к альфа-версии коммерческого инструмента.)
Учитывая, насколько редки ошибки в компиляторах, гораздо выгоднее тратить время и силы на поиск ошибок в собственном коде, а не пытаться доказать, что компилятор ошибается. Тут действуют все обычные соображения по отладке: изолировать проблему, поставить заглушки вместо вызовов, окружить проблемный участок проверками; проверить выполнение соглашений по вызовам, общие библиотеки и номера версий; описать проблему коллеге; выяснить, не поврежден ли стек, и установить соответствие типов переменных; попробовать выполнить код на разных компьютерах и в разных конфигурациях сборки, например отладочной и окончательной (release).
Подвергайте сомнению собственные допущения и допущения других людей. Допущения в основе работы инструментов разных производителей могут не совпадать; то же верно и для разных инструментов одного и того же производителя.
Если коллега сообщает об ошибке, которую вы не можете воспроизвести, подойдите и посмотрите, как она у него возникает. Его действия или последовательность их выполнения, возможно, никогда не приходили вам в голову.
Моя личная система такова: если я не могу обнаружить ошибку и начинаю грешить на компилятор, пришло время проверить целостность стека. Это особенно полезно, когда при добавлении кода трассировки локализация проблемы меняется.
Многопоточность — еще один источник ошибок, из-за которых программисты начинают орать на компьютер и раньше срока седеют. Все советы писать простой код многократно увеличиваются в цене для многопоточных систем. При поиске таких ошибок трудно системно полагаться на отладку и модульное тестирование, поэтому простота конструкции приобретает первостепенное значение.
Итак, прежде чем забрасывать обвинениями компилятор, вспомните совет Шерлока Холмса — «Если исключить все невозможное, то, что останется, и будет истиной, какой бы неправдоподобной она ни казалась» — и следуйте ему, а не совету Дирка Джентли:[5] «Если исключить все неправдоподобное, то, что останется, и будет истиной, какой бы невозможной она ни казалась».