суббота, 18 апреля 2009 г.

Разработка управляемая исключениями

Это перевод Exception-Driven Development. Автор: Jeff Atwood.

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


Также, если это действительно ваш случай, то извините меня, но я вынужден сказать, что вы делаете свою работу действительно хреново (you kind of suck at your job) - которая заключается в том, чтобы знать о своём приложении больше, чем это знают пользователи. Когда пользователь извещает меня о настоящей ошибке, которую они нашли в моей программе, мне становится очень неловко. Если не сказать стыдно. Мне не удалось увидеть и решить проблему до того, как мне на неё указали. Я проигнорировал свою ответственность за вылет приложения.

Каждый ответственный разработчик приложений первым делом должен создать механизм отправки баг-отчётов (exception and error reporting facility). Ned Batchelder сравнивает это с надеванием кислородной маски сначала на себя, а потом на своего ребёнка:
Когда в вашем приложении возникает проблема, всегда прежде всего проверяйте, что ошибка будет соответствующе обработана. Если нет - сразу же исправляйте обрабатывающий её код (в первую очередь). Для такого порядка работы есть несколько причин:
  1. Если у вас есть на руках проблема - у вас есть отличный test-case для ошибки в вашем приложении. Если вы исправите проблему, то как же вы будете проверять обработку ошибки? Не забывайте, что одной из причин, почему у вас возникла ошибка - потому что это было непросто проверить.
  2. Когда исходная проблема решена, срочность исправления кода обработки ошибок исчезает. Вы можете сказать: да, я починю это, но зачем спешить? Вы будете похожи на человека, который живёт под протекающей крышей. Когда идёт дождь = крышу починить нельзя, но когда дождя нет - то ведь и не капает!
Вам нужно иметь централизованное место, где будут скапливаться все ваши ошибки - место, которое все разработчики вашей команды будут знать и посещать каждый день. На Stack Overflow мы используем свою реализацию ELMAH.

stackoverflow exception log
Мы проверяем эти логи исключений ежедневно; иногда ежечасно. Наши логи исключений являются де-факто списком TO-DO для нашей команды. И на это есть хорошая причина. Microsoft годами собирает аналогичные отчёты об отказах, как для себя, так и для сторонних разработчиков программ, под флагом их службы Windows Error Reporting (WER). Выводы весьма убедительны:
Когда пользователь получает вылет приложения, ему показывается диалоговое окно, которое просит отправить их отчёт об ошибке. Если он выбирает отправку отчёта - WER соберёт информацию как о приложении, так и о модуле, в котором произошёл вылет, и отправит через безопасное соединение в Microsoft.

Сопоставленный bucket-у разработчик сможет получить доступ к данным для своих продуктов, проанализировать их, найти источник проблемы и предоставить решение как в диалоговом окне об ошибке, так и через Windows Update.

Широкомасштабный анализ присланных данных показывает, что 80% пользовательских проблем могут быть решены исправлением 20% наиболее "популярных" багов. Даже исправление 1% самых частых ошибок устранит 50% пользовательских проблем! Примерно аналогичные результаты обычно истинны и для company-by-company.
Хотя я остаюсь поклонником разработки управляемой тестами (Test-Driven Development, TDD), спекулятивный характер вложения временных затрат - это то, с чем мне всегда приходится считаться. Если вы исправили ошибку, которая не встречалась ни одному из ваших пользователей, то что действительно вы исправили? Хотя существует множество других причин для применения TDD, но на мой вкус, с точки зрения механизма исправления багов, TDD выглядит как преждевременная оптимизация. Я предпочитаю тратить моё время на исправление багов, которые являются проблемами на практике, а не в теории.

Конечно же, вы можете применять оба подхода. Но при недостатке времени разработчиков, я предпочту выделить его для исправления проблем реальных пользователей, основываясь на голых числах. Это я называю разработкой управляемой исключениями (Exception-Driven Development, EDD). Выпустите свой продукт, усадите за него как можно больше пользователей, и тщательно изучайте баг-репорты, которые они начнут генерировать. Используйте эти баг-отчёты для фокусировки на проблемных участках вашего кода. Перепроектируйте и исправьте свой код, так чтобы 3 самые популярные ошибки не могли бы больше произойти. Выпускайте обновления часто, устанавливайте их и повторяйте процесс. Этот цикл по данным отчётов настолько сильный, что (по крайней мере, по мнению пользователей) вы будете иметь исключительно надёжное приложение (rock stable app) за разумное число итераций.

Логи исключений - это, верояно, самый мощная форма обратной связи (feedback), которую конечные пользователи могут вам дать. Эта обратная связь основана на распространяемом продукте, так что вам не надо просить или уговаривать пользователей ради неё. Также вам не нужно будет интерпретировать невнятные, динные рассуждения пользователй о том, какие же проблемы есть у вас - настоящие проблемы, вместе с call stack-ми и дампами памяти будут собираться для вас автоматически и молча. Логи исключений - это высшая форма пользовательской обратной поддержки.

carnage4life: getting real feedback from customers by shipping is more valuable than any amount of talking to or about them beforehand
Неужели я оправдываю бажный код? Некомпетентный код? Плохо написанный код? Конечно же нет. Я говорю, что чем скорее вы вытащите свой код из редактора IDE и поставите его перед реальными пользователями, тем больше данных у вас будет, чтобы улучшать ваше приложение. Логи исключений являются значительность частью этого процесса; а также и статистика использования. И вам нужно говорить со своими пользователями. Да, если вытерпите.

Ваше программа всё равно выйдет с багами. Любая программа. Настоящие приложения вылетают. Настоящие приложения теряют данные. Настоящие приложения тяжело использовать и тяжело изучать. Вопрос не в том, как много багов будет у вас, когда вы выбросите программу из редактора, а как быстро вы сможете исправлять эти ошибки? Если ваша команда практикует EDD, ответ будет: "Что? Да мы можем улучшить наши программы моментально! Просто смотрите, как они становятся лучше!"

А это сладкая, сладкая музыка для ушей каждого пользователя.

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

  1. Привет.
    Хочу задать тебе интересующий меня вопрос о TDD. А ты пишешь тесты перед началом разработки?

    ОтветитьУдалить
  2. Неа, я их вообще не пишу :(
    По основной работе никто на это время не выделяет - да, "российко-драконовский" подход :(((( А для себя - ну, там нет никаких сложных проектов. Поэтому никогда и не заморачивался.

    Ну, вот для EurekaLog test-case-ы мы используем, но сборку выполняю не я. Все тесты были написаны до меня и работает с ними кто-то другой. Мой код (фиксы с работы в support) только проходит проверки. Сам я не писал ещё ничего.
    Но сейчас вот идёт разработка v7 - там часть функционала пишу я. Так что, скорее всего, тесты для своего нового кода буду писать уже я. Заодно и пощупаю этого зверя :D

    ОтветитьУдалить
  3. У нас на работе такая же ботва. Хотя не из-за времени, а просто потому, что никто из делфистов не умеет, да и просто ленятся. Да я и сам не исключение. Но речь, не о том. Я пытался начинать писать тесты, но как правило на стадии - когда каркасы классов уже написаны - меня хватало только на пару тривиальных тестов, и дальнейшее написание я бросал.
    Так вот у меня, есть большое желание почитать что-нибудь о том, как человек привыкший аккуратно писать код без тестов, началиспользовать TDD, с какими трудностями он столкнулся, и как их обходил.

    Если будет время, отпишись, пожалуйста, о том как у тебя будет проходить переход.

    ОтветитьУдалить
  4. Хорошее предложение - я попробую :)
    Только вполне может получиться так, что особо писать будет и не о чем. Ну, например, у меня была похожая ситуация с системами контроля версий. На работе не использовались, дома вроде и не надо - вот я и поставил сам для себя на работе и использовал в своё удовольствие.
    Только вот писать особо и не о чем - её просто надо взять и использовать ;) Есть подозрение, что так же будет и с тест-кейсами.
    Кроме того, я заметил, что на QC, когда баг правят, там иногда приписывают: на этот случай создан TC (test-case). Т.е. нельзя заранее предугадать все возможные случаи покрытия, поэтому TC добавляются "естественным образом" по ходу использования продукта, при фиксе багов. (не, понятно, что если какую-то функциональность мы запланировали - то её тут же можно закрепить в TC)

    ОтветитьУдалить
  5. Система контроля версия - великая штука. Больше никаких бекапов. Всегда можно найти рабочие исходники для любой версии продукта. Мммм... Плюс, всегда доступны последние стабильные исходники. Кстати, не знаю как у тебя было, а мне, с началом использования SVN, пришлось пересмотреть свой подход к программированию(прощай хаотичное исправление с одновременным рефакторингом, здравствуй последовательное выполнение только одной задачи за раз).

    А насчёт тестов.. У себя в рабочих проектах я столкнулся с тем, что просто не представляю как покрыть тестами 80% существующего кода. Т.е. теоретически это возможно, но для этого в большинстве тестов пришлось бы воссоздавать большую часть объектов, включая и базу данных. Ибов коде слишком много перекрёстных ссылок, слишком много глобальных объектов. В общем, я пришёл к мысли, что мне, для того чтобы начать использовать TDD, придётся пересмотреть свой подход к программированию(например, полностью проектировать структуру и взаимодействие классов до начала написания актуального кода). Вот мне и интересно стало, у кого как такой переход происходит.

    Забавно, как раз сегодня в DelphiFeeds появислся пост на эту тему: Exploring Test Driven Development

    ОтветитьУдалить
  6. >>> прощай хаотичное исправление с одновременным рефакторингом

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

    >>> У себя в рабочих проектах я столкнулся с тем, что просто не представляю как покрыть тестами 80% существующего кода

    Я себе это тоже слабо представляю. Особенно, такие субъективные критерии, как "отчёт в FastReport в новой версии выглядит некрасиво!" ;)

    ОтветитьУдалить
  7. >Я себе это тоже слабо представляю. Особенно, такие субъективные критерии, как "отчёт в FastReport в новой версии выглядит некрасиво!" ;)

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

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

    ОтветитьУдалить

Можно использовать некоторые HTML-теги, например:

<b>Жирный</b>
<i>Курсив</i>
<a href="http://www.example.com/">Ссылка</a>

Вам необязательно регистрироваться для комментирования - для этого просто выберите из списка "Анонимный" (для анонимного комментария) или "Имя/URL" (для указания вашего имени и ссылки на сайт). Все прочие варианты потребуют от вас входа в вашу учётку (поддерживается OpenID).

Пожалуйста, по возможности используйте "Имя/URL" вместо "Анонимный". URL можно просто не указывать.

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