27 Февраля 2019
Reading time: 5 min
«Вечно голодная» IT-отрасль со студентами-программистами не церемонится: уже отличаете if от for – всё, пожалуйте разрабатывать комплексные бортовые программы для миссии на Марс. В нашем сегодняшнем кейсе расскажем, как статистическое управление процессами, обратная связь и карты Шухарта помогли таким вот ребятам без опыта коммерческой разработки. Новички смогли снизить число багов, видимых пользователю информационного портала, в 10 000 раз по сравнению со старой версией сайта, которую создали программисты с 5-10-летним опытом. Оригинал статьи мы разместили на vc.ru.
Часть 1. Ситуация и проблема
На этот раз наша задача состояла в том, чтобы написать новую версию портала, который предоставлял информационные услуги населению: на нем можно было размещать объявления и откликаться на них, общаться, читать новости и т.п.
О том, что мы еще делали для этого клиента, можно почитать по ссылкам ниже.
Искусственный интеллект (AI) модерирует контент
В чем была основная проблема? Старая версия сайта, как мы уже упомянули, была создана опытными программистами, но в нашем случае сложилось так, что проект нужно было сделать студентам, у которых ранее не было опыта коммерческой разработки, это было их первое серьезное испытание.
Почему так получилось? Мы много работаем над тем, как организовать работу компании так, чтобы конечный результат не зависел (или минимально зависел) от конкретных исполнителей и их уровня.
Есть такой вариант, когда с согласия заказчика на проект берутся программисты с минимальным опытом и проходят, что называется, боевое крещение. Здесь в плюсе остаются все - молодежь, которая получает бесценный опыт, заказчик, который получает скидку и определенные гарантии (например, возврата денег в случае, если результат не устраивает) и компания, которая отрабатывает технологии выполнения реальных проектов с молодыми разработчиками.
Но, разумеется, на таком проекте важно и даже критично обеспечить контроль качества и мониторинг всего на свете. У нас была масштабная «новорожденная» система, которая должна была обрабатывать огромное количество запросов – есть что контролировать. И, разумеется, избежать ошибок в ней было просто невозможно, учитывая наших неопытных адептов.
Часть 2. И что мы тогда сделали?
У нас с самого начала разработка строилась по принципу «Если что-то может сломаться, оно обязательно сломается». О том, почему такая логика для программирования гораздо эффективнее подхода «система будет просто работать», можно почитать здесь.
В связи с этим, был поставлен вопрос: «Как сделать так, чтобы наши сбои как можно реже приводили к проблемам пользователя?».
Для решения этой задачи мы придумали следующее. На дворе был 2012 год, и микросервисная архитектура была еще не так популярна, как сегодня. Тем не менее, именно этой технологией мы воспользовались.
Все запросы с браузера отправлялись на API в JSON-формате. Первым, что происходило с запросом любого сервиса, который приходил в микросистему, было сохранение в изначальном виде в базу данных. Поскольку это JSON, то его легко было превратить в строчку и при необходимости восстановить обратно. Так у нас сохранялись все те данные, которые нам отправляли пользователи. А дальше этот запрос проходил по цепочке обработчиков.
Что это значит? Когда запрос приходил на сервер, его там ждал не один монолитный контроллер, а целый «конструктор». Обработка запроса представляет собой цепочку, в которой каждый элемент – обработчик – отвечает за какую-либо определенную, специфическую операцию.
В качестве примера подобной архитектуры можно привести функции промежуточной обработки (middleware) в Node.JS. Чем это удобно? Обработчики легко конфигурировать, причем без программирования.
Еще важный момент: все обработчики должны быть идемпотентны. Идемпоте́нтность — свойство объекта или операции при повторном применении операции к объекту давать тот же результат, что и при первом. (Спасибо, Вики). Поскольку мы допускаем, что для некоторых данных наш обработчик может быть вызван многократно, мы должны быть уверены, что всегда получим один и тот же результат его использования.
Часть 3. Checkpoint
Специально для этого сайта мы придумали отдельный сервис, названный нами «Сheckpoint», который состоял из двух видов обработчиков.
Первый обработчик «Сheckpoint» располагался в начале каждой цепочки, именно он сохранял запрос в базу данных в его изначальном виде. В конце каждой цепочки обработчиков стоял еще один обработчик от «Сheckpoint», он сообщал сервису о том, что запрос успешно добрался до конца и операция выполнена. Все равно, что стоящий в конце строя, который говорит: «Расчет окончен!».
Если же в течение определенного времени последний «Сheckpoint» не сообщал о том, что запрос прошел цепочку обработчиков до конца, мы считали, что с этой операцией что-то пошло не так. В этом случае запускался автоматический процесс, который воспроизводил всю цепочку заново. То есть, он брал указанный запрос в виде строчки, восстанавливал обратно в JSON и снова прогонял по тем обработчикам, которые изначально были запланированы.
Сервис «Сheckpoint» был написан нами один раз и с тех пор никогда не менялся. Таким образом, у нас получился надежный компонент системы. Что мы имеем ввиду? Он работал долго, без нареканий к качеству работы, а значит и без изменений, которые могут повлечь за собой ошибки.
В отличие от него, остальные обработчики в цепочке могли меняться, модифицироваться, и в них при этом могли появляться новые и новые ошибки.
Благодаря «Checkpoint», если мы фиксили баг в каком-то обработчике, нам не нужно было беспокоиться об остальном: через какое-то время система сама повторяла обработку запроса, на котором случилась ошибка. Это позволяло избежать более серьезных неполадок.
Часть 4. А где же карты Шухарта?
Сейчас все расскажем. Статистический контроль качества на службе программирования – это более чем интересно.
Когда мы выстроили систему таким образом, как описали выше, то автоматизировали сбор статистических данных по работе сайта и их обработку с помощью контрольных карт Шухарта (про них читаем здесь).
Что именно мы измеряли? Разницу между теми запросами, обработка которых началась, и теми, для которых она закончилась.
Эти данные мы фиксировали не непрерывно, а в строго определенное время, и смотрели, сколько запросов у нас ушло в обработку и сколько «вышло». В итоге у нас получалось некое количество тех запросов, которые почему-то не обработались до конца.
Это число было не нулевое
Само по себе то, что количество запросов в обработке не 0 не говорит о наличии ошибки. Система работает, запросы поступают постоянно, и это нормально, что в ходе функционирования какие-то из них еще не прошли свой цикл.
Это число всегда было разным
В то же время теперь мы могли искать аномалии в количестве запросов, которые начали выполняться, но по каким-то причинам не завершились. Для этого мы определились, какое количество «в обработке» — это норма (точнее, вывели некие нижнюю и верхнюю контрольную границу, значения в «коридоре» между которыми мы считаем нормой). Согласно теории, сформированной Шухартом, выход за эти границы свидетельствует о возможном наличии особой причины (в нашем случае – некой аномалии, связанной с запросами).
В один момент мы обнаружили, что, фактически, уже на протяжении нескольких дней у нас количество сообщений о том, что запрос не прошел обработку, запредельно растет. То есть, график все время идет только вверх и нисколько не уменьшается. Соответственно, все контрольные пределы уже давным-давно пройдены, мы вышли за границы - и это говорит как раз о том, что, возможно, у нас есть особая причина.
Когда мы стали разбираться, то действительно нашли ошибку. Баг исправили, разработчик отчитался об этом. Но проблема, особенно с неопытными программистами, в том, что причин одной наблюдаемой ошибки может быть несколько.
Часть 5. В чем особенность ошибок?
Часто бывает так, что ошибку поправили, а она на самом деле никуда не ушла. Программист может найти три причины наблюдаемой ошибки, а на деле их окажется четыре, найти пять, а их десять. И вроде бы баг исправлен, все проверили, все причины ликвидированы и кажется, что система работает, но неполадки могут вернуться вновь просто потому, что сработала еще одна причина, о которой никто не подумал.
Новичкам в данной ситуации труднее - у них нет опыта, они еще толком не видели, как ведет себя реальная система изнутри. Ввиду этого они часто принимают нерациональные решения.
Разница между найденными и существующими причинами ошибок – это то, что отличает новичка от более опытного программиста.
Именно здесь на помощь приходят методы обнаружения разладки, в том числе карты Шухарта. Они помогают сократить количество итераций и быстрее понять, все ли причины багов мы устранили или нет.
Часть 6. Результат
Что мы увидели после того, как исправили баги в нашей системе? По картам Шухарта мы обнаружили, что количество сообщений об ошибках стало уменьшаться. Спустя некоторое время количество сообщений в контрольных точках ушло под нижнюю границу нашего процесса, рассчитанную ранее. Это говорит о том, что внесенные нами изменения существенно улучшили характеристики системы. Таким образом, процесс у нас сдвинулся: он получил новые характеристики, а соответственно, мы построили новые контрольные карты с их учетом.
В результате мы поняли, что с помощью карт Шухарта можно наблюдать за состоянием системы и, если вдруг возникает аномалия, разобраться с причинами. И по ним же отследить, решена ли эта задача.
В итоге, по прошествии трех месяцев количество ошибок на сайте удалось уменьшить в 10 000 раз по сравнению со старой версией системы, которая была написана опытными программистами (5-10 лет опыта). При этом, когда мы стартовали, конечно же, количество ошибок у наших новичков было значительно большее, потому что они писали такой проект впервые. Поэтому можно говорить и о том, что внутри нашего проекта прогресс был еще в разы больше.
В дальнейшем все возможные процессы в системе, которые мы считали важными, были оснащены специальными датчиками, для каждого датчика строилась карта Шухарта. С их помощью шел мониторинг всей системы, показатели собирались один раз в сутки. Поэтому, если появлялась аномалия мы могли с большой вероятностью судить о том, что она связана с воздействиями, которые произошли за последние 24 часа. За такой период очень легко отследить все изменения, выложенные на сервер.
То есть, мы сократили цикл обратной связи между нашим воздействием и реакцией системы на него.
Плюс в том, что каждое исправление обнаруженных багов выглядело как небольшое, незначительное изменение. Нам не нужно было выкатывать масштабные «новые версии», которые могли опять же повлечь за собой серьезные неполадки. Количество изменений было небольшим и сами по себе они были маленькими. Сегодня это называется Continuous Delivery (непрерывная поставка).
Еще раз повторим – это произошло не за один день мы. К сожалению, те три месяца, что мы отлаживали систему, пользователи страдали, но итог превзошел все ожидания.
Часть 7. Как автоматизируются карты Шухарта?
Для этого нами была написана специальная библиотека. С ее помощью мы автоматизировали расчет карт Шухарта и разработали датчики для сбора информации, которые в любой момент легко встраивались в любую часть системы без программирования. Кроме того, библиотека позволяла визуализировать эти графики так, чтобы мы легко могли оценить результат: зайти на специальную страницу и посмотреть на все имеющиеся карты.
Часть 8. Вместо резюме
Во-первых, в старой версии системы, у «старших» программистов тоже было достаточно много ошибок, примерно 7% страниц вообще не открывались. Но проблема была не в том, что они были такие-сякие, плохие и безграмотные. Дело в том, что у них не было обратной связи, которую мы выстроили на своем проекте. Разумеется, на их стороне был опыт и при прочих равных условиях они могли совершать меньше ошибок, но система очень громоздкая сама по себе, а потому баги медленно, но верно накапливались – это неизбежно.
Во-вторых, наши молодые разработчики вовсе не были волшебниками. Мы начали работу над проектом в гораздо худшей ситуации, но у нас была обратная связь и возможность обнаружения аномалий, а потому мы видели, в какую сторону нам развивать систему.
Читайте также