Skip to main content

Дядя Боб и серебряные пули

  • Эта публикация - перевод статьи. Ее автор - Hillel Wayne. Оригинал доступен по ссылке ниже:

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

Его последний ответ, когда он сетует на правильность программного обеспечения, был для меня ключевым моментом, поэтому я собираюсь пойти дальше и высказать то, о чем многие из нас думали:

Дядя Боб дает ужасный совет. После этого ваш код будет хуже.

Он начинает с того, что Инструменты - это не ответ, перечисляя некоторые «новые» средства, которые не являются «ответом»: Light Table, Model Driven Engineering и TLA +. Теперь, я довольно предвзят касательно написания руководства TLA + и всего прочего. Но я согласен с тем, что (мне казалось) было основной критикой: нет никакой серебряной пули. TLA + продемонстрировал некоторые поразительные успехи в Amazon и Microsoft, но он проверяет только спецификации, а не код. Хотя это невероятно для проектирования систем, вы должны объединить его с другими методами правильности, такими как системы типов и тесты. Хороший аргумент.

Но оказывается, что аргумент был только в моей голове, потому что он следует за этим:

Решение апокалипсиса программного обеспечения - не увеличение количества инструментов. Это улучшение программирования.

Так или иначе, что такое «дисциплина»? Дядя Боб говорит, что это означает, что он не выполняет «полузасушливую работу». Дядя Боб говорит, что решение для людей, пишущих плохой код, - это не писать плохой код. Наши программы были бы идеальными, если бы не программисты!

Одним из основных допущений современной системной инженерии (1) является то, что существует постоянный поток дефектов: люди ошибаются . Вы не можете полагаться на людей, чтобы не трахаться самостоятельно: в конце концов, в США по-прежнему насчитывается 30000 смертей в год в год. Скорее, лучший способ уменьшить объем и серьезность ошибок - это настроить саму систему. Либо сделать их труднее сделать, сделать их легче поймать, либо заставить их наносить меньше урона, когда они происходят. Не просто обвиняйте водителей, дайте им безопасные дороги! Дайте им ремни безопасности!

Один из способов сделать это - добавить бюрократический процесс , такой как обзор кода. Если ваш код не соответствует требованиям (в нем отсутствуют тесты, вы указали свои переменные xи x2 т. д.), Код будет отклонен. Это на системном уровне уменьшает количество ошибок. (2) Когда мы применяем механические инструменты, такие как тесты и IDE, все, что мы делаем, это автоматизация этих процессов. Мы используем способ создания кода и тип кода, который мы создаем, чтобы проверить нашу работу. Это обширная область корректности программного обеспечения и охватывает все: от систем типов до языкового дизайна.

Дядя Боб в порядке с правильностью программного обеспечения: в конце концов, он использует фразу «unit testing», как smurf использует «smurf». Но как насчет любой другой техники правильности?

Другими словами, любой метод правильности, который не является модульным тестом, может быть отклонен. (3) Но модульные тесты не дают вам большой уверенности в вашем коде. Это потому, что люди ошибаются, и мы не всегда можем гарантировать, что ошибки, которые мы совершаем, - это хорошо проверенные единицы. Например, вот функция потолка, которую я написал. Быстро, с какими номерами вы его проверите?

function ceiling(num) {
    if (num == (num | 0)) {
        return num;
    }
    return Math.round(num + 0.5);
}

Вы пытались -1e-100? Вы бы это видели, ceiling(-1e-100) == 1когда это было так 0. Это из - за того , как с плавающей точкой работает: 0.5 - 1e-100 == 0.5. Я был бы в шоке, если бы многие люди помнили, что, если бы они даже знали, что с плавающей точкой есть причуды. Но тест на основе свойств позволяет легко его поймать. Хорошо, функция вторая:

function clamp(min, x, max) {
    return Math.max(Math.min(max, x), min);
}

Функция отличная. Ошибка не в функции вообще! Это то, что в нашей кодовой базе 50 kLoC существует один путь, который в конечном итоге заканчивается вызовом clamp с нулевым значением. Вы собираетесь проверять все возможные пути? Разве это действительно превосходит использование системы типов? Хорошо, последний:

function append_to_body(type, text) {
    var d = document.createElement(type);
    d.innerHTML = text;
    document.body.appendChild(d);
}

Функция работает нормально, за исключением того, что теперь вы открыли вектор XSS. Вот почему у нас есть статический анализ. Это не просто примеры игрушек. Это темы с большим количеством исследований, большим количеством развития и большим количеством истории. (4) Мы узнали, для чего они хороши, и каковы их ограничения. Мы используем этот инструмент, потому что они работают. Точно так же мы имеем модульные тесты и TDD.

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

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

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


  1. Системная инженерия - это планирование и проектирование крупных целевых человеческих систем, таких как сбор мусора или строительная компания, или проект Манхэттена. 
  2. Говоря о процессах, вы которые с помощью PR контрольного списка, не так ли? Правильно?
  3. Ладно, я не нашел, что он опирался на контракты, но я не выглядел очень тяжело, и это (к сожалению) тема ниши достаточно, что он, возможно, не слышал о них. 
  4. QuickCheck старше JUnit. TLA + почти на десять лет старше популярного TDD. MDE почти на десять лет старше TLA +. Z-спецификация старше C ++ и Smalltalk-80. Во всяком случае, модульное тестирование - это «новая и блестящая» вещь!