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

В этой статье мы продолжим эту тему, сосредоточившись на сравнении двух подходов к организации кода: Package by Feature и Package by Layer. Мы подробно рассмотрим, как каждый из этих методов влияет на структуру проекта, поддерживаемость и масштабируемость кода.


? Примеры из реальной жизни

Пример №1. Строительство города

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

Package by Layer – это когда все одинаковые здания стоят в одном месте: Все магазины в одном районе, Все дома в другом, Все школы в третьем. Хотели бы жить в таком городе?

Package by Feature – это когда у тебя есть районы, где всё нужное находится рядом: В одном районе есть и дома, и магазины, и школы – всё для жителей этого района.

Пример №2. Организация одежды в гардеробе

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

Package by Layer – все футболки на одной полке, все брюки на другой, а все носки в отдельном ящике.

Package by Feature - А теперь представь, что ты складываешь вещи для разных занятий. Все вещи для плавания - в одном месте (купальник, полотенце, очки), все вещи для школы - в другом (учебники, тетради, ручки).

Пример №3. Организация кухни ресторана

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

Package by Layer - Этот способ похож на то, как ты можешь разложить всё по типам, независимо от того, для какого блюда это нужно. Например:

  • Коробка "Все овощи"

  • Коробка "Все инструменты"

  • Коробка "Специи"

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

Package by Feature  - ты можешь разложить всё, что нужно для каждого блюда, в отдельные коробки или зоны на кухне. Например:

  • Коробка "Пицца"

  • Коробка Салаты

  • Коробка Дисерты

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

Пример №4. Собираем школьный рюкзак

Представь что нам нужно собрать школьный рюкзак.

Package by Layer - это как сложить все учебники вместе, все тетради вместе, все ручки вместе. Удобно, когда нужно найти все учебники, но неудобно собираться по предметам.

Package by Feature - это как сложить отдельно все для математики (учебник, тетрадь, линейка), отдельно все для рисования (альбом, краски, кисточки). Удобно собираться на конкретный урок, но сложнее найти все учебники сразу.


? Как парадигмы программирования влияют на организацию кода?

Прежде чем углубляться в организацию кода, важно понимать, что разные парадигмы программирования могут влиять на выбор между Package by Layer и Package by Feature.

? Обектно ориентированое програмирования (ООП) и организация кода

ООП — это парадигма, в которой программа строится вокруг объектов, которые представляют собой экземпляры классов. Основные принципы ООП включают:

  1. Инкапсуляция: Сокрытие внутреннего состояния объекта и предоставление доступа к нему только через методы.

  2. Наследование: Возможность создания новых классов на основе существующих, что позволяет повторно использовать код.

  3. Полиморфизм: Возможность объектов разных классов обрабатываться как объекты одного класса.

  4. Абстракция: Упрощение сложных систем путем моделирования классов, которые отражают только существенные характеристики.

    Package by Feature

    • Package by Feature естественным образом поддерживает принципы ООП, такие как инкапсуляция и сокрытие реализации. Классы, связанные с одной функциональностью, группируются вместе, что упрощает понимание и поддержку кода.

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

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

    • Легче соблюдать принцип единственной ответственности (SRP), так как каждый пакет отвечает за конкретную функциональность.

    • Лучше сочетается с DDD (Domain-Driven Design), так как позволяет группировать объекты, связанные с одной бизнес-фичей, в одном месте.

    Package by Layer

    • Package by Layer в ООП часто встречается в классических монолитах, где слои (контроллеры, сервисы, репозитории) разделены, и каждый слой отвечает за свою часть логики.

    • При package by layer объекты и классы, отвечающие за разные аспекты одной функции, также оказываются разделенными по разным слоям. Это может затруднить применение принципов ООП, таких как полиморфизм, и привести к созданию более сложных и запутанных связей между объектами.

? Функциональное программирование (ФП) и организация кода

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

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

  2. Неизменяемость: Данные не изменяются после создания, вместо этого создаются новые данные.

  3. Функции высшего порядка: Функции, которые могут принимать другие функции в качестве аргументов или возвращать их.

  4. Рекурсия: Часто используется вместо циклов для обработки данных.

Функциональное программирование основывается на идее чистых функций, неизменяемости данных и композиции. В ФП акцент делается на том, что делает программа, а не на том, как она это делает. Это ведёт к иному подходу к структуре кода:

Package by Feature

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

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

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

Package by Layer

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


? Что говорят эксперты?

1️⃣ Эрик Эванс в "Domain-Driven Design"?

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

"При создании сложных программ критически важно разделить код на слои с разными зонами ответственности."
Эванс, DDD, Глава 4 "Изоляция доменной логики"

? Четыре слоя по Эвансу:

  • Доменный слой (Domain) должен быть изолирован от инфраструктуры. (Entities, Value Objects, Aggregates)

  • Сценарии использования (Application) управляют бизнес-процессами, но не содержат бизнес-логики. (Use Cases)

  • Инфраструктурный слой (Infrastructure) реализует хранилища данных, API, интеграции.

  • Интерфейсный слой (UserInterface) отвечает за взаимодействие с пользователем

Эванс не говорит, что именно так должна быть организована структура файлов. Он дает концепцию разделения ответственности, но не конкретное правило именования папок. Также Эванс подчеркивает важность Bounded Context и разделения кода по контекстам, а не только по слоям.

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

Это намекает на Package by Feature, когда код разделен по фичам/контекстам (Bonus/, Customer/, Order/), а не просто слоям (Domain/, Application/, Infrastructure/).

2️⃣ Вон Вернон в "Implementing Domain-Driven Design"

Вон Вернон также поддерживает разделение слоев, но он более гибко подходит к организации кода. В книге "Implementing DDD" он даже упоминает Package by Feature как возможный вариант!

Bounded Context и организацию кода:

Ограниченный контекст (Bounded Context) — это центральный паттерн в Domain-Driven Design (DDD). Он определяет границы, в рамках которых конкретная модель применима и остается согласованной. Организация кода вокруг ограниченных контекстов, а не только вокруг технических слоев, помогает сохранять ясность и соответствие бизнес-домену.

"Ограниченный контекст (Bounded Context) — это логическая граница. Применение архитектурных слоев внутри него — это выбор, а не требование. Главное — сохранить чистоту и выразительность доменной модели в рамках этой границы."

- Вернон, IDDD, Глава 2: Границы контекста

Организация кода и возможные подходы:

«Организация кода строго по слоям часто приводит к искусственному разделению ответственности. Вместо этого рассмотрите возможность группировки кода по доменным концепциям в первую очередь, а затем решите, нужны ли слои внутри каждого контекста.»— Вон Вернон, Реализация Domain

- Вернон, IDDD, Глава 4: Стратегическое проектирование с использованием ограниченных контекстов*

Что это говорит о структуре кода?

"DDD не диктует жесткую структуру пакетов. Важно, чтобы код отражал границы контекста и модель домена."
Вернон, IDDD, Глава 2 "Границы контекста"

Он  признает, что Package by Feature можно использовать внутри DDD и советует группировать код по Bounded Context, а внутри можно использовать слои. Также предлагает гибридный вариант между Package by Layer и Package by Feature:

3️⃣ Карлос Буэносвинос, Кристиан Соронеллас и Кейван Акбари в книге «DDD in PHP»

В книге PHP in DDD также затрагивается вопрос организации кода, включая модели, слои и Bounded Context. Авторы книги ориентируется на принципы Эванса и Вернона, но с адаптацией под PHP.

Поддержка Bounded Context и Package by Feature

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

— PHP в DDD, Глава 6: Организация кода с использованием ограниченных контекстов.

Поддерживает Bounded Context и Package by Feature, а не только слои. Код внутри Domain Layer должен скрывать детали реализации и работать через Use Cases.

Слои используются гибко

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

— PHP в DDD, Глава 10: Роль уровней приложений и инфраструктуры

4️⃣ Дядюшка Боб в чистом коде

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

Как это связано с пакетированием по функциям и пакетированием по слоям?

Принципы дяди Боба показывают, что Package by Feature — более гибкий и масштабируемый подход, так как:
Избегает циклических зависимостей.
Каждая фича меняется независимо.
Группирует код по смыслу, а не по техническим слоям.

Однако, если вы используете Package by Layer, вам нужно очень тщательно управлять зависимостями, чтобы не нарушить принципы! ?

Сравнение подходов к организации кода в DDD

Ключевые моменты:

? Ограниченный контекст как основа (как подчеркивают все три автора).
? Package by Context + Package by Layer внутри каждого контекста.
? Гибкое использование слоев (отделяем домен от инфраструктуры, но избегаем излишней сложности).
? Доменная модель играет ключевую роль (Сущность, Агрегат, Объекты-Значения).

? DDD не диктует структуру папок, но требует четкого разделения ответственности.

? Главный принцип: DDD → сначала контексты, затем слои, а не наоборот! ?


? Use Cases в Чистой архитектуре и Package by Feature

Use Cases — это один из ключевых элементов Чистой архитектуры, который отвечает за обработку бизнес-логики.
Package by Feature — это способ организации кода, при котором все файлы, связанные с одной функциональностью (фичей), хранятся в одной папке.

Эти два подхода отлично дополняют друг друга: Use Cases позволяют выделить бизнес-логику, а Package by Feature делает кодовую базу более модульной и понятной. 

Use Cases и Package by Feature не противоречат друг другу. Напротив, они отлично работают вместе, поскольку обе методики направлены на улучшение структуры кода.

  • Use Cases помогают изолировать бизнес-логику и делают код тестируемым.

  • Package by Feature позволяет хранить весь код, связанный с одной функцией, в одном месте, делая его модульным.

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

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

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

  • Удобная для разработчиков кодовая база, в которой легче ориентироваться и работать.

Такое сочетание ведет к чистой, модульной и эффективной архитектуре. ?


? Когда что использовать?

В PHP-проектах оба подхода — Package by Feature и Package by Layer — применяются в зависимости от архитектурных решений и масштабов проекта. Давай разберем их с примерами.

Package by Layer подходит, когда:

  • У вас небольшое приложение

  • Много новых разработчиков в команде

  • Нужна простая, понятная структура

  • Функциональность тесно связана между собой

Package by Feature подходит, когда:

  • У вас большое приложение

  • Разные команды работают над разными функциями

  • Функциональность слабо связана между собой

  • Важна независимость модулей

  • Планируете переход на микросервисы

  • Проект большой с четкими доменными границами

  • Команда знакома с DDD

  • Используете собственную архитектуру или модульные фреймворки


? Как организовать код?

Давайте рассмотрим на примерах.

Package by Layer (Пакетизация по структурным слоям)

Этот подход разделяет код по уровням ответственности:

? Controller (контроллеры) – обработка HTTP-запросов
? Service (сервисы) – бизнес-логика
? Repository (репозитории) – работа с БД
? Entity (сущности) – модели данных

Package by Layer (Пакетизация по архитектурным слоям)

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

 Package by Feature (Пакетизация по фичам)

Здесь код группируется по фичам (сценариям работы), а не по слоям.

DDD и организация кода

На своем опыте я сталкивался с несколькими подходами. Я покажу два из них. Оба подхода технически работоспособны и потдерживают тактические патерны. На практике часто используется гибридный подход, который сочетает лучшие стороны Package by Feature и Package by Layer

Подход №1. Доменно-ориентированные слои

С точки зрения DDD и Layer Architecture, более предпочтительным является такой подход и вот почему:

Ограниченные контексты (Bounded Contexts)

  • Первый подход лучше отражает концепцию ограниченных контекстов в DDD

  • Каждая функциональная область (order, bonus) представляет собой отдельный ограниченный контекст

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

    Модульность и масштабируемость

  • При первом подходе легче добавлять новые функциональные модули

  • Каждый модуль содержит все необходимые слои и может развиваться независимо

  • Проще работать нескольким командам над разными модулями

    Поддержка и навигация

  • Легче находить весь связанный код конкретной функциональности

  • Проще понять границы каждого модуля

  • Меньше риск случайного смешивания кода разных доменов

    Соблюдение принципов DDD

  • Лучше отражает стратегический дизайн DDD

  • Четче видны границы агрегатов и доменных сервисов

  • Проще контролировать зависимости между модулями

Подход №2. Слои с доменными компонентами

Этот подход имеет следующие недостатки:

  • Смешивание разных доменных моделей в одном каталоге

  • Сложнее контролировать зависимости между доменами

  • По мере роста проекта становится труднее навигировать по коду

  • Выше риск нарушения границ между доменами

Советы по организации DDD-проекта:

  1. Начните с выделения ключевых доменов.

  2. Определите границы контекстов.

  3. Создайте базовую структуру папок.

  4. Поместите общий код в отдельный модуль shared/common.

  5. Используйте чистую архитектуру внутри каждого домена.

  6. Определите четкие правила взаимодействия между доменами.


Выводы

Оба подхода к организации кода имеют свои преимущества и недостатки. Выбор между package by feature и package by layer зависит от конкретных требований проекта и предпочтений команды разработчиков.

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

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

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

Источники

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


  1. Sergey_Kh
    16.02.2025 09:31

    В реальной жизни выглядит так, как будто package by layer удобнее.

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

    Или на кухне отдельная соль для пиццы, отдельная соль для салатов, отдельная соль для супов.

    Ну вы поняли - большое количество сущностей может быть использовано в разных features


    1. dykyi_roman Автор
      16.02.2025 09:31

      .


    1. dykyi_roman Автор
      16.02.2025 09:31

      тут как посмотреть) В целом имеет место быть обоим подходам. Как и в программировании все зависит от ситуации.

      Я не хотел бы жить в городе где все школы в одном районе, аптеки в другом, а магазины в третем. Тут package by layer никак не может быть применен.

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

      Также в магазинах одежды мы можем заметить упорядоченые вещи по типу - package by layer. Но если мы зайдем в шоу-рум там ты увидешь готовые луки - package by feature.

      Если на кухне несколько поваров и каждому нужна своя рабочая зона для готовки еды, то удобно что все приборы и ингредиенты будут в районе этой зоны и тогда они у каждого свои, тогда package by feature выглядит идеальным выбором. Я это знаю так как у меня Брат повар) Но! если у нас повар один или зона она для готовки еды маленькая, то в этом случаи больше подойдет - package by layer.


      1. Sergey_Kh
        16.02.2025 09:31

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


    1. DExploN
      16.02.2025 09:31

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

      А не искать среди работы,ресторана,друзей, свадьбы, подработки


  1. GospodinKolhoznik
    16.02.2025 09:31

    Package by Layer – это когда все одинаковые здания стоят в одном месте: Все магазины в одном районе, Все дома в другом, Все школы в третьем. Хоели бы жить в таком городе?

    Сомнительная аналогия. В городе расстояние до магазина имеет значение. А в ПО разве так? Может быть ссылки на методы или данные из другого модуля вызываются гораздо дольше чем аналогичные ссылки в своем модуле?


    1. dykyi_roman Автор
      16.02.2025 09:31

      Комментарий уходит в сторону производительности, а статья ведь про связность (cohesion) и сцепление (coupling).

      Скорость вызова методов или доступа к данным внутри одного модуля vs. из другого модуля – это не относиться к выборе структуры кода. В статье речь идет не о производительности, а о логической связанности (cohesion) и слабом сцеплении (low coupling).

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

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


      1. GospodinKolhoznik
        16.02.2025 09:31

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


        1. vadimr
          16.02.2025 09:31

          Прорвёт в этом месте канализацию – и город останется вообще без магазинов. Паразитная зависимость.

          В случае программирования – пошли исправлять модуль ради одного, а сломалось при этом другое.


          1. GospodinKolhoznik
            16.02.2025 09:31

            А так дело в канализации! Потому что я думал вы приводите аналогию города с точки зрения шаговой доступности магазинов, школ и т.п.

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

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


            1. vadimr
              16.02.2025 09:31

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


              1. GospodinKolhoznik
                16.02.2025 09:31

                Замечательная общая фраза. Только она не объясняет как модуль поможет справиться с тем, сломается или не сломается зависимость?

                Можете привести пример, где метод B зависит от метода A и в случае когда они в одном модуле B ломается при изменении A, а когда они в разных модулях не ломается?


                1. vadimr
                  16.02.2025 09:31

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

                  Ваши ожидания о [не]зависимости могут не соответствовать фактическому положению дел. Если, условно говоря, в начале модуля вы случайно переопределите операцию "+", то конец модуля от этого тоже пострадает.


                  1. GospodinKolhoznik
                    16.02.2025 09:31

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

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

                    Такие дела))


                    1. vadimr
                      16.02.2025 09:31

                      Я привёл конкретный пример.


                      1. GospodinKolhoznik
                        16.02.2025 09:31

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

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


                      1. vadimr
                        16.02.2025 09:31

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

                        Куда уж мне.

                        Ок, есть Вася у него есть свои функции, есть Петя, у него свои. Давайте положим все функции Васи в один Модуль,

                        Заметим, я этого не предлагал.

                        а функции Пети в другой и они друг другу ничего не сломают. Да? А потом приходит Ииигорь! Игорь говорит - мне нужны для работы вот те 25 функций Васи и 30 функций от Пети. Куда их класть?

                        В каком смысле куда класть? Эти функции как были, так лежат в модулях Васи и Пети.


                      1. dykyi_roman Автор
                        16.02.2025 09:31

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


                      1. dykyi_roman Автор
                        16.02.2025 09:31

                        Правильное применение DDD и чистой архитектуры решает эту проблему.

                        1. Код должен группироваться по bounded context’ам, а не по людям. Если Вася и Петя работают над разными бизнес-сущностями, их код логично разделять, но если у них общие задачи — значит, их код должен находиться в одном контексте.

                        2. Если Игорю нужны 25 функций Васи и 30 функций Пети, он не должен напрямую использовать их модули. Вместо этого можно выделить абстракции (интерфейсы), которые предоставляют нужные функции, не привязывая код жестко к модулям.

                        3. Наташа не должна тянуть весь код Васи, Пети и Игоря. Вместо этого можно создать слой API или фасад, который предоставляет только нужные ей функции.

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

                        4. Если у нас есть четкие слои (Domain, Application, Infrastructure) и фичи (Package by Feature), архитектура останется устойчивой, даже если добавится новый разработчик или новая функциональность.


                      1. vadimr
                        16.02.2025 09:31

                        .


                      1. vadimr
                        16.02.2025 09:31

                        Тут у вас некоторая путаница между классами и модулями.


            1. santjagocorkez
              16.02.2025 09:31

              А если 2 сущности А и Б, где Б зависит от А, значит в любом случае для Б доступна видимость А

              Не всегда. Если А и Б в одном модуле, то Б имеет доступ к internal (C#) потрохам А, а если в разных, то Б может пользоваться только public. Если, конечно, не лезть в интроспекцию.


    1. AlexGorky
      16.02.2025 09:31

      Да, надо как-то комбинировать.
      Например, бизнес-центр в городе - один. И все туда едут на работу утром.
      А заводы - в другом месте (желательно за городом).
      Будет не очень комфортно, если в каждом районе, кроме аптеки и школы будет завод?


      1. dykyi_roman Автор
        16.02.2025 09:31

        Вот не ожидал что холерной темой будут именно города)))


    1. vadimr
      16.02.2025 09:31

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

      Во многих реализациях языков программирования (наиболее распространённым примером является C/C++) так и есть. Вызов из своего модуля такой компилятор может, скажем, заинлайнить, а из другого – нет.


  1. vadimr
    16.02.2025 09:31

    Обычно на нижнем уровне располагаются универсальные примитивы, выделенные по принципу by layer (условно говоря, то, что разработчики системы программирования забыли положить в системную библиотеку – да собственно и сама системная библиотека), а над ними – предметно-ориентированные модули по принципу by feature.


  1. Dhwtj
    16.02.2025 09:31

    В одном случае by layer проще сделать DRY, но больше риск зависимостей. Удобно, когда 100500 похожих функций.

    В данном случае всё изолированно. Удобно, когда много предметных областей и/или программистов

    В общем то и вся разница.