• Нет, у меня нет сторонних проектов, чтобы вам показать
    0

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

  • Нет, у меня нет сторонних проектов, чтобы вам показать
    0

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

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

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

  • Нет, у меня нет сторонних проектов, чтобы вам показать
    0

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


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

  • Нет, у меня нет сторонних проектов, чтобы вам показать
    +1

    Как уже упоминалось в комментах — есть куча классических исследований на эту тему. Сто не сто, но в десять а то и десятки раз — такие цифры результаты этих исследований действительно выдавали. Хотите более конкретно — посмотрите у Макконнелла, он кучу такой статистики в Code Complete приводит, со ссылками на конкретные исследования.


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

  • Альманах пакетных менеджеров Linux
    +3

    Ещё из достаточно популярных есть apk — используется в Alpine Linux, который часто встречается в контейнерах докера.


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

  • Нет, у меня нет сторонних проектов, чтобы вам показать
    +11

    Дело вовсе не в том, что надо в чём-то обязательно участвовать. Это получается само собой — при определённом подходе к работе. И, соответственно, наличие PRов в сторонние библиотеки и собственных проектов служит индикатором этого подхода к работе. А подход очень простой:


    • Сейчас практически не существует проектов, которые не используют сторонние опенсорсные библиотеки/утилиты. А когда используешь что-то в таких количествах — обычно сталкиваешься с проблемами. И при наличии достаточной квалификации нередко проще решить проблему самостоятельно — форкнув и пофиксив что нужно. Мы все это постоянно делаем. Вопрос в том, что будет сделано дальше: будет ли этот фикс правильно оформлен и отправлен PRом в оригинальный проект? Компании тратить на это свои ресурсы выгодно по ряду причин (качество фикса/фичи увеличится если её отревьювит автор проекта, а главное дальнейшая поддержка этого изменения будет на авторе, а не на нашей компании). Так что если этого не делается, то либо изменение кривое и вы заранее знаете, что автор его не примет, либо не хватает квалификации корректно его оформить (угу, дока, тесты, кодстайл — всё это действительно необходимо для дальнейшей поддержки этого изменения, кто бы ей не занимался), либо не хватает ума объяснить начальству почему компании это выгодно (и не хватает ума работать в компании, в которой это и так понимают). И какова бы не была причина — в любом случае это минус лично Вам.
    • При правильной декомпозиции в большинстве задач возникают небольшие универсальные кусочки, не связанные с бизнес-логикой текущего проекта. Если такие куски не оформлять полноценными библиотеками, с докой и тестами — этот код быстро загниёт и не будет повторно использоваться даже в проектах этой же компании, так что нормально оформлять эти библиотеки компании выгодно. А дальше их можно выложить в публичный доступ — выгода от этого для компании уже не столь очевидна, но она есть — плюс в карму, больше привлекательности для сильных разработчиков работать в этой компании, возможность дополнительно пиариться на этих проектах, и если эти проекты заинтересуют кого-то ещё то сторонняя бесплатная помощь в развитии этих проектов, … (здесь троеточие не потому, что больше нечего добавить, а потому что многое зависит от специфики и размера компании — например когда крупная компания выкладывает свои инструменты/фреймворки в паблик у неё появляется возможность со временем нанимать людей уже знакомых с используемыми в компании инструментами/фреймворками). Отсутствие же таких проектов говорит либо о том, что у вашей компании проблемы с корректной декомпозицией или оформлением библиотек, либо о том, что компания пока не доросла до осознания пользы от выкладывания таких проектов в паблик. В первом случае это минус и Вам, во втором нет, но… как говорится, серебряные ложечки нашли, но осадочек всё-равно остался.
  • Нет, у меня нет сторонних проектов, чтобы вам показать
    +1

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

  • Модули вместо микросервисов
    0

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

  • Вашим пользователям не нужны пароли
    –1

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

  • Вашим пользователям не нужны пароли
    +1

    Некоторые делают: webmoney, startssl. Геморроя с этими сертификатами — море. Нет, после регистрации всё неплохо, сертификат установлен в браузер и дальше логиниться несложно. Но чтобы не остаться без доступа приходится из браузера этот сертификат выковыривать, сохранять в отдельный файл, при этом его шифруя паролем (который ещё нужно добавить в менеджер паролей, угу), импортировать его в другие свои браузеры (а что, если доступ нужен с чужого компа, кстати?) и потом ещё не забывать обновлять эти сертификаты (во всех браузерах, чтобы не скучно было) раз в 1-3 года. Спасибо, но нет!

  • Вашим пользователям не нужны пароли
    0

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

  • Вашим пользователям не нужны пароли
    0

    Я в курсе. И? К чему Вы это сказали?

  • Вашим пользователям не нужны пароли
    0

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


    Что касается большого срока жизни сессии — какая разница, надо вводить пароль или нет, если это надо делать раз в год?


    Ну и последнее, про менеджеры паролей. По-хорошему, если уж Вы заботитесь о безопасности пользователей, то нужно наоборот, приучать и стимулировать использовать менеджеры паролей. Что касается сложности в использовании — то с тем же KeePass всё наоборот намного проще, чем в Вашей схеме — когда я вижу форму логина на сайте я нажимаю Ctrl-Alt-A и… всё. KeePass сам определяет что это за сайт, сам вводит логин/пароль или что на этом сайте нужно, и сам отправляет форму. Так что вся "сложность" использования менеджера паролей заключается в однократном добавлении записи о новом сайте при регистрации (с процессом которой KeePass так же помогает генерируя пароль).

  • Модули вместо микросервисов
    0
    и натыкаться на потерю запросов, зависание запросов, нарушения порядка запросов

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


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

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


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

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


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


    К тому же сетевое взаимодействие у вас все равно осталось, с клиентами, с вешними сервисами, между инсталляциями и т.д., так что код для сетевого взаимодействия у вас никуда не делся.

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


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

    Не совсем так. Невозможность полезть напрямую в базу другой части монолита не приводит к eventual consistency — ведь для доступа к данным всё-равно вызывается какой-то локальный метод, и какой части монолита он принадлежит — значения не имеет. Eventual consistency возникает не из-за разделения данных, а из-за уменьшения скорости доступа к ним: там, где вызов локальной функции не проблема, делать сетевой запрос так часто, как часто нужны данные, обычно нет возможности.


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


    Упомянутое Вами нарушение консистентности — слишком общее понятие. Там, где оно было вызвано eventual consistency — оно исчезнет. Там, где оно было вызвано необходимостью делать транзакции — если транзакции есть, пусть даже и распределённые — с консистентностью данных всё в порядке, а там, где распределённые транзакции решили не делать — с консистентностью будут одинаковые проблемы и в обычном и во встроенном микросервисе.


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

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


    плюсы: отсутствие сетевого слоя

    Не отсутствие, как уже описано выше.


    минусы: отсутствие раздельного деплоя,

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


    отсутствие разделение аппаратных и программных ресурсов,

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


    распределенные системы только полной установкой,

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


    длительная сборка и деплой,

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


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


    Кроме того, в том же Go сборка работает нереально быстро, так что разница между сборкой одного или десятка микросервисов — будет в несколько секунд… а в других языках для ускорения сборки большого проекта есть много других средств, от make до ccache.


    ограничение на выбор инструментов и языков,

    Да. Но это не проблема, если всё это и так уже используется.


    только единая среда выполнения

    Да. Как и в любом монолите, и редко это создаёт сложности.


    и общие зависимости,

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


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

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


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

    Нет. В этом-то вся фишка. Эти проблемы встраивание микросервисов как раз и решает!

  • Модули вместо микросервисов
    +2

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


    • Возможность упростить кучу кода, занимающегося отправкой запросов в другие сервисы: выкинуть таймауты, обработку сетевых ошибок, разделение на идемпотентные и не идемпотентные запросы с разной логикой их повтора при ошибках и защиту от дубликатов, саму логику повтора с задержками и защитой от бесконечного повтора, асинхронное выполнение запросов.
    • Возможность упростить архитектуру, реализацию и улучшить юзабилити — во многих (а то и всех, если повезёт) местах, где в обычных микросервисах возникает eventual consistency.

    Это — для меня основное. Есть ещё всякие мелочи, вроде упрощения: рефакторинга проекта в целом, использования монорепо, изменения внутренних API между встроенными микросервисами, интеграционного тестирования.


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


    Основной недостаток — неприменимость этого подхода в большинстве проектов, где действительно необходима высокая доступность и/или масштабирование (в меньшинстве возможно удастся выкрутиться запустив несколько одинаковых монолитов).


    Что касается мелких подробностей вроде общего конфига — я вообще не понимаю, в чём проблема. Чаще всего конфиг находится либо в переменных окружения, либо передаётся аргументами при запуске приложения (а если он был в файле или распределённой БД — там его и оставьте, ничего страшного что у монолита будет кучка конфиг-файлов вместо одного). Встраивание нескольких микросервисов в монолит означает только то, что выбирая имена для переменных окружения и/или аргументов командной строки нужно использовать префиксы-namespace чтобы исключить конфликты между разными встроенными микросервисами. Это — проблема, достойная обсуждения и отказа от возможности выкинуть всю вышеупомянутую сложность? Серьёзно? Странно, а больше похоже на троллинг. Мержи изменений? Каких? Кода в main() разбирающего аргументы и вызывающего Init() каждого микросервиса? Это — проблема? А как Вы вообще код пишете больше чем одним разработчиком на проекте? Где Вы увидели издержки на коммуникацию — я не понял, вся коммуникация находится на уровне обсуждения публичного API микросервисов, как всегда. Выделить проект отдельному сотруднику ровно настолько же просто — встроенный микросервис вполне возможно писать и тестировать в отдельном репо, как обычную библиотеку. Деплоить его отдельно нельзя — это правда, но разработке это не сильно мешает.


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

  • Модули вместо микросервисов
    +1

    Конкретные средства развёртывания и управления сервисами к микросервисной архитектуре отношения не имеют.


    Слова "у нас архитектура микросервисов" в голове понимающего слушателя формируют примерно такое впечатление: "ага, ясно, кучка мелких проектов, так что с кодом возиться будет не очень сложно, очень вероятно что бардак с архитектурой и связями между микросервисами — надо обязательно уточнить как в этом проекте с eventual consistency и распределёнными транзакциями — плюс выяснить что из себя представляют местные девопсы, как справляются, и есть ли они вообще". :)


    И NoSql в конейнере и рдбмс вне контейнера (это стандартная рекомендация docker) всё микросервисы. И одинокий сервис генерации id вдали от монолита — тоже типа микросервис.

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


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

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


    Практический вопрос: вот представляют мне систему и говорят «у нас она на микросервисках», какой вопрос задать, чтобы он не повисал в воздухе? Потому что «докер используете» обычно неприятно повисает (если докер не используется).

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

  • Модули вместо микросервисов
    0

    Причём тут "произвести впечатление", что за глупости? Причина использования более корректного термина в том, чтобы точнее описать суть, а не в том, что этот термин на кого-то может произвести впечатление.


    Основная причина выбора термина "микросервис" вместо SOA отлично описана у того же Фаулера в боковой врезке.

  • Модули вместо микросервисов
    0

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

  • Модули вместо микросервисов
    0

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

  • Модули вместо микросервисов
    0

    Очень просто они выглядели, ровно так же, как и сейчас:


    • программка на любом языке
    • запущенная под управлением какого-нибудь супервизора (runit, daemontools, s6, …), который будет её гарантированно перезапускать после падения
    • зарегистрировавшаяся в каком-нибудь сервисе выполняющем роль реестра сервисов и использующая его для обнаружения других сервисов
    • предоставляющая REST или RPC API на нестандартном порту, возможно с nginx перед группой таких сервисов
    • имеющая личное хранилище данных (обычно либо в файлах, либо в SQL/NoSQL базе) если оно ей вообще нужно
    • записывающая лог в файл (обычно через дополнительную утилиту вроде собственного syslog-совместимого сервиса или просто тулзы вроде svlogd), с опциональным дублированием записей лога через UDP в сторону сетевого syslog-сервиса для агрегирования логов
    • сервисы старался делать как можно меньше (например есть у меня сервис, который выдаёт уникальные ID для остальных сервисов, и больше ничего не делает)

    Придумал я этот подход пытаясь симулировать то, как работают приложения в OS Inferno — только в OS Inferno были лёгкие нити и каналы для взаимодействия приложений запущенных на одной машине, плюс файловый сетевой протокол Styx для взаимодействия приложений запущенных где угодно — хоть на одной машине, хоть на разных. А на Perl у меня тогда ничего этого не было, поэтому для получения нужного уровня изоляции и коммуникации между сервисами пришлось использовать сетевые RPC-протоколы (в основном, иногда REST). В качестве сервиса реестра-сервисов я запускал приложение файл-сервер registry из OS Inferno, добавив к нему обёртку которая предоставляла доступ к его файлам (файлы были внутри виртуальной машины OS Inferno) по TCP, плюс написал модуль для Perl Inferno::RegMgr чтобы подключаться к этому реестру из своих Perl-сервисов (плюс использовал ещё один сервис из Inferno для авторизации между сервисами).


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


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


    P.S. Что касается подвоха — когда я сам задался вопросом "а сколько же лет я уже пишу микросервисы" то я сам выяснял это по датам своих же коммитов, например того же Inferno::RegMgr. У меня воспоминания что я это делал и до 2009, но фактические подтверждения удалось найти только начиная с 2009 — вероятно до этого были в основном эксперименты, а не применение в реальных проектах.

  • Модули вместо микросервисов
    –1

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

  • Модули вместо микросервисов
    0
    То что к одному прикрутили, к другому забыли.

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


    Один написали в одном стиле, а другой в другом

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


    А когда нужно что-то поменять что аффектит несколько микросервисов

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

  • Модули вместо микросервисов
    0

    Это в теории. Может, ещё лично в Вашей практике, с конкретной командой/начальством. У меня вот с практикой тоже всё в порядке, особенно пока код кроме меня пишет 1-2 человека и я успеваю и свою работу делать и их работу проверять. Но это скорее исключение, а не правило.


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


    Существует множество техник, которые помогают писать хороший код — включая такие тривиальные как стараться избегать goto и глобальных переменных. Это не означает, что если эти техники игнорировать то нельзя написать хороший код — можно. Равно как и использование и goto и глобальных переменных в некоторых случаях необходимо чтобы код стал лучше. Но, в большинстве случаев, применение этих техник очень помогает, и без них было бы хуже. Раскладывать по папочкам это хороший старт, но если добавить к этому компилятор, который не даст лазить в чужие папочки — станет ещё лучше. Можно использовать соглашение "свойства объекта начинающиеся на подчёркивание снаружи класса использовать нельзя", а можно явно объявить их не экпортируемыми/приватными/защищёнными и не волноваться о том, что кто-то, специально ради быстро-грязной фичи или нечаянно, всё-таки в эти свойства полезет снаружи. Гвозди можно забивать подручными предметами, но молотком обычно удобнее.

  • Модули вместо микросервисов
    0

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


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


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

  • Модули вместо микросервисов
    +2

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

  • Модули вместо микросервисов
    0

    На самом деле, когда я начал писать обычные микросервисы (в 2009, когда ещё и термина такого не существовало), я пытался симулировать архитектуру OS Inferno, где тоже лёгкие нити, каналы, процессов нет вообще а вместо них обычные модули выполняющиеся в лёгких нитях. Сеть тогда пришлось всунуть между модулями-микросервисами только потому, что больше ничего не давало необходимого уровня изоляции (я тогда писал на Perl). А сейчас хочется вернуться обратно к варианту, когда для взаимодействия микросервисов сеть не обязательна, благо у Go и OS Inferno немало общего. И да, Erlang тоже в этом смысле очень хорош и умеет всё необходимое из коробки.

  • Модули вместо микросервисов
    0

    А, в этом смысле. Да, можно вместо каналов использовать, например, pipe(2) или socketpair(2). Это не так здорово, потому что придётся тратить ресурсы на (де)маршалинг, плюс в зависимости от выбранного формата передачи данных можно и строгую типизацию потерять.

  • Vim спустя 15 лет
    +3

    Теги не читают, по ним ищут. Спасибо за перевод.

  • Модули вместо микросервисов
    0
    • Уменьшается скорость запуска (разогрев кешей, etc.).
  • Модули вместо микросервисов
    0

    Нельзя. Через loopback — это всё-равно сеть. И все ошибки, которые бывают при обычном сетевом взаимодействии, бывают и на loopback (может не все, а почти все, но это не помогает).

  • Модули вместо микросервисов
    –1

    Может и лучше. Надо экспериментировать на практике.

  • Модули вместо микросервисов
    –1

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

  • Модули вместо микросервисов
    0

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


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


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


    Тем не менее, раз у Вас есть реальный практический опыт — поделитесь проблемами, которые возникали в процессе использования этого подхода?

  • Модули вместо микросервисов
    0

    Как я упомянул в статье, я лично в таком стиле пока ещё не писал, но тут в комментариях отписывались люди, которые нечто подобное уже используют — вопрос про недостатки это скорее к ним. Я в статье постарался описать недостатки, которые очевидны сходу, и уменьшение скорости запуска приложения там есть.

  • Модули вместо микросервисов
    +1

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

  • Модули вместо микросервисов
    0

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


    Проблема с ослаблением уровня изоляции в том, что тогда изоляцию нужно поддерживать не с помощью языка и/или инструментов, а исключительно внутренней дисциплиной разработчиков. К сожалению, факты говорят о том, что если писать монолитное приложение полагаясь на дисциплину — в большинстве случаев всё-равно со временем получается big ball of mud.

  • Модули вместо микросервисов
    0

    Зависит от языка. Например, на Go, на низком уровне это может выглядеть вот так:


    // создаём канал, по которому придёт ответ на конкретно этот запрос
    replyc := make(chan SomeRPCReply)
    // отправляем наш запрос (включающий параметры конкретного RPC и
    // только что созданный канал для ответа) в канал ведущий в другой модуль
    someModule.SomeRPC <- SomeRPCParams{ 42, replyc }
    // ожидаем и принимаем ответ - содержащий либо ошибку либо результат
    reply := <- replyc

    Как Вы понимаете, нет никакой проблемы завернуть всё это в функцию, чтобы сделать удобно:


    func someModule_SomeRPC(id int) (SomeRPCResult, error) {
        replyc := make(chan SomeRPCReply)
        someModule.SomeRPC <- SomeRPCParams{ id, replyc }
        reply := <- replyc
        return reply.Result, reply.Error
    }

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

  • Модули вместо микросервисов
    +2

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


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


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


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


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

  • Модули вместо микросервисов
    0

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