Принципы модульного программирования программных продуктов во многом сходны с принципами нисходящего проектирования. Сначала определяются состав и подчиненность функций, а затем – набор программных модулей, реализующих эти функции.
Однотипные функции реализуются одними и теми же модулями. Функция верхнего уровня обеспечивается главным модулем; он управляет выполнением нижестоящих функций, которым соответствуют подчиненные модули.
При определении набора модулей, реализующих функции конкретного алгоритма, необходимо учитывать следующее:
каждый модуль вызывается на выполнение вышестоящим модулем и, закончив работу, возвращает управление вызвавшему его модулю;
принятие основных решений в алгоритме выносится на максимально «высокий» по иерархии уровень;
для использования одной и той же функции в разных местах алгоритма создается один модуль, который вызывается на выполнение по мере необходимости.
В результате дальнейшей детализации алгоритма создается функционально-модульная схема (ФМС) алгоритма приложения, которая является основой для программирования (рис. 18.3).
Архитектура ПО. Введение
Рис. 18.3.Функционально-модульная структура приложения
Пример 18.5.Некоторые функции могут выполняться с помощью одного и того же программного модуля (например, функции Ф1 и Ф2).
Функция Ф3 реализуется в виде последовательности выполнения программных модулей.
Функция Фm реализуется с помощью иерархии связанных модулей.
Модуль n управляет выбором на выполнение подчиненных модулей.
Функция Фх реализуется одним программным модулем.
Состав и вид программных модулей, их назначение и характер использования в программе в значительной степени определяются инструментальными средствами. Например, применительно к средствам СУБД отдельными модулями могут быть:
экранные формы ввода и/или редактирования информации базы данных;
отчеты генератора отчетов;
стандартные процедуры обработки информации;
меню, обеспечивающее выбор функции обработки и др.
Алгоритмы большой сложности обычно представляются с помощью схем двух видов:
обобщенной схемы алгоритма – раскрывает общий принцип функционирования алгоритма и основные логические связи между отдельными модулями на уровне обработки информации (ввод и редактирование данных, вычисления, печать результатов и т.п.);
Наиболее часто детально проработанные алгоритмы изображаются в виде блок-схем согласно требованиям структурного программирования; при их разработке используются условные обозначения согласно ГОСТ 19.003-80 ЕСПД (Единая система программной документации). Обозначения условные графические, ГОСТ 19.002-80 ЕСПД. Схемы алгоритмов и программ. Правила обозначения.
Дата добавления: 2021-12-14 ; просмотров: 163 ; ЗАКАЗАТЬ НАПИСАНИЕ РАБОТЫ
Источник: poznayka.org
Модульное программирование
1. Марченко А.И., Марченко Л.А. Программирование в среде Turbo Pascal 7.0. – 8-е изд. – К.: ВЕК+, СПб.: КОРОНА принт, 2004. с. 232-238.
2. Ставровский А.Б. Первые шаги в программировании. Самоучитель. – М.: «Вильямс», 2003. с. 113-133.
3. Вирт Н. Алгоритмы и структуры данных. – М.: Мир, 1989.
4. Иванова Г.С. Технология программирования: Учебник для вузов. – М.: Изд-во МГТУ им. Н.Э.Баумана, 2002. -320 с.
Промышленный подход к разработке программных продуктов породил ряд современных технологий проектирования алгоритмов и программ, среди которых наибольшее распространение получили:
- структурное проектирование программных продуктов;
- информационное моделирование предметной области
и связанных с ней приложений;
- объектно-ориентированное проектирование программных продуктов и др.
< p>Целью данного занятия является изучение основных принципов структурного и объектно-ориентированного проектирования программ
В основе технологии структурного проектирования лежит последовательная декомпозиция, целенаправленное структурирование задачи на отдельные составляющие.
Методы структурного проектирования представляют собой комплекс технических и организационных принципов системного проектирования.
Типичными методами структурного проектирования являются:
- нисходящее проектирование, кодирование и тестирование программ;
- модульное программирование;
- структурное программирование и др.
В зависимости от объекта структурирования различают:
- функционально-ориентированные методы — последовательное разложение задачи или целостной проблемы на отдельные, достаточно простые составляющие, обладающие функциональной определенностью;
- методы структурирования данных.
Для функционально-ориентированных методов в первую очередь учитываются заданные функции обработки данных, в соответствии с которыми определяется состав и логика работы (алгоритмы) отдельных компонентов программного продукта. С изменением содержания функций обработки, их состава, соответствующего им информационного входа и выхода требуется перепроектирование программного продукта. Основной упор в структурном подходе делается на моделирование процессов обработки данных.
Для методов структурирования данных осуществляется анализ, структурирование и создание моделей данных, применительно к которым устанавливается необходимый состав функций и процедур обработки. Программные продукты тесно связаны со структурой обрабатываемых данных, изменение которой отражается на логике обработки (алгоритмах) и обязательно требует перепроектирования программного продукта.
Структурный подход использует:
- диаграммы потоков данных (информационно-технологические схемы) – показывают процессы и информационные потоки между ними с учетом событий, инициирующих процессы обработки;
- интегрированную структуру данных предметной области (инфологическая модель, ER-диаграммы);
- диаграммы декомпозиции – структура и декомпозиция целей, функций управления, приложений;
- структурные схемы – архитектура программного продукта в виде иерархии взаимосвязанных программных модулей с идентификацией связей между ними, детальная логика обработки данных программных модулей (блок-схемы).
Спецификация задачи служит отправной точкой в создании программы. Нужно понять, какие действия должны быть совершены для решения задачи, описать их на естественном языке и на достаточно высоком уровне абстракции. В программировании уже давно используются специальные языки — языки формальных спецификаций. Однако их изучение требует определенной подготовки. Поэтому ограничимся неформальными спецификациями, но как можно более точными и полными.
Спецификация задачи является ее первичным проектом. От него мы движемся к программе, постепенно уточняя описание.
Постепенное уточнение проектов широко используется во многих отраслях инженерной деятельности и называется методом проектирования сверху вниз (пошаговой детализации или нисходящего проектирования).
В качестве примера рассмотрим проект одевания ребенка.
Конкретизация цели на первом шаге:
Одеть нижнюю половину.
Одеть верхнюю половину.
Нижнюю половину можно одеть в два этапа:
Надеть носки и ботинки.
Верхнюю половину можно также одеть в два этапа:
Окончательный проект выглядит так:
Метод нисходящего проектирования предполагает последовательное разложение общей функции обработки данных на простые функциональные элементы («сверху-вниз»). В результате строится иерархическая схема, отражающая состав и взаимоподчиненность отдельных функций, которая носит название функциональная структура алгоритма (ФСА) (рис. 1.1).
Последовательность действий по разработке ФСА приложения следующая:
1) определяются цели автоматизации предметной области и их иерархия (цель-подцель);
2) устанавливается состав приложений (задач обработки), обеспечивающих реализацию поставленных целей;
3) уточняется характер взаимосвязи приложений и их основные характеристики (информация для решения задач, время и периодичность решения, условия выполнения и др.);
4) определяются необходимые для решения задач функции обработки данных;
5)
выполняется декомпозиция функций обработки до необходимой структурной сложности, реализуемой предполагаемым инструментарием.
Подобная структура приложения отражает наиболее важное – состав и взаимосвязь функций обработки информации для реализации приложений, хотя и не раскрывает логику выполнения каждой отдельной функции, условия или периодичность их вызовов.
Разложение должно носить строго функциональный характер, т.е. отдельный элемент ФСА описывает законченную содержательную функцию обработки информации, которая предполагает определенный способ реализации на программном уровне.
Функции ввода-вывода информации рекомендуется отделять от функций вычислительной или логической обработки данных.
По частоте использования функции обработки делятся на:
- однократно выполняемые;
- повторяющиеся.
Степень детализации функций может быть различной, но иерархическая схема должна давать представление о составе и структуре взаимосвязанных функций и общем алгоритме обработки данных. Широко используемые функции приобретают ранг стандартных (встроенных) функций при проектировании внутренней структуры программного продукта.
Уточнение действий при нисходящем проектировании — это, по сути, переход от описания того, что нужно сделать, к тому, как это сделать.
При уточнении действий в процессе проектирования программа разбивается на систему подпрограмм и программных единиц, а также конкретизируется представление данных.
В программировании также применяется метод последовательной модернизации. Сначала проектируется и реализуется упрощенный вариант решения задачи — прототип (однако и для него применяется нисходящее проектирование). Затем спецификации постепенно усложняются, а программа наращивается с соответствующим расширением возможностей, пока не будет получен окончательный вариант.
Модульное программирование является естественным следствием проектирования сверху вниз и заключается в том, что программа разбивается на части – модули, разрабатываемые по отдельности. В программировании под модулем понимается отдельная подпрограмма, а подпрограммы часто называются процедурами или процедурами-функциями. Поэтому модульное программирование еще называется процедурным.
Модуль должен обладать следующими свойствами:
- один вход и один выход – на входе программный модуль получает определенный набор исходных данных, выполняет содержательную обработку и возвращает один набор результатных данных, т.е. реализуется стандартный принцип IPO (Input — Process — Output — вход-процесс-выход);
- функциональная завершенность – модуль выполняет перечень регламентированных операций для реализации каждой отдельной функции в полном составе, достаточных для завершения начатой обработки;
- логическая независимость – результат работы программного модуля зависит только от исходных данных, но не зависит от работы других модулей;
- слабые информационные связи с другими программными модулями – обмен информацией между модулями должен быть по возможности минимизирован;
- обозримый по размеру и сложности программный код.
Установить разумные размеры модулей трудно, хотя стоит придерживаться правила: выделять модули, пока это целесообразно. Обычно размеры модуля ограничены несколькими десятками строк кода на языке высокого уровня. Считается, что малый модуль лучше большого, поскольку с увеличением размеров модулей их восприятие и отладка усложняются ускоренными темпами. Кроме того, большие модули часто оказываются взаимозависимыми, и изменения в одном из них влекут необходимость модификации других.
Модули содержат определение доступных для обработки данных, операции обработки данных, схемы взаимосвязи с другими модулями.
Каждый модуль состоит из спецификации и тела. Спецификации определяют правила использования модуля, а тело – способ реализации процесса обработки.
Принципы модульного программирования программных продуктов во многом сходны с принципами нисходящего проектирования: сначала определяются состав и подчиненность функций, а затем — набор программных модулей, реализующих эти функции.
Однотипные функции реализуются одними и теми же модулями. Функция верхнего уровня обеспечивается главным модулем; он управляет выполнением нижестоящих функций, которым соответствуют подчиненные модули.
При определении набора модулей, реализующих функции конкретного алгоритма, необходимо учитывать следующее:
- каждый модуль вызывается на выполнение вышестоящим модулем и, закончив работу, возвращает управление вызвавшему его модулю;
- принятие основных решений в алгоритме выносится на максимально «высокий» по иерархии уровень;
- для использования одной и той же функции в разных местах алгоритма создается один модуль, который вызывается на выполнение по мере необходимости.
В результате дальнейшей детализации алгоритма создается функционально-модульная схема (ФМС) алгоритма приложения, являющася основой для программирования (рис. 1.2).
Состав и вид программных модулей, их назначение и характер использования в программе в значительной степени определяются инструментальными средствами.
Алгоритмы большой сложности обычно представляются с помощью схем двух видов:
Наиболее часто детально проработанные алгоритмы изображаются в виде блок-схем согласно требованиям структурного программирования. При их разработке используются условные обозначения согласно:
- ГОСТ 19.003-80 ЕСПД (Единая система программной документации). Обозначения условные графические,
- ГОСТ 19.002-80 ЕСПД. Схемы алгоритмов и программ. Правила обозначения.
Статьи к прочтению:
- Мой компьютер® пкмдиск3,5а® форматировать® выбрать способ форматирования (полное (по умолчанию), быстрое ) ® начать
- Монтирование файловых систем
Информатика. Язык Си: Модульное программирование на Си.Центр онлайн-обучения «Фоксфорд»
Похожие статьи:
- Метод объектно-ориентированного программирования. Методология и технология программирования. Приведем основные определения. Программа — завершенный продукт, пригодный для запуска своим автором на…
- Методы и искусство программирования ПРОЕКТИРОВАНИЕ ПРОГРАММ В предыдущем разделе, посвященномязыку Паскаль, приведено немало примеров программ. Однако, при анализе готовой программы чаще…
Источник: csaa.ru
Иерархия модулей: как выстроить связи между модулями в Android
Всем привет! Меня зовут Георгий Рябых, и я — android-разработчик в hh.ru. Сегодня поговорим об иерархии модулей и разберемся, как правильно их укрощать. Если у вас многомодульное приложение, то вы скорее всего уже сталкивались с проблемами в зависимостях между модулями и сложностями в навигации по проекту. Но если вы только планируете разделение на модули, то вам еще предстоит познакомиться с этими сложностями.
А чтобы избежать проблем у вас должны быть четкие правила по работе с многомодульностью. Мы в hh.ru много думали над подходом работы с модулями и считаем, что у нас получилось хорошее решение.
В этой статье: расскажу, какие проблемы решали и какие типы модулей выделили, обсудим правила подключения модулей между собой, разберем разделение большой фичи на несколько модулей и посмотрим на наш settings.gradle. Поехали!
Какие проблемы решаем
Первая проблема — если у нас большой проект, становится сложно ориентироваться в коде. Наше приложение — многомодульный проект, в котором несколько сотен модулей. Если сложить весь код в одну директорию, потеряться будет проще простого.
Еще важно, чтобы по имени модулей было понятно, что это за модуль и как правильно с ним работать. А если мы встретим имя модуля в gradle-файле, то было бы здорово легко определять, где лежит его код, а затем быстро туда навигироваться.
Вторая проблема — если не накладывать ограничения на зависимости между модулями, можно потерять одно из преимуществ многомодульного проекта — относительно небольшое время сборки проекта. Давайте здесь остановимся и чуть подробней и изучим проблему.
Чтобы понять, как такое может произойти, рассмотрим схему нашего воображаемого мини-приложения:
Итак в нашем мини-приложении есть app-модуль “applicant” и всего одна-единственная фича — “vacancy” (экран вакансии), и в этом модуле содержится ее код. Также есть несколько базовый модулей: “remote-config”, “model”, “utils”.
Приложение развивается, и у нас появляется еще одна фича — “resume” (экран с резюме).
Процесс сборки в нашем случае будет выглядеть так: сборка начинается с самого низу, с наших двух модулей “model” и “utils” — у них никаких связей и дополнительных зависимостей, поэтому они собираются первыми и параллельно. А вот модули “remote-config” и “user” зависят от модулей “model” и “utils”, поэтому они дожидаются своей очереди. Как только первые два модуля закончат сборку, начнут собираться “remote-config” и “user”, а за ними “vacancy” и “resume”. При этом получается, что фича “vacancy” и фича “resume” могут собираться параллельно — на разных потоках.
В итоге сборка проекта занимает примерно столько же времени, сколько было до добавления новой фичи “resume”.
Еще здесь можно оценить сложность наших зависимостей с помощью критического пути. Критический путь — это самый длинный путь от верхнего модуля до нижнего. В данном случае он равен трем. И чем он меньше, тем быстрее будет собираться проект.
Допустим, проект продолжает развиваться. Теперь мы хотим доработать фичу “resume”. У нас уже есть некоторый код из модуль “vacancy”, который отлично подходит для нашей новой функциональности в фиче “resume”. Поэтому мы, недолго думая, просто берем и подключаем один модуль к другому. И в итоге получается, что нам даже не пришлось ничего рефакторить: мы просто взяли и переиспользовали уже существующий код.
На первый взгляд проблемы нет. НО давайте-ка посмотрим, что стало со сборкой приложения.
Теперь фича “resume” уже зависит не только от модуля “user”, но и от модуля “vacancy”. И теперь, перед тем как собрать модуль “resume”, приходится ждать пока синий блок полностью соберется. По итогу, мы теряем параллельную сборку модулей — фичи больше не могут собираться одновременно, это грустно.
Также у нас вырос критический путь — теперь он равен четырем, стало хуже. А ведь эта схема достаточно простая по сравнению с настоящим приложением. Там у вас может быть гораздо более глубокая иерархия модулей. И такие неудачные связи могут повторяться, увеличивая критический путь. Так было и в нашем приложении.
Изначально у нас был монолит, который мы решили поделить на модули. Не было четких правил, как мы будем подключать их друг к другу: просто брали кусочек приложения и выделяли его в отдельный модуль. А только потом стали разбираться, как можно уменьшить время сборки приложения. Посмотрели наш критический путь — он оказался равен 23.
Представьте, 23 модуля, которые связаны друг с другом. Жуть!
Типы модулей в приложении
Чтобы решить эти проблемы, для начала мы выделили несколько основных типов модулей в нашем приложении:
- app-модули
- feature-модули
- core-модули
Начнем с app-модулей. Они предназначены для связи частей приложения воедино. Это те самые модули приложений, которые находятся на самом верху иерархии модулей. Сколько app-модули, столько и приложений в проекте.
Далее по списку — feature-модули. Feature-модули предназначены для кода конкретной фичи. Это может быть какой-нибудь экран приложения или базовая фича для работы с геолокацией. Также мы выделяем нескольких различных типов feature-модули. Есть feature-модуль, который шарится для всех приложений внутри проекта — так называемые shared:feature-модули.
Еще каждое из приложений может иметь специфичные модули для себя app:feature-модули. Например, определенный экран, который предназначен только для этого приложения.
А core-модули предназначены для хранения общей логики и моделей для всех приложений. Они могут быть общими для всех приложений. Core-модули содержат код, который может переиспользоваться во всех остальных частях приложений. По аналогии с feature-модулями они у нас лежат в директории shared, только дальше идет не feature-директория, а core-директория.
По итогу мы имеем три app-модуля для соискательского (applicant), работодательского (hr-mobile) и технического (design-gallery) приложений. У нас есть две директории для каждого из основных приложений и общая shared-директория. В каждой из этих директорий есть core-директория и feature-директория для модулей.
Здесь главное не путаться app-модуль приложения headhunter-applicant и директорию applicant. Они специально имеют похожие названия, чтобы по смыслу связать модуль приложения с директориями для feature- и core-модулей.
В дополнение хотелось бы рассказать про деление модулей внутри фичи. Могут быть core-модули предназначенные только для определенной группы фич. Как пример, в приложении hr-mobile есть ряд feature-модулей, связанных с функциональностью аутентификации. При этом они имеют общую логику. Мы не хотим вытаскивать эту логику на уровень hr-mobile:core, т.к. она связана только с группой фич.
Поэтому мы выделяем core-модуль внутри общей директории для этих feature-модулей.
Правила подключения модулей
Чтобы не создавать хаос в зависимостях и тем самым не ухудшать скорость сборки приложения, выделим правила подключения модулей между собой.
Shared:core подключаем куда угодно: модули могут подключаться к любому из других модулей. А всё потому что shared:core-модули — это фундамент нашего приложения, и обычно собираются они в первую очередь. После первой сборки приложения мы можем подключать их куда угодно и быть спокойными, что это никак не замедлит наш последующий ребилд приложения.
Важно понимать, что core-модули — это не помойка, куда вы просто складываете всё, что хотя бы отдаленно напоминает общий код для нескольких модулей. Если у вас будет слишком много всего в базовом core-модуле, то рано или поздно нарветесь на то, что при изменениях, касающихся определенной группы фич, будет пересобираться весь проект. Просто по потому, что вы поменяли что-то в shared:core модуле, а он подключен везде.
Поэтому следует четко понимать, что именно вы хотите туда вносить. И важно следить за тем, чтобы эти модули сильно не разрастались. Если у вас действительно есть код, который вы используете чуть ли ни в каждом втором модуле, то его можно и нужно положить в shared:core-модуль. Но если у вас всего лишь пару feture-модулей и у них есть общий код, то лучше вынести их в core-модули на уровне приложения — в app:core-модуль.
Shared:feature подключаем к любому app-модулю. И хоть модули и называются shared, это вовсе не значит, что мы можем подключить их напрямую к другому feature-модулю. У нас также остается правило, что мы подключаем все feature-модули только к app-модулям. И только через app-модуль связываем фичи между собой.
:core — только к core- и feature-модулям определенного app-модуля.
:feature — только к определенному app-модулю. Это те самые фичи, предназначенные только для определенного application. А поскольку они предназначены только для конкретного app-модуля, то и подключаться могут лишь к нему.
И последнее — это :feature::core. Их подключаем только к определенному sub-feature-модулю.
Где растет сложность зависимостей и критический путь
Нашу схему модулей можно рассмотреть и другим способом — поделить её на горизонтальные блоки.
Первый блок — это app-модули. И здесь понятно, что он никак не может расти по вертикали, app-модули не зависят друг от друга, а значит и критический путь никак не увеличивается.
Второй блок — feature-модули. Можно условно принять, что здесь также не может появляться модулей ниже уровня. Но поскольку у feature-модулей все-таки могут возникать core-модули, критический путь может увеличиваться на 1-2 уровня. Однако это происходит далеко не всегда, и такой рост весьма ограничен. По итогу, здесь критический путь и сложность зависимостей тоже особенно не растут.
Третий блок — core-модули. Здесь сложность зависимостей может расти непредсказуемым образом, поскольку эти модули легко становятся зависимыми друг от друга. Но этот участок обычно меняется реже всего — риск минимальный. Поэтому за ними достаточно следить время от времени и проверять, чтобы не было каких-то адских зависимостей и больших цепочек связей.
В этом и заключается преимущество нашего подхода — наша иерархия модулей растет в основном вширь (за счет feature-модулей), а не вглубь. При этом не появляются лишние связи между модулями, особенно горизонтальные. Это обеспечивает нам сборку проекта, когда большая часть модулей собирается параллельно.
Зачем делить большие фичи
Очевидно, что чем больше кода, тем сложнее становится с ней работать. Допустим, у нас есть фича “резюме”. В нашем случае она разделена на несколько модулей, но представим, что это один большой модуль. Во время разработки можно делать всё в одном модуле: разложить по директориям и запомнить, как что работает.
Разработал — отложил на год, а когда вернулся, то обнаружил, что уже не все так очевидно. Все забылось.
Разные экраны, которые непонятным образом связаны между собой, много зависимостей, всё и везде используется. С этим не всегда удобно работать, особенно, когда нужно внести одну маленькую правочку в конкретном месте. А если выделить несколько фич в рамках резюме, то у них будет четко выделенное API и зависимости для взаимодействия с другими участками кода. В таком коде проще разобраться.
Также мы делим большие фичи на несколько, когда хотим переиспользовать часть кода между фичам. Например, в том же резюме есть некоторый код, который оказался общим для нескольких модулей. Поэтому логично вынести всё это в core-модуль и использовать в соседних модулях резюме.
Важную роль играет еще и уменьшение времени сборки. Если бы мы собирали модуль целиком, то это заняло бы много времени. Но поскольку он разделен на множество мелких модулей, они могут собираться параллельно. А изменение в одном из модулей, не спровоцирует сборку остальных модулей резюме при пересборке проекта.
Оздоровление gradle-файлов
Раньше на gradle-файлы выглядели так:
// settings.gradle include ‘:shared-core-utils’ project(‘:shared-core-utils’).projectDir = new File(settingsDir, ‘./shared/core/shared-core-utils’) // build.gradle implementation project(’:shared-core-utils’)
Из-за того, что имя модуля не совпадало с директорией, в котором он лежит, нам приходилось писать две дополнительных строчки — include и project. А поскольку у нас таких модулей сотни, эти две строчки превращались в огромную простыню.
Еще были ситуации, когда модуль shared-core-utils мог лежать вообще не в директории shared/core, что тоже вносило свою путаницу. И непонятно, где этот модуль искать.
Чтобы это исправить мы четко связали нейминг модулей с его положением в проекте.
После того, как мы стали использовать этот подход, те же самые gradle-файлы стал выглядеть следующим образом:
// settings.gradle include(’:shared:core:utils’) // build.gradle implementation project(‘:shared:core:utils’)
У нас сохранился наш понятный нейминг, но появилась новая возможность быстро снавигироваться на модуль, поскольку мы четко понимаем, где он лежит. А в settings.gradle-файле наша простыня сократилась в два раза.
В итоге наш settings.gradle стал выглядеть вот так:
// Feature Help include(«:shared:feature:help:help-screen») include(«:shared:feature:help:core:faq-domain») include(«:shared:feature:help:core:faq-data-webim») // Feature vacancy include(«:applicant:feature:search-vacancy:core:logic») include(«:applicant:feature:search-vacancy:search-vacancy-full») include(«:applicant:feature:search-vacancy:search-vacancy-shorten») include(«:applicant:feature:search-vacancy:search-clusters») include(«:applicant:feature:search-vacancy:search-advanced») // Feature negotiation include(«:applicant:feature:negotiation:core:logic») include(«:applicant:feature:negotiation:core:network») include(«:applicant:feature:negotiation:negotiation-with-similar-result») include(«:applicant:feature:negotiation:negotiation-screen») include(«:applicant:feature:negotiation:negotiation-list») // Feature search include(«:applicant:feature:search-history:core:logic») include(«:applicant:feature:search-history:search-history-list») include(«:applicant:feature:search:core:logic») include(“:applicant:feature:search:search-quick-query») include(«:applicant:feature:search:search-query») include(«:applicant:feature:search:search-main»)
Итоги
Чтобы легко работать со сложной иерархией модулей, у нас в проекте есть строгое деление на типы модулей, а имя модуля полностью отражает его суть. А для легкой навигации по проекту, имя модуля полностью совпадает с его директорией в проекте.
Для контроля зависимостей между модулями у нас существуют строгие правила подключения модулей между собой. Корректность подключения модулей проверяется статическим анализом кода на каждом PR.
Если вы планируете разбить ваш проект на модули или в начале этого процесса, то лучше сразу задуматься о том, какие правила вам нужны как для именования модулей, так и для связей между ними.
Потому что искать и решать проблемы в зависимостях между модулями из-за непродуманной иерархии долго и сложно.
Источник: temofeev.ru