Closed kuraobi closed 4 years ago
Thanks for this very first contribution!
Despite all my comments on a great deal of small "issues", I'd be happy to process and merge in a very near future and then continue with other contexts.
I hope my comments won't drive you off. There are two main points:
There is also a couple of changes that I believe do not belong to this PR.
Thanks again for the work you did so far!
I was also wondering how do you feel about the UI/Application/Domain/Infrastructure hexagonal architecture like. Should we add that inside of the context folder? Or do you firmly believe contexts should never grow enough to require such a separation?
I was also wondering how do you feel about the UI/Application/Domain/Infrastructure hexagonal architecture like. Should we add that inside of the context folder? Or do you firmly believe contexts should never grow enough to require such a separation?
I'm not sure about that. In the other projects where I use this architecture, the domain and infrastructure are completely separate, they are not in the App\
namespace and are actually in separate projects.
I think it may be too soon for this project to decide on that, since the project is still pretty small and we're not really sure how it will evolve in structure.
I was also wondering how do you feel about the UI/Application/Domain/Infrastructure hexagonal architecture like. Should we add that inside of the context folder? Or do you firmly believe contexts should never grow enough to require such a separation?
I'm not sure about that. In the other projects where I use this architecture, the domain and infrastructure are completely separate, they are not in the
App\
namespace and are actually in separate projects.I think it may be too soon for this project to decide on that, since the project is still pretty small and we're not really sure how it will evolve in structure.
Right, let's keep this in mind for sometimes later on
PR information
Description
This is a proof of concept for a more modular code organization. I refactored code for Talks, with the different use cases being index (list), create, update, delete, show. This is a very simple example, but gives a good preview of the target code structure. I'll try to explain the main aspects.
Namespacing and naming
All the code related to Talks should be in the
App\Talk
Namespace. Classes are then organized around each feature, i.e.Create
,Delete
,Index
,Update
andShow
. Namespaces describing the type of objects inside (Controller, Entity, ValueObject...) are a very low form of cohesion and are highly discouraged, as they go against a functional structure. As a result, this information is better conveyed with suffixes:App\Controller\Talk\Create
becomesApp\Talk\Create\CreateTalkAction
I also used a more complete class name (
CreateTalkAction
vsCreate
) because it makes code easier to read, it prevents name collision and the necessity for using aliases, and it prevents refactoring errors, but this one is maybe more a personal choice.Configuration files (DI and routes)
Configuration files are also grouped by domain, which means each domain can have its own configuration files. This means a
services.yaml
, adoctrine.yaml
and aroutes.yaml
file in most cases. I have located these files in aResources
directory insidesrc/Talk
because it's convenient and in line with how Symfony bundles are organized, which could be useful if our modules evolve into bundles later on. That being said, one could argue thatsrc
should be code only while all config should go toconfig
, in which case it would also be feasible to replicate this structure inside theconfig
directory.This requires a few lines in the
App\Kernel
to allow detection of config and route files in the right directories.Dependency Injection
One drawback of a functional organization of code is that we basically can use the
resource
option to declare and configure services in Symfony DI. So we need to explicitly list the classes that we want to set as services.Tagging of Actions
A new
App\Action
marker interface has been created to allow easy selection of all actions in theservices.yaml
file, to add thecontroller.service_arguments
tag required. Without the interface, we would have to add the tag on each one of the actionsDoctrine
Doctrine being an implementation, It is kept separated from the rest of the code. This includes the repositories implementations, the fixtures classes, and also the mappings, which are switched to XML for this purpose.
Misc
Having
create
methods into theTalkRepository
really seemed off to me, as I had a dependency between the repository and theRequest
object coming from the form. I chose to move them to a separateTalkFactory
, which I added into theApp\Talk\Create
namespace.