вторник, 12 марта 2013 г.

Мобильные интернеты

Спасибо гуглу и его enterprise-like бенчмаркам за то, что у меня таки дошли руки написать эту статью.

Если вкратце, то ребята по ссылке выше для своих маркетинговых целей по продвижению SPDY решили не париться с мобильной сеткой (она же совсем нестабильная) и тупо пошейпили себе траффик (пожали канал до одного мегабита и сделали задержку в 150 ms). Покет лосс убрали нафиг, видимо вокруг их офиса с мобильными интернетами проблем нет. Счастливчики.

Про то, почему сам этот эксперимент является обычным enterprise-like бенчмарком, и почему радужные статьи ребят из гугла про SPDY на данный момент несколько не соответствуют реальности я писать не буду. По этому за последний год только ленивый не топтался. А вот то, что из себя представляет мобильный интернет вообще (и в моем ареале обитания в частности) я постараюсь расписать достаточно подробно (тот еще секрет полишинеля, но что-то с раздражением делать надо).

"Хвосты"
Начнем с простого эксперимента - сидя на месте попингуем что-нибудь, что находится в том же городе что и я, скажем, тыщенкой пакетиков. Должно быть достаточно шустро и без адского расколбаса, который обычно видно при попытке попинговать тот же Google, ближайшие сервера которого, судя по всему, находятся далеко за Уралом, где-то возле Москвы.

С моего домашнего компьютера получается 1-22ms, со средним очень устремленным к 1ms. Т.е. есть какой-то "хвост", но очень маленький. Когда до местячковых сайтов начинают появляться "хвосты" до 200ms у меня, обычно, начинают возникать нехорошие слова в адрес моего провайдера. С не местячковыми чуть хуже - ирландский датацентр амазона со своими вечными 120+ уже убил желание пользоваться услугами ряда милых стартапчиков.

Ок, давайте произведем такую же операцию, подключив компьютер через телефон к WiFi и к 3G поочередно. Проверять, понятное дело, не из кафешек, где можно вдоволь налюбоваться гавеным хипстерским интернетом, а из офиса/дома, где с интернетами дела обстоят сильно лучше.
WiFi: 2-249ms, со средним где-то в районе 9ms. Первый подвернувшийся ноут показал ровно те же результаты. Ура мобильной железке отвечающей за WiFi!
3G: 37-1366ms, со средним где-то в районе 130ms.

Т.е. вроде бы почти те же самые 150ms, которые использовались ребятами из гугла для имитации мобильной сети, только временами у нас запросы начинают залипать на секунду с лишним. Но попытка открыть какой-нибудь современный сайт это сильно больше чем один запрос. Та же m.lenta.ru это почти три десятка запросов, где практически любой запрос, залипнув на полторы секунды, может заставить пользователя в два раза дольше пялиться на пустой экран. И это, поверьте мне, далеко не самое страшное, что может случиться с вами при попытке просмотреть "мобильную" версию сайта. Что уж говорить про "не мобильные" сайты или ваше любимое приложение, которые открывает пяток соединений и начинает туда отсылать все подряд с завидной регулярностью.

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

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

Мой коллега, которому я показал эти цифры, провел аналогичные замеры. И цифры у нас значительно разошлись. Мало того, что среднее для 3G оказалось почти в два раза больше (напомню, что мы все еще пингуем ресурс в пределах города), но еще и "хвосты" выросли чуть ли не на порядок.

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

Происходит это безобразие во многом потому, что воздух, по которому мы передаем сигналы 3G и прочего WiFi - это не только слегка сопротивляющаяся среда доставки (как в случае проводов, например), но еще и открытое пространство для всевозможных вмешательств. Радиоволны, стены, микроволновое излучение, электромагнитное излучение и тросионные поля магических единорожков - это все лишь небольшой перечень возможных преград, увеличивающих latency пока сигнал с вашего телефона прорывается к вышке и обратно. Даже обычная открытая микроволновка может здорово подпортить опыт пользования беспроводными интернетами. И в центре города этих препятствий сильно больше, чем посреди леса. Пара тысяч городских жителей с карманами, забитыми гаджетами, мешает вам сильнее, чем полторы голодные белки, бегающие от дерева к дереву.

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

При этом стоя на месте маловероятно, что вы увидите потери пакетов - мобильные сети их отлично прячут за здоровенными задержками. Но когда вы начнете перемещаться по городу, то на потери пакетов насмотритесь почти гарантированно - при переключении между вышками или попадании в зону с фиговым покрытием потери пакетов еще как случаются. При этом можно сказать спасибо мобильным операторам, которые довольно странно ставят свое оборудование - спальный район почти гарантированно получит свой 3G, а вот бизнес-центр или молл, который недавно забабахали посреди пустыря, может еще долго довольствоваться одним только EDGE да WiFi с кафешек. Куски дороги, пролегающие мимо промзон и пустырей, так же не дадут насладиться быстрым и качественным интернетом. И мобильному оператору плевать, что там вечная пробка уже лет десять как.

Этот таинственный мобильный роутинг
Ок, я стою в чистом поле, сигнал отличный, но пинги все еще конские. ЧЯДНТ?

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

Дело в том, что GGSN стоят не у каждого подъезда, а где-нибудь, где удобно мобильному оператору. Так, например, несколько лет назад траффик TELE2 роутился через швецию. Т.е. сидите вы попивая чай где-нибудь в Екатеринбурге, а ваш прогноз погоды для мобильного телефона несется в швецию, оттуда на сайт, скажем, гисметео, и обратно. И дело не в раздолбайстве отечественных операторов - американцы спокойно заруливают траффик из Вегаса в Сан-Франциско.

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

Итого
Дальше можно было бы затянуть шарманку про слабое мобильное железо и толщину канала, но будем честными - мобилки по железу уже потихоньку перестают отставать от персональных компьютеров большинства обывателей, а толщина канала от EDGE к 3G и далее в LTE растет весьма внушающими темпами. Но избавления от мобильного latency, которое на пустом месте норовит стать из плохого просто чудовищным, пока не видно. Скорее наоборот - от WAP отказались, других альтернатив под беспроводные сети не придумали и при этом все кому не лень стараются использовать HTTP и другую привычную TCP-машинерию, весьма чувствительную к высокому latency и потерям пакетов. Да, разработчикам стало жить проще, но  мы с вами платим за это своим собственным временем.

вторник, 26 февраля 2013 г.

Перезапуск тестов

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

У автоматического теста есть всего один полезный выхлоп - падение теста. Все остальное время автоматические тесты просто греют воздух укрепляя в нас уверенность в нашем продукте (не всегда обоснованную, но это другая история). Это нагревание воздуха, безусловно, полезно для процесса и так далее, но большую часть времени никакой полезной информации не несет. Примерно как ребята в аэропортах, которые могут каждый год рапортовать, что в 100500 проверенных за год пар обуви ни одной бомбы не обнаружено. Работа, безусловно, полезная, но самое крутое что они могут сделать - это, как ни странно, исполнить свое предназначение и найти уже наконец эту чертову бомбу в этих чертовых ботинках. И перезапуск теста это примерно как "ой, кажется у вас в ботинках бомба, пройдите, пожалуйста, повторный досмотр - вдруг мы ошиблись?".

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

И что же означает это падение тестов? Обычно причины две:
  1. Баги в продукте
  2. Нестабильные тесты/Баги в тестах/Нестабильное тестовое окружение
Второе в одной группе, т.к. это, как правило, и является основным объяснением перезапуска тестов. И если мы начинаем перекладывать падение наших тестов на второй пункт, то мы попадаем в страну, где хреновые тесты - это норма, и где-то прячутся баги, которые мы могли бы найти раньше (и мы их, возможно, нашли, но успешно проигнорировали).

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

Да, я понимаю, что у всех своя специфика, уникальный внутренний мир проекта, сроки горят, начальство негодует и KPI не выполняется. Все это может заставить вас игнорировать какие-то упавшие тесты. Как правило это просто пустые отмазки. Как правило, но далеко не всегда.  Но тем не менее не позволяйте нестабильным, хреново написанным тестам становиться нормой. Не делайте нормой нестабильное тестовое окружение. Это все инженерные задачи - они решаются (не всегда легко, но тем не менее решаются). Если, конечно, суть вашей работы не заключается в том, чтобы демонстрировать пару тысяч зеленых квадратиков on commit.

среда, 13 февраля 2013 г.

MBT Начало

Традиционный подход к автоматическим тестам выглядит примерно так - тестописатель изучает тестируемую систему и после этого руками пишет каждый отдельный сценарий для проверки искомой системы. Кто-то может написать тут гордое слово "handcrafted", а я называю это словом "handjob". А все потому, что обычно этот подход к созданию и написанию тестов страдает от двух проблем:
  • "Парадокс пестицида", описанный Борисом Бейзером в 1990-м году. Заключается он в том, что тесты все менее и менее эффективны в отлове багов, так как баги, для обнаружения которых эти тесты написаны, уже найдены и починены. Если же этого не происходит, то возникают серьезные вопросы к написанному коду и к рабочим процессам
  • Тесты статичны и их сложно менять, в то время как тестируемая система имеет свойство постоянно эволюционировать, обрастать новым функционалом и менять поведение старого. И тесты нужно менять каждый раз, когда функционал изменяет внешний вид программы или ее поведение. И с ростом сложности обновления тестов оправдывать чудовищные издержки на поддержку тестов становиться все сложнее.
Model-Based Testing данные проблемы практически полностью игнорирует, поскольку тесты создаются автоматически из точной модели приложения. Это сильно упрощает как поддержку уже существующих, так и генерацию новых, крайне полезных и гибких тестов.

Что такое модель?

Модель - это описание тестируемой системы. Формальная спецификация вполне сойдет. Модель должна быть сильно проще описываемой системы и как-то помогать нам понимать и предсказывать поведение тестируемого продукта.

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

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

Что такое Model-Based Testing?

Это довольно немолодая идея использовать формально описанные модели для того, чтобы сделать тестирование ПО более дешевым и простым занятием. Само Model-Based Testing это такая "продвинутая" техника тестирования через "черный ящик". У нее есть ряд бонусов перед традиционными методами:

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

Зоркий поклонник Agile может воскликнуть "эй! у нас есть BDD и оно покрывает первые три пункта и еще это спецификация!". Я же отвечу "нихрена подобного - ваши примеры станут нормальной спецификацией только тогда, когда короля Шака Зулу можно будет считать спецификацией на все человечество".

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

Короткий ликбез по теории графов

Теория графов зародилась в 1736-м году в стареньком Прусском городе Кёнингсберге. Город стоял на двух берегах реки и попутно занимал еще и пару островов посреди этой самой реки. Жители этого города от безделья пытались придумать как посетить все семь мостов не проходя ни по одному дважды. Решали на практике, во время прогулок, и в теории, во время кухонных посиделок. Долгое время никто не мог доказать или опровергнуть возможность существования данного маршрута, пока не пришел зануда Эйлер и не испортил горожанам праздник.
Эйлер придумал изобразить каждый кусок суши как вершину графа, а мосты - ребрами графа.
И тут внезапно стало понятно, что нужного маршрута не существует. И все потому, что все вершины имеют нечетное число ребер. Ведь если у вершины четное число ребер, то гуляющий гражданин каждый раз заходя на этот кусок суши может выйти оттуда по новому мосту. Таким образом получается, что прогуляться по всем мостам не пересекая какой-то мост дважды не получится.

С тех пор граф, в котором все вершины имеют четное количество ребер называется "Эйлеровым Графом". А полный обход этого графа носит гордое имя "Эйлерова пути".

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

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

И в честь Куана эту задачку назвали "задачей китайского почтальона".

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

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

И если в случае Эйлерова Пути или Проблемы Китайского Почтальона мы оперировали дугами касающимися вершин, то тут приходится принимать во внимание еще и направление движения. И доля "Эйлеризации" такого графа нам требуется чтобы количество входящих в вершину дуг равнялось количеству исходящих. И считая каждую входящую дугу как "+1", а исходящую как "-1" мы можем вычислять "полярность" каждой вершины орграфа. Например вершина в двумя входящими и одной исходящей дугой имеет  полярность "2 - 1 = 1".

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

Причем тут тестирование?

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

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

С другой стороны, исполнение всех возможных действий это хорошо, но даже самый недалекий тест-менеджер понимает, что это банальное "покрытие состояний" в терминах тестирования сырого кода. Но у множителей есть одно неприятное свойство - у них, как правило, очень много "следующих" состояний у каждой вершины. Что же нам делать, если мы хотим проверить все возможные комбинации действий? Решения задач вроде задачи Китайского Почтальона не подходят, поскольку они гарантируют только посещение каждой дуги, но никак не посещение всех возможных комбинаций дуг.

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

Решение предложил некий де Брюийн. Алгоритм выглядит примерно так:

  • Рисуем сбоку граф, где каждое ребро исходного графа является вершиной.
  • Там где у исходного графа дуга "1" входит в вершину, откуда выходит дуга "2" рисуем в свежеиспеченном графе дугу из вершины "1" в вершину "2".
  • Эйлеризуем полученный граф.
  • Рисуем Эйлеров путь на данном графе.
В принципе можно не напрягаться и просто сделать случайный обход графа. Что примечательно - такая стратегия достаточно устойчива к "парадоксу пестицида". С другой стороны, у любого мало-мальски сложного приложения довольно развесистый граф состояний, на которых можно потратить кучу времени, прежде чем получить хоть какое-то покрытие "случайным обходом".

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

Итого

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

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

И, поскольку Теория Графов позволяет нам работать непосредственно с моделью:
  • Новые обходы можно автоматически генерировать при изменении модели
  • Наши тесты могут легко и непринужденно меняться в рамках одной и той же модели
  • Различные алгоритмы обхода могут удовлетворять различным потребностям тестирования
  • Полученные алгоритмы обхода легко можно переиспользовать в совершенно новой среде

понедельник, 10 декабря 2012 г.

Самоорганизующиеся высоконадежные организации (revised edition)

Тут недавно cartmendum вспомнил одну замечательную статью: "The Self-Designing High-Reliability Organization: Aircraft Carrier Flight Operations at Sea"

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

Можно долго спорить с тем, что ближе к разработке ПО этот наш авианосец или производство машин в недрах toyota. На мой взгляд и то и то достаточно далеко, но не в этом суть. Суть в том, что и там и там есть проблемы, которые в разработке и сопровождении ПО встречаются регулярно. А есть проблемы, которые нашему менеджменту только в страшном сне снятся. И при этом и там и там с ними справляются несколько лучше, чем в разработке ПО. Так что вместо того, чтобы примерять к IT авианосец просто выделю несколько ключевых, на мой взгляд, моментов, которые авторы статьи упоминают как средства сокращения факапов на авианосце:

  • Тесные взаимозависимости между различными групами
  • Тесная взаимная координация и обмен информацией, как результат частично дублирующихся знаний
  • Высокая операционная избыточность - много разных людей наблюдают за одними и теми же событиями и обмениваются наблюдаемой информацией
  • Широкое толкование того, кто принадлежит к команде
  • Сокомандники включаются в коммуникационные цепочки, а не исключаются из них
  • Регулярная работа над ошибками
  • Высокий уровень понимания текущей ситуации - поддерживается постоянное понимание того, что сейчас происходит и какова вероятность тех или иных факапов
  • Высокий уровень навыков межличностного общения
  • Хранение детальных данных о прошлых факапах, которые внимательно пересматриваются с целью обучения
  • Командная цепочка изменяется для того, чтобы отвечать текущей ситуации - высокая организационная гибкость
  • Сообщения о просчетах и ошибках вознаграждаются, а не наказываются
Посмотрите на этот список. Посмотрите на организацию, в которой вы работаете. И крепко задумайтесь.

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

воскресенье, 2 декабря 2012 г.

Средства сокращения ошибок

"Мы не можем изменить природу человека, но мы можем изменить условия, в которых люди работают"
- Доктор Дж. Ризон

Люди ошибаются. Если верить доктору Куку, то примерно 70-82% ошибок, связанных с анестезией, списывается на человеческий фактор. Примерно те же цифры показывает авиация и ядерная энергетика. Да и в целом подобные исследования в различных областях дают похожие результаты. Во многом из-за этого там и возникает ощущение "проблемы человеческого фактора", которую пытаются всячески урегулировать стандартами, правилами и автоматизацией. Увы, эти меры часто приводят к обратному эффекту - делают все еще хуже. Происходит это, в том числе, из-за серьезных изъянов в дизайне этих превентивных систем. Специалисты, исследовавшие подобные меры в здравоохранении и авииации, выделяют пять классов проблем, которые обычно приводят к увеличению количества ошибок: сложность, рабочая нагрузка, плохой дизайн, прерывания и культура. Возможно, их больше, но я остановлюсь на разборе тех, на которые указывают работы доктора Ризона.

Сложность
В сложном коде ошибаться проще, чем в коде простом.
В сложной, многоходовой процедуре ошибиться проще, чем в одноходовой.
Коммуникации, в которые вовлечено большое количество людей, увеличивают энтропию больше, чем коммуникации 1 на 1.
Любые усложнения требуют дополнительной концентрации, тренировок и знаний. Это порождает дополнительные требования к оператору, которые нельзя наращивать бесконечно - в конце-концов вам потребуется какой-нибудь сверхчеловек, чтобы такая система работала без сбоев.
Так же любая сложная система защиты от ошибок создает дополнительные возможности для ошибок, которые она, в идеале, должна предотвращать.

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

  1. Найти среднюю нагрузку не всегда легко
  2. Бизнес обычно заинтересован в максимальной производительности
В принципе, вторую проблему частично решил еще дедушка Форд, понявший, что неполная загрузка работников помогает избежать затыков из-за колебаний в работе различных звеньев системы. Доктор Ризон же утверждает, что это ведет к снижению количества ошибок в системе.
Но менеджеров, согласных пойти на эти меры, найти крайне сложно, несмотря на то, что работам Ризона уже больше двух десятков лет, а Форду и того больше.

Плохой дизайн
Лет десять назад в эфире практически отсутствовали такие слова как usability и user experience. Сейчас об этом говорят и пишут достаточно много. Отвратительный софт и сайты-лабиринты от этого не исчезли, но о проблеме хотя бы говорят. Увы говорят обычно про пользователя, зачастую подразумевая совсем не работника и не оператора. А стоило бы.
Потому что плохой дизайн рабочего места приводит к росту ошибок.
Потому что плохой дизайн рабочих инструментов приводит к росту ошибок.
Продолжать можно долго, но практически все это можно увидеть посетив какой-нибудь банк. Да и в разработке ПО у нас все еще есть множество языков программирования с сомнительным дизайном, аналогичного качества IDE и фреймворки. И это я еще от монитора глаза не отводил.

Прерывания и отвлекающие факторы
Врача скорой помощи в штатах отвлекают от работы в среднем 10 раз за час. Демаете от этого он начнет меньше ошибаться? Нет, у него от этого вылетают из головы важные мелкие детали.
У авиации все еще печальнее. По статистике примерно 50% ошибок в авиации (а они порой бывают очень ссмертельными) происходят потому, что пилотов отвлекали.
Думаете в разработке ПО все сильно лучше? Тогда придите как-нибудь на работу пораньше и поработайте пару часиков, когда никого в офисе нет, и в почту ничего не ломится. Если вам в одиночестве работается гораздо лучше, то у меня для вас плохие новости.
При этом понятно, что совсем без прерываний нельзя. Разработка ПО так или иначе связана с коммуникациями, т.е. нужно как минимум общаться друг с другом и с заказчиком. И совсем избавиться от этого никак нельзя, потому что тогда все встанет колом. Но сводить это общение к минимуму тоже непросто - слегка переборщил и все пошло наперекосяк.
Но даже не смотря на эти проблемы возьмите того же тестировщика. Если он у вас одним глазом смотрит в систему управления тестами, а другим в тестируемое приложение, то у него прерывания не просто периодически случаются - он в них живет.

Культура
Культура безопасности в ядерной энергетике появилась после аварии на Чернобыльской АЭС. По сути ее отсутствие и явилось причиной той аварии. Подробности по культуре безопасности можно прочитать, например, на сайте минатома.
Если вкратце, то это когда вся организация честно признает безопасность приоритетной целью и действует соответствующим образом. Т.е. методы управления, отношения в организации и подготовка персонала должны быть в первую очередь сосредоточены на безопасности, никак не снижать мотивации эту безопасность поддерживать и не подавлять коммуникаций. Звучит просто, но обычно в умах управляющего персонала "ответственность" подменяется "страхом перед ошибками", что чаще приводит к замалчиванию и педалированию проблем.
Только проблема тут в том, что культура безопасности или есть, или ее нет совсем. Никаких полумер тут быть не может, в отличие от остальных пунктов.


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

И все же, при чем тут тестирование?

Сложность.
Можно взять, например, большущий талмуд под названием "предрелизные регрессионные тесты", заглянуть в него, и на этом вопросы об избыточной сложности должы сразу отпасть.
А можно пойти дальше и посмотреть, сколько у вас дополнительных полей накручено в вашей JIRA. Если на экран не помещается, то это просто плохо. А если на два, то... Нет, они все, безусловно, очень важные и полезные. И, возможно, у вас кто-то уже писал документ зачем нужен вон тот чекбокс, но их же действительно дохрена. Посмотрите на какой-нибудь девственно чистый FogBugz - там едва набирается десяток полей компактно упакованный на один экран. И где-то после первого десятка уже пора начинать кричать "горшочек не вари!".
А автоматические тесты с кучей ассертов? Ладно бы стоимость поддержки этих монстров, но это настоящее кладбище ложных срабатываний.

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

Плохой дизайн
Про системы управления тестами я уже писал ранее. Так что повторю еще раз - у них, как правило, отвратительный дизайн. И еще ими пытаются решать задачи, для которых они не предназначены.
А можно взять, скажем, вендорский софт для тестирования. Там до сих пор встречаются попытки создать собственный язык программирования, которые и как ЯП плохи, и тесты на них писать очень неудобно. А схемы лицензирования раннеров тестов? Или невозможность оперировать ничем, кроме виртуальных пользователей в нагрузочных инструментах? Да, так проще продавать. Но это очень сильно усложняет работу и приводит к тотальному закостыливанию.

Прерывания и отвлекающие факторы
С прерываниями чего-то совсем специфичного для тестирования нет. Ну да, наша работа требует концентрации. Да, нарушение этой концентрации во время работы повышает риск пропуска багов. Но для борьбы с этим придумано порядочно техник - тестовые сессии, парное тестирование и далее вглубь exploratory тестирования.
Но и это еще не все. Есть старый опыт с невидимой гориллой. Он сообщает нам, что проще искать проблемы, если знаешь куда смотреть. К сожалению проблемы с testability тестируемого продукта, а иногда и сами постановки задач, превращают простейшую работу в Тест Струпа.

Культура
Сколько у вас не закрытых багов? И как давно они у вас там живут? Если баги живут в багтрекере долго и не чинятся, то тут, как правило два варианта.
Первый - это не баг вовсе. Для всех участников проекта (включая пользователя) это нормльное поведение. Или поведение с которым вы почему-то миритесь (менеджер знает почему). Или поведение с которым всех принудили мириться (это тоже плохо, но так бывает). Так или иначе - его там быть не должно. Если у вас менеджер в проекте изображает помещицу Коробочку из "Мертвых Душ", то это плохо. Если ваш работник, занятый в тестированиии, не понимает, что же действительно важно для вашего проекта - это тоже плохо. Так или иначе это свидетельство того, что с "культурой безопасности" в головах не все хорошо.
Второй - это действительно проблемы, но они игнорируются. Нет времени, нет людей, нет идей - не важно, т.к. вы уже придумали отмазку чтобы пустить безопасность под нож. О какой "культуре безопасности" можно говорить в этом случае?

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

Анатомия ошибки

Вместо предисловия

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

Контекст

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

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

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

У нас есть организация. Обзовем ее системой.

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

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

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

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

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

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

Но так или иначе разработка ПО это тоже социотехническая система, к тому же более сложная в плане эксплуатации и работы, чем фабрика. Если фанаты фабричной модели хотят поспорить - можно начать с чтения работ Эрика Триста о социальных последствиях смены метода добычи угля. Да даже если не хочется спорить почитайте - интереснейшая работа.

Первые сюрпризы

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

И в этом всем вареве есть парочка неприятных сюрпризов.

Первый - ETTO Principle. Его сформулировал Доктор Холлнагель в одноименной книжке. Вкратце выглядит так - мы работаем или очень эффективно, или очень безопасно. Ну или как-то балансируем. Обычно все жертвуют безопасностью в угоду эффективности. Проблема происходит потому, что человек хоть и классно адаптируется в изменяющихся условиях, но ему нужно на это время. И чем меньше времени, тем менее точно человек подстраивается под новые условия.

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

Второй неприятный сюрприз выглядит вот так:

Я про него уже писал раньше, но на всякий случай повторю.
Это модель тупого и острого конца. Ее придумали Доктор Вудс и Доктор Кук.

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

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

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

Обратно на фабрику

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

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

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

Если вы думаете, что никто еще не пытался проделать подобных фокусов, то вы жестоко ошибаетесь. Взять хотя бы индустрию мирного атома в США. Пресловутый Three Mile Island.

Это АЭС расположенная в штате Пенсильвания, примерно в 150км от Филадельфии, да и до Нью-Йорка там тоже недалеко. По понятным причинам автоматики там было более чем порядочно, и персонал состоял в основном из операторов этой самой автоматики. В 1979 году там сломался датчик, и автоматика сошла с ума. Операторы, перегруженные противоречивой информацией, поступающей с автоматики, пытались разобраться в чем проблема, но в итоге потеряли кучу времени, и случилась самая тяжелая ядерная авария в США. Это была бы самая тяжелая ядерная авария в мире, если бы через 7 лет не случился Чернобыль.

Как итог: один из реакторов не эксплуатируется до сих пор, а зараженную радиацией по самое нихачу зону в довольно густо населенном уголке США только в середине 90-х закончили чистить. К тому же, анализ ситуации привел к тотальному пересмотру обучения персонала на американских АЭС, сильно изменил подход к автоматике, которой пичкают ядерные станции, начали отрабатывать различные экстренные меры вплоть до эвакуации населения вокруг АЭС.

Так же эта катастрофа вскрыла ряд фундаментальных проблем автоматизации:
  • Автоматика не способна справиться с неизвестными ей проблемами
  • Автоматика не избавляет нас от человеческого фактора хотя бы потому, что делают ее тоже люди
  • В критической ситуации все равно разгребать все человеку, и лучше чтобы засбоивший кусок автоматики был разработан исходя из этого предположения
  • Automation bias - это своего рода худший вариант "тупого" и "острого" конца, т.к. робот на "остром" конце не может сообщить человеку, в чем он ошибается
И мы вновь возвращаемся к модели "тупого" и "острого" конца, которая сообщает нам, что для того, чтобы вырабатывать превентивные меры и адекватно оценивать происходящее, нам нужно понимать, как работает система. Не то, как мы нарисовали ее на бумажке и думаем, что она так работает, а то, как она работает на самом деле.

Шум в эфире

Для начала давайте посмотрим, как в любой системе происходит ошибка. Возьмем, например, большой и сочный факап. Между непосредственным появлением самой ошибки и разбором полетов условно выделим четыре фазы:
  1. Обнаружение. Очевидно, т.к. не обнаруженная проблема таковой не считается
  2. Исследование/Локализация. Прежде чем что-то делать, нам нужно понять, в чем именно суть проблемы, и надо ли ее вообще чинить
  3. Починка.
  4. Убедились, что все ОК. Мы же серьезные люди и не считаем фазу починки завершенной, пока не убедились, что проблема устранена.
В обычной ситуации все выглядит примерно так:
Нашли проблему - тут же испугались. Оценили масштабы бедствия, нашли что и где чинить - может даже слегка отпустило. Какое-то время чиним, и чем дольше мы это делаем, тем больше нарастает напряжение. А потом все становится ок, и нас отпускает.

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

Другой сценарий совсем плохой:
Это когда у нас уходит куча времени на устранение проблемы. Там нервные клетки теряются в гораздо большем количестве.

И кроме потери наших собственных нервных клеток последний вариант еще неприятен потому, что всю дорогу мы получаем кучу информационного мусора и теряем информацию о том, что же черт побери произошло. Это происходит потому, что все вокруг нервничают, потому что для ускорения процесса нам приходится импровизировать (ответ на практически любой мало-мальски крупный факап это сплошь и рядом импровизация). Еще всю дорогу происходит много коммуникаций - с другими членами команды, не понимающими, что творится и сыплющими гипотезами, с менеджментом, который паникует. Словом со всеми. И чем дольше это происходит, тем больше информационного мусора мы собираем. И чтобы нам проще было понять, что же случилось на самом деле, нам нужно иметь возможность как можно быстрее восстанавливаться после факапа. Практически весь continuous delivery об этом, с его фиче свичами, тотальным мониторингом и прочим счастьем. Нам важно не просто быстро фигачить фичи на продакшен, но и уметь быстро реагировать на происходящие факапы. Если вы не умеете делать последнего, то лучше возьмите книжек и почитайте в песочнице.

Уборка мусора

Как писал Талеб - "человек - животное объясняющее". Нам нужно знать, почему произошла проблема. Ответ "не знаю" для нас неприемлим. Вы часто видите менеджеров которые честно говорят "не знаю"? Да этих чуваков учат чему угодно, только не этому. Другими словами:
"Основное правило: любое объяснение лучше его отсутствия" 
- Ницше про Root Cause Analysis
Да, Root Cause Analysis это именно то, чем в хорошем обществе занимаются после факапов. Но тут впору вспомнить о том, что у нас всю дорогу шум в эфире. Это приводит к двум серьезным (их на самом деле больше, но эти две самые опасные) проблемам - Ошибке Ретроспекции и Отклонению в Сторону Результата.

Ошибка Ретроспекции заключается в том, что знание результата сильно влияет на анализ произошедшего. Реконструируя произошедший факап мы из подручных материалов сооружаем сильно упрощенное подобие реальности. То есть строим примерно такое:
Вместо вот такого:
Это приводит к соверешнно бесполезным советам вида "надо было быть внимательнее", потому что "все же как на ладони видно, надо просто не проморгать". И мы... соглашаемся. То есть на сложную проблему мы находим универсальный ответ "надо быть внимательнее". И пофиг, что принцип системостроительства говорит, что идеальная работа каждого звена это утопия! У нас есть универсальный ответ - "надо быть внимательнее". Как мы раньше жили без этого знания - непонятно. Почему я не был тогда достаточно внимателен? Не важно. Наш очень классный ответ на этот вопрос не отвечает. А другой на моем месте был бы достаточно внимателен? Тоже не важно - наш универсальный ответ такие глупые вопросы просто игнорирует.

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

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

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

Теперь перейдем непосредственно к Root Cause Analysis. Есть ряд техник, которые, к сожалению, используются еще и для оценки рисков. Вот некоторые названия:
  • Ишикава
  • FMEA
  • "Пять почему"
  • Дерево отказов
Их можно перечислять еще долго, но все они похожи на принцип домино. "Пять почему" отлично иллюстрируют всю бездну ужаса подобных методик. У вас случилась проблема и вы задаете вопрос "почему?". Ответив на этот вопрос вы задаете вопрос "почему?" уже ответу на первый вопрос. И так пять раз. Вы не получаете ответ на то, почему в действительности произошла ошибка - вы просто выстраиваете небольшую линейную цепочку. Или большую цепочку, если это Ишикава. Или большую ветвистую, но все еще линейную, если это дерево отказов. То есть вместо поиска причин вы делает вот это:
Такие вот узаконенные методы оценки рисков, целиком состоящие из Отклонения в Сторону Результата и Ошибки Ретроспекции. К тому же они очень сильно фокусируются на компонентах заданной цепочки, всячески игнорируя окружение.

Есть чуть более продвинутая модель:
Это Модель Швейцарского Сыра. Ее придумал Доктор Джеймс Ризон. Я о ней уже писал ранее, но опять повторю.
У нас есть куча слоев защиты. И согласно правилу моделестроения - все неидеальные. Т.е. дырявые, как швейцарский сыр. Как только дырки совпали - случилась ошибка.

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

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

Потому что в реальности все происходит примерно так:
  • Слетел балансировщик нагрузки
  • Невовремя протух кэш
  • Легла база
  • Лег вебсервер
  • Последние месяцы перед новым бюджетом и денег свободных нет
  • Криво задизайнили пару графиков в мониторинге
  • Админу в машину на перекрестке въехала тетенька
  • Половина разработчиков отдела на конференции
  • Корпоративный почтовый сервак на плановом обслуживании
  • Проблемы с наймом и недокомплект
  • Маркетинг написал про вас клевую статейку и пошел тиражировать
  • Пропустили учения для инженеров
И все это друг с другом как-то вот так переплетено:

Часть проблем тут технические. Часть люди. Часть вообще черте что. При этом часть проблем, вроде найма, вообще системного характера. Обычные методики Root Cause Analysis игнорируют системные проблемы.

Убрав любой из пунктов мы или не получим проблему вовсе или получим, но куда менее страшную. Очень похоже на сырную модель, только не линейное. При этом большую часть из этих проблем по традиции можно назвать "Root Cause". Какую именно? Зависит от ваших предпочтений. Не нравится администратор? Давайте его. Маркетинг? Ну вы поняли.

Мы можем начать рассматривать каждый элемент отдельно. Это сильно упростит задачу. И выглядеть будет как-то так:
Но тут получается проблема, с которой знаком каждый тестировщик, занимавшийся интеграционными тестами - каждый кусок по-отдельности может работать хорошо, а вот их взаимодействие может приводить к нежелательным последствиям. В плане организации все еще хуже - допустимые вариации в работе того или иного куска организации могут быть в норме, но все вместе они порой будут создавать резонанс с крайне печальными последствиями. Доктор Холлнагель назвал это явление "Функциональный Резонанс".

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

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

Учиться, учиться и еще раз учиться.

Откуда, собственно, учиться? Начнем с трех небольших тезисов.

Тезис Первый. Человеческий фактор - это не причина ошибки, а лишь побочный эффект.

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

Тезис Второй. Успех - это частный случай ошибки.

По Холлнагелю люди, подразделения и организации приспосабливаются к новым условиям и задачам всеми возможными способами, но так как информация, ресурсы и время у нас всегда конечны, попытки приспособиться всегда будут не очень точными, приблизительными. И когда у вас все хорошо - это значит, что организация/человек умудрились достаточно точно подстроиться и, как правило, предотвратить все значимые риски до того, как они смогли нанести какой-то ущерб. Ошибка же происходит потому, что человек или организация по какой-то причине не смогли подстроиться - продемонстрировали временную или полную утрату способности адаптироваться к изменившимся условиям. ETTO Principle в действии.

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

Тезис Третий. Ошибка - это частный случай успеха.

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

Но по большому счету разницы между факапом и успехом нет. Ваша система просто работает, и работает нормально, пока не случится резонанс нескольких ее компонент, который приводит к факапу. Вспомните модель швейцарского сыра, один слой повернулся - и все нормально. Нет ошибки. Повернулся не так - встречайте проблему. И чтобы этого не происходило надо минимизировать количество дырок на каждом слое. Надо искать источники энтропии. Нужно не просто задавать себе вопрос "почему случился факап?", но и вопрос "почему у нас все хорошо?". Это здорово увеличивает выборку для анализа, ведь если вы читаете это, то у вас дела чаще идут хорошо, чем плохо. Так же это позволяет хоть как-то бороться с Ошибкой Ретроспекции и Отклонением в Сторону Результата - у вас будет больше разнообразных результатов, на которых вы почти наверняка будете строить разные цепочки событий.

То есть учимся не только на ошибках, но и на успехах.

И на основе этого уже выстраивается стандартная цепочка превентивных мер:

  1. Прогнозирование. Т.е. попытки предугадать то, что стоит ожидать
  2. Мониторинг. Т.е. надо знать куда смотреть (так проще искать - вспомните невидимую гориллу)
  3. Ответные меры. Т.е. в случае чего надо не бегать кругами, а просто знать, что делать для минимизации проблемы. Вырабатывать план эвакуации, когда у вас уже плавится реактор - плохая идея
  4. Обучение. Т.е. нужно точно знать, что произошло. Это самый важный пункт, т.к. без него первые три не работают - им неоткуда черпать информацию
И для упрощения этого обучения нужно не упускать из виду следующие вещи:
  • Избегать ошибок оценки решений - ошибки ретроспекции и отклонения в сторону результата
  • Понимать, что происходит на "остром" конце. Подобные коммуникации - это практически единственный способ справляться со сложностью системы
  • Проверять, к каким уязвимостям могут привести изменения на любом уровне системы
  • Технологии нужны, чтобы помочь человеку, а не для того чтобы его заменить. Особенно, если этот человек принимает кричиные и сложные решения
  • Надо понять, что безопасных систем не существует в принципе - все ломаются. Путь самурая вас прикончит, тогда как путь минимизации ущерба от ошибок и их частоты может сильно помочь
  • Человеческая ошибка - это данность, она прилагается к любой сложной системе.
  • Не стоит пытаться оправдывать человеческой ошибкой что-либо - это путь, на котором вы отказываетесь учиться на ошибках
  • Человеческая ошибка не случайна

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

Ложь в картинках

 "А график для менеджера - как клипарт для дизайнера, постоянно для совещаний надо"


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

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

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

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

Если же вам читать Тафти лень, то попробую дать краткую выжимку.

0. Мешайте читать информацию

Любой график это история. Чтобы запутать слушающего простой историей надо обладать нехилым мастерством. Поэтому самый простой способ загадить людям мозги картинкой - загадить картинку лишней информацией. Даже врать не надо - просто засоряйте эфир.

Если работать с данными не умеете - засоряйте чем угодно. Если умеете - не мне вам объяснять.

У Тафти есть простая формула Data-Ink Ratio - пропорция чернил затраченных на полезную информацию к всем чернилам затраченным на картинку. Чем дальше эта цифра от 100% тем сложнее зрителю будет понять что вы нарисовали.

У Тафти это выглядит примерно так:
Хорошо
Плохо
Запомните - первое это ваш враг, а второе ваш друг. Но можно пойти еще дальше - использовать объемные изображения и массивные элементы диаграммы не несущие в себе  ничего полезного кроме украшательства. Люди фигово на глаз оценивают разницу в объеме и плозади. К тому же это придаст вашему графику вид произведения искуства и создаст ощущение что вы много над ним поработали.

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

Вот парочка отличных примеров:

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

На этом, в принципе, можно закончить, так как остальное это просто частные случаи.

1. Уберите к чертям весь контекст

Это уже практически мастерство лжи. Можно делать как Fox News. Например у вас есть вот такой график:

А вы не палитесь и сделайте вот так:
Цифры на месте - вы просто слегка поиграли со шкалой. Зато какой эффект! Сразу виден весь драматизм 4,6%!

Или можно сделать вот так круто:

Тут, правда нужны пояснения. На самом деле ребята просто склеили два этих графика:

Первый график показывает данные за 11 лет, а второй вообще за 35. При этом оба показывают изменение разных параметров. Так же второй график показывает изменение в рейтинге. Т.е. на самом деле его вертикальную шкалу вообще нужно развернуть. Но в этом же самый сок! Резкое падение на втором графике на самом деле ни что иное как резкое улучшение дел. Но из хорошего не делаются газетные сенсации...

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


2. Больше цветов, хороших и разных

Тут вам может помочь художественное образование - там иногда рассказывают про работу с цветом.

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

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

В третьих - куча цветов усложнит чтение не только тем, что читателю придется постоянно обращаться к легенде графика, но и послужит визуальным шумом и поводом для поиска разницы в данных там, где ее нет.
Мыло цветов, да? Надо занять мозг читателя попытками поиска разницы в совершенно однородных данных:
3. Пироги!

Менеджеры любят пироги. Не знаю почему, но чую все от того, что у Pie Chart'а есть одна фундаментальная проблема - человек еще может сравнить две линии по длине, а вот углы секторов круга различает очень плохо.
Это, наверное, самый честный pie chart  в истории. Но даже для него кто-нибудь может мне сказать какой процент пирога съеден?

Можно усложнить задачу и добавить кучу полей. Например простой топ100 в виде колонок это отвратная идея, а в случае пирогов она начинает играть новыми цветами:
Но если топ100 это откровенное палево, то можно сделать меньше данных и усложнить восприятие секторов круга добавлением перспективы. Ребята из Microsoft в свое время сделали классный вклад в такую визуализацию:
Что тут меньше - Word 2000, Word 2002 или Word 2003? Как нужно повернуть пирог, чтобы Word 2002 выглядел поменьше? Большой простор для творчества, бесспорно.

В конце концов - комбинируйте с предыдущими пунктами.
Попробуйте не сломав мозг осмыслить то, что нарисовано тут:

4. Отупляйте!

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

Не стоит показывать исполнительным директорам шедевры вроде работ Минарда:
В этой картинке слишком много концентрированных данных. Надо много осмыслять и думать. Читать. И не важно что соотношение полученных данных к затраченному времени тут эффективно как никогда. График не дает главного для менеджера - не говорит что ему делать. И при этом съедает кучу времени. Так что в идеале надо слушать дядюшку Година и упрощать этот график до такого:

понедельник, 20 августа 2012 г.

Confirmation bias как он есть

Хороший, годный пример одной из тысяч главных болячек тестирования вообще и автоматического в частности. Учитесь видеть то что было на самом деле.