25 October 2019

Как мы пишем микросервисы и почему не делаем этого быстро

RBK.money corporate blogPayment systemsJavaErlang/OTPDevelopment for e-commerce


Истории по распиливанию монолита часто похожи одна на другую. Был у команды здоровенный неповоротливый монолит, решили его распилить на россыпь правильных и шустреньких микросервисов, все стало круто. Отличаются истории лишь степенью ужаса “до”, радости “после” и рядом вторичных характеристик.


У нас в RBK.money тоже микросервисы. Но пришли мы к ним немного не так, как большинство. У нас все было даже хуже монолита — у нас на старте просто все было хреново.


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


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


Быстро vs хорошо


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


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


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


Очень часто человек начинает говнокодить не потому, что он за этим и устраивался к вам работать, а потому, что у него банально глаз замыливается и скучно становится. Если один человек постоянно сидит на одном и том же микросервисе, он может начать генерить говнокод. И это не столько вопрос профессионализма, сколько вопрос времени. Месяцев через 7-8 человек устанет поддерживать один и тот же микросервис, будет смотреть по сторонам — а там жизнь, после зимы пришла весна, у коллег какая-то движуха, опять новый айфон вышел, а ты все сидишь на одном и том же микросервисе. Вот так рождается монолит с единой точкой отказа в виде этого уставшего человека с мешками под глазами.



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


  1. Запустить сервис.

Как было:


  1. Зайти в реестр винды.
  2. Найти там определенный ключ.
  3. Поменять его на 1.
  4. Запустить сервис.
  5. Сбросить значение ключа на 0.

Это классический пример сложности ради сложности и “Без меня тут ничего не работает”. На самом деле, без подобного всё работает. Только быстрее и лучше. Избавиться от этого можно ротацией — в идеале когда человек пишет один микросервис примерно пару спринтов, а потом уходит делать другую задачу. Этим же мы поддерживаем и постоянный обмен знаниями в команде.


Код от протокола



Если взять любое ТЗ от бизнеса, хорошенько перевести на человеческий, отряхнуть от шелухи и выпарить — получится протокол, язык, по которому и будет общаться машина. То есть мы берем бизнес-задачу, понимаем для себя, что именно и как мы будем делать, и превращаем это в спецификацию на thrift или swagger (микросервисы внутри общаются по thrift). Первый шаг — всё подробно описать: что будет делать микросервис, какие типы данных принимать, чем отвечать, какие будут структуры и прочее. Этот протокол проходит первое ревью у тех, кто точно представляет себе, как все работает (де-факто — архитекторы). Срабатывает как фильтр грубой очистки, через который какое-то откровенное фуфло не пройдет даже на уровне концепции.


Как только появляется протокол, можно садиться писать код. И если протокол ревьюится вполне себе универсальными людьми, то сам код — в команде конкретных людей. Мы пишем на трёх языках — JS, Java, Erlang. Главное — никого не торопить ни с ревью, ни с написанием кода. Да, бизнесу всегда и везде надо быстро и круто. Но я как техдир редко тороплю ребят, потому что понимаю, что они хотят сделать хорошо. В итоге получается ситуация, что я часто бываю взбодрен бизнес-заказчиками за сроки. Зато практически не приходится краснеть за качество.


Мы поспешили лишь однажды, когда наложился джекпот — суперзаказчик и крайне срочные дедлайны, как раз создавали наш Wallet. Тогда да, мы чууууток спустили рукава и сделали все быстрее, чем планировали (и хуже, чем хотели, да). В идеале все задумывалось как кучка аккуратных микросервисов. Получился такой себе кусочек монолита. Плюсы ситуации в том, что мы еще разок для себя поняли, что спешить не надо. А сам сервис уже потихоньку растаскиваем на отдельные микросервисы, как и хотели.



Микросервисов в RBK Money штук 50, их пишут около 20 человек. Внутри везде thrift, для разрабов это довольно сложный протокол, дебажить сложно, документацию писать тоже сложно. И если бы я выпустил thrift наружу в чистом виде, меня бы стали называть нехорошими словами. Поэтому мы не стали ничего придумывать — наружу у нас бодро торчит рестовый JSON, простой и понятный, плюс OpenAPI. Чтобы иметь возможность принимать эти запросы снаружи, их надо валидировать, авторизовывать, а потом другими микросервисами уже запускать внутрь платформы. И всё это дело мы тоже написали в качестве самостоятельного микросервиса, который:


  • принимает снаружи swag;
  • валидирует схему;
  • авторизует пользователя;
  • превращает всё это в thrift-запрос;
  • ну и логи пишет, конечно.

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



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

Tags:RBKmoneyмикросервисыerlang/otpjavaплатежные системыраспределенные системы
Hubs: RBK.money corporate blog Payment systems Java Erlang/OTP Development for e-commerce
+24
10k 56
Comments 23