Comments 7
про критический путь.
По сути, это реализация паттерна «Адаптер» на уровне модулей.
"Медиатор" же. "Адаптер" как раз в первом примере.
Последний вариант действительно очень мощный, но и неоправданно сложный. Особенно в больших проектах. При прочих равных его выбирать не стоит. Разница между вторым и третьим вариантом описывается разницей между оркестровкой и хореографией (это как раз из теории распределенных систем, о которых Вы в выводах упоминаете). Там вроде даже правило есть, что без особой необходимости надо предпочитать оркестровку (т.е.второй вариант из Вашей статьи).
Вот конкретно я бы хотел почитать про графы, артефакты сборки (не смотрели в сторону Nexus?) и все перечисленные Вами инструменты. Ссылки Вы дали (и спасибо за них), но хочется опыт и проблемы.
Какой, кстати, способ уменьшения критического пути выбрали? Я бы вот почитал еще и про сравнение второго и третьего пути. Оно пока интуитивное. Хоть я выше и дал некоторые ссылки, но однозначно утверждать пока не решаюсь. Эту статью бы тоже почитал, если у Вас есть информация.
Не функциональные зависимости как-то можно изолировать? Откуда эта градация? можно ссылку? Есть там что-то про то, как их влияние минимизировать? Те же адаптеры или что-то еще?
В заключение.
Статья – просто огонь. Давно не получал такого удовольствия от чтения материалов с Хабра. Настоящий инженерный труд. Спасибо за него. Ответить бы на мои вопросы выше – получится еще и отличный научный труд. ^.^ Ждем следующих статей.
Спасибо большое за такой развернутый комментарий и фидбек. Ниже постараюсь ответить на часть вопросов. Более того, на основе вопросов частично дополню текущую статью, остальное - учту в следующем материале.
Итак, к ответам.
Про критический путь.
В первом случае нет никакого паттерна — просто прямое общение, без оптимизаций, на основе доменной логики, за исключением разбития по слоям, и настройки взаимодействия модулей из разных слоев между собой.
Этот пример нужен для начала размышлений об оптимизациях.Про «Медиатор» — хороший поинт. Вы абсолютно правы. Но я немного уточню. Я парадигмально размышляю так:
- Действительно модуль верхнего уровня является «Медиатором» для общения модулей нижнего слоя между собой, устраняя связанность этих модулей между собой.
- В тоже время, нужно учитывать, что модули нижнего модуля в момент оптимизации, скорее всего знают, как общаться между собой. И за счет инверсии зависимостей, чаще всего, выделяются объекты/методы взаимодействия, которые модуль верхнего уровня «адаптирует». То есть запросы/методы от каждого из модулей «адаптируются» в АПИ соседнего модуля, с которым нужно взаимодействовать.
- Поэтому я расширю описание этого пункта и добавлю проведения аналогии с «Медиатором» для прозрачности.
Последний вариант действительно несет много накладных расходов на разработку: усложняется DI и появляются сущности API модулей.
И тут мое мнение, что при маленьких и средних проектах его внедрение сложно оправдать.
Все изменяется когда проект подходит к размерам большого. Часто проекты приходят к этому «эмпирически», но я бы тут отметил правило, что это происходит тогда, когда компиляция при разработке продуктовых фичей начинает влиять на Time to market.
В таком случае, и это тот путь, к которому сейчас идем мы внутри нашего проекта, API/IMPL подход применяется к фиче-модулям, то есть к тем модулям, где происходит около 90% всей разработки и 99% продуктовой разработки.
Просто потому, что поддержав для конкретного продуктового модуля API/IMPL один раз, потратив на это время, продуктовая команда сильно экономит на расходах при разработке в этом модуле, за счет компиляции и, как правило, «правильнее» подходит к проектированию API модуля.
Думаю что мы можем немного расширить статью, включив в нее терминологию оркестрации и хореографии. Для дополнительной аналогии.Мы используем Nexus для кеширования зависимостей, чтобы изолировать наш внутренний контур от интернета. Также мы решаем проблемы кибербезопасности — артефакты на Nexus проверяются отделом КБ на предмет уязвимостей.
Уточните пожалуйста по этому вопросу, что конкретно хотелось бы узнать/прочесть? Постараемся учесть ваши пожелания в будущей статье.Мы долгое время уже живем как раз в реалиях хореографического принципа. Но, как отметил выше, идем в сторону API/Impl на уровне фиче-модулей. Причем тут задача платформенной команды объяснить продуктовым командам как работать в этом подходе и внедрить или помочь внедрить подход в продуктовый модуль.
Причина: рост проекта и снятие метрик и настроения разработчиков касательно времени компиляции.
Мы расскажем о конкретных решениях и истории нашего пути в следующей статье.Градация выведена внутри нашей команды. Если быть точным — мной. И отлично относится к критике. Не могу тут, к сожалению, поделиться ссылкой.
Я думаю, что в абсолютном большинстве случаев изолировать не удастся и такая зависимость прочно укрепится в вашем технологическом стеке и будет влиять на ваш найм.
Решение тут почти во всех командах, где я работал, приходит к тому, чтобы просто при устаревании технологии, помечать ее deprecated (в вашем технологическом радаре) и планово (в рамках технического долга или других практик устранения Legacy кода), устранять/переходить на новые технологии.
1.1 Все же это адаптер получится по факту, т.к. вы примените принципы разбиения на слои, как Вы написали. Верхний не будет взаимодействовать с нижним, их интерфейсы не совместимы. При этом между ними и будет некая часть, которая их соединяет. В чистом виде - адаптер. Правда, в этом случае там будет еще куча функционала и будет нарушен принцип единой ответственности. Но функционал адаптера там точно есть.
1.2 Понял, адаптером Вы его назвали только из-за функции адаптации данных.
Но поглядите, что медиатор тоже "адаптирует" сигналы от одного модуля к другому и обратно. Из-за этого он не становится адаптером. Медиатор от адаптера как раз расположением в слоях и зависимостью различаются (кто выше, кто ниже, кто от кого зависит). Блок1 -> Адаптер -> Блок2 против Блок1 <- Медиатор -> Блок2. Это ключевое и, кажется, единственное, отличие между ними.
Ну, кажется, подробности того, как вы это все настроили, как оно работает, какие проблемы, какие выгоды. Почему именно так, а не иначе. Какие вообще варианты рассматривали, какие критерии выбора и т.д. Скрипты, утилиты и т.д. Советы.
Жду следующую статью. Там обсудим предметно. Но пока мы вот наоборот от хореографии обратно в оркестровку предпочитаем все возвращать (на медиаторах, не на адаптерах, это важно), ибо проще. Даже в большом проекте. У хореографии единственный плюс – когда есть шина и общий формат общения. Возможно, это ваш случай. Но если это не ваш случай, то осветите, пожалуйста, этот момент в следующей статье очень детально. Возможно, откроете для себя ошибки.
Спасибо за подробные ответы.
Дополнил статью в соответствии с комментариями по различиям между "Адаптацией" и "Посредничеством".
По вопросам оркестрации и хореографии вынесем разбор подходов и детали реализации в следующую статью.
И спасибо большое за вашу вовлеченность в обсуждение!
>что ĸаждый модуль А, от ĸоторого напрямую зависит модуль Б, будет заставлять модуль Б переĸомпилироваться при ĸаждых изменениях в модуле А. Одновременно с этим модуль А не позволит модулю Б встать в очередь на ĸомпиляцию, до тех пор поĸа не сĸомилируется сам, то есть страдает параллелизация сборĸи.
>Чем больше модуль А, тем дольше мы откладываем компиляцию модуля Б. Если есть возможность разбить модуль Б на более мелкие и независимые модули Б1 и Б2, изменения в модуле Б1 заставят пере-компилироваться модуль А, но модуль Б2 перекомпилировать не потребуется
Если изначально проблема была в том, что А заставляет перекомпилироватсья Б при изменениях в А, то как вышло что потом мы разбили модуль Б на сабмодули, и теперь Б1 заставляет перекомпилироваться А?
Многомодульное iOS-приложение: подходы к организации межмодульного взаимодействия