Про ёжика в тумане, зазнайство, языки программирования и вериги

Dec 27, 2012 23:57

Ещё один текст, вероятность появления которого в нормальных условиях была бы мала. Тем более, что блог для трёпа, а не для производства чего-то серьёзного. Но всё-таки допишу, раз уж тема была затронута в посте про вериги, радости мазохизма и типизацию и в комментариях к теме про звездизм и функциональное программирование.

Про мужество называть вещи своими именами


Есть слово, приносящее индустрии каждый год огромные убытки. И слово это - bug.

В принципе, на этом можно закончить. Кто понял, тому ничего объяснять не нужно. Кто не понял, тот не воспримет. Однако, раз уж начал, попробую уложить в один пост то, что вряд ли влезет в книжку. Без доказательств и объяснений. Схематично и коротко.

Баги - это некие виртуальные вредоносные жучки, прячущиеся внутри программ. Они обладают собственной волей.

Стоп.

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

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

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

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

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

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

Да-да. Среди читающих это таких нет. Как нет и среди читателей всего, где проходит деление на «Специалисты» и «Идиоты»

Но я приглашаю вас на другую сторону.

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


Если сделать программиста не идеальным, получается одна интересная штука: код перестаёт быть готовым результатом. Он даже перестаёт быть результатом. И становится отражением текущего понимания программистом условий поставленной задачи и способов её решения.

Код именно отражает, а не описывает. Последнее возможно, но требует перестройки всего процесса, от форматов записи до мозгов.

Мозги критичны. Попытайтесь, например, записать в комментарии что-нибудь типа «NOTE: use delay at least 500 ms. I do not know why, but does not work oterwise.» Потом покажите это начальнику. Или одному из гениальных коллег. Впрочем, последним можно не показывать: среди них дофига таких, кто любит свою гениальность распространять в массы, так что увидит и сам прибежит с кучей гениальных теорий (и советов по английскому) или, ещё хуже, тайком внесёт гениальные изменения.

Писать то, что думаешь, - это всегда отсутствие культуры, презрение к окружающим и хамство. Если кто-то ставит в своём коде комментарий «Stupid idea. Does not work, if N < 0. Correct ASAP.», он рискует прослыть минимум странным. А вот если это попадёт в участок ответственности гениального программиста, тут уже мелкой истерикой не ограничится. Даже, если «stupid» будет подразумеваться только по контексту.

И, конечно, гораздо выгоднее говорить «Мы исправляем баги в коммуникационном модуле», а не «Читая документацию мы прошляпили несколько критических моментов и неделю будем всё с нуля переделывать.»

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

// There are several other possibilities to correct the absence of the sizeof operator
// but they are not better.

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

Ладно, оставим. Большинство такого не выдерживает. Страшно. И ронять чувство собственного достоинства тоже страшно. И лицо потерять... И начальство тоже... Короче, фиг с ним, перейдём к плюшкам.

Качество определяется тем временем, которое в системе живёт ошибка

Jidoka.

Собственно, по этой теме всё. Вот только концепция волшебным образом прошла мимо европейского менталитета.

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

Если программа работает не правильно, она должна останавливаться. Точка.

Да, если на презентации клиенты увидят, как программа вылетит с NullPointerException, это будет не очень хорошо для коммерции. Есть ещё тысяча и одна причина доказать, почему ошибки нужно прятать. Но, если говорить о коде как об отражении понимания, двигаться вперёд можно только исправляя ошибки.

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

И тут можно упомянуть ещё одно интересное качество.

Любой интерфейс должен возвращать ошибку на адекватном уровне

Первое, что я обычно делаю на любом проекте - пишу собственный модуль диагностики. Потому что всё имеющееся удовлетворяет нужды гениев, но слабо предназначено для идиотов. В результате в моих руках оказывается очень мощный инструмент, одно из основных свойств которого - адекватность.

Адекватный уровень для ошибки в логике выполнения - останов программы.

Потому что, если в логике сбои, их нельзя игнорировать. Нужно разбираться.

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

Это ужасно медленно и ужасно дорого. (И ужасно страшно.)

В теории.

На практике это значительно спрямляет пути к цели и вовремя отсекает ошибочные решения. (Только не надо сюда приплетать agile, который на русский переводится словосочетанием «Мы - гении!»)

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

Если вы видите, что гениальный коллега произвёл фигню, ни в коем случае не надо обращаться к нему с намёками про то, что файлы не всегда открываются или исходные данные не всегда правильны. Это приведёт только к ненужным дискуссиям о вероятностях, надёжности и тупых пользователях. Особенно, если гений получил гуманитарное образование или докторскую по программизму. В немецких условиях возникнут ещё траблы с начальством.

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

Да, он прибежит. Да, он будет возмущён. Он расскажет про качество и искусство писать нормальный код. Намекнёт про криворуких раздолбаев, на неумение создавать правильные программы, на людей, которые вместо функциональности производят ошибки.

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

После чего изобразить искреннее удивление, поговорить о редких и невероятных случаях, и отправить гения с пойманным багом в зубах вносить «неожиданные дополнения».

Это работает даже с индусами.

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

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

Приходится создавать сообщение на языке, понятном пользователю, с точным указанием места, причин и возможностей исправления, а потом не просто выводить его в лог (который не адекватен уровню ошибки), а тащить до самых конечных результатов. Чтобы, когда пользователь возмутится «А почему у меня тут значение пустое!», спокойно открыть соседний столбец в таблице и громко и с выражением зачитать, почему именно.

Впрочем, если у нас коробочный софт или проект для клиентов, о пользователях можно забыть. Служба поддержки тоже должна на чём-то деньги зарабатывать. И желательно, чтобы это были не наши ошибки.

Не надо ловить блох - ошибки можно прогнозировать

die "OK!" ;

Вот так или аналогом на других языках выглядит у меня самое частое средство отладки программы. Естественно, в большинстве случаев строчкой выше стоит $diag->DBG(...), который выводит всё, что я хотел узнать и что мне было интересно. Иногда это пара значений, иногда структура на полтора мегабайта, которая затем тщательно изучается ручками или программой.

Индустрия молится на Unit Testing. Это модно, это прогрессивно, это агильно. Вот только цель его ответить на вопрос «Я, правда, гений, да?»

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

Когда программист не идеален, ему не нужно зеркало, ему важно понять, что же на самом деле внутри происходит. А тут наиболее простой способ - сделать функциональный прототип или в реальной ситуации на реальных данных в нужном месте остановиться и посмотреть, что на данном этапе получилось. Естественно, проще всего это делать, когда код пишется, потому что именно в данный момент программист строит предположения на счёт того, что должно и не должно получиться. Потому «die», потому «OK!»

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

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

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

Ошибки можно ловить там, где их проще всего понять

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

Приходится ручками делать что-нибудь вроде такого.

$diag->ASSERT( ($max_depth >= 1), "Depth must be an integer >= 1" );

Всё просто. Если условие precondition выполнено, работаем дальше. Если получили данные, с которыми не можем работать, останавливаемся.

Есть один нюанс, из-за которого модуль диагностики приходится делать заново. И это совсем не потому, что стандартные средства не позволяют гибко перенаправлять ввод в файл или диалоговое окно. Секрет в текстовом сообщении.

Это короткое послание в будущее. От сомневающегося автора из времени написания программы неизвестному лицу, которому придётся разбираться с тем, почему условие не сработало.

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

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

$diag->ASSERT( defined( $network->{ $first_vertex }->{ $second_vertex } )
, "Fatal error with deletion"
);

$diag->ASSERT( defined( $net->{ $cur_vert } ), "Wrong subnet" );

$diag->ASSERT( ( $main_name and $main_name !~ /^NA$/i )
, "Main name is empty"
);

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

С другой стороны, зазнаваться вредно. Оптимизированная программа, работающая не правильно, просто производит больше мусора за единицу времени. Потому в коде полно проверок типа такой.

$diag->ASSERT( ( defined( $cur_patient_data->{"start"} )
and defined( $cur_patient_data->{"end" } )
and defined( $cur_patient_data->{"ratio"} )
)
, "Impossible state. See the source code."
) ;

Как правило, подобное никогда не срабатывает. Но, если случается невероятное, программа сама сообщает, что не надо было задирать нос, самые беспочвенные опасения оправдались, и придётся лезть внутрь, разбираться.

Ладно, на этом пора закругляться. Всё отложенное в черновик удалось вписать в текст, а углубляться в теорию или практику - это надолго. Да и чревато конфликтами в коллективе, если кто, вдруг, попробует применить на неподготовленном контингенте.

Copyright

(CC BY-NC-ND 3.0) vit_r, 2012



This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivs 3.0 Unported License.
Перевод на английский запрещён, потому как нефиг портить хорошую вещь.

it, ru, qa, motivation, quality, fp, management, agile, psychology, se, freelancer

Previous post Next post
Up