Искусство программирования под Unix (и не только). Часть седьмая, «правило прозрачности»

    Я продолжаю цикл статей, посвященных некоторым простым правилам разработки под Unix «по версии Эрика Реймонда», которые, по моему глубочайшему убеждению, могут быть распространены на любые другие операционные системы. Я уже рассказывал в первых трех частях о правилах модульности, ясности, композиции, разделения, простоты и кодоэкономии. Сегодня дело дошло до седьмого правила —

    Правило прозрачности: проектируйте ПО сразу с учетом отладочных инструментов

    Смысл этого правила можно представить двумя постулатами:
    • приложение должно не просто работать хорошо, но и показывать, что она работает хорошо;
    • должна быть предусмотрена возможность «высокоуровневой отладки» приложения;
    Возьмем для примера современные почтовые программы. Прием и отправка писем — очень непростой процесс, потому что им приходится «общаться» с неким почтовым сервисом, который может повести себя совершенно непредсказуемым образом в любой момент времени. Обрабатывать эти исключительные ситуации, конечно, надо, но, как говорится, за всем не угонишься. Ошибки могут быть буквально на каждом шагу — в почтовой базе, в канале связи, в почтовом сервере, в формате письма. Для того, чтобы понять, что за проблема привела к проблемам с приемкой писем, нужно вести подробный журнал общения с почтовым сервером и место, на котором «споткнулась» программа скажет о многом. Но нужно ли это простому пользователю? Нет, для этого и ставят кнопку «Подробнее».

    Или — типичный Windows-FTP-клиент. Вещь, вроде, уже давно вошедшая в арсенал обычного пользователя. Ну ладно, продвинутого пользователя, но по-всякому уже давно не обязательно программиста, понимающего в тонкостях протоколов. Ставишь себе программу, в которую встроен FTP-клиент, чуть ли не ради него ее выбрал, а он — не коннектится к серверу. Почему — не определишь. Никак он себя не выдает. Ошибка — и все!..

    Хорошо, спустимся еще ниже. Вот есть скайп и аська под Windows. У них обоих есть настройки на прокси-серверы. И каждый раз, когда проблемы с соединением, не знаешь, почему они-то ли что-то с прокси-сервером, то ли это «у них» проблема, то ли — у меня.

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

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

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

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

    Приведенный пример может быть использован как положительный, так и как отрицательный. В частности, в нем удобным является то, что журнал представляется в форме структуры. Минус в том, что собирать и обрабатывать численные данные из такого журнала довольно непросто, непросто, например, зафиксировать изчезновение из структуры какого-нибудь обязательного блока. Он похож на XML, но совершенно не «валидный».

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

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

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

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

    Недавно занимались системой расчета сроков доставки. Там довольно хитрый алгоритм, учитывающий особенности логистики. Понять правильность расчета сходу невозможно, нужно вооружаться калькулятором и таблицами. Поэтому для того, чтобы быстро отвечать на вопросы, правильно ли работает механизм, нужно было добавить для него «прозрачности»: при отработке в журнале должна отражаться вся логика расчета срока, понятная неспециалисту. Отражать ее на сайте, конечно, не нужно было, но зато отвечать на вопрос вида «как это так получилось, что доставка занимает целых 15 дней!» стало отвечать очень просто — понятный для человека ответ буквально дает сама система. Также была разработана система автоматизированного тестирования, рассчитывающая сроки сразу для десятков ситуаций и сравнивающих результаты с рассчитанными вручную.
    « Ранее: правило кодоэкономии
    AdBlock has stolen the banner, but banners are not teeth — they will be back

    More
    Ads

    Comments 16

      0
      забыли cut, вероятно.
        +1
        Спасибо. Как ж это хабра тогда сохранила…
        0
        Мне кажется, любую сколько-нибудь сложную систему просто невозможно построить без логирования. Другое дело, что не нужно логирование прятать от пользователя.
          0
          Мне кажется, это вы про свой софт. А когда заглядываешь в уже сделанное кем-то ранее, удивляет, почему там иначе. Вот в продукте, который достался в прошлом году мне — иначе. Не буду оглашать компанию-разработчика, там уже из тех программеров давно никого не осталось.
            0
            Госпади, ну ведь почти все разрабы при отладке пишут в stdout какие-то сообщения, перехватить этот поток и перенаправить его в файл, а там уж навести марафет в виде даты, конкретного модуля, который дебаг сообщение постит.
            • UFO just landed and posted this here
                0
                >Окромя stdout есть еще stderr. А вот в него не все пишут…

                Вообще отладочные мессаги лучше как раз туда писать, тут я не уточнив написал.
                • UFO just landed and posted this here
        • UFO just landed and posted this here
            0
            Первая часть (про модульность) недоступна. Можете достать ее открыть? (:
              0
              открыл. На хабре дефолтный сабмит — в черновики. Жмешь энтер и — прощай, статья:)
                0
                Спасибо.
              0
              Про логирование можно еще полторы статьи написать.

              Хотелось бы сказать, что иногда STDERR и STDOUT слишком мало, ибо нужно сортировать сообщения по теме, а потом отдельно эти темы просматривать.

              Я, конечно знаю, что существует grep|sed|awk и т.п., и даже люблю эти утилиты, однако считаю, что иногда удобно просто взять и распечатать файл через tail -n XX или tail -f. Вот тогда на помощь приходит логирование каждой отдельной темы в свой файл.

              Приведу пример:
              1. обновление данных
              2. обновление кода
              3. обновление графики .{jpg,gif,png}
              4. экспорт данных
              5. обработка данных ( тут можно еще побить на отдельные темы )
              6. диагностика поддержания работоспособности П.О. (и тут можно на каждый аспект отдельный файл)

              При логировании очень полезен шаблон проектирования «Наблюдатель».

              1. Тот за кем нужно наблюдать может рассылать сообщения в никуда, если за ним никто не наблюдает.
              2. Один наблюдатель может подглядывать за несколькими темами сообщений (объектами, аспектами, добавить свое)
              3. За одной темой может следить несколько наблюдателей, каждый из которых может по разному на сообщения реагировать (писать в файл, слать в Jabber и т.д.)

              В этом плане рекомендую посмотреть на Logger в стандартной библиотеке Python — ИМХО мега юзабельно!
                0
                Прекрасное правило. Я к нему к большому сожалению шёл своими граблями, работая в очень сильно молчаливом проекте — при введении неправильных данных в форме, а их там порой было более двух десятков, в случае опечатки или ещё какой случайной напасти, максимум что выдавалось: «Ошибка данных». Каких? чего? Где? А порой попадалось так, что программа вообще всё проглатывала и потом неправильно считала, вылетала и не хотела работать (я пришёл уже в проект и мне рассказывали, что раньше там везде так было). В данном случае на фразу «Молчание — золото» возникали ассоциации с золотухой (уж простите). Потом, когда эти очевидные вещи поправили и пользоваться стало удобнее, как пользователям, так и нам, программерам (отсекался целый пласт ошибок из-за неправильных входных данных), пришло понимание о том, что нужно вести и логи для непользовательских действий — об этом-то и статья. Но как же долго я к этому шёл: это и выдавание на отладочной версии как можно более информативных сообщений о том, что внутри что-то не так, потом переход к ведению текстовых логов через создание дополнительных классов с единым интерфейсом, чтобы информацию от предыдущей версии на основе всплывающих сообщений не потерять и внедрить в новую концепцию сохранения логов, потом всякие штучки и финтифлюшки наприкручивал для очистки, сигнализации и пр.! О боже, какое же долго всё же пришлось идти… Зато какой опыт!
                  0
                  Да, вот увлёкся и забыл, что стоит ещё сказать, что к включению отладочного режима уже в релизе через флаг так и не дошёл (куча пепла на мою виндузятную голову). Ну не успел. А идея действительно замечательная. Статья полезная!
                  0
                  Реквестирую продолжение. Пожа-а-а-алуйста!

                  Only users with full accounts can post comments. Log in, please.