a soa approximation on symfony
TRANSCRIPT
![Page 1: A soa approximation on symfony](https://reader033.vdocument.in/reader033/viewer/2022042906/58a6c4b91a28abcc458b4973/html5/thumbnails/1.jpg)
A SOA Approximation using Symfony
Joseluis Laso & Carlos Agudo
![Page 2: A soa approximation on symfony](https://reader033.vdocument.in/reader033/viewer/2022042906/58a6c4b91a28abcc458b4973/html5/thumbnails/2.jpg)
Who we are
•Carlos Agudo (@karloslupus)•Joseluis Laso (@jl_laso)
And Others.. (Spanish team)• Petar Georgiev (@pgkirilov)• Daniel Abad (@ruudy_es)• Noel García (@wolfwolker)• Joaquín Fernández Campo
(@xocas__)• Miguel Vilata
(@miguelvilata)
![Page 3: A soa approximation on symfony](https://reader033.vdocument.in/reader033/viewer/2022042906/58a6c4b91a28abcc458b4973/html5/thumbnails/3.jpg)
Where?
![Page 4: A soa approximation on symfony](https://reader033.vdocument.in/reader033/viewer/2022042906/58a6c4b91a28abcc458b4973/html5/thumbnails/4.jpg)
What is Digilant
DSP: Demand Side Platform => programmatic advertising.
We have a backend to configure ours RTB bidder(s) architecture.• A programmatic campaign can have thousands of
parameters.
![Page 5: A soa approximation on symfony](https://reader033.vdocument.in/reader033/viewer/2022042906/58a6c4b91a28abcc458b4973/html5/thumbnails/5.jpg)
Long journey
From monolithic sf1 (legacy , 8 years of development) to a SOA in sf2-3:
![Page 6: A soa approximation on symfony](https://reader033.vdocument.in/reader033/viewer/2022042906/58a6c4b91a28abcc458b4973/html5/thumbnails/6.jpg)
Requirements
• API Rest• Auto Scalable (can be a huge huge demanding
platform)• Symfony 2• Easy to deploy
![Page 7: A soa approximation on symfony](https://reader033.vdocument.in/reader033/viewer/2022042906/58a6c4b91a28abcc458b4973/html5/thumbnails/7.jpg)
So?
![Page 8: A soa approximation on symfony](https://reader033.vdocument.in/reader033/viewer/2022042906/58a6c4b91a28abcc458b4973/html5/thumbnails/8.jpg)
Do not try this at home
![Page 9: A soa approximation on symfony](https://reader033.vdocument.in/reader033/viewer/2022042906/58a6c4b91a28abcc458b4973/html5/thumbnails/9.jpg)
Yes Symfony 2-3
Bundle: “A bundle is simply a structured set of files within a directory that implement a single feature. “
-- We can split services as bundles, and start here.This sounds weird??Uncle Bob: “Don't leap into microservices just because it sounds cool. Segregate the system into jars using a plugin architecture first. If that's not sufficient, then consider introducing service boundaries at strategic points.”
![Page 10: A soa approximation on symfony](https://reader033.vdocument.in/reader033/viewer/2022042906/58a6c4b91a28abcc458b4973/html5/thumbnails/10.jpg)
Some Questions arose
• One repo? One per service orchestrated with composer? • One repo, let’s split it later, and coordinate with composer
later. (easier to develop)• One Db per service? One db for the whole project, with
soft-relations between services?• One Db for the whole project, let’s split it later. (easier to
develop??, careful with soft-relations, lost of referential integrity)
![Page 11: A soa approximation on symfony](https://reader033.vdocument.in/reader033/viewer/2022042906/58a6c4b91a28abcc458b4973/html5/thumbnails/11.jpg)
Our motto
Let’s split it later
And let’s start!!
![Page 12: A soa approximation on symfony](https://reader033.vdocument.in/reader033/viewer/2022042906/58a6c4b91a28abcc458b4973/html5/thumbnails/12.jpg)
Backend Services View
Bundles
![Page 13: A soa approximation on symfony](https://reader033.vdocument.in/reader033/viewer/2022042906/58a6c4b91a28abcc458b4973/html5/thumbnails/13.jpg)
Yes, services bundles
![Page 14: A soa approximation on symfony](https://reader033.vdocument.in/reader033/viewer/2022042906/58a6c4b91a28abcc458b4973/html5/thumbnails/14.jpg)
Service- Machine
We can create as many services-machine as we want. Depending on demand. We can cook them!!
Fully elastic scalability.LineItem Service - Machine
LineItem Core
LineItem- Campaign - Machine
LineItem
Campaign
Core
![Page 15: A soa approximation on symfony](https://reader033.vdocument.in/reader033/viewer/2022042906/58a6c4b91a28abcc458b4973/html5/thumbnails/15.jpg)
Cooking Process 1
Using ansistrano (ansible), in each deploy, we can select how many bundles a machine have.
Machine A- Geo and Creatives Machine B- All services but Pixel
![Page 16: A soa approximation on symfony](https://reader033.vdocument.in/reader033/viewer/2022042906/58a6c4b91a28abcc458b4973/html5/thumbnails/16.jpg)
Cooking Process 2
We need to dynamically load, our “bundles-service” on deploy, our models, our routings, etc..
A lot of magic happens here!
Compiler pass to the rescue!
![Page 17: A soa approximation on symfony](https://reader033.vdocument.in/reader033/viewer/2022042906/58a6c4b91a28abcc458b4973/html5/thumbnails/17.jpg)
Cooking Process 3
In our AppKernel.php. We have the LocateBundles (utility class) in a CoreBundle
![Page 18: A soa approximation on symfony](https://reader033.vdocument.in/reader033/viewer/2022042906/58a6c4b91a28abcc458b4973/html5/thumbnails/18.jpg)
Core Bundle
We have a CoreBundle, that act as a glue, (Compiler passes)• Communication between services (Can be http-
external, http-internal, process) We have a call Router. API-REST, that’s why http-internal or external
• Some bussines event listeners (a filter for accounts, softdelete, audit db listener)
• User-Permission Model
![Page 19: A soa approximation on symfony](https://reader033.vdocument.in/reader033/viewer/2022042906/58a6c4b91a28abcc458b4973/html5/thumbnails/19.jpg)
Models 1
In order to don’t get coupled to the persistence implementation (Doctrine), don’t use annotations for defining the model, map in an xml:
![Page 20: A soa approximation on symfony](https://reader033.vdocument.in/reader033/viewer/2022042906/58a6c4b91a28abcc458b4973/html5/thumbnails/20.jpg)
Models 2
We want to use our own folders:
Base?? We will explain it later, we have an autogenerator of code.
![Page 21: A soa approximation on symfony](https://reader033.vdocument.in/reader033/viewer/2022042906/58a6c4b91a28abcc458b4973/html5/thumbnails/21.jpg)
Models 3
Compiler Pass to Load Models in our own folders.
We pass through our bundles, and load models, in our folders.
The key:DoctrineOrmMappingPass
We also use an alias:
LineItem:ThirdPartyDataGeo:City
ServiceName:Model
![Page 22: A soa approximation on symfony](https://reader033.vdocument.in/reader033/viewer/2022042906/58a6c4b91a28abcc458b4973/html5/thumbnails/22.jpg)
Others Compilers Passes
Here we load our services (symfony) in each Bundle.
Also Lists calls (api-rest list call, defaults limit per model, orderby etc..)
![Page 23: A soa approximation on symfony](https://reader033.vdocument.in/reader033/viewer/2022042906/58a6c4b91a28abcc458b4973/html5/thumbnails/23.jpg)
Others Compilers Passes II
Load the routes per each bundle!
![Page 24: A soa approximation on symfony](https://reader033.vdocument.in/reader033/viewer/2022042906/58a6c4b91a28abcc458b4973/html5/thumbnails/24.jpg)
Controller Services
GeoBundle/Resources/config/services.ymlimports: - resource: ServicesControllers/alpha.yml
We load versionable controllers (alpha, v1..) as services:Right now: alpha (Remember WIP?)
Routes:/alpha/creative/*/current/creative/*
![Page 25: A soa approximation on symfony](https://reader033.vdocument.in/reader033/viewer/2022042906/58a6c4b91a28abcc458b4973/html5/thumbnails/25.jpg)
A lot of CRUD tables-controllers
We have a lot of master- admin tables.
We have a RestController for this purpose.
Controversy:- We have a lot of
classes child of this one.
- Needs refactor in services!
![Page 26: A soa approximation on symfony](https://reader033.vdocument.in/reader033/viewer/2022042906/58a6c4b91a28abcc458b4973/html5/thumbnails/26.jpg)
2nd part
And now ….
The funny part :)
![Page 27: A soa approximation on symfony](https://reader033.vdocument.in/reader033/viewer/2022042906/58a6c4b91a28abcc458b4973/html5/thumbnails/27.jpg)
Generator of code
Once upon a time …We had time and we were youngs :) and we decide to invest time creating a code generator to make our life easier … you know ? developers ... this lazy race
With a lot of database schemas per create we thought that was a good idea to convert this MWB files directly in code … and was a really nightmare ...
![Page 28: A soa approximation on symfony](https://reader033.vdocument.in/reader033/viewer/2022042906/58a6c4b91a28abcc458b4973/html5/thumbnails/28.jpg)
Code generator (AKA mwb-import)
But … it worked
MWB file
it’s a ZIP
xmlsqliteetc ..
unzip
generate code with twig
generate fixtures
![Page 30: A soa approximation on symfony](https://reader033.vdocument.in/reader033/viewer/2022042906/58a6c4b91a28abcc458b4973/html5/thumbnails/30.jpg)
ApiDoc documentation generator
document !document !document !document !document !document !
![Page 31: A soa approximation on symfony](https://reader033.vdocument.in/reader033/viewer/2022042906/58a6c4b91a28abcc458b4973/html5/thumbnails/31.jpg)
ApiDoc documentation generator
But not only generates documentation.Why don’t use annotations to generate automatic documentation of API routes ?
There are a couple of bundles in the market that do this.
Again … we thought that we can do better.
![Page 32: A soa approximation on symfony](https://reader033.vdocument.in/reader033/viewer/2022042906/58a6c4b91a28abcc458b4973/html5/thumbnails/32.jpg)
ApiDoc documentation generator/*** @ApiDoc\Description("Create an Account")* @ApiDoc\Method("post")* @ApiDoc\Route("/account")* @ApiDoc\Version("~")* @ApiDoc\Subdomain("account")* @ApiDoc\Param(name="maxBudgetValue",type="decimal",nullable=false,description="Account maxBudgetValue")
* @ApiDoc\Header(name="Authorization", placeholder="Authorization: Bearer {token}", type="string", nullable=false, description="mandatory token obtained in login check call")
* @ApiDoc\ReturnHeader("* HTTP 200 OK* Cache-Control: no-cache* Content-Type: application/json* ")* @ApiDoc\ReturnData(type="json", sample="{'id':'integer'}")*/public function createAction(Request $request)
![Page 33: A soa approximation on symfony](https://reader033.vdocument.in/reader033/viewer/2022042906/58a6c4b91a28abcc458b4973/html5/thumbnails/33.jpg)
DocumentatorFeatures:automatic creation of documentation in html format, including a sandbox to test API endpoints
![Page 35: A soa approximation on symfony](https://reader033.vdocument.in/reader033/viewer/2022042906/58a6c4b91a28abcc458b4973/html5/thumbnails/35.jpg)
DocumentatorFeatures:automatic creation of documentation in html format, including a sandbox to test API endpoints
- export to POSTMAN collection
![Page 36: A soa approximation on symfony](https://reader033.vdocument.in/reader033/viewer/2022042906/58a6c4b91a28abcc458b4973/html5/thumbnails/36.jpg)
Call Router
How to make a call to a service that you even know where is ?
LineItem Service - Machine
LineItem Core
LineItem- Campaign - Machine
LineItem
Campaign
Core
![Page 37: A soa approximation on symfony](https://reader033.vdocument.in/reader033/viewer/2022042906/58a6c4b91a28abcc458b4973/html5/thumbnails/37.jpg)
Call Router
How to call a controller method if you don’t know where exactly is ?
Remember, we can deploy to n-servers …To solve that we created a CallRouter that makes the call internally (if the server has the service required) or makes the call external (guzzle) if the service is in another server.
![Page 38: A soa approximation on symfony](https://reader033.vdocument.in/reader033/viewer/2022042906/58a6c4b91a28abcc458b4973/html5/thumbnails/38.jpg)
Call Router
try { // ... $route = $this->router->match($pathInfo);
return $this->makeInternalCall($route['_controller'], $request);
} catch (ResourceNotFoundException $e) {
return $this->makeExternalCall($request->getMethod(), $subdomain, $pathInfo, $request->getContent());
}
![Page 39: A soa approximation on symfony](https://reader033.vdocument.in/reader033/viewer/2022042906/58a6c4b91a28abcc458b4973/html5/thumbnails/39.jpg)
![Page 40: A soa approximation on symfony](https://reader033.vdocument.in/reader033/viewer/2022042906/58a6c4b91a28abcc458b4973/html5/thumbnails/40.jpg)