В комментариях DZone под моим постом о многоуровневой архитектуре некоторые люди полагали, что расслоение должно быть реализовано как то, что я называю « Упаковка по функциям» . Я намеренно отложил писать об этом, чтобы сначала покрыть шестиугольники и лук, но теперь, когда они у нас есть, мы можем прыгнуть прямо в столь востребованный архитектурный стиль.
Что такое пакет по функции?
В типичной многоуровневой архитектуре организация кода следует горизонтальной декомпозиции, созданной путем разделения системы на слои. Это то, что часто называют Package by Layer .
Проблема этого подхода заключается в том, что когезия внутри каждой упаковки обычно низкая, а связь между упаковками очень высокая. Это похоже на то, что мы хотим достичь. В то же время большинство людей сходятся во мнении, что разделение задач представления, приложения, домена и инфраструктуры имеет смысл. Package by Feature использует обе точки, перемещая уровень на уровень вниз — до уровня класса — и концентрируясь на соединении и связности на более высоком уровне, сохраняя все классы, связанные с одной и той же функцией, в одном пакете / модуле:
Вы можете спросить, что это за функция? Это правильный вопрос. Я видел различные реализации и примеры, которые варьировались от функции, означающей эффективное использование одного варианта использования, до функции, означающей целый набор операций, связанных с конкретной коммерческой задачей. Я видел больше последних, когда проводил исследование для этой статьи, но я не думаю, что это обязательно хорошая вещь.
Суть пакета по особенностям
Я вижу две вещи, которые формируют суть Package by Feature : поддержание высокой когезии и низкой связи на уровне пакета / модуля и возможность сказать, что делает приложение, глядя на его структуру пакета / модуля.
В типичной многоуровневой архитектуре когезия внутри пакета низкая, а связь между пакетами высокая. Мы редко меняем технологии или соглашения, относящиеся к определенному слою, по сравнению с тем, как часто мы добавляем одну особенность, следовательно, низкая сплоченность . И в большинстве случаев каждый класс в слое (пакете) зависит как минимум от одного класса в другом слое (пакете), что делает связь между ними высокой. В стиле « Пакет по элементам» мы в идеале меняем классы только в одном пакете — связанном с функцией, над которой мы работаем, — чтобы сплоченность была высокой, а между функциями было всего несколько зависимостей , поэтому связь была низкой.
Два приведенных выше термина полезны, но, если честно, это метрики ботаников. Более человеческая сторона Package by Feature заключается в том, что вам не нужно быть ботаником, который знает каждый фрагмент кодовой базы, чтобы иметь возможность сказать, что он делает — быстрый взгляд на структуру пакета / модуля скажет вам об этом. Это один шаг к тому, что дядя Боб называет « Кричащей архитектурой» .
package com.ecommerce.catalog; // enables user to browse the products
package com.ecommerce.checkout; // enables user to make an order
package com.ecommerce.orders; // enables the shop to process the orders
Реализация пакета по функциям
Название Package by Feature настоятельно рекомендует вам реализовать этот стиль, поместив каждую функцию в отдельный пакет, и это в основном так. Единственное предостережение, которое я вижу, это то, что это может быть также модуль, пространство имен или любой другой механизм, доступный на вашем языке, если вы не используете Java.
Вторая важная вещь в Package by Feature состоит в том, что когда связанные вещи находятся в одном пакете, можно, наконец, использовать модификаторы доступа, то есть сделать большинство вещей локальными, а не общедоступными. Таким образом, мы можем ограничить общедоступный интерфейс нашей функции только теми вещами, которые мы действительно хотим показать. В стиле Package by Layer это было невозможно, потому что связанные классы должны были взаимодействовать между пакетами, что вынуждает нас делать все общедоступным.
пример
Несмотря на то, что я чувствую, что Spring Pet Clinic — не лучший ресурс для изучения разработки программного обеспечения, она довольно неплохо представляет презентацию Package by Feature . В особенности , в этом случае представляют собой наборы операций , выполняемых на тех же объектов предметной области:
Как видите, у нас есть три доминирующие функции — управление владельцами, ветеринарами и визитами. Является ли это разложение на особенности хорошим или нет, это очень сложная тема. На данный момент, мы должны сосредоточиться на том , что классы , представляющие различные слои , такие как контроллеры, хранилище и объекты предметной области все держались вместе, и что структура пакета больше функции ориентированной.
Преимущества пакета по функции
- Более информативная структура пакета — вы можете вывести некоторые основные функции или поведение системы из структуры кода
- High Cohesion & Low Coupling — мы объяснили этот момент уже в основной части, хотя и немного идеалистически
- Лучшая инкапсуляция — вы можете эффективно использовать модификаторы доступа, чтобы скрыть информацию, которая должна оставаться скрытой
- Лучший потенциал роста , в смысле объема кода — если вы не разрабатываете слишком большие или слишком маленькие функции , вы не должны сталкиваться с проблемой слишком большого или слишком большого количества пакетов
Недостатки пакета по особенностям
- Unspecified Feature Size — я не нашел четких указаний или доказательств того, что одно понимание функции лучше, чем другое
- Кривая обучения — концепция проста, но поскольку вам нужно найти свой собственный способ разбить систему на функции , освоить ее может быть очень сложно
- Потенциал беспорядка — в запутанной области, в которой все связано со всем, разделение на функции может стать искусственным, и обещание низкой связи может не быть выполнено
Когда использовать пакет по функции?
Очевидно, что он может работать для небольших приложений, в которых вы можете перетасовать вещи и пробовать разные вещи по очень низкой цене. В то же время, поскольку он обещает более высокую когезию , более низкое сцепление и лучший потенциал роста, он идеально подходит для более крупных применений, которые могут фактически страдать от недостатков упаковки за слоем . Учитывая его умеренную кривую обучения, то есть необходимость выбора лучшего определения функции , я бы с осторожностью использовал ее впервые при работе с критически важным приложением. Я бы предпочел разделить проблему на ограниченные контексты и реализовать каждый из них слоистым / гексагональным способом.
Резюме
Упаковка по функциям — действительно привлекательная идея, и я совершенно не удивлен, что многие люди продвигают ее вперед. Наши любимые метрики, такие как сплоченность и связь, кажутся хорошими, и мы можем увидеть, что делает приложение, просто посмотрев на пакеты. В то же время, я вижу его недостатки и потенциал стать огромным беспорядком, если кто-то попытается использовать искусственное разделение на функции в запутанной области. Если вы знаете, как эффективно использовать его преимущества, сделайте это. Если вы этого не сделаете, будьте осторожны.