О карте МегаФона — технические подробности
В предыдущих постах мы уже обсуждали банковскую карту МегаФона как финансовый продукт и рассказывали о ее возможностях для конечного потребителя. Но, безусловно, за таким проектом стоит огромная работа, которую проделала команда профессионалов. В этот раз мы подробнее расскажем именно о технических особенностях реализации этого проекта и об устройстве программного обеспечения.
Учитывая масштаб проекта, описать все тонкости в рамках одного поста не получится, поэтому начнем мы с рассказа о бэкенде системы ДБО (дистанционного банковского обслуживания). Задача бэкенда — обеспечить рабочую связку всех специализированных систем в рамках единой логики, а также функционирование множества фоновых процессов. А самое главное — удобный и функциональный личный кабинет для пользователей. Техническим партнером проекта карты Мегафон выбрал компанию TYME. Все время работы специалисты двух компаний работали в тесной связке с поставщиками банковского ПО, биллинга, платежными системами и другими поставщиками, собирая разрозненные функциональные кусочки мозаики будущего проекта в единое целое.
В 2013 стартовал проект «Терминалы», и с этого времени мы постоянно совершенствовали решение, интегрируя его со своими сервисами и новыми провайдерами услуг и добавляя новые функции для клиентов.
У TYME довольно большой опыт работы в финтех-отрасли, они успешно преодолели все трудности и мы вместе с технологическими партнёрами успешно запустили карту МегаФона. Далее на страницах блога МегаФона даём слово команде TYME, пусть ребята сами расскажут о деталях своей части проекта.
Детали большого проекта
После реализации каждого масштабного проекта мы оглядываемся назад, чтобы оценить проделанную работу. В весьма сжатые сроки нам удалось запустить крайне сложную систему, которая находится в самом сердце финансового продукта федерального масштаба.
Немного цифр для примера:
- 18 внешних систем для интеграции
- 600 бизнес-процессов были реализованы в рамка проекта
- 770 страниц технической документации
- 2500 сценариев для автотестов
- 15000 человеко-часов разработки
Ноябрь 2015-го. Проект — на стадии концепции. В переводе на человеческий — у нас есть лишь четко оговоренная дата запуска и приблизительное ТЗ от бизнеса.
Отсекаем мрамор
Возможность изучить заказчика и не доставать его постоянными вопросами у нас появилась благодаря правильно выстроенным отношениям и нескольким годам совместной работы.
Вот некоторые принципы, следование которым нам очень помогло:
-
Работать, исходя из текущего состояния требований. Нужно искать конкретные задачи, за которые уже можно взяться прямо сейчас, вместо того, чтобы заниматься скрупулезной детализацией.
Agile и долгосрочное планирование
О достоинствах Agile-методологии сказано уже много. Не будем повторяться и сконцентрируемся на тех моментах, которые обычно заказчику тяжелее всего принять.
- Нет жестких сроков окончания большого проекта
- Затраты на большой проект могут вырасти при его проработке
- Непредсказуемые границы проекта, то есть скоуп работ всегда будет относительным, а попытка его финализировать лишь приведет к сильно отложенному старту.
Часто можно увидеть следующую рекомендацию: если вы хотите получить долгосрочный план, работая по Agile, заведите в Project каждый спринт или итерацию как задачу. В результате на выходе будет примерно следующая картина:
Рекомендация настолько общая, что у нас не прижилась. Этот вариант плана не показывает вехи продукта, значимые для заказчика, и не может быть полноценно использован для обсуждения долгосрочного графика проекта.
Серебряную пулю в 1986-м придумал Барри Боэм, американский военный. Его идея — спиральная модель разработки. Многие айтишники уже знают, что это, но на практике все равно очень часто наблюдаются крайности — или Agile без долговременных планов, или водопад со сроками и бюджетами, которые постоянно изменяются.
Артемий Лебедев в «Ководстве» неплохо высказался на этот счет.
Благодаря спиральной модели мы решили две задачи сразу:
- поддерживали актуальный долгосрочный план, понятный заказчику
- выдавали в разработку задачи итеративно, не превращая при этом SCRUM в водопад.
- Итеративная детализация требований. Документ, который описывал требования по каждому из модулей системы, имел свою внутреннюю структуру, когда составляющие ее компоненты могут находиться в разной степени готовности. На каждой из итераций детализация требований увеличивалась, давая возможность взять в разработку очередной объем задач.
- Эволюция рабочих продуктов. На каждой итерации разработки мы пересматривали весь стек рабочих продуктов на полную глубину в соответствии с новыми реалиями требований и фидбеком на прототипы. Это заставляло нас иногда переделывать архитектуру продукта. К примеру, на старте проекта планировалось, что все процессы будут обеспечиваться в рамках 40 микросервисов, и в ходе детализации архитектуры их количество было сокращено до 20.Так эволюционировали представления о том, каким образом необходимо декомпозировать бизнес-логику по сервисам. В итоге это дало очень большое преимущество — мы постоянно имели возможность получать фидбек о текущей реализации архитектуры, и практически не накапливали технический долг.
- Регулярное перестроение плана. Долгосрочный план проекта также был «живым», исходя из актуальных требований, информации о графике разработки внешних систем и других вводных. Мы не относились к плану как к константе, закрепленной на старте проекта, для нас это был «маршрут», который должен привести из той точки, где мы находимся, к итоговой цели. Соответственно, если ситуация вокруг меняется (а происходит это регулярно), уточняется и план.
- Ориентированность на ранний результат. Мы постоянно работали над тем, чтобы максимально рано взять задачу в разработку, и как можно быстрее выдать результат для приемки и тестирования. При этом мы старались разбивать зависимости, мешавшие нам это сделать — если не готов внешний сервис, мы не ждем его реализации, а пишем «заглушку»; если существует неопределенность по какой-то части задачи, стараемся декомпозировать ее еще сильнее и выполнить работы по тем составляющим, где определенность есть. Часто команды разработки не идут на подобные затраты, опасаясь сделать лишнюю работу, и зачастую эти опасения обоснованы. В этот раз мы сделали ставку на скорость.
- Разработка по SCRUM. Мы прикладывали максимальные усилия для того, чтобы изолировать разработчиков от неопределенностей в проекте, не нарушая привычный ритм SCRUM. Управление проектом было построено таким образом, что в каждый момент времени был «буфер» понятных команде задач как минимум на один спринт вперед. Это позволило не терять темп на протяжении всего периода активной разработки.
За само управление потоком работ отвечала Jira (но это мог бы быть любой удобный для Agile продукт), а план в MS Project был нужен для контроля глобального статуса работ и его визуализации для заказчика.
Макроэффект от микросервисов
Проект превратился в кучу подпроектов, которые были весьма связаны между собой. Так как мы еще вначале выбрали подход, обеспечивающий такое дробление — мы могли это себе позволить.
Тренд микросервисов существует в мире разработки уже довольно давно. Огромное количество обсуждений на эту тему происходят на профильных конференциях. Кто-то принципиально отрицает пользу от такого построения систем, есть и те кто занял прямо противоположную позицию и переводит все свои сложные системы на микросервисную архитектуру.
Микросервисная архитектура — это подход к разработке, при котором вместо создания одного большого приложения, может быть, разделенного на слои (GUI, Бизнес-логика, БД), создается множество небольших, изолированных друг от друга компонент, которые называются микросервисами. Не вдаваясь в теоретические детали, которые можно достаточно легко найти на Хабре, хотелось бы остановиться на том, как оказался данный подход полезен в нашем проекте.
Вот главные плюсы такого подхода (на наш взгляд):
-
Каждый сервис решает конкретный набор задач, у него определен API, по которому можно обращаться к сервису. Мы отлично изолируем ответственность внутри одного сервиса.
-
Самое сложное решение — о границах микросервиса. Нужно ответить безошибочно на вопрос — какой из существующих микросервисов должен выполнять эту задачу? На старте нам приходилось дублировать некоторые решения в нескольких микросервисах, чтобы сохранить их изолированность. Да, для разработчика это немного непривычная ситуация, так как переиспользование кода — основная задача.
Быть в центре событий
Наша система не только обеспечивает бизнес-логику представления данных банка для клиента, это еще и интеграционная шина, объединяющая front-end и все участвующие внешние системы.
Когда отказывает наш бэкенд - это автоматически означает, что пользователь видит сбой. Когда отказывает любая другая система — у нас есть возможность смягчить проблему и сохранить работоспособность большей части функций.
Это значит, что наша система должна обладать эксплуатационными характеристиками, превышающими эти показатели любой смежной с нами платформы:
- Лучший uptime
- Самый большой запас по производительности
- Лучшая устойчивость по отношению к отказам и сбоям
Эти вводные данные предопределили дополнительные условия для разработки:
- Быстрая доставка обновлений
- Максимальное качество работы каждого сервиса
- Исчерпывающее сквозное лигирование
Когда работаешь с платформой, построенной на микросервисах, важно понимать:
-
Обновление нужно максимально автоматизировать. Пора забыть про ручное обновление и максимально устранить человеческий фактор.
Объединив усилия службы эксплуатации и разработчиков, мы получили решение, которое обладает всеми нужными свойствами:
- Быстрое обновление, которое не требует «ручного» вмешательства разработчиков или администраторов. Мы настроили авто-deploy, который обеспечил выкатывание «одной кнопкой» с учетом всей нашей специфики. Подготовка сборки происходит на ресурсах поставщика, а фактическое развертывание – в защищенном контуре заказчика.
- Во время обновления сервис не останавливается. Так как каждый сервис развернут и работает минимум на двух параллельных серверах, во время обновления мы отключаем от траффика группу обновляемых в текущий момент серверов и распределяем нагрузку по другим экземплярам микросервисов. После обновления — проверяем smoke-тестом работу новой версии сервиса и, если все прошло успешно, обновляем следующую группу сервисов, переводя трафик на уже обновленные сервисы. Так, постепенно поднимая версии, мы получаем работающую систему, без полной остановки платформы.
- Непрерывный контроль деградации функционала. Благодаря покрытию автотестами всех процедур, нам удалось обеспечить возможность очень быстро диагностировать отклонения перед деплоем на бой и осознанно принять решение о проведении обновления.
- Быстрая доставка функционала на бой. Благодаря всем ранее изложенным моментам, мы можем очень быстро выкатывать в промышленную эксплуатацию исправления и новый функционал без ущерба для непрерывности работы.
Если это будет интересно, мы с удовольствием выпустим отдельную статью о тех подходах, которые мы применяем у себя.
Философия качестваСервис, который не должен останавливаться, и при этом динамично развивается, всегда находится между двух огней. В случае простоя финансовые и репутационные потери будут колоссальными. А если вспомнить про чрезвычайно сжатые сроки и меняющиеся требования в процессе разработки, то степень сложности продолжала повышаться. Поэтому перед отделом качества встала амбициозная задача выстроить тестирование продукта таким образом, чтобы оно было:
- Быстрым. У нас сжатые сроки, короткие спринты и мы не хотим ждать по нескольку дней, пока тестеры проведут регрессионное тестирование по чек-листам. В идеале – нужно получать ответ, какой регресс понесла система после каждого изменения кода.
- Полным. Быстрое осуществление тестов – не самоцель. Настоящая цель – быть уверенными, что если тесты прошли успешно, то наша система готова к обновлению. А значит тесты должны быть не только быстрыми, но и полностью охватывать функционал продукта.
- Гибким. Быстрые и полные тесты это прекрасно. Но если у заказчика есть новые требования, и изменения требуют полного переписывания тестов – это никуда не годится, потому что мы опять теряем скорость. Соответственно, тесты должны быть гибкими к изменениям.
- Дешевым. Ресурс тестировщика при большой скорости разработки всегда будет выходить на первый план, если нам нужно получить высокое качество. Поэтому всё, что описано выше, должно выполняться существующим количеством специалистов по тестированию. Мы здесь лишь подтвердили общее соотношение, когда на 3 разработчиков приходится 1 тестировщик.
В качестве агрегатора результатов: билд-сервер TeamCity с установленными плагинами для интерпретации итогов проверки от py.test.
Сами тесты пишутся максимально изолированно, выполнение каждого теста никак не зависит от результата выполнения остальных тестов. Если тесту нужно подключаться к БД системы и получать данные, значит, фикстура теста должна эти данные там обеспечить до выполнения теста. Если на тест может повлиять значение, лежащее в кэше, значит другая фикстура должна обнулить кэш до выполнения этого теста. Да, это привело к тому, что много времени потребовалось для разработки систематизированной сетки фикстур, но очень быстро эти инвестиции стали окупаться скоростью добавления новых тестов и, самое главное, стабильностью их результатов. Полный контроль над тестируемой системой означает минимум ложных срабатываний тестов.
Интеграция с сервером сборки TeamCity дала возможность просто нажать одну кнопку, чтобы тесты проверили все процессы платформы. При этом никаких приготовлений делать не нужно, а значит, это может сделать любой член команды. Отчет о тестировании в подробном и наглядном виде отображается на веб-интерфейсе build-сервера.
Не пожалели мы и о полном отказе от автоматизации тестов API через специализированные решения. Да, такие инструменты дают набор функциональности прямо из коробки. Но, во-первых, это недешево, во-вторых, нам всё равно нужно больше возможностей.
К примеру, в определенных тест-кейсах нашего API было нужно получать СМС-код подтверждения на операцию, пробрасывать его в тесты и наблюдать за поведением системы. Вот здесь и выходит на первый план мощь coded тестов, пусть их разрабатывать и дороже, чем, к примеру, собрать test-step’ы в SoapUI.
В итоге, сейчас процесс построен таким образом, что Postman или тот же SoapUI используется тестировщиками только на этапе первичной проверки. В конечном итоге процесс всё равно должен быть покрыт автотестами на Python и внедрен в общий репозиторий. Это закон.
Ни одно изменение функционала системы не обходится у нас без тестирования вообще и без автотестов в частности. Story просто не считается выполненной, пока она не покрыта автотестами. Такой подход требует высокой самодисциплины от команды и производительности от тестировщиков, но результат того стоит: если на билд-машине тесты зеленые, мы уверены в качестве своей системы.
Сейчас количество функциональных тестов перевалило за 2500 и продолжает расти. Выполнение занимает 25 минут.
Правильный выбор инструментов и полное покрытие автотестами с ранних этапов разработки позволило нам поддерживать высокую скорость внедрения новых функций на всем протяжении проекта, оставаться гибкими к изменениям требований, и при этом не жертвовать качеством продукта.
One more thingДокументация — это аспект ИТ-проектов, который часто остается в тени историй про архитектуру, проектирование и общение с заказчиком. Но это очень важная деталь, невнимание к которой может усложнить эксплуатацию и развитие даже самой замечательной, с точки зрения внутренней организации, системы.
Нами был выбран подход, при котором документация эволюционирует по ходу прохождения цикла разработки:
-
Начальные требования от заказчика сразу же образуют первые страницы будущей документации
- Работа над документацией оказалась распределена по процессу разработки, мы избежали ситуации, когда по завершении нужно выделить большой ресурс на документирование
- Документация по каждому модулю правилась в тот момент, когда все участники максимально погружены в тему, и это позволило сделать ее максимально точной и не тратить время на попытки вспомнить «а как же оно сделано», которые неизбежны, если бы мы вынесли этот этап за рамки разработки
- В случае каких-то споров и сомнений у нас всегда есть возможность провести трассировку, включающую исходные требования, задачи на разработку и документацию
Благодаря паре дней, которые ушли на общую редактуру и настройку выгрузки из Confluence, выгрузка итогового документа сейчас может быть выполнена в течение часа по всем компонентам системы.
Вместо заключенияМы постарались описать общий принцип работы двух компаний и раскрыть внутреннюю кухню разработки.
Было бы здорово услышать от вас сложные вопросы, которые бы мы могли использовать как основу для новых статей!
Спасибо ребятам за такой подробный рассказ! Это только первая часть технической составляющей карты Мегафона, будут ещё истории. Оставайтесь на связи.