пятница, 2 ноября 2012 г.

К вопросу о долгосрочной надёжности систем, написанных на языке с динамической типизацией.

Есть у нас один продукт, написанный полностью на Коммон Лиспе - конфигуратор и супервизор наших же железкок на FPGA. Не сильно большой, 10к строк движка, UI и компиляторов DSL, плюс 7к5 строк на DSL. Но из-за того, что это сплошные "кластеры метапарадигм", как выразился аноним на ЛОРе, то каждое действие - это маленькое инженерное чудо: классы, код и интерфейсы генерируются и убиваются на лету, в памяти гоняются сотни мегабайт развесистых структур данных, всё такое сложное, динамичное и многопоточное, что аж зубы скрипят.

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

У клиента через 49.7 дней аптайма софта отвалился внутренний механизм кэширования. В ходе анализа ситуации выяснилось, что для маркировки времени обновления кэша использовались встроенные лисповые часы, обновляющиеся 1000 раз в секунду. Лисповская функция, читающая часы, возвращает bignum, но из-за реализации внутренностей кэша от этого числа сознательно брались только 32 младших бита. Через 49.7 дней происходило переполнение, и кэш маркировался всегда устаревшим. Я подчёркиваю слово "сознательно", потому что код, делающий эту операцию со временем, был спецом так написан. И на момент написания 2 года назад он был логически правильным, но потом изменились требования, и код стал неправильным, но про него никто не вспомнил. Соответственно, это тупая алгоритмическая ошибка, и этот же алгоритм, переложенный на, скажем, Хаскель, воспроизводил бы ровно ту же самую ошибку.

А бараны вместо коров в реальной жизни никогда не приходят. Вот.

12 комментариев:

  1. Не так давно правил багу, которая заключалась в том, что при работе с хэш-таблицей в качестве ключа использовалась ссылка на другой хэш вместо строки. Perl в таких случаях преобразует ссылку в строку типа "HASH(0x28412244)" и ошибка остается незамеченной до поры до времени.

    Так что коровы вместо баранов в реальной жизни время от времени приходят, но нормальные тесты в большинстве случаев позволяют это отловить. Плюс в Perl есть средства для проверки типов, хотя они и не очень быстрые, поскольку построены поверх динамической типизации. А вот если нет ни типов, ни тестов, это беда.

    ОтветитьУдалить
    Ответы
    1. У нас есть автоматическое регрессионное тестирование. У кого нет - ССЗБ, и без разницы, на каком ЯП пишут :)

      Удалить
    2. Так в моем случае код как раз был покрыт автоматическими тестами. Писалось все по TDD за редкими исключениями (сначала немного кода, потом тесты для него). Так что вот.

      Удалить
    3. @afiskon ну, вообще-то TDD как раз про следование вот этим трём правилам http://butunclebob.com/ArticleS.UncleBob.TheThreeRulesOfTdd

      ну и, всё же, к функциональным/регрессионным тестам не очень относится (они тоже нужны).

      особенно ужасны тесты после кода тем, что вы не можете узнать, тестируют они вообще что-либо или нет.

      Удалить
  2. на прошлой недели чинили похожий баг - баркод кастовался в Objective C int. В результате сравнение было не предсказуемым. Если первые 8 цифр совпадали - true. Так что не в типизации дело.

    ОтветитьУдалить
  3. https://en.wikipedia.org/wiki/List_of_cognitive_biases#Decision-making.2C_belief_and_behavioral_biases
    https://en.wikipedia.org/wiki/Base_rate_fallacy

    ОтветитьУдалить
  4. Когда придётся менять коров на баранов, то отвалится не при компиляции, а при работе в неожиданном месте. Тот факт, что для замены типизации пишутся тесты, говорит лишь в пользу необходимости типизации.

    ОтветитьУдалить
    Ответы
    1. Статическая типизация как замена тестам? Ой, насмешил ;)

      Удалить
    2. Где это я такое написал, не подскажете?

      Удалить
    3. > Тот факт, что для замены типизации пишутся тесты, говорит лишь в пользу необходимости типизации.

      Удалить
    4. По-вашему, это одно и то же?

      Удалить

Архив блога