Rein Baarsma
Rein Baarsma

Reputation: 1536

Splitting a Symfony 2 project?

We have a pretty large Symfony 2 web application which has many different endpoints and features:

The database layer (in Doctrine) on this is tightly coupled. Transactions from both the POS and our legacy product are used in the loyalty end-user portals and invoices are based on the same transactions. Obviously there's also many entities that are solely for specific parts of the application.

We originally decided on the single app+bundle approach for ease of programming, which has served us well in developing the whole platform. Unfortunately the main drawbacks are:

I've done some research to splitting a Symfony project into multiple projects (each with it's own github) and using SOA to connect them. My personal experience so far with SOA is that it makes things very hard to test fully and adds lots of overhead when migrating from standard Symfony 2 forms (which I totally love).

I was also thinking on another solution by creating a shared bundle with the shared entities and repositories. This would make it much easier to test code and share common services (managers), although I've also heard argumentation against big managers. The big downside to this is that we cannot simply use doctrine:schema:update then, because sharing the database and updating the database on a project with a lower version of the shared bundle, will remove fields.. causing loss of data. Also on this approach I have been unable to find any examples or use-cases.. which leads me to wonder if it wouldn't have many more downsides.

So my question is: what are common approaches and solutions for splitting a big project like this? And: are there reasons that maybe it should not be split at all?

Upvotes: 4

Views: 555

Answers (2)

Yehor
Yehor

Reputation: 6813

Rein, what was the solution you've finally ended up with? Have you actually split your project?

There is really a lack of information in this area, I just found one reasonable article https://ig.nore.me/presentations/2015/04/splitting-a-symfony-project-into-separate-tiers/

Upvotes: 0

Alisson Reinaldo Silva
Alisson Reinaldo Silva

Reputation: 10695

Although I'm answering your question, It's kinda hard to come with a magical solution for your problems. This is not an attempt to solve all of your problems, nor impose you of following it. This is not the only possible solution, actually this might not even solve your problems. That said, let's begin.

I'd split the project in 4 layers:

  • Presentation Layer: Desktop aplications, Web interfaces (no matter if is php, C#, if it uses Symphony or any other framework and third library components), Mobile Apps, everything end users can see and interact with (also known as GUI). These guys only communicate with Application/Service to request something, like a list of available products, update some data somewhere, send an e-mail for customers. The key here is they really don't know how and where is Appication/Service layer going to do the requested actions.
  • Application/Service Layer: I'd treat this as controllers which can receive requests from the Presentation Layer, and external webservices as well. They look like APIs, and will decide if they have to access/manipulate data through a Repository, or send e-mails using some SMPT service. They just makes the communication between GUI or external webservices which might consume your APIs and Domain/Infra layers. Yet they don't actually know what SMPT service they are using, or where data is going to be stored and how (in a MySql through Doctrine? in Sql Server through Entity Framework? in a NoSql database? txt files?). Application layers usually have their own Models (also known as ViewModels), which are exposed to the world and returned to the requester (GUI or external Webservice), representing part of the domain models. This mapping (convert Domain classes to Application classes) can be done with patterns like Facade and Adapters (also called the Anti-corruption layer), and there are plenty of packages to resolve this (for C#, there is Automapper, for PHP there might exist something either). Why should you need this? To avoid exposing your full domain to the world. Suppose you have Invoice and Loyalty end-users, but you wanna treat them as one unique domain class "User" with their corresponding properties together. You could create a LoyaltyUser and an InvoiceUser classes in your application, each one containing only the necessary properties for that purpose, then use this Mapping technique to map the domain User class to each one of them. Therefore, the application layer usually contains authentication and authorization rules, so only the Loyalty end-user would have permission to access controller's actions which would deal with the LoyaltyUser model. Inside a single action in a controller, you shouldn't take different paths/ways depending on the requester (for mobile, do this, for website, do that). Instead, you might have different actions for each one, and tue Presentation layer knows what they want to request.
  • Domain Layer: This is your core, containing all business logic. This is what provide value to your business. Domain layer container models/classes representing real entities from your world, interfaces for services and repositories. Domain must be the most clean and natural possible. They can't know what application is asking something, nor how type of infra is being used. They just do business logic. The Domain layer don't know if your are using Doctrine or Laravel as an ORM, nor if the application is a php website done with Symphony, or an Android Native App.
  • Infra Layer: Here you implement things like database, SMPT service, Logging, and other things your application might need. Doctrine would reside here. Therefore, you would create Repository classes implementing the repository interfaces of your domain. The Repository implementation uses Doctrine to do stuff. These implementations are providen to Application Layer (normally via Dependency Injection). This means the Application Layer shouldn't know if is Doctrine or Laravel, that's why the Application uses the Repository (so logic to access database are encapsulated).

Your web interfaces would reside in Presentation. If the framework you use in your web have to use MVC and therefore have controllers, these controllers should dispatch to the Application Layer (I know it sounds redundant). Your APIs would reside in Application Layer.

This is very decoupled, if you need to change from Doctrine to Laravel, your don't need to change your Domain nor your Apps. If your need to change from Symphony to anything else, or even change your website from PHP to ASP or Java, your domain don't have to be changed.

Adding more layers, mapping objects, using DI shouldn't make requests slower, considering the hardware's price and capacity nowadays, the difference in time is almost imperceptible. You should put efforts attempting to improve your domain, which brings value for the business. Separating layers improve decoupling, chances of changing part of application breaking other parts, increase flexibility of scaling your app, and makes testing easier.

Upvotes: 3

Related Questions