presenta
Previously:
- CTO / Co.Founder @ Kaleidoscope
- Fullstack Freelance Dev
- Team Leader @ Chroma / London
- Founder di
(alias come iniziare lo sviluppo di web app for dummies)
(alias come l'ho presa sui denti a voler semplificare troppo)
L’applicativo ha:
62.574 linee di codice
(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
(...e l’ecommerce con il PIM
e integra l’ERP ...
che al mercato mio padre comprò…)
701.105 linee di codice
(...e l'app per i clienti
e la piattaforma eventi
che al mercato mio padre comprò…)
1.189.829 linee di codice
(alias dove sta davvero il problema?)
(alias dove sta davvero il problema?)
(alias dove sta davvero il problema?)
(alias dove sta davvero il problema?)
(alias dove sta davvero il problema?)
(alias dove sta davvero il problema?)
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
<?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]);
}
}
<?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;
}
}
<?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]);
}
}
<?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;
}
}
Ho unificato la logica, senza avere codice ripetuto.
E la manutenzione sul lungo periodo is a breeezeee…
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 |
(alias come pensavo fosse facile la vita coi DB)
<?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
{
//[...]
}
}
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');
}
}
<?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;
}
}
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 |