Upgrade to Pro — share decks privately, control downloads, hide ads and more …

CQRS v rohlik.cz

CQRS v rohlik.cz

Ukázka použití CQRS v praxi, na projektu Rohlik.cz, který je postavený na Doctrine 2 ORM s MySQL a Elastic Search.

Filip Procházka

December 21, 2015
Tweet

More Decks by Filip Procházka

Other Decks in Technology

Transcript

  1. CQRS v @ProchazkaFilip

  2. Co si povíme - Na čem běží Rohlik.cz - Co

    je ORM, a proč ho používat - Seznámení s Doctrine 2 - Seznámení s ElasticSearch - CQRS
  3. Na čem běžíme

  4. Na čem běžíme: platforma - PHP-FPM - NGINX - Percona

    (MySQL) - Redis - RabbitMQ - ElasticSearch
  5. Na čem běžíme: aplikace - Nette Framework - Doctrine 2

    ORM - Symfony komponenty - React.PHP
  6. Na čem běžíme: podpůrné technologie - NewRelic - Papertrail -

    Travis CI - GitHub - Slack - Composer - ...
  7. Proč používat ORM

  8. “Nejhloupější” modely class OrdersModel { private $db; function __construct(DbConnection $db)

    { $this->db = $db; } function findAll() { return $this->db->query("SELECT * FROM orders"); }
  9. ORM? Object-relational mapping is a programming technique for converting data

    between incompatible type systems in object-oriented programming languages. via https://en.wikipedia.org/wiki/Object-relational_mapping
  10. Pseudo-ORM class OrdersModel { private $db; function __construct(DbConnection $db) {

    $this->db = $db; } function findAll() { return $this->mapResult( $this->db->query("SELECT * FROM orders") ); }
  11. Active Record $user = User::create(['name' => 'Tito']); $user = User::find_by_name('Tito');

    $user->name = 'Tito Jr'; $user->save(); $user->delete();
  12. SOLID • Single responsibility principle • Open/closed principle • Liskov

    substitution principle • Interface segregation principle • Dependency inversion principle
  13. Data Mapper $user = new User('Pepa'); $em->persist($user); $em->flush(); $user =

    $em->find(User::class, 1);
  14. Data Mapper - Můžu mít kompletně objektový model - Entity

    jsou objekty, které se nestarají o persistenci - To že je entita uložena v DB je “detail”
  15. Doctrine 2 ORM

  16. Doctrine: architektura DBAL Doctrine ORM Entities Services Facades Database EntityManager

    Repository
  17. Doctrine: DBAL - Obálka nad PDO - Abstrakce mezi databázemi

    - Primitivní datové typy - Schéma - Snadnější DB migrace
  18. Doctrine: - Persistence entit - Událostní systém (Eventy) - UnitOfWork

    - Identity Mapa - DQL Doctrine ORM
  19. Doctrine: class Product { /** @var int */ private $id;

    /** @var string */ private $name; Entities
  20. Doctrine: /** @Entity @Table(name="products") **/ class Product { /** @Id

    @Column(type="integer") @GeneratedValue **/ private $id; /** @Column(type="string") **/ private $name; Entities
  21. Doctrine: Services - Logické jednotky a operace v aplikaci -

    Může být více services na jednu entitu - Může být více entit na jednu service
  22. Doctrine: DQL SELECT b, e, r FROM Bug b JOIN

    b.engineer e JOIN b.reporter r ORDER BY b.created DESC
  23. Doctrine: Facades - Zapouzdřují services - Jedna metoda využívá několik

    service
  24. Doctrine: nevýhody - Je nutné chápat OOP - Je nutné

    chápat DataMapper a spol. - Leaky abstraction - Výkon
  25. ElasticSearch

  26. ElasticSearch - schema-less search engine - umí schéma - škálování

    za hubičku - REST api
  27. ElasticSearch - obsahuje index - indexy obsahují typy - typy

    obsahují dokumenty - dokumenty mají id a fieldy GET /rohlikcz/product/123
  28. ElasticSearch: (de)normalizace - app -> databáze = normalizace - méně

    dat - méně duplikací - horší na dotazování - databáze -> ES = denormalizace - duplikace, duplikace, duplikace - so fucking fast
  29. ElasticSearch GET /megacorp/employee/_search?q=last_name:Smith { ... "hits": { "total": 2, "hits":

    [ { ... "_source": { "first_name": "John", "last_name": "Smith", "age": 25, "about": "I love to go rock climbing", "interests": [ "sports", "music" ] } },
  30. ElasticSearch + Doctrine - Entity se nemapují 1:1 na typy

    - Typy mají vlastní serializery - V serializerech můžu pokládat SQL dotazy - Synchronizace běží v RabbitMQ workeru
  31. ElasticSearch + Doctrine $product = $em->find(Product::class, 1); $product->name = 'Banán';

    $em->flush(); // volá se automaticky $searchSync->append($product);
  32. ElasticSearch + Doctrine

  33. ElasticSearch + Doctrine class ProductSerializer { public function serialize($product) {

    return [ 'id' => $product->id, 'name' => $product->name, ]; }
  34. ElasticSearch + Doctrine $query = (new Query(...)) ->andMust(...); $resultSet =

    $searchManager ->search($query); $products = $productsMapper ->mapResult($resultSet);
  35. ElasticSearch + Doctrine function mapResult(ResultSet $resultSet) { $result = [];

    foreach ($resultSet->results as $item) { $result[$item->id] = new ProductDTO($item->id, $item->source); } return $result; }
  36. ElasticSearch + Doctrine class ProductDTO { private $id; private $source;

    public function __construct($id, $source) { $this->id = $id; $this->source = $source; }
  37. ElasticSearch + Doctrine class ProductDTO { // ... public function

    __get($field) { return $this->source[$field]; }
  38. Command Query Responsibility Segregation

  39. CQS It states that every method should either be a

    command that performs an action, or a query that returns data to the caller, but not both. In other words, Asking a question should not change the answer. via https://en.wikipedia.org/wiki/Command%E2%80%93query_separation
  40. CQRS Applies the CQS principle by using separate Query and

    Command objects to retrieve and modify data, respectively. via https://en.wikipedia.org/wiki/Command%E2%80%93query_separation
  41. CQRS - lepší škálování - větší komplexita - častěji je

    snažší použít CRUD
  42. Shrnutí - ORM je super - S ORM je jednodušší

    se střelit do nohy - ElasticSearch je super - CQRS je super
  43. Dotazy?

  44. Díky za pozornost! @ProchazkaFilip / @PecemeRohlik