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

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

Человеку, который только начинает заниматься разработкой или поддержкой программных решений, придется столкнуться с тем, что микросервисная архитектура является очень размытым и плохо определенным понятием:

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

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

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

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

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

Микросервисы и SOA

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

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

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

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

Микросервисы и монолит

Это еще раз подводит нас к вопросу - что же такое микросервисы, насколько маленькими они должны быть и как должны взаимодействовать между собой? 

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

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

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

Фантазия художника на тему сравнения архитектур
Фантазия художника на тему сравнения архитектур

Микросервисы и боль

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

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

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

Да что там отдельный API интерфейс! Часть сервисов будет устаревшими, но никто не будет способен гарантировать, что ни один из сотен остальных сервисов их более не использует. Даже если все согласны, что они в целом и общем более не нужны, эти интерфейсы все еще могут использоваться во второстепенных и не критичных для функционирования механизмах. К примеру, в каких-нибудь периодических заданиях по составлению отчётности. Может так случиться, что вы все же захотите найти эти зависимости во внешних системах и удалить их. В этом случае препятствием может выступить то, что люди, которые ответственны за эти системы, могут быть весьма загружены и не иметь времени вам содействовать. А может быть это будет один из тех сирот-сервисов, который уже никому не принадлежит, но все еще активно используется. Поэтому, только если это не является абсолютно критичным, программисты обычно предпочитают не трогать чужие проекты, надеясь на то, что в будущем кто-то другой их починит и удалит ненужный или неработающий код.

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

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

  • Сервис не стабилен - разработчик выделяет ему больше ресурсов, не предполагая, что причина кроется совсем в другом и его действия ни на что не повлияли.

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

Тогда бизнес говорит - давайте равняться на международный опыт лучших компаний и руководствоваться принципом “You own it - you run it”, подразумевающий то, что разработчики будут сами отвечать за те сервисы, что создают и будут управлять всем их жизненным циклом. Вплоть до поддержки той инфраструктуры, с которой непосредственно взаимодействуют клиенты. В этом случае ещё сильнее, чем раньше, начинает размываться технологический стёк и каждая команда начинает писать что-то совершенно свое, без оглядки на опыт других. Именно так в системе появляется зоопарк решений, где PostgreSQL соседствует с MariaDB, Kafka соседствует с Pulsar, Redis соседствует с Memcached, а так же порождается много других забавных и нелепых ситуаций. Было бы неправильно думать, что операционная сложность системы в результате таких действий уменьшится, скорее наоборот. В какой-то момент каждая команда может принять решение использовать разные системы сборки, разные инструменты для тестирования и выката изменений. Понятно, что для каждой такой миграции могут понадобиться месяцы, в течении которых необходимо будет поддерживать обе системы, а возможно ее рудименты будут сохраняться годами в качестве ненужных файлов в репозитории, не использующихся классов и библиотек. А также запущенных сервисов, которые все еще кем то используются.

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

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

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

То, куда стремятся все разработчики микросервисов
То, куда стремятся все разработчики микросервисов

Монолиты и монолитность

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

Как мы уже говорили, исторически многие даже очень крупные системы разрабатывались как единый программный код, который компилировался в один довольно раздутый бинарный файл и непосредственно запускался на продакшене как системный сервис. В нем находилась вся бизнес-логика организации, были реализованы все возможные интерфейсы на все случаи жизни. И до какого-то момента это всех устраивало. Единство всей кодовой базы позволяло хранить все модули и библиотеки внутри проекта и эффективно их переиспользовать. А с другой стороны, внутри такой программы все функции и данные доступны в едином адресном пространстве, что позволяло при необходимости создавать неявные связи между модулями, создавая так называемый “спагетти код”. Некоторый уровень изоляции мог быть в какой-то степени реализован средствами самого языка, однако, в общем случае, всегда существовала масса способов получить доступ к внутренним ресурсам других модулей, не получив на это разрешения у команд, которые их разрабатывают. Это могло приводить и постоянно приводило к разным трудно уловимым проблемам. Разобраться в ситуации, найти источник проблемы и исправить ее было крайне трудно. Эту ситуацию можно до какой-то степени смягчить, введя очень подробные стандарты и жесткие правила аудита, как это сделано, например, в ядре Linux, но все же в полной мере эта проблема решена быть не может.

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

В попытках исправить эту ситуацию появилась идея разбивать эти самые модули на отдельные процессы. В этом случае программа будет лучше изолирована от других таких же сервисов и все взаимодействие между ними сможет происходить по заранее прописанным интерфейсам и никак иначе. Может показаться, что это решает проблему, что железные межпроцессорные барьеры помогут создавать лучший и более безопасный код. Но на самом деле весь тот ужас, что мы описывали ранее, переместился на уровень выше, но от этого не перестал существовать, но только усугубился дополнительными уровнями абстракций. По сути, проблема заметается под ковер, когда ее как бы не существует на уровне программного кода, где ее не видят разработчики. Но она же возникает на уровне инфраструктуры, создавая и запутывая связи между сервисами, усложняя конфигурацию и без того непростой системы. К примеру, если вы используете Kubernetes, это может выразиться в том, что часть бизнес логики переносится в манифесты сервисов (Deployments, StatefulSets), одноразовых заданий (Jobs, CronJobs), каждый из которых необходимо настроить, в том числе передать ему секреты для защищенного подключения к другим системам, базам данных и многое другое. То, что раньше было одной программой и ее отдельными модулями, теперь выражено манифестами, которые повторяют логику ее разбиения на модули, но уже в инфраструктуре.

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

Но в чем именно заключается эта роль?

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

Даже самая хорошая технология сама по себе ничего не значит. Легко дать примеры, когда замечательный с первого взгляда инструмент оказывается не востребован и заменяется менее удобным, а более удачный язык программирования остается нишевым продуктом и не приобретает массового успеха. Та легкость, с которой огромная IT индустрия приняла эту технологию и в кратчайшие сроки адаптировала в своих системах, позволяет предположить, что причины успеха микросервисной архитектуры нужно искать не только в технических, а скорее в корпоративных ее особенностях. Дело в том, что микросервисы позволяют легко создать условия, при которых инженерные границы повторяют границы административные. То есть такие границы, которые копируют отношения внутри компании, повторяют деление между разными командами и даже разными отдельными инженерами. Границы микросервисов с их отдельными репозиториями, отдельными базами данных, независимым процессом CI/CD позволяет очень гибко очерчивать зоны ответственности и гибко перераспределять людские ресурсы между проектами. Создание новой бизнес логики легко отслеживать по созданию новых микросервисов и даже технически неподкованным людям легко визуализировать процесс разработки. И, наконец, знать кто конкретно отвечает за конкретный микросервис и конкретный функционал, чтобы быстро реагировать на инциденты и распределять новые задания. В целом, микросервисная архитектура позволяет снизить сложность управления людьми, позволив одному и тому же количеству инженеров строить более сложные и масштабные системы. А значит, быть более конкурентноспособными на рынке, что обычно выражается в большей прибыли.

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

Золотая середина

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

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

Конкретно это может выразиться в следующем:

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

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

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

  • При добавлении новых коммитов в репозитории проекта будет автоматически запускаться процесс, который соберет для каждого из сервисов их исполняемые файлы, затем построит для каждого свой образ и сохранит эти образы в специальном репозитории. Все это можно делать параллельно, ведь зависимостей между сервисами быть не должно. Вы также можете создать для каждого сервиса свой Helm Chart, поместить его в отдельной директории репозитория проекта, а затем специальной утилитой, вроде Helmfile или ее аналога, разворачивать новую версию ваших сервисов в кластере Kubernetes.

Самый важный совет, который только можно дать на первом этапе разработки, это избегать плодить лишние сервисы. На этом этапе весь API Backend можно разместить в одном сервисе, логически разделив префиксами те API, что в последствии будут выделены вами в отдельные микросервисы. Весь код такого сервиса должен быть модульно организован, а межмодульные связи должны быть реализованы через тот же самый HTTP API, даже если фактически достаточно локально вызвать метод.

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

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

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

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

  • Сервис для API Backend, с которым непосредственно взаимодействуют клиенты. Взаимодействует с шиной сообщений и с базой данных.

  • Сервис для асинхронных заданий, который получает из шины сообщений задания разных типов и параллельно их исполняет. Взаимодействует с сервисом API Backend, а так же может самостоятельно посылать задания в шину сообщений. В особых случаях может работать напрямую с базой данных связанного с обработчиком сервиса.

  • Сервис для статичного контента, построеный как обертка поверх nginx. Хранит html, JavaScript и любой другой редко изменяющийся контент для функционирования сервиса.

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

  • Реляционная база данных. Хранит все состояние системы.

  • Брокер, реализующий шину сообщений нашей системы.

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

Какой же вывод можно сделать из всего нами сказанного?

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

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

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

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

А на сегодня это все.

Комментарии (97)


  1. makar_crypt
    28.05.2022 11:07

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

    например

    { PrepareBuyLot()

    sendToBilling_PAY(userid, 50) }

    А потом как бы еще хэндлить ответ

    { receiveMessageFromBilling()

    MoreCodeForFinishBuyLoy() }

    Кстати на картинке показано что в твитере более 500 микросервисов , я очень в этом сомневаюсь


    1. baldr
      28.05.2022 11:30
      +1

      Кстати на картинке показано что в твитере более 500 микросервисов , я очень в этом сомневаюсь

      Я не сомневаюсь.

      Работал 10 лет назад в провайдере SIP-телефонии. Вроде бы 1млн клиентов было, может поменьше. Микросервисы внутри плодились со страшной силой. Когда я пришел, то всю архитектуру из 10 сервисов знали наизусть все 30 сотрудников, включая, кажется, даже бухгалтера... Но пришло много творческих людей и через 7 лет, когда я увольнялся, количество компонентов приближалось к 200. Насколько мне известно, через пару лет перевалило за 300, а потом точное число мне уже не смогли назвать.


  1. gleb_l
    28.05.2022 12:02
    +10

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

    Здесь как в шумоподавителе Dolby - мы уменьшаем количество заметных человеком искажений за счёт увеличения количества незаметных. КПД этого процесса всегда < 1.


    1. felixd7u Автор
      28.05.2022 14:01
      +1

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


      1. gleb_l
        28.05.2022 21:59
        +1

        Да, но примерно наоборот. Истинная сложность системы с введением даже неудачного разделения не вырастет - вырастет воспринимаемая человеком сложность. Представьте, что представитель некоего плоского мирка F не знает квадратных уравнений. Ему показывают график параболы, и он считает, что для описания набора точек на этой кривой нужно бесконечное количество информации. Затем приходит представитель выпуклого мира U, видит параболу, и говорит, что для ее описания на бесконечном интервале нужно всего три числа. Истинное кол-во информации для описания параболы будет равно этим трём числам. Воспринимаемое U - в данном случае = истинному. Воспринимаемое F - равно бесконечности.


        1. felixd7u Автор
          29.05.2022 01:55
          +2

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

          Я понял вашу аналогию, позвольте дать другую. Есть программа для сжатия данных. Текст до сжатия занимает один мегабайт, после сжатия 100 килобайт. Учитывая, что современные алгоритмы пытаются учитывать не только универсальные свойства текста, но еще и его специфические особенности, эти 100 килобайт находятся очень близко к теоретическому пределу, к информации системы по Шеннону. В вашем примере, зная специфическую природу данных, эта информация свелась к 3 параметрам.

          Так и сервис. Представим, что для конфигурации нашего сервиса можно задать 5 переменных, каждая из которых может находиться в 10 состояниях. Тогда, сервис имеет 10^5 состояний, каждое из которых уникально и может иметь свои побочные эффекты и особенности. Эти состояния(вернее его логарифм по степени 2) и есть энтропия системы, та мера хаоса, призванная оценить пространство возможных конфигураций. Возможных, так как сервис как правило будет находиться в одном из них в конкретный момент времени. Инженеру, как правило, эти состояния доступны и не скрыты. Заметим, что при таком определении сложность сугубо обьективна.

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

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


    1. DaneSoul
      29.05.2022 02:30
      +2

      Сложность, истинную сложность системы невозможно уменьшить, съесть, скукожить и выбросить без того, чтобы снять покрытие каких-нибудь бизнес-процессов.
      Но ее можно РАЗДЕЛИТЬ на части, так что для решения отдельных задач не нужно будет постигать всю систему целиком. Собственно такое разделение и есть основная цель микросервисов.


  1. build_your_web
    28.05.2022 12:33
    +6

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

    На текущий момент, проблема микросервисов в том, что люди не изолируют их в отдельные небольшие группы (подсистемы), создавая bonded context более высокого уровня, а сваливают в единую кучу, решив что два уровня абстракции достаточно (объекты внутри микросервисов и сами микросервисы). В итоге, мы выносим сложность решения с уровня кода, на уровень межсервисного общения и там её никак не решаем.

    Следующий шаг, это организация микросервисов в группы. К примеру, с помощью неймспейсов в кубернетесе, стеков в aws или ресурсных групп в azure. Если их станет много, то строим следующий уровень (конвенциями в наименовании групп, виртуальными/реальными кластерами, отдельными аккаунтами облачных провайдеров).


  1. powerman
    28.05.2022 13:35
    +12

    В целом я полностью согласен и со статьёй, и с предлагаемым подходом к решению проблемы - кроме технических подробностей этого решения.

    На мой взгляд, изолировать префиксами таблицы в БД и методы API - идея очень плохая. Равно как и собирать функционал в один микросервис по типам операций - все обработчики API в один, все фоновые задачи в другой… Это приведёт только к тому, что никакой изоляции между сервисами не будет - не теми, которые создаются сейчас в этом стиле, а теми настоящими микросервисами, на которые (возможно) придётся разделять эту систему в будущем.

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

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

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

    Но! При этом необходимо тем или иным способом обеспечить жёсткую изоляцию сервисов:

    • Одних каталогов мало, нужен ещё и автоматический контроль, что микросервис из одного каталога не использует код из каталогов других микросервисов. (Например, в Go это реализуется через internal-каталоги.)

    • Использовать общий сервис СУБД - да, но изолировать данные разных сервисов нужно не префиксами таблиц, а средствами самой СУБД. Т.е. у каждого микросервиса должен быть собственный аккаунт, дающий доступ только к его данным. (В MySQL каждому микросервису нужно создать собственный database, в PostgreSQL нужно создать разные схемы в рамках одного database и заблокировать доступ к схеме public, etc.)

    • API каждого сервиса должен реализовываться им самим и подниматься на собственном порту. (Т.е. в случае вышеупомянутого сервиса-монолита он при запуске будет раздавать API разных встроенных в него микросервисов на разных портах.)

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

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

    Ну и в конце отвечу на заданный в статье вопрос: что мешает вместо микросервисов написать модульный монолит, для чего нужны границы процессов/API? В теории - ничего не мешает. Если нет каких-то серьёзных требований к масштабированию (а в 99.9% проектов их нет), то такой монолит вполне может решить все проблемы. Но на практике всё упирается в то, что если изоляцию этих модулей друг от друга не соблюдает на 100% бездушная машина, то люди её будут нарушать, обязательно, и скорее рано, чем поздно. А нарушенные границы приведут нас обратно к обычному спагетти-монолиту.


    1. BugM
      28.05.2022 14:05

      Равно как и собирать функционал в один микросервис по типам операций - все обработчики API в один, все фоновые задачи в другой…

      Если убрать квантор ВСЕ, то достаточно неплохо получается.

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

      о люди её будут нарушать, обязательно, и скорее рано, чем поздно. А нарушенные границы приведут нас обратно к обычному спагетти-монолиту

      Добавляем периодический рефакторинг с восстановлением границ и переделкой их на более хорошие. Я не уверен что это выйдет дороже поддержки микросервисов.


      1. dopusteam
        28.05.2022 14:38

        Рефакторинг с восстановлением границ часто может быть невыполним в разумные сроки. Ну, имхо. Иначе проблем бы вообще не было


      1. powerman
        28.05.2022 14:42
        +3

        Насчёт разделения фоновых процессов и API - да, это обычно хорошая идея. Но я писал именно про ВСЕ, и проблема в этом.

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


        1. BugM
          28.05.2022 17:12
          +3

          Я никогда не понимал почему люди готовы делать нормальные модули в виде сервисов, но не в виде программных модулей? Это по сути одно и тоже.

          АПИ это всегда накладные расходы на сеть. Микросервисы это проблема распределенных логов и распределенного дебага. При небольшой логической ошибке в проектировании появляется нерешаемая для большинства проблема распределенных транзакций. Надо пилить всякие circuit breaker, балансировки на разных уровнях и кучу производных rps считать и мониторить.

          Нужно вам вот к этим данных ходить из разных мест? Такое бывает и это нормально. Ну вынесите ДАО для работы с ними в подходящий коммон модуль и ходите на здоровье.

          Нужно вам надежно писать данные? Сделайте транзакцию в БД. Это почти бесплатная абсолютная гарантия.

          Поняли что у вас спагетти образовалось? Соберитесь отделом разработки обсудите как это переделать хорошо и переделайте. Страшно только первый раз.

          Я не про то что надо делать все одном монолите. Я про разумный баланс. Если у вас для отрисовки странички пользователю задействовано больше 2-3 ваших сервисов, то наверно вы пошли куда-то не туда. Стоит остановиться и подумать.

          И в обратную сторону. Если вы поняли что из апишки пишите очередь заданий на обработать потом и в той же приложеньке читаете ее и обрабатываете наверно стоит подумать о разделении.


          1. baldr
            28.05.2022 17:21

            Ну, например, сервисы могут писать разные люди. В разных местах. И на разных языках программирования.

            Сервисы надо масштабировать и деплоить - и это тоже может налагать условия на дизайн.

            Если у вас для отрисовки странички пользователю задействовано больше 2-3 ваших сервисов, то наверно вы пошли куда-то не туда.

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


            1. BugM
              28.05.2022 18:43

              Ну, например, сервисы могут писать разные люди. В разных местах. И на разных языках программирования.

              Это худшее что можно придумать. Как это потом дебажить и поддерживать? Бизнесу глубоко все равно что у вас разные языки и команды. У него есть неработающая фича, или еще хуже внезапно сломавшаяся фича. Ее надо починить. Срочно.

              У вас точно есть распределенный трейсинг, общее удобное хранилище логов, понимание как это все в комплексе работает и как это дебажить? Желательно чтобы этим всем владел один человек. Ему эту фичу чинить.

              Сервисы надо масштабировать и деплоить - и это тоже может налагать условия на дизайн.

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

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

              Я именно про ваши аппликейшен сервера. Которые вы сами пишете и отвечатете за их работу.

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


              1. baldr
                28.05.2022 19:03
                +1

                С ростом сервиса меняется все.

                Был проект на старом ASP.VB и древнючем IIS (кажется еще 4 версии, давно это было), начали переписывать под ASP.NET потихоньку. Внезапно директор получил нового большого клиента и много денег на развитие. Пришел крутой чел, сказал что все напишет на жабе, будет круто, быстро и с API. Начал переписывать, все затянулось. В итоге имеем уже три версии, которые друг без друга жить не могут. Это, фактически, монолит, но уже как минимум на трех языках. Рядом стоят SIP-сервера, телефонные сервера и биллинг. Часть на C (четвертый язык), часть вообще из опенсорса откуда-то скомпилена с конфигами то ли на lua, то ли хз на чем еще.. Еще огромный кусок логики в хранимках в базе Oracle (5 язык).

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

                Параллельно развиваются сисадмины. Раньше все делал один человек на 10 серверах - теперь нужно 10 человек для 200 серверов в 2 разных дата-центрах. А еще они научились мигрировать сервера на ESXi вживую и надо чтобы приложения поддерживали такую миграцию и не обрывали соединения (деплой влияет на логику и уровень приложений)..

                Это просто вкратце и не полностью что случилось всего за год. Бизнес развивается стремительно и самое быстрое решение - не всегда самое правильное (но решение), вы и сами это знаете наверняка.


                1. BugM
                  28.05.2022 19:06

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


                  1. baldr
                    28.05.2022 19:15

                    А предложите вариант? Было 10к пользователей, внезапно выросло до 150к. Надо все очень быстро масштабировать. Деньги есть, времени нет. Конечно будут ошибки, но как же без них.

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


                    1. BugM
                      28.05.2022 19:22

                      А предложите вариант?

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

                      Когда все устаканится садиться делать нормально. Один раз, предварительно хорошо подумав.


          1. powerman
            28.05.2022 17:23

            Поняли что у вас спагетти образовалось? Соберитесь отделом разработки обсудите как это переделать хорошо и переделайте.

            Это не работает, к сожалению. И именно этот факт окупает все эти лишние накладные расходы на API, деплой, распределённые логи и т.п.

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


            1. baldr
              28.05.2022 17:45
              +1

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

              По мере эксплуатации и добавления фич редко когда (никогда) получается следовать архитектуре из предыдущей итерации, копится технический долг и через какое-то время он закрывается. Если повезет - то целиком. Если не повезет - то частично и остаются легаси-артефакты вроде api/v1


              1. powerman
                28.05.2022 19:07
                +4

                Архитектура - это не что-то высеченное в камне. Меняются требования - архитектура тоже должна адаптироваться. Ожидать, что первой архитектуре удастся следовать вечно - довольно странно.

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

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

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

                (Извините, немного углублюсь в теорию вопроса.)

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

                В этом смысле на уровне кода тоже есть своя архитектура. Условно, можно разделить "архитектуру" проекта на три уровня:

                • низкий: стиль (форматирование), идентификаторы (переменные, функции)

                  • Типичный пример плохой архитектуры (отсутствия границ) на этом уровне - сделать все переменные глобальными.

                • средний: логическая структура (объекты/классы, пакеты, модули)

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

                • высокий: инфраструктура (микросервисы, API)

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

                В монолитах грань между средним и высоким уровнем… обычно сильно размыта и никем не контролируется. Если в микросервисной архитектуре сложно добавить новый микросервис или новые методы API в существующий сервис пройдя мимо внимания архитектора, то в монолите аналогичные изменения делаются незаметно даже для самих разработчиков, не говоря уже об архитекте. Границы, которые архитект определил в микросервисной архитектуре очень сложно нарушить в принципе, и абсолютно невозможно их нарушить нечаянно, даже не заметив этого. А в традиционном монолите - запросто.

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

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

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


                1. baldr
                  28.05.2022 21:01

                  У меня совершенно нет возражений на то что вы написали. Однако я уже не понимаю в чём вы не согласны со мной и товарищем выше.


                  1. powerman
                    28.05.2022 21:09

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


                    1. baldr
                      28.05.2022 21:48

                      Отнюдь. Я за монолит не топил никогда.

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

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

                      Быстрый пример: есть две базы с разными данными, внезапно понадобилось сделать между ними join в одном запросе. Что-то придумывать сложное сейчас смысла нет, поскольку непонятно - нужно ли это будет через месяц. Я сделал одну таблицу через foreign table и связал их в запросе. Сделал пометку в TODO вернуться к этому через какое-то время. Потом можно будет оценить целесообразность переноса таблиц, выделения запроса в отдельный сервис или вообще выкинуть этот хак.


                      1. powerman
                        29.05.2022 00:01
                        +2

                        Хак добавить - это проще всегда. Правильно переписать потом - чаще всего не случается никогда. Частично потому, что хак работает, и нужно заниматься новыми фичами, а не пересмотром старых TODO. Частично потому, что нет ничего более постоянного, чем временное.

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

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

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

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

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


            1. BugM
              28.05.2022 18:46

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

              Я бы оценил в 10-20 процентов сил команды разработки на поддержку кодовой базы с хорошем состоянии. Это постоянный процесс. Если забросить на годы, то потом плохо. Не надо забрасывать.


    1. felixd7u Автор
      28.05.2022 14:18

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

      Что качается использованию разных портов для разных сервисов, это интересная идея. Я не думал об этом. Единственным припятствием к реализации такого решения вижу в отсутствии многопоточности. Что если используется однопоточный Python сервис, где нет возможности в подобном разделении? Хотя, это всего лишь догадка, необходимо поизучать эту тему.


      1. powerman
        28.05.2022 14:47

        Если честно, я вообще не верю в возможность использовать языки вроде питона в таком стиле - скриптовые языки не особо располагают к тому, чтобы обеспечивать жёсткую изоляцию в рамках одного приложения. Наоборот, обычно они предоставляют массу возможностей любую изоляцию обходить. Даже в Go писать изолированные модули/микросервисы в рамках монолита не было никаких шансов, пока не появилась поддержка internal-каталогов. Потому что без них Go обеспечивал жёсткую изоляцию на уровне только одного пакета, а писать целиком весь микросервис как один пакет… ну, такое.


      1. powerman
        28.05.2022 14:54
        +2

        Не все базы данных такое поддерживают.

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

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


    1. Bromles
      28.05.2022 20:37
      -1

      PostgreSQL нужно создать разные схемы в рамках одного database

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


      1. mitya_k
        29.05.2022 11:07
        +1

        А есть какая-нибудь статья на эту тему или замеры?


        1. Bromles
          29.05.2022 13:38

          https://stackoverflow.com/questions/14893964/how-many-schemas-can-be-created-in-postgres

          https://postgrespro.ru/list/thread-id/2064050

          Был еще один, более актуальный (около 1к схем, а не 10-20к) тред на StackOverflow, но не могу его найти. Там у человека pg_dump вообще крашился

          Общая суть в том, что при дампе такой большой бд pg_dump должен развесить кучу локов и все проверить, что очень сильно замедляет процесс (вплоть до невозможности делать это ежедневно) или вообще приводит к его падению

          Возможно, в более новых версиях это пофиксили, не проверял (у нас не настолько много сервисов)

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

          Но в случае отдельных бд мы полностью исключаем использование чужих данных из других схем


          1. powerman
            29.05.2022 14:02

            Проблема не выглядит реальной для нашего use case. Во-первых, обычно в проектах нет такого (тысячи) количества stateful микросервисов использующих именно постгрес. Во-вторых, тупо из соображений производительности никто не направит даже сотню таких микросервисов в общий инстанс постгреса. Обычно речь идёт о порядке десятка(ов) микросервисов на один постгрес.


            1. Bromles
              29.05.2022 17:37
              -1

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


              1. mayorovp
                29.05.2022 20:30

                Для того, чтобы запретить влезать в соседнюю схему, разделять БД совершенно не требуется.


                1. Bromles
                  30.05.2022 15:22
                  -1

                  Не требуется, но это бесплатная гарантия на уровне бд. Так еще и ускоряет и упрощает дампы потом. Так-то много где и что можно отдельно гарантировать, на уровне CI код проверять и прочее. Но зачем?

                  Меня вот все минусуют, но я вижу в ответ только спорные высказывания типа "плюсы - не плюсы", а не проблемы и конструктив. И тихие нажатия на кнопочку "-rep". Собственно, говорит многое о уровне несогласных)


                  1. mayorovp
                    30.05.2022 16:44

                    Смотрите, для того чтобы создать отдельную БД для сервиса, получив "бесплатную гарантию" 100% разделения сервисов, нужно сделать что?


                    1. Завести отдельного пользователя для этого сервиса;
                    2. Создать БД;
                    3. Дать права на БД из пункта 2 пользователю из пункта 1

                    Теперь смотрим как то же самое делается для схемы. Нужно:


                    1. Завести отдельного пользователя для этого сервиса;
                    2. Создать схему;
                    3. Дать права на схему из пункта 2 пользователю из пункта 1

                    В чём разница-то, ёпрст? Почему у вас первое — бесплатно, а второе требует проверки кода на уровне CI?


  1. themen2
    28.05.2022 16:27

    А что по версионности? Кто как организует хранение старых версий?


    1. powerman
      28.05.2022 16:55

      Если Вы про API (хотя тут неясно о каком "хранении" речь), то самый лучший совет - не относится к версионированию с лёгкостью.

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

      Версионирование API как способ решения всех проблем чем-то напоминает идею плодить сотни микросервисов как способ решения всех проблем - какие-то проблемы это решает, но и новых проблем добавляет немало.

      Из этих соображений я не люблю использовать версионирование первой версии API - вроде /api/v1/ для REST или pkg.v1 для gRPC. Это не мешает в будущем начать использовать v2, но сам факт того, что это будет смотреться не очень элегантно (/api/register и /api/v2/register) чисто психологически стимулирует оттягивать появление v2 как можно дольше.

      В целом, проблема тут не столько в номере версии - в конце концов никто не мешает рядом с /api/register сделать /api/register_oauth или тупо /api/register2. Проблема в том, что новые методы API нельзя добавлять с лёгкостью, и не важно, какой у них префикс версии. Но новая версия как бы "подталкивает" к тому, что можно сделать улучшенную копию всего старого API, и к тому, что если с первой попытки это не выйдет, то можно ещё новых версий сделать будет - что в результате приводит к появлению намного большего количества новых методов API, чем необходимо. В т.ч. и потому, что кажущаяся лёгкость переделки API позволяет меньше сил уделять качественному проектированию, что увеличивает количество и ошибок и новых версий.


      1. themen2
        28.05.2022 20:34

        Не согласен с тем, что надо оттягивать появление новых версий итд. Это попросту не возможно в долгоживущем апи.

        Посмотрите апи Телеграм, там версионность сделана через так называемые слои - layers. Текущий слой уже переваливает за 100:

        https://core.telegram.org/api/invoking#layers

        https://core.telegram.org/api/layers

        То есть когда они добавляют поле в метод или меняют объект, добавляют новый метод и поднимают версию. Старая версия при этом поддерживается.

        На клиенте же в switch по crc32 коду возвращаемого объекта смотрят что это за объект пришел (метод в общем случае может вернуть разные обьекты) и десереализуют данные в объект.

        Не уверен, что у ребят из Телеграм не достаточно опыта, как вы выразились ;)

        Было очень интересно с точки зрения изучения кода глянуть на их реализацию, как это все организовано.

        Уверен на 95% что там монолит. Так как бекенд ВК был монолит, который компилился в vk.exe на 4гб


  1. vagon333
    28.05.2022 17:21
    +2

    Из моего опыта, для взаимодействия всех сервисов продукта важно иметь метаданные в некой БД:

    1. схему данных, которая включает в себя:
      1.1. Classes - словарь классов
      1.2. Properties - словарь свойств
      1.3. Enumerations - используются в №2
      1.4. ClassProperties - свойства классов (№№1+2)
      1.5. ClassRelations - иерархия и связи между классами (inheritance, subclasses and superclasses)

    2. репозитарий сервисов

    3. схемы запросов/ответов для каждого сервиса (№2), которые опираются на №№ 1.1, 1.3, 1.4

    4. возможность генерить sample payload, на основании схем (№3)

    5. mocked API endpoints - тестовые сервисы, которые на основании №3 и №4 позволяют протестировать

      Как бонус:

    6. описание процессов через BPMN, как сложная логика взаимодействия сервисов

    7. оркестратор сервисов и процессов, BPM engine, если возможно (Camunda)

    Для упрощения и масштабирования, метаданные желательны, но можно и без них.
    И, насчет управления метаданными:

    • желательно веб-приложение для работы с этими данными,

    • желательно легко расширять метаданные, чтоб можно было легко навешивать автоматизацию или добавлять описание

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

    Из чего следует, что метаданные лучше хранить в стандартной DBMS, типа реляционных Postgres, MSSQL, MySQL, etc.


    1. BugM
      28.05.2022 18:48

      А кто это будет поддерживать?

      Как будет гарантированно 100% соответствие тому что в проде?

      Чем вы будете бить своих разработчиков чтобы они не забивали на поддержку этого?


      1. vagon333
        28.05.2022 18:51
        +2

        Я неясно описал: метаданные выше, это primary source of truth, автоматизирующий часть задач.
        На основании этого описания формируется swagger сервисов, для этих mock формируется код с функционалом микросервисов.
        Т.е., отвечая на ваш вопрос - не нужно синхронизировать, нужно дополнять кодом и оборачивать devops CI/CD для deploy на среды (test, dev, dr, etc.).


        1. BugM
          28.05.2022 18:59

          Не. Правда только то что на проде. И в любой момент прод будет обгонять любое описание и любую документацию. Разработчики так код пишут. Бизнес так деньги зарабатывает. Консенсус.

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

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

          Для примера прикиньте сколько сил в вашей схеме займет небольшой рефакторинг вида: Из кучи бизнес логики выделили несколько новых ДАОшек/сервисов и обобщенным кодом и запихнули их в отдельный модуль. По пути переименовав полсотни классов и изменив пару сотен связей внутри.

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


          1. baldr
            28.05.2022 19:10
            +2

            Я предполагаю что для этого их надо ежедневно бить. Других вариантов я вообще не вижу.

            А так и есть.

            Один раз разработчик зашел на продакшен и залил конфиг с совсем небольшим изменением. Только забыл что у него Windows, а на сервере Linux, и переносы строк другие. Через какое-то время сервис подхватил конфиг и все упало. Искали долго (визуально конфиг тот же самый). Сильно поругали, но простили.

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

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


            1. BugM
              28.05.2022 19:18
              +2

              Один раз разработчик зашел на продакшен и залил конфиг с совсем небольшим изменением. Только забыл что у него Windows, а на сервере Linux, и переносы строк другие. Через какое-то время сервис подхватил конфиг и все упало. Искали долго (визуально конфиг тот же самый). Сильно поругали, но простили.

              Написать код так чтобы он работал с любыми переносами строк так и не догадались? Сделать мониторинг вот такого падения с откатом конфига/версии приложения по одной кнопке тоже не догадались?

              Ругать просто. Но это никак не помогает. И сильно вредит.

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

              Странная у вас БД которая падает от одного дополнительного коннекта или транзакции. У всех приличных БД есть куча разные ручек с разными настройками, которые позволяют автоматом все неприличное отключать.

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

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

              А когда продакшен пришел в непонятное состояние и деньги бизнеса горят ярким факелом кто это чинит? Допустим простой откат версии не помог.


              1. baldr
                28.05.2022 19:27

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

                Написать код так чтобы он работал с любыми переносами строк так и не догадались?

                Kamalio SIP server (он же OpenSer) - опенсорсная тулзовина. Напишите им сами об этом.

                Странная у вас БД которая падает от одного дополнительного коннекта или транзакции.

                Мне кажется что почти в любой базе можно запросто устроить дедлок просто забыв сделать коммит. А если у вас в одной IDE две вкладки - для продакшена и для локального сервера - вполне можно и не в том его сделать.

                А когда продакшен пришел в непонятное состояние и деньги бизнеса горят ярким факелом кто это чинит? Допустим простой откат версии не помог.

                Было всего один раз за следующие 6 лет когда легло просто ВСЕ. 6 часов чинили особо ответственные люди, директор бегал вокруг и рвал все волосы во всех местах себе и окружающим. Были сделаны сильные выводы, показательно уволено много людей, включая VP по разработке. Те кто остались - запомнили. После этого архитектура стала такой что просто ВСЕ упасть уже не могло сразу.


                1. BugM
                  28.05.2022 19:43
                  +1

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

                  Мне кажется что вы даже не стремитесь к тому чтобы получалось.

                  Kamalio SIP server (он же OpenSer) - опенсорсная тулзовина. Напишите им сами об этом.

                  Не использовать тузлу в которой есть такие примитивные ошибки.

                  Сделать PR в мастер.

                  Форкнуть и дописать.

                  На самый крайний случай обнести прод именно этой тулзы дополнительным забором. Если против остальных методов есть очень убедительные аргументы.

                  Выбирайте.

                  Мне кажется что почти в любой базе можно запросто устроить дедлок просто забыв сделать коммит.

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

                  Были сделаны сильные выводы, показательно уволено много людей, включая VP по разработке.

                  У меня один вопрос остался. Как эта фирма называется? Чтобы не вляпаться случайно.


                  1. baldr
                    28.05.2022 20:19
                    +1

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

                    Так-то все умные и указывать на чужие ошибки через 20 лет довольно просто.

                    Конешн, чего там - взять Kamailio или Asterisk, найти там все баги и пофиксить. На один вечер работы.


                    1. BugM
                      29.05.2022 15:08

                      Конешн, чего там - взять Kamailio или Asterisk, найти там все баги и пофиксить. На один вечер работы.

                      План что будет сделано до конца года чтобы стало лучше и выделенные под него люди тоже подойдет.

                      У вас же этого тоже не сделано?


                1. dopusteam
                  29.05.2022 08:44

                  Были сделаны сильные выводы, показательно уволено много людей, включая VP по разработке. Те кто остались - запомнили. После этого архитектура стала такой что просто ВСЕ упасть уже не могло сразу.

                  Во-первых, сомневаюсь, что такую архитектуру можно сделать.

                  Во-вторых, раз за шесть лет - увольнение. Серьёзно? Считали процент доступности то? Или в 100% метите?

                  В-третьих, часть разработки уволили, часть адекватных сами ушли, оставшиеся будут бояться что то делать. Профит


                  1. baldr
                    29.05.2022 09:45

                    Во-первых, сомневаюсь, что такую архитектуру можно сделать.

                    Ну, общие точки есть всегда, конечно. Разнесли пользователей по 6+ разным окружениям с отдельной инфраструктурой и в 3 дата-центрах, сначала Active-Passive, а потом частично Active-Active схема. Больше 4к серверов только на продакшене, в 2-3 раза больше в тестовых окружениях. На время больших обновлений пользователи переносятся в другое окружение, переключаются все девайсы и звонки..

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

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


                1. dopusteam
                  29.05.2022 09:36

                  Были сделаны сильные выводы

                  А что за сильные выводы, кстати?


                  1. baldr
                    29.05.2022 09:52

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


          1. vagon333
            28.05.2022 20:00
            +3

            Правда только то что на проде.

            Это кохоз, а не правда.
            Должно быть separation of duties, когда разрабочики не имеют доступ на прод, а прод обновляется через автоматизированные CI/CD.

            Офтоп:
            Минус за мой коммент выше - гигантский демотиватор.
            Какой смысл делиться мнением, если хамовитый оппонент тупо заминусует?
            Я не пишу статьи и когда Хабр меня уведомляет, что я не могу комментировать т.к. моя карма в плинтусе, причем я никого не оскорблял и не обижал словом ... хочется вежливо послать и оставаться при своем мнении.


            1. BugM
              28.05.2022 20:59
              +2

              Ci/CD и доступ разработки на прод это перпендикулярные вещи. Они отлично живут одновременно. Доступ нужен для тушения пожаров и дебага неповторимых нигде, кроме прода, проблем.

              «Правда только то что на проде» это суровая правда жизни. Нельзя считать правдой то что не работает и может быть никогда не заработает. Это путь в тупик. У вас будет «официальный источник правды» и народ который шепотом будет говорить новичкам где на самом деле посмотреть правду.


              1. baldr
                28.05.2022 21:03
                +1

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

                Тогда "правда" и переезжает в скрипты деплоя. Ну или в те части, которые ещё не автоматизированы.


                1. BugM
                  29.05.2022 13:57

                  Конечно затрет. И это скорее хорошо. Есть способ привести систему в конкретное состояние по одной кнопке.

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


              1. vagon333
                28.05.2022 21:19

                Ваши советы от тяжелых условий, но оторваны от стандартов разработки.

                Зарубежные аудиторы (SOC2) запретят доступ к вашим продуктам т.к. у вас любой разработчик может зайти на прод и не только подшаманить код, но и:
                - скопировать данные клиентов (для траблшутинга, конечно)
                - вставить зловредный код, пока не будет перезатерт след. деплоем

                Обе истории не выдуманные, а из моей практики.


                1. BugM
                  29.05.2022 14:04
                  +1

                  Зарубежные аудиторы (SOC2) запретят доступ к вашим продуктам

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

                  Аудиторы это нормальные люди. Они не выдумывают неисполнимых требований. Они понимают что работать как-то надо. Все требования в основном про прозрачность и бюрократию.

                  Обе истории не выдуманные, а из моей практики.

                  Уголовные дела покажете? Второй случай это чистая уголовщина.

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


                  1. vagon333
                    29.05.2022 20:54

                    SOC аудит требует аудита каждого доступа на прод и вроде как логов всего что там делалось. 

                    Написанное вами пересказывает мои слова.
                    Благодарю за минус. :)

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

                    Аудиторы это нормальные люди.

                    Странное панибратство.
                    SOC2 - не нормальные люди, а процессы и и правила соблюдения этих процессов.
                    Как только регуляторы обнаруживают, что аудиторы нормальные люди и можно срезать углы в вопросах безопасности, требования к аудиту сразу изменят.
                    Именно так случилось с SAS70, который был ранее, в 200х.

                    Уголовные дела покажете? Второй случай это чистая уголовщина.

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


                    1. BugM
                      29.05.2022 21:52

                      Написанное вами пересказывает мои слова.Благодарю за минус. :)

                      Нет и нет. Между запретом и логами с аудитом есть огромная пропасть.

                      Я не минусовал

                      SOC2 - не нормальные люди, а процессы и и правила соблюдения этих процессов

                      Я тоже проходил аудиты и общался с аудиторами. Нормальные люди это в смысле их цель не запретить вам работать или не завалить вас на аудите. А обеспечить нужный уровень безопасности. Это достигается без всяких экстремальных методов которые вы предложили вот тут https://habr.com/ru/post/668300/comments/#comment_24387092

                      Вы часто видели случаи, когда компания выметает мусор и роняет свою репутацию?

                      Это как раз повышение репутации. Готовность наказывать по закону своих сотрудников, которые сознательно нарушили уголовный кодекс, поднимает доверие к компании и ее сотрудникам.


              1. powerman
                28.05.2022 21:21
                +1

                Доступ разработки на прод - это способ создать проблемы, а не решить их. Да, в виде исключения, кто-то один, самый главный и ответственный, этот доступ может иметь. Техлид/архитект/техдир - такого уровня главный, в зависимости от размера компании. Но точно не разработчики. И, по возможности, даже этот доступ должен быть read-only - типа посмотреть в БД прода чтобы понять что в ней не так, но не фиксить её ручками - фиксить надо выкатом штатной миграции через CI/CD.

                Для дебага именно "доступ" - не нужен. Для дебага есть куча инструментов, от логов и метрик до встроенного профайлера. Это - доступ уровня read-only, от него проблем нет. Да, это может требовать выката отладочных версий штатным CI/CD - но это хорошо, а не плохо. Уж всяко это лучше, чем ручками на проде менять код (если это скриптовый язык) или напрямую БД.

                Что до правды - Вы правы. Если на проде одно API, а по доке должно быть другое - правда на проде. Но решать эту проблему (а это проблема!) нужно с другой стороны: поставить процессы так, чтобы на проде физически не могло оказаться что-то, что не описано в доке на API. Это довольно просто: любое изменение API сначала делается в доке, а уже потом в коде (в идеале - путём кодогенерации из доки).


                1. mayorovp
                  29.05.2022 12:54

                  Это довольно просто: любое изменение API сначала делается в доке, а уже потом в коде

                  Ага. Вот сделал разработчик изменение API в доке, и внезапно заболел. Или уволился. А задача, которую он делал, оказалась не такой срочной и упала в бэклог. Что дальше по вашим процессам происходить будет?


                  (в идеале — путём кодогенерации из доки)

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


                  1. baldr
                    29.05.2022 13:09

                    сделал разработчик изменение API в доке, и внезапно заболел. Или уволился

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


                    1. dopusteam
                      29.05.2022 13:58

                      Если дока и реализация в рамках одного реквеста делаются, то что значит "любое изменение API сначала делается в доке, а уже потом в коде"?


                    1. mayorovp
                      29.05.2022 14:07

                      Ветка началась с предложения держать метаданные в БД.


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


                      Опять же, даже в случае файловой БД возможности ветвления и пул-реквестов резко ограничены форматом.


                  1. powerman
                    29.05.2022 14:05
                    -1

                    Разница громадная: API прода либо соответствует доке, либо нет. А то, что часть методов может не работать (возвращать 501 Not Implemented в случае HTTP API) или не работать корректно (напр. возвращать 500 Internal Server Error) - это штатная ситуация, и клиенты должны быть к этому готовы в любом случае. Но клиенты не должны получать ошибки вроде 404 Not Found или 400 Bad Request (говорящие о баге в коде клиента!) если они отправляют запросы соответствующие доке на API.


                    1. BugM
                      29.05.2022 14:15

                      Вы точно код для прода пишите и мониторите?

                      Пятисотки это первый сигнал что у вас что-то сломано. Код который может отдавать пятисотки не должен доежать до прода никогда. А если доехал, то чиниться asap.

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

                      Документация написанная и выложенная после релиза прода дает гарантию что все методы из нее работают. Понятно что сломаться может все. Но это авария которая будет максимально быстро чиниться.


                      1. powerman
                        29.05.2022 15:23

                        Вы не уловили суть. Вы описываете отношение с точки зрения бэка, а я с точки зрения клиента.

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

                        Для бэка 400 это ситуация штатная, мало ли что клиенты прислали. Для клиента 400 - это признак бага в коде клиента, и в проде такое случаться в принципе не должно (аналогично 500 в проде на бэке).

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


                      1. BugM
                        29.05.2022 15:39

                        Документация на API описывает представление архитекта о том, как оно должно работать, и даёт возможность параллельно разрабатывать как сервер, так и клиент

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

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


                      1. powerman
                        29.05.2022 15:47
                        +1

                        Документация должна описывать то что есть и работает.

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

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


                      1. BugM
                        29.05.2022 15:57

                        Ну, знаете, вот эти вот олдскульные ТЗ.

                        Мы живем в мире agile, user story, еженедельных релизов и фича флагов с экспериментами.

                        Стабильное ТЗ на продолжительной срок это уже много лет как что-то эфемерное. Бизнес уже сделал свой выбор что ему важнее.

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


                      1. powerman
                        29.05.2022 16:03

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

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


                      1. BugM
                        29.05.2022 16:23

                        Я люблю работать с людьми для которых ТЗ на двухнедельную фичу занимает абзац текста. Джуны или новички в команде это исключение. С ними работаем индивидуально.

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

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

                        Целевое состояние понятно. Подробные ТЗ написанные сверху в него никак не укладываются. Они убивают все развитие разработчиков и их активность. Такие разработчики не являются целевым состояние команды.


                      1. powerman
                        29.05.2022 16:35

                        Размер ТЗ на 2 недели определяется исключительно тем, сколько всего необходимо продумать для реализации этого функционала. Если это что-то типовое для этого проекта или вообще тупой CRUD - да, это может быть абзац текста. Если что-то достаточно сложное - ТЗ может быть детализировано вплоть до описания конкретного алгоритма, и займёт это далеко не один абзац. Тут важно то, что сколько бы не заняло ТЗ - оно не содержит воды и лишних подробностей, только то, что в любом случае пришлось бы продумывать при написании кода.


                      1. BugM
                        29.05.2022 16:50

                        И это все пишет тот человек который код писать будет. Потом только валидация что он дичь какую-то не придумал.

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

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


                      1. powerman
                        29.05.2022 19:23

                        А кто сказал что ТЗ за этого сениора пишет кто-то другой? Написание ТЗ перед реализацией - это просто поставленный процесс. (Кстати, большая часть моих комментов под этой статьёй - как раз про постановку правильных процессов.)

                        Если сениоры тянут написание ТЗ для собственных задач - пусть сами и пишут. ТЗ всё-равно потом проходит ревью/аппрув у бизнеса или архитекта.


                      1. dopusteam
                        29.05.2022 16:10

                        Как клиент отработает 500 если она всегда возвращается?


                      1. powerman
                        29.05.2022 16:25

                        Штатно - повтором запроса с экспоненциальной задержкой и/или уведомлением юзера. Я к тому, что клиент должен в любом случае иметь поддержку этой ситуации.

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


                1. BugM
                  29.05.2022 14:26
                  +1

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

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

                  Вера в волшебника на голубом вертолете который прилетит и все починит это очень наивно. И не работает на практике.

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

                  Что до правды - Вы правы. Если на проде одно API, а по доке должно быть другое - правда на проде. Но решать эту проблему (а это проблема!) нужно с другой стороны: поставить процессы так, чтобы на проде физически не могло оказаться что-то, что не описано в доке на API. Это довольно просто: любое изменение API сначала делается в доке, а уже потом в коде (в идеале - путём кодогенерации из доки).

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


                  1. powerman
                    29.05.2022 15:28

                    Вы только то поставили всю компанию в зависимость от одного человека. При этом того кто вероятно не в курсе конкретики того что в проде крутится.

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

                    При необходимости начальство кому-то откроет временный доступ, и кто именно будет руками это чинить - уже не так и важно. Важно, что свободный доступ к проду у разработчиков отсутствует, и что если он всё-таки понадобился - это не пройдёт незаметно для начальства.


                    1. BugM
                      29.05.2022 15:48
                      +1

                      Всё верно. Так и задумано

                      После этого на бизнесе можно ставить крест. Бизнес зависящий от одного человека нестабилен по определению. Мерфи говорит нам что проблемы будут именно в тот момент когда этот человек уехал на рыбалку в Сибирь и будет 4 дня без любой связи.

                      Важно, что свободный доступ к проду у разработчиков отсутствует, и что если он всё-таки понадобился - это не пройдёт незаметно для начальства.

                      Про незаметность я ничего никогда не говорил. Логи, аудит, возможно даже тикеты. Это хорошие практики одобренные всеми аудиторами.

                      Когда надо у кого-то что-то лично просить заметная часть разработчиков предпочтет сделать все чтобы этого не делать. Люди так устроены. Проблемы будут всеми силами заметаться под ковер, лишь бы не ходить и не просить кого-то. Особенно если проблема произошла около 4 утра по времени этого начальника которого надо просить.

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

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


                      1. powerman
                        29.05.2022 16:00

                        Бизнес зависящий от одного человека нестабилен по определению.

                        В моём варианте никакой зависимости нет. Есть кто-то ответственный, мимо которого доступ к проду получить нельзя. Но на его личность при этом ничего не завязано, и ответственного можно в любой момент поменять. Звонки в 4 утра - не проблема, если случаются раз в 2 года. А если руками в прод надо лазить чаще - то проблема совсем в другом.

                        Логи, аудит, возможно даже тикеты.

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

                        Более того. Всю эту инфраструктуру дающую доступ к проду с соответствующим аудитом - ещё надо построить. (Ни на одном мелком-среднем проекте я такой не встречал. А вот прод на этих проектах есть…) И строить её будут только если в ней есть необходимость. А необходимости такой быть не должно! И если она всё-таки есть, то у нас проблема где-то в другом месте, а вовсе не в отсутствии этой инфраструктуры.


                      1. BugM
                        29.05.2022 16:12

                        В моём варианте никакой зависимости нет. Есть кто-то ответственный, мимо которого доступ к проду получить нельзя.

                        Эти два предложения прямо противоречат друг другу. Вы уж определитесь.

                        Но на его личность при этом ничего не завязано, и ответственного можно в любой момент поменять.

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

                        Да, эти логи помогут когда-нибудь в будущем всё это отследить, но проблема "разработчикам регулярно надо руками чинить прод" есть уже сейчас, и сейчас её никто (из тех, кто должен в этот момент вмешаться и устроить разборки причин происходящего) не замечает.

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

                        Дальше как обычно. Тикет чтобы больше по этой причине не надо было, исполнитель и исправление причины в рабочем порядке.

                        Всю эту инфраструктуру дающую доступ к проду с соответствующим аудитом - ещё надо построить. (Ни на одном мелком-среднем проекте я такой не встречал. А вот прод на этих проектах есть…) И строить её будут только если в ней есть необходимость

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

                        Проблемы тут нет. Это нормальная плата за гибкость и быстроту развития. Надо ее просто принять и платить. Когда/если бизнес вырастет, то значит пора строить инфраструктуру аудита, безопасников и все вокруг. Когда именно это надо делать видно только местному высокому руководству. Это тоже нормальная плата за вырастание бизнеса. Ее просто надо заплатить когда придет время.

                        Строить небольшой бизнес по критериям банка не выйдет. Вас обойдут ребята с прямым доступом в прод и игнорированием всей безопасности. Просто за счет более быстрого развития и большей гибкости. Ваш бизнес будет полностью безопасным и мертвым.


                      1. powerman
                        29.05.2022 16:29

                        Я прекрасно знаком с описываемым Вами подходом. И даже сам так делал лет 17 назад.

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


                      1. BugM
                        29.05.2022 16:43

                        Ваш подход тоже имеет право на жизнь. Главное понимать когда именно.

                        Если вы делаете Google ID, то да. Доступы минимизируем максимально. Звонки руководителям в 4 утра считаем неизбежным злом, выдаем спутниковые телефоны всем ответственным. Платим людям за это все. И миримся с замедлением разработки. Это нормальная плата за максимизацию безопасности.

                        А вот если вы делаете очередной интернет магазин или очередную CRM то зачем все это? Вам надо выжить в конкуренции с другими 100500 магазинами. Платить за максимизацию безопасности нет смысла, вероятность погибнуть проиграв конкуренцию заметно выше.

                        По моим наблюдениям разработку замедляет как раз наличие доступа к проду - чинить так быстрее, только вот потом приходится разгребать последствия ручного ковыряния прода, которые вылезают далеко не сразу, и времени это съедает довольно много.

                        А вот тут я не согласен. Нужен процесс разгребания того что делалось в проде руками. Этот процесс может быть разным. Зависит от конкретного этапа развития бизнеса. Степень его формализации тоже может быть разной.

                        В стартапе на 5 разработчиков процесса "в пятницу за пивом на уровне байки рассказали" хватит.

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

                        Любые промежуточные варианты тоже возможны.


                      1. powerman
                        29.05.2022 19:33
                        -1

                        А вот если вы делаете очередной интернет магазин или очередную CRM то зачем все это?

                        Затем, что, как ни парадоксально, так писать быстрее. Реализация появляется чуть медленнее, но в сумме время разработки экономится за счёт меньшего количества проблем, багов и потерь времени на расследования инцидентов и отладку.

                        Конечно, если просто запретить доступ к проду - такого эффекта не будет, наоборот, всё станет хуже. Но в комплексе с рядом других процессов - ТЗ (и вообще documentation-first, включая доку на API с кодогенерацией), CI/CD, автоматизированные миграции БД, правильные юнит-тесты и немного интеграционных, обязательные и тщательные ревью - картина кардинально меняется.


                      1. BugM
                        29.05.2022 21:58
                        +1

                        Но в комплексе с рядом других процессов - ТЗ (и вообще documentation-first, включая доку на API с кодогенерацией), CI/CD, автоматизированные миграции БД, правильные юнит-тесты и немного интеграционных, обязательные и тщательные ревью - картина кардинально меняется.

                        Вы точно работали в чем-то небольшом и стартапоподобном? Или хотя бы в среднем, а конкурентном рынке?

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

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

                        PS: Исключения вроде CI/CD могут быть, я в целом про картину.


                      1. powerman
                        30.05.2022 00:51
                        +1

                        Точно работал, и сейчас в таком работаю.

                        По моим наблюдениям "в сумме время разработки" с этими процессами догоняет разработку в стиле "быстро-грязно" за 2-3 месяца, если небольшая команда (4-5 человек) уже умеет работать по этим процессам, и через полгода, если не умеет и учится на ходу. Цифры относительно с потолка, разумеется, потому что одновременно в обоих подходах один и тот же проект никто не делал, но порядок примерно такой. Для стартапа это вполне приемлемо.

                        И дело не в стабильности или безопасности, а в том, на что конкретно тратится время разработки.

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

                        В одном из выступлений дяди Боба был отличный пример: любую задачу можно сдать во-время, просто закоммитив то, что готово (у него в примере это был вообще пустой файл без кода). А на вопрос тестировщиков "а где же фича?" ответить "это баг! сейчас буду чинить…" и тем самым получить дополнительное время на разработку.

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

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

                        При другом подходе картина совсем иная: код пишется не так быстро (доку сначала надо написать, API спроектировать до кода, а, главное, понять что же мы пишем и как оно должно работать!), но зато на порядок меньше времени уходит на переделки, отладку и багфиксы. А ещё лучше то, что время на переделки, отладку и багфиксы практически не увеличивается по мере роста проекта. Поэтому, если измерять время разработки по скорости появления полноценно рабочей бизнес-фичи в проде - этот подход очень быстро обгоняет быстро-грязный даже в стартапах.

                        Скорее всего, Вы в это не верите. :) И я даже догадываюсь почему: в тех проектах, которые Вы наблюдали лично или слышали от знакомых, попытка писать нормально заканчивалась обычно очень плохо: куча времени уходила непонятно на что и стартап просто не доживал до прода. Так происходило потому, что всё вышеописанное нужно уметь делать, а большинство разработчиков этому никогда не учили и даже не говорили, что всё это нужно делать в принципе. Чтобы это работало на проекте нужен нормальный архитект, нужно понимать как писать ТЗ чтобы это не было тратой времени на никому не нужные и неактуальные документы, как писать юнит-тесты чтобы они ускоряли разработку а не съедали время разработки впустую… Если всего этого нет - попытка писать так, как я предлагаю - ничем хорошим для проекта не кончится.

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


    1. Stas911
      29.05.2022 05:03

      Дык все уже придумано давно и инструменты это поддерживающие были еще в прошлом веке (типа PowerDesigner, ERwin и тд). Тот же Sparx EA позволяет сколь угодно сложные взяимосвязи моделировать и я работал в паре контор, где в нем были сделаны огроменнейшие модели всех сервисов, систем и интерфейсов между ними. Проблема, что с waterfall это еще как-то работает, а вот с agile я уже такого не видел. Ну и плюс огромная трудоемкость поддержания всего этого в адекватном состоянии.


      1. vagon333
        29.05.2022 05:35

        Благодарю за коммент.

        Приходится работать со Sparx EA и ER Studio DA (в Sparx схема и в ER Studio рисуем ERD всей банковской системы штатов). Неудобный зоопарк.
        Функционал Sparx и ER Studio - не то, что я описывал, не покрывает нужный функционал.
        Помимо этого, эти виндовые продукты довольно тяжелые, не поддерживают многопользовательский доступ и модификацию.
        Насчет ERwin - был хорош в 90ые годы, да и Sparx тоже архаичный. :)

        Повторюсь: я про БД с метаданными, описывающую схему, сервисы, процессы, тестовые данные, моки сервисов и симуляцию процессов.
        К этой БД прикручивается необходимый функционал.

        В текущем проекте большая часть вышеописанного реализована и результаты продуктивности высокие. Над остальными работаем.
        С таким подходом микросервисы не выглядят unmanageable, хоть и значительно сложнее монолитов.


        1. Stas911
          29.05.2022 06:19

          Sparx конечно архаичный, но совместную работу давным-давно поддерживает через СУБД. У нас вроде и через SVN репо работало тоже лет 10 назад.

          Но я понял о чем вы, из модели Sparx эти данные по-простому не добыть.


  1. AlexunKo
    29.05.2022 01:28
    +1

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


  1. Alexrook
    29.05.2022 13:21

    Но честно, уж лучше микросервисы, чем монструозных монолит. У меня на работе есть такой монстр и он уже давно устарел, но слезть с него уже не выходит, так как весь его функционал тесно взаимосвязаны и переводить какой-то функционал частично на новые рельсы крайне сложно. Микросервисы можно постепенно переписывать и подменять, тут так не выйдет. В результате принято решение ничего не трогать и работать с тем, что сеть. А это совершенно жуткая корпоративная система, через которую прошли десятки разных разработчиков со своим подходом. В результате в системе присутствуют и многие минусы, озвученные для микросервисов. Например, дублирование функционала. Ты можешь в совершенно разных местах встретить аналогичный функционал. Это потому, что некоторым разработчикам лень искать, реализован этот функционал в системе или нет. А с самого начала это все слабо документировалось. Плюс ли, что весь функционал написан на одном языке? Скорее нет, так как одни языки и фреймворки сильны в одном направлении, другие в другом. А тут встречается куча каких-то костылей. В результате получаем очень связанную CRM систему, систему управления производством и систему управления документооборотом, с которой очень трудно слезть. По сути требуется переписать ее полностью, разбив на подсистемы. Этим должна заниматься команда с отсутствием текучки, что в современных реалиях трудно достижимо. Чтобы понять систему хотя бы в первом приближении уходит год. То есть потеря ключевых участников команды может просто убить проект. А у нас ИТ отдел крайне нестабилен. Если посмотреть, большинство специалистов отрабатывают от 2х до 3х лет. И напомню, что только после первого года работы приходит понимание, как работает система. То есть сейчас и не понятно, с какой стороны к этому всему подойти.


  1. ZhilkinSerg
    29.05.2022 15:44

    сколько орехов нужно собрать, чтобы получилась целая куча.

    Четыре. Не благодарите.