Как стать автором
Обновить

Комментарии 29

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

Такие дела))

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

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

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

Куда уж мне.

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

Подход Package by Feature рассмотрю на примере большого приложения, использующего одну общую базу данных. При многослойном приложение функционал работы с бд размещается в persistence layer и вышележащие слои пользуются им. Для Package by Feature в каждом пакете получается надо дублировать код для работы с бд ??? Или всё-таки для работы с бд может быть выделен отдельный слой несмотря на методологию Package by Feature?

В Package by Feature можно выделять общий слой для работы с БД, Но главное чтобы он не превратился в God Object. Можно сделать как общий слой в `shared/infrastructure/persistence` так и отдельные репозитории внутри фичевых пакетов;

Код у тебя будет разный в репозиториях и дублирования будет минимальным. дублирования кода - хорошо; дублирования логики - плохо. Важно не путать эти два момента.

При многослойном приложение функционал работы с бд размещается в persistence layer и вышележащие слои пользуются им.

Можно, но я бы так не делал, чтобы уменьшить связаность и возможность возникновения ошибок при изменениях в одном репозитории. Я в таких случаях использую отдельный конект (или EM если у вас доктрина) к БД внутри своего слоя инфраструктуры.

Зарегистрируйтесь на Хабре, чтобы оставить комментарий

Публикации