В коде:
|
<?php namespace App; class SendReceipt {} |
Структура папок:
|
src Receipt ReceiptRepository SendReceipt SendReceiptHandler User UserRepository CreateUser CreateUserHandler |
Преимущества:
- Проще не иметь дело с подпространствами имён. В очень маленьких приложениях это может быть нормально. Если у вас есть 5 классов, кто сказал, что вам вообще нужны подпространства? Если это одиночный пакет с определённым назначением или приложение, у которого есть только 1 «модуль», возможно, не нужно ничего больше, чем одно глобальное пространство имён.
Недостатки:
- В тот момент, когда в ваше приложение прийдёт определённая степень сложности, будет сложно находить классы в большой массе глобального пространства имён. Если у вас есть разделение сущностей и назначений в ваших классах, например, Пользователи и Рецепты — глобальное пространство имён скидывает всё в одну большую кучу. Совсем не модульно.
2. Группировка по паттернам
В коде:
|
<?php namespace App\Commands; class SendReceipt {} |
Структура папок:
|
src Commands SendReceipt CreateUser Entities Receipt User Handlers SendReceiptHandler CreateUserHandler Repositories ReceiptRepository UserRepository |
Преимущества:
- Когда вам нужно найти команду, вы точно знаете, где её искать. Если ваш мозг говорит: «Мне нужно отредактировать одну из моих команд. Какую именно? Ту которая шлёт рецепты», — то этот способ вполне подходит. Эта одноуровневая организация лучше, чем игнорирование пространств имён, но и не глубокая, таким образом она вполне может подойти для средних сайтов.
- Кроме того, ваши связанные классы (например, команды) могут жить рядом друг с другом. Вы сможете найти некоторые сходства, например, между командами
SendReceipt
и SendReminder
.
- Этот метод также позволяет вам проектировать связи между классами программно. Например,
Command Bus
может всегда знать, что обработчик команды (которая живёт вApp\Commands\{commandName}
) всегда находится в App\Handlers\{commandName}Handler
.
Недостатки:
- Этот способ организации разносит ваши классы из одного контекста по различным пространствам имён. Например, у вас может быть
App\Commands\SendReceipt
,App\Receipt
или App\Entities\Receipt
, App\Providers\ReceiptServiceProvider
,App\Handlers\Commands\SendReceiptHandler
, App\Repositories\ReceiptRepository
и т.д. Вся логика рецептов разнесена по различным местам.
- Если вы сфокусированы на модульности и инкапсулированности — этот способ точно не победитель. Потому как вы разносите весь ваш код, например, оплаты, по всему пространству имён. Этот способ организации не фокусирует классы оплаты в одном модуле. Классы находятся рядом только потому, что они связаны архитектурным паттерном, а не потому, что они действительно связаны по смыслу.
3. Группировка по контексту
В коде:
|
<?php namespace App\Billing; class SendReceipt {} |
Структура папок:
|
src Billing Receipt ReceiptRepository SendReceipt SendReceiptHandler User User UserRepository CreateUser CreateUserHandler |
Преимущества:
- Если вы работаете исключительно над Billing в данный момент, вы знаете, что у вас есть всё, связанное с этим, в одном месте. Для ваших рецептов — сущность, команды, обработчики, репозиторий и т.д. — всё в одном месте, красиво связано и находится по одному адресу в одной группе.
- Именно здесь мы начинаем экспериментировать с инкапсуляцией и модульностью. Все наши Billing классы, независимо от их паттерна, находятся в одном месте, что помогает сгруппировать их ментально. Мы можем думать о них как об отдельном модуле, который живёт в нашем приложении.
Недостатки:
- Ваши команды теперь разбросаны по всему коду. Ваши репозитории — тоже. И сущности. И ваши обработчики.
4. Группировка по контексту и паттернам
В коде:
|
<?php namespace App\Billing\Commands; class SendReceipt {} |
Структура папок:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
|
src Billing Entities Receipt Repositories ReceiptRepository Commands SendReceipt Handlers SendReceiptHandler User Entities User Repositories UserRepository Commands CreateUser Handlers CreateUserHandler |
Преимущества:
- Разделение таким способом даёт вам большой уровень разделения пространств имён. Это очень полезно, если у вас большая база кода с большим количеством классов — чем больше классов, тем больше вы будете ценить такой способ разделения.
- Как и в группировке по паттерну, вы можете программно связывать ваши классы.
- И пока ваши классы сгруппированы по паттерну, они всё ещё сгруппированы по контексту. У вас есть модульность и группировка по контексту одновременно.
Недостатки:
- Чем больше ваше пространство имён, тем больше умственной энергии вы потратите на понимание всего пространства имён. Для маленьких и средних приложений это может быть разрушительно.
- Из-за группировки по паттернам на низком уровне у вас больше нет такой же простой организации, как при организации по контексту.
Пример
Небольшой пример организации кода по каждому способу:
Одно глобальное пространство имён
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
|
app Conference ConferenceRepository CreateConference CreateConferenceHandler CreateTalk CreateTalkHandler DeleteConference DeleteConferenceHandler DeleteTalk DeleteTalkHandler ProposeTalkToConference ProposeTalkToConferenceHandler RetractTalkProposal RetractTalkProposalHandler Talk TalkRepository UpdateConference UpdateConferenceHandler UpdateTalk UpdateTalkHandler |
Группировка по паттерну
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29
|
app Commands CreateConference CreateTalk DeleteConference DeleteProposal DeleteTalk ProposeTalkToConference RetractTalkProposal UpdateConference UpdateTalk Entities Conference Proposal Talk Handlers CreateConferenceHandler CreateTalkHandler CreateProposalHandler DeleteConferenceHandler DeleteProposalHandler DeleteTalkHandler ProposeTalkToConferenceHandler RetractTalkProposalHandler UpdateConferenceHandler UpdateTalkHandler Repositories ConferenceRepository TalkRepository |
Группировка по контексту
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
|
app Conferences Conference ConferenceRepository CreateConference CreateConferenceHandler DeleteConference DeleteConferenceHandler UpdateConference UpdateConferenceHandler Talks CreateTalk CreateTalkHandler DeleteTalk DeleteTalkHandler ProposeTalkToConference ProposeTalkToConferenceHandler Talk TalkRepository RetractTalkProposal RetractTalkProposalHandler UpdateTalk UpdateTalkHandler |
Группировка по контексту и паттерну
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31
|
app Conferences Commands CreateConference DeleteConference UpdateConference Entities Conference Handlers CreateConferenceHandler DeleteConferenceHandler UpdateConferenceHandler Repositories ConferenceRepository Talks Commands CreateTalk DeleteTalk ProposeTalkToConference RetractTalkProposal UpdateTalk Entities Talk Handlers CreateTalkHandler DeleteTalkHandler ProposeTalkToConferenceHandler RetractTalkProposalHandler UpdateTalkHandler Repositories TalkRepository |
Вывод
Так какой же ответ?
Он различен в зависимости от каждой конкретной ситуации.
Возможно, что более простая организация лучше работает с маленьким количеством классов и сущностей, а более сложная структура организации подходит для более сложных систем. Но это не жёсткое правило. Я даже не уверен, что это вообще правило.
Я думаю, модульность и инкапсуляция даёт вашему разуму больше пищи для размышления. Даёт вам возможность думать о проектировании каждого подпространства модулем, который может быть в любой момент удалён.
В любом случае, всё зависит только от вас.
Понравилась статья или книга? Поделись с друзями: