пятница, 25 июня 2010 г.

[prog] В завершение темы об ошибках в программе, unit-тестах и системах типов

Созрел до заключительного поста в поднятой несколькими заметками (первая и вторая) ранее теме.

Ошибки в программах – это плохо. Даже если они не досаждают пользователям и не отваживают клиентов от производителей ПО, все равно ошибки обходятся дорого. Главным образом за счет времени и ресурсов, которые направляются на их обнаружение и исправление. Замечу, что на обнаружение и исправление, а не на предупреждение. Поскольку наиболее распространенные способы обеспечения качества ПО (читай: различные формы тестирования) обеспечивают, в лучшем случае, хороший отлов ошибок. Уже внесенных в ПО ошибок.

Более выгодно было бы иметь средства предупреждения ошибок. Тогда и тестировать нужно было бы меньше.

И тут на арену вырываются отдельные яркие представители того или иного экзотического направления в программировании. В последнее время это функциональщики, размахивающие флагами систем типов; сравнивающие программирование с доказательством теорем; объясняющих, что в отсутствии побочных эффектов однажды написанный фрагмент кода будет оставаться корректным… И обещающие другие благодати их славной, но воинствующей религии :)

Не буду пытаться оспорить эти тезисы. Пусть даже все это так и есть. На мой взгляд, если всем этим заветам следовать, то программирование должно превратиться в математическую дисциплину. Что невозможно, поскольку программирование – это не математика. Именно поэтому огромный объем полезного и успешно работающего кода ежедневно и ежечасно пишут люди вообще не имеющие математического образования.

Но, если формализованные и заматематизированные методы программирования не пройдут, то что же останется?

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

  • строгая типизация;
  • статическая типизация;
  • модульность и инкапсуляция;
  • исключения;
  • сборка мусора и отсутствие адресной арифметики;
  • статически-типизированные шаблоны и генерики (в таких языках как Ada, C++, Eiffel, Java, D, C#, Scala);
  • void safety в языке Eiffel;
  • паттерн-матчинг, который приходит в мейнстрим благодаря Scala, OCaml и Haskell;
  • иммутабельность данных, на которой делается акцент в OCaml, Haskell, D. В зачаточном виде привнесена в мейнстрим C++ным const-ом;

Это, я бы сказал, крупные, очень заметные изменения. А есть и менее заметные, очень обыденные, но не менее эффективные. Например, запрещение присваиваний внутри оператора if. Или появление в Java специального оператора for. Мелочи, но изрядный объем неприятных ошибок они устранили как класс.

Я думаю, что в дальнейшем мейнстримовые языки программирования будут вбирать в себя разнообразные техники из различных более-менее маргинальных языков. Каждое новшество (которое может быть совсем не новшеством в своем исходном языке) будет бороться с каким-то определенным классом ошибок. И так, потихоньку, шаг за шагом, разработчики языков будут лишать программистов возможности совершать хорошо известные нам сейчас ошибки (например, присваивание вместо сравнения в операторе if). Наверняка при этом будут возникать какие-то новые типы ошибок, сейчас неведомые.

Подчеркну, что я говорил только об очень узком классе ошибок. Можно разбить причины возникновения ошибок на три класса:

  • ошибки по недомыслию. Не додумались разработчики, что старый код нельзя использовать в новых условиях – Ариан 5 взорвался на старте;
  • ошибки по незнанию. Не знали программисты одного отдела, что программный модуль, разработанный в другом отделе, будет выдавать координаты в другой системе счисления – потерялся марсианский спутник;
  • ошибки по невнимательности. Забыл программист при выделении буфера добавить один байтик для завершающего ноль символа и…

Так вот, все о чем я говорил выше касается только ошибок по невнимательности. Языки программирования, к счастью, становятся все более и более дуракоустойчивыми bulletproof-естыми. Что есть хорошо, ибо чем меньше возможности разработчику допустить случайную, глупую ошибку – тем лучше.

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

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

Qrilka комментирует...

А чем тебя пугает программирование как математика?
У меня такое ощущение, что у тебя некое представление о "заформализированной математике" как о некой детерминированной вселенной, где всё чётко определено и выход жёстко определяется входными параметрами.
Это я неверно домыслил?

Евгений Охотников комментирует...

>А чем тебя пугает программирование как математика?

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

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

Это моя личная особенность восприятия математики. Но я вынужден с ней считаться.

>У меня такое ощущение, что у тебя некое представление о "заформализированной математике" как о некой детерминированной вселенной, где всё чётко определено и выход жёстко определяется входными параметрами.

Ну где-то очень близко.

Qrilka комментирует...

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

Евгений Охотников комментирует...

>Но, с друго стороны, считаю, что "наука ради науки" это, скажем так, "довольно странная вещь" (т.е. нечто не совсем здоровое)

Я в аспирантуре наблюдал, как коллеги занимались подбором ядер несобственных интегралов. Т.е. была какая-то вполне реальная задача, кем-то когда-то формализованная. В результате был получен набор несобственных интегралов. Решение которых и давало решение исходной задачи. Проблема была в том, что интегралы эти не решались в общем случае. Можно было для каких-то конкретных условий выбрать какое-то частное ядро и получить некоторое частное решение. Все это дело требовало больших матиматических выкладок (как чисто математических, так и из области вычислительной математики). При этом никто особенно не представлял себе, какой же физический смысл во всем этом деле.

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

>Ну и не согласен я с твоим восприятием математики.

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

Qrilka комментирует...

По-моему как раз сейчас порой очень похоже на "подбор", а не на нормальную математику (пусть это будет моё субъективное восприятие, формализовать его толком не берусь), ограничения - ТЗ :)
К сожалению аргументировать несогласность по поводу математики тоже не возьмусь, скажу только, что поиск доказательства чего-либо нетривиального, вещь далеко не формализуемая.

Евгений Охотников комментирует...

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

Именно. Поэтому здесь так же есть камень преткновения. Происк решения какого-нибудь уравнения непредсказуем. И его можно будет считать успешным даже если будет показано, что решения не существует. Что вполне нормально для математики. Но производство ПО на то и "производство", что продукт надо выдавать, с ограничением на сроки и бюджет. Так что и с этой точки зрения программирование далеко от математики. Поэтому в программировании "подбор" гораздо более распространен. И работает к тому же :)

Rustam комментирует...

Ну производство ПО не совсем производство, вот Gaperton недавно на эту тему очень неплохо выступил http://www.rsdn.ru/forum/philosophy/3808250.1.aspx

Rustam комментирует...

Все-таки функциональщина даже в виде таких штук как Coq и т. п. совсем не математика, математики вон даже математическую физику, которая по сути дала жизнь многим разделам современной математики, за математику не признают :)

Евгений Охотников комментирует...

2Rustam:

>математики вон даже математическую физику, которая по сути дала жизнь многим разделам современной математики, за математику не признают :)

Ну, это проблемы математиков. ;)
Подозреваю, что среди математиков, скажем, алгебраистов, найдется не мало тех, кто ни в зуб ногой в хардконых диффурах и УМФ :))

Евгений Охотников комментирует...

2Rustam: С Гепертоном не так все просто -- он пишет интересно, умно, увлекательно, аргументированно. И, на первый взгляд, правильно. Однако на уровне подсознания у меня часто возникает несогласие -- не верю, хотя аргументированно обосновать не могу.

Производство ПО -- это все таки производство. Т.е. гарантированное получение результата. Этим программирование отличается от исследований.

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

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

Кроме того, Гапертон говорит об очевидной вещи -- программирование vs производство массовой одинаковой продукции. Но это уже давны-давно обсуждалось и не раз. А вот почему-то не сравнивают производство ПО с производством уникальной штучной продукции. Например, сверхбольших зеркал для телескопов (недавно смотрел передачу по Discavery, поэтому такой пример в голову и пришел).

В общем, не зацепил меня текст Гапертона. Да и сухого остатка в этом тексте, имхо, не так уж много.

Rustam комментирует...

Гапертон да часто излишне категоричен, но по сути все-таки прав, в отличии от большинства которое ждет, только на моей памяти уже лет 15 (реально еще больше, те же японцы со своими фабриками софта в начале 80-ых) что еще вот чуть-чуть и производство ПО индустриализуется и миллионы "индусов" на конвейере полностью заменят программистов.

Qrilka комментирует...

Соглашусь с рустамом и гапертоном.

Alexey Romanov комментирует...

> На мой взгляд, если всем этим заветам следовать, то программирование должно превратиться в математическую дисциплину. Что невозможно, поскольку программирование – это не математика. Именно поэтому огромный объем полезного и успешно работающего кода ежедневно и ежечасно пишут люди вообще не имеющие математического образования.

Это доказывает, что сейчас программирование -- не математическая дисциплина. Но не доказывает, что не может или не должно стать ей в будущем (хотя по-моему, всё-таки не может).

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

Но это не мешает более активному применению математики в программировании. Как аналогию, можем представить инженера, который говорит: "Мне важно знать, что вот эта кривая описывает форму моста, а этот интеграл -- действующую на него силу тяжести." И он-таки прав -- если считать абстрактно, то будет куда труднее.

> Просто не хочется, чтобы программирование приняло вот такой же вид. Кто-то когда-то перевел прикладную задачу в форму уравнений и граничных условий. А потом программисты занимаются подбором математических решений для этих уравнений.

Мне кажется, что дело здесь объясняется просто тем, что людям для диссертации нужны какие-то результаты, а нужны ли они кому-то -- неважно. Если будут программисты, которым для получения нужно "что-то запрограммировать", то такая же ситуация возникнет без всякого превращения программирования в математику. А если нет, то сведение к таким результатам не приведёт :)

Евгений Охотников комментирует...

2Rustam:

>еще вот чуть-чуть и производство ПО индустриализуется и миллионы "индусов" на конвейере полностью заменят программистов.

Не могу здесь спорить, поскольку к управлениями проектами имею очень далекое отношение.

Однако вот что я думаю: поиски подходящего для разработки ПО процесса идут именно потому, что массовое производство ПО возможно лишь за счет "индусов". Т.е. программистов с заведомо более низкими способностями, меньшими знаниями, совсем не таким уровнем мотивации и пр. Гуру на всех не хватит. А в очень больших проектах и гуру нужно огранизовывать, чтобы был какой-то налаженный процесс.

Так что у индустрии нет другого выхода -- нужно учиться задействовать миллионы "индусов".

Евгений Охотников комментирует...

>Но не доказывает, что не может или не должно стать ей в будущем (хотя по-моему, всё-таки не может).

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