presenta
Repository Pattern e Service Layer, come sono rimasto fulminato sulla via di Damasco
Dal pattern MVC al Repository Pattern e Service Layer
Filippo Matteo Riggio
Filippo Matteo Riggio
Technical Project Manager @
Previously:
- CTO / Co.Founder @ Kaleidoscope
- Fullstack Freelance Dev
- Team Leader @ Chroma / London
- Founder di
In principio fu l'MVC
(alias come iniziare lo sviluppo di web app for dummies)
MVC Pattern
Il caso reale
(alias come l'ho presa sui denti a voler semplificare troppo)
Macro funzionalità
L’applicativo ha:
- Una serie di script di import / export dei dati verso Dynamics 365
- Una serie di api json che leggono / scrivono dati
62.574 linee di codice
Il cliente inizia a chiedere CR
(faccio 2 etti di notifiche, che faccio lascio?)
Il cliente richiede nuove funzionalità:
- Sincronie e integrazioni con sistemi esterni (Cerved, OneSignal, Mailgun)
- Notifiche push / email / ecc.
- Tutto tramite Comandi ed Observer di Laravel
187.724 linee di codice
Il cliente chiede altre CR
(...e l’ecommerce con il PIM
e integra l’ERP ...
che al mercato mio padre comprò…)
701.105 linee di codice
Il cliente chiede ancora altre CR
(...e l'app per i clienti
e la piattaforma eventi
che al mercato mio padre comprò…)
1.189.829 linee di codice
Come poteva finire?
Dove si trova la logica applicativa?
(alias dove sta davvero il problema?)
Dove si trova la logica applicativa?
(alias dove sta davvero il problema?)
Dove si trova la logica applicativa?
(alias dove sta davvero il problema?)
Dove si trova la logica applicativa?
(alias dove sta davvero il problema?)
Dove si trova la logica applicativa?
(alias dove sta davvero il problema?)
Dove si trova la logica applicativa?
(alias dove sta davvero il problema?)
Ed ecco che arriva il Service Layer
Service Layer
MVC Ideale VS MVC Reale VS Service Layer
Service Layer - Quando applicarlo?
You probably don't need a Service Layer
if your application's business logic will only have one kind of client
- say, a user interface - and it's use case responses don't involve multiple transactional resources. […]
But as soon as you envision a second kind of client, or a second transactional resource in use case responses, it pays to design in a Service Layer from the beginning.
- Patterns of Enterprise Architecture, Martin Fowler
Service Layer - un esempio in Laravel
<?php
namespace App\Http\Controllers\Api;
use Illuminate\Routing\Controller as BaseController;
use App\Models\Coupon;
class CouponController extends BaseController {
public function store(CouponRequest $request)
{
// Validation in the custom request
$coupon = Coupon::create($request->all());
return response()->json(['coupon' => $coupon]);
}
}
Service Layer - un esempio in Laravel
<?php
namespace App\Services;
use Illuminate\Database\Eloquent\Model;
use App\Models\Coupon;
class CouponService {
public function store(array $data): Model
{
// TODO: Validation
$coupon = Coupon::create($data);
return $coupon;
}
}
Service Layer - un esempio in Laravel
<?php
namespace App\Http\Controllers\Api;
use Illuminate\Http\Request;
use Illuminate\Routing\Controller as BaseController;
use App\Services\CouponService;
class CouponController extends BaseController {
public function store(Request $request)
{
$couponService = app()->make(CouponService::class);
$coupon = $couponService->store( $request->all() );
return response()->json(['coupon' => $coupon]);
}
}
Service Layer - un esempio in Laravel
<?php
namespace App\Console\Commands;
use Illuminate\Console\Command;
use App\Services\CouponService;
class ImportCoupon extends Command {
public function handle()
{
$data = [...]; // IMPORT FROM CSV || IMPORT FROM EXTERNAL DATA SOURCE
if ( $data && count($data) > 0 ) {
$couponService = app()->make(CouponService::class);
foreach ( $data as $item ) {
$coupon = $couponService->store( $item );
}
}
return;
}
}
Service Layer Yahoooo!!
Ho unificato la logica, senza avere codice ripetuto.
E la manutenzione sul lungo periodo is a breeezeee…
Service Layer - Quando NON usarlo
1. Dimensione dell'applicativo non ha senso
2. Durata del progetto è breve (non c'è manutenzione, ecc.)
3. Budget basso
Pro |
---|
- Business Logic centralizzata |
- Manutenzione comoda |
- Testabilità! |
Un buon punto di partenza: https://github.com/zendaemon/service-layer
Contro |
---|
- Verboso |
- Dimensione dell'applicativo crescono |
- Budget |
Credo in un solo ORM
(alias come pensavo fosse facile la vita coi DB)
Svariati ORM
Object-Relational Mapper
Non va inserita
Data Business Logic
Un esempio reale
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Model;
class Company extends Model {
protected $fillable = [...];
public static function getCompaniesByCoords( float $lat, float $lng, int $zoom, array $filters ): Collection
{
//[...]
}
}
Altro problema: Accoppiamento con la tecnologia di persistenza
Ed ecco che arriva
il Repository Pattern in soccorso!
Che cosa è un repository?
Repositories are classes or components that encapsulate the logic required to access data sources.
They centralize common data access functionality, providing better maintainability and decoupling the infrastructure or technology used to access databases from the domain model layer.
- Patterns of Enterprise Architecture, Martin Fowler
<?php
namespace App\Repositories;
use Illuminate\Database\Eloquent\Model;
use App\Models\Company;
class CompanyRepository extends BaseRepository {
public function model()
{
return Company::class;
}
public function getCompaniesByCoords( float $lat, float $lng, int $zoom, array $filters ): Collection
{
$columns = [...];
return $this->model->select($columns)
->havingRaw('distance < ?', [ (40000 / pow(2, $zoom)) *2 ])
->orderBy('distance', 'ASC');
}
}
Repository - un esempio in Laravel
<?php
namespace App\Services;
use App\Repository\CompanyRepository;
class CompanyService {
protected $repository;
public function __construct()
{
$this->repository = app()->make(CompanyRepository::class);
}
public function getCompaniesByCoords( float $lat, float $lng, int $zoom, array $filters ): Collection
{
$companies = $this->repository->getCompaniesByCoords($lat, $lng, $zoom, $filters);
// DO SOME LOGIC WITH $companies
return $companies;
}
}
Repository e Service
MVC Ideal VS MVC Reale VS Service Layer VS Service Layer + Repository Pattern
Repository, yeppa!!
Repository Pattern - In Conclusione
Pro |
---|
- Comodità nel cambio di layer di persistenza |
- Centralizzare query complesse |
- Applicare un layer di caching |
- Applicare transformer layer al dato |
- Applicare presentation layer al dato |
- Testabilità! |
Un buon punto di partenza: https://github.com/andersao/l5-repository
Contro |
---|
- Verboso |
- Dimensione dell'applicativo crescono |
- Budget |
Bibliografia
-
Patterns of Enterprise Application Architecture - Martin Fowler
-
Clean Architecture - Robert C. Martin
Come finiva la storia?
Question Time
Repository Pattern e Service Layer, come sono rimasto fulminato sulla via di Damasco
By Filippo Matteo Riggio
Repository Pattern e Service Layer, come sono rimasto fulminato sulla via di Damasco
Nello sviluppo di applicativi, capita spesso di utilizzare il pattern MVC (probabilmente il pattern più conosciuto). Al crescere delle dimensioni, però, questo pattern risulta "stretto"; con limiti di architettura all'aumentare del numero di funzionalità. Con il repository pattern ed il service layer, molte delle problematiche legate al pattern MVC spariscono; rendendo agevole e consistente lo sviluppo e la manutenibilità degli applicativi. Il tutto verrà illustrato attraverso un progetto reale in PHP / Laravel.
- 233