DarkmiraTour / community-event-manager

Web application with a collection of tools helping people organising community events such as multi-days conference with reminders, CRM and such
GNU General Public License v3.0
21 stars 22 forks source link

feature oriented architecture #211

Closed kuraobi closed 4 years ago

kuraobi commented 4 years ago

PR information

Q A
Branch? Develop
Bug fix? no
New feature? no
Tests pass? yes
Related issue Fixes #210

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 and Show. 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 becomes App\Talk\Create\CreateTalkAction

I also used a more complete class name (CreateTalkAction vs Create) 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, a doctrine.yamland a routes.yaml file in most cases. I have located these files in a Resources directory inside src/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 that src should be code only while all config should go to config, in which case it would also be feasible to replicate this structure inside the config 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 the services.yaml file, to add the controller.service_arguments tag required. Without the interface, we would have to add the tag on each one of the actions

Doctrine

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 the TalkRepository really seemed off to me, as I had a dependency between the repository and the Request object coming from the form. I chose to move them to a separate TalkFactory, which I added into the App\Talk\Create namespace.

tdutrion commented 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!

tdutrion commented 4 years ago

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?

kuraobi commented 4 years ago

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.

tdutrion commented 4 years ago

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