Slide 1

Slide 1 text

You're modeling it wrong

Slide 2

Slide 2 text

Marijn Huizendveld

Slide 3

Slide 3 text

@marijn

Slide 4

Slide 4 text

@huizendveld

Slide 5

Slide 5 text

Your tickets, our concern.

Slide 6

Slide 6 text

Command Query Responsibility Segregation

Slide 7

Slide 7 text

Command Query Responsibility Segregation

Slide 8

Slide 8 text

CQRS? Did you mean cars? cqrs

Slide 9

Slide 9 text

Relevantie: Complexe applicaties

Slide 10

Slide 10 text

•Waardevolle data •Continue onderhevig aan andere vereisten •Schaalbaarheid is belangrijk Dat wil zeggen:

Slide 11

Slide 11 text

Applicaties die direct bijdragen aan het concurrentievoordeel van de organisatie

Slide 12

Slide 12 text

Wie van jullie werkt momenteel aan een complexe applicatie?

Slide 13

Slide 13 text

Huidige situatie

Slide 14

Slide 14 text

No content

Slide 15

Slide 15 text

RDBMS

Slide 16

Slide 16 text

NoSQL

Slide 17

Slide 17 text

CREATE READ UPDATE DELETE

Slide 18

Slide 18 text

CREATE

Slide 19

Slide 19 text

POST /products

Slide 20

Slide 20 text

INSERT INTO product (name, version) VALUES (“iPhone”, 5)

Slide 21

Slide 21 text

READ

Slide 22

Slide 22 text

GET /products/iphone

Slide 23

Slide 23 text

SELECT * FROM product WHERE name = “iPhone” AND version > 4

Slide 24

Slide 24 text

UPDATE

Slide 25

Slide 25 text

PATCH /products/iphone

Slide 26

Slide 26 text

UPDATE product SET available = 0 WHERE version < 4

Slide 27

Slide 27 text

DELETE

Slide 28

Slide 28 text

DELETE /products/iphone

Slide 29

Slide 29 text

DELETE product WHERE version < 4

Slide 30

Slide 30 text

OOP I

Slide 31

Slide 31 text

OOP

Slide 32

Slide 32 text

OOP WE

Slide 33

Slide 33 text

name = $name; } public function getId() { return $this->id; } public function getName() { return $this->id; } }

Slide 34

Slide 34 text

Enter ORM

Slide 35

Slide 35 text

persist($iPhone); $entityManager->flush();

Slide 36

Slide 36 text

INSERT INTO product VALUES (“iPhone”)

Slide 37

Slide 37 text

Awesome?

Slide 38

Slide 38 text

Voor een blog app?

Slide 39

Slide 39 text

Ja!

Slide 40

Slide 40 text

Voor complexe applicaties?

Slide 41

Slide 41 text

Nee!

Slide 42

Slide 42 text

We're modeling this wrong

Slide 43

Slide 43 text

Problemen •Betekenisarm model •Niet intuïtief voor de gebruiker •Het model is beperkt en niet contextueel •Complexe queries zijn moeilijk •Waardevolle data gaat continue verloren

Slide 44

Slide 44 text

En nu?

Slide 45

Slide 45 text

Command Query Responsibility Segregation

Slide 46

Slide 46 text

Je kunt er vandaag nog mee beginnen...

Slide 47

Slide 47 text

Echt waar Mike?

Slide 48

Slide 48 text

Stap 1: Splits je universele model in twee modellen

Slide 49

Slide 49 text

Een read-model

Slide 50

Slide 50 text

name; } public function getAddress() { return $this->address; } public function getGender() { return $this->gender; } }

Slide 51

Slide 51 text

Een write-model

Slide 52

Slide 52 text

name = $name; } public function setAddress(Address $address) { $this->address = $address; } public function setGender($gender) { $this->gender = $gender; } }

Slide 53

Slide 53 text

So what?

Slide 54

Slide 54 text

Je kunt ze nu onafhankelijk inrichten

Slide 55

Slide 55 text

Je kunt ze onafhankelijk schalen

Slide 56

Slide 56 text

Stap 2: Geef de methoden van je write- model betekenis

Slide 57

Slide 57 text

name = $name; $this->gender = $gender; $this->address = $address; } public function moveToNewLivingAddress(Address $newAddress) { $this->address = $newAddress; } }

Slide 58

Slide 58 text

So what?

Slide 59

Slide 59 text

Nu is het duidelijk welke gegevens samen gewijzigd mogen worden

Slide 60

Slide 60 text

Je kunt nu formulieren maken voor alleen die wijzigingen

Slide 61

Slide 61 text

Stap 3: Ontwikkel specifieke read-models

Slide 62

Slide 62 text

* @version $Revision: 163 $ changed by $Author: buroknapzak $ * * @copyright De Baas Media (2010) */ class kluPublicationPeer extends BasekluPublicationPeer { /** * Select the publications that have recently been updated. * * @param string $arg_connection * * @return array */ static public function retrieveRecentlyUpdatedForDomain ($arg_domainUnifiedResourceName = NULL, $arg_connection = NULL) { $sql = "SELECT * FROM (SELECT `publications`.`id` AS ID " . ", `publications`.`name` AS NAME " . ", `publications`.`unified_resource_name` AS UNIFIED_RESOURCE_NAME " . ", `publications`.`domain_unified_resource_name` AS DOMAIN_UNIFIED_RESOURCE_NAME " . ", `publications`.`introduction` AS INTRODUCTION " . ", `publications`.`created_at` AS CREATED_AT " . ", MAX(`revision_requests`.`applied_at`) AS UPDATED_AT " . ", `publications`.`deleted_at` AS DELETED_AT " . "FROM `revision_requests` " . "LEFT JOIN `updates` " . "ON (`updates`.`id` = `revision_requests`.`update_id`) " . "LEFT JOIN `update_collections` " . "ON `updates`.`collection_unified_resource_name` = `update_collections`.`unified_resource_name` " . "LEFT JOIN `publications` " . "ON (`publications`.`id` = `revision_requests`.`publication_id`) " . "WHERE `updates`.`revision_request_id` IS NULL " . "AND `publications`.`deleted_at` IS NULL " . "AND `publications`.`domain_unified_resource_name` = ? " . "AND `update_collections`.`publish_at` <= NOW() " . "AND `update_collections`.`publish_until` > NOW() " . "GROUP BY `revision_requests`.`publication_id` " . "ORDER BY `updated_at` DESC) " . "`publications` ORDER BY `updated_at` DESC"; $connection = NULL === $arg_connection ? Propel::getConnection(self::DATABASE_NAME) : $arg_connection; $statement = $connection->prepareStatement($sql); return self::populateObjects($statement->executeQuery(array(0 => $arg_domainUnifiedResourceName), ResultSet::FETCHMODE_NUM)); } }

Slide 63

Slide 63 text

* @version $Revision: 163 $ changed by $Author: buroknapzak $ * * @copyright De Baas Media (2010) */ class kluPublicationPeer extends BasekluPublicationPeer { /** * Select the publications that have recently been updated. * * @param string $arg_connection * * @return array */ static public function retrieveRecentlyUpdatedForDomain ($arg_domainUnifiedResourceName = NULL, $arg_connect { $sql = "SELECT * FROM recently_updated WHERE domain = ? ORDER BY `updated_at` DESC"; $connection = NULL === $arg_connection ? Propel::getConnection(self::DATABASE_NAME) : $arg_connection; $statement = $connection->prepareStatement($sql); return self::populateObjects($statement->executeQuery(array(0 => $arg_domainUnifiedResourceName), ResultSe } }

Slide 64

Slide 64 text

Samenvatting

Slide 65

Slide 65 text

Samenvatting •Splitsen heeft het model betekenis gegeven •De interface is nu task-oriented •Het model kent de context van de data •Complexe queries zijn geëlimineerd

Slide 66

Slide 66 text

Vragen?

Slide 67

Slide 67 text

• http://cqrs.files.wordpress.com/2010/11/cqrs_documents.pdf • http://codebetter.com/gregyoung/2010/02/16/cqrs-task-based-uis-event-sourcing-agh/ • http://martinfowler.com/bliki/CQRS.html • http://www.viddler.com/v/dc528842 Meer informatie: