Sergey Protko

Life Without ORM

1970s

Appearance of RDBMS

1980s

OO is a new thing!

1990s

TopLink - First ORM

ORM

is for converting data between incompatible type systems

 id  | customer_id | customer_name | start_point_address | start_point_latitude 
-----+-------------+---------------+---------------------+----------------------
5131 |         243 | John Doe      | 5 Galvin Street     | 42.2123441
Journey({
   "id": "5131",
   "passenger": Passenger({
        "id": "241",
        "name": "John Doe"
   }),
   "startingPoint": Location({
     "address": "5 Galvin Street Strongsville, OH 44136"
         "latitude": 42.2123441,
         "longitude": 71.043143
    }),
    "destination": Location({
         "address": "931 Wakefield Street, OH 44136",
         "latitude":42.26524,
         "longitude": 71.18643
    })
})
Journey({
   "id": "877c41d5-5677-405d-a19d-73ff2e27e2e1",
   "startingPoint": Location({
     "address": "5 Galvin Street Strongsville, OH 44136"
         "latitude": 42.2123441,
         "longitude": 71.043143
    }),
    "destination": Location({
         "address": "931 Wakefield Street, OH 44136",
         "latitude":42.26524,
         "longitude": 71.18643
    }),
    "passenger": Passenger({
        "id": "05737a99-eae6-4a22-bdc3-01a5a6952331"
    })
})

Object Model

Relational Model

Relations,

variables, attributes

Journey({
   "id": "877c41d5-5677-405d-a19d-73ff2e27e2e1",
   "startingPoint": Location({
     "address": "5 Galvin Street Strongsville, OH 44136"
         "latitude": 42.2123441,
         "longitude": 71.043143
    }),
    "destination": Location({
         "address": "931 Wakefield Street, OH 44136",
         "latitude":42.26524,
         "longitude": 71.18643
    }),
    "passenger": Passenger({
        "id": "05737a99-eae6-4a22-bdc3-01a5a6952331"
    })
})

Object Model

Aggregate!

Value Objects!

So... relations vs objects

  • Primitive obsession
  • No encapsulation
  • No references
  • No custom data types

The Vietnam of Computer Science

2000s

Object-oriented Databases
so HOT right now!

2000s

Object-oriented Databases
so HOT right now!

There is no silver bulet

ORM

still useful for OLTP

How things going in PHP?

  • Doctrine ORM
  • Eloquent
  • Propel
  • RedBeanPHP
  • Atlas.ORM

Why the hell

you want to live without ORM?

Hidden Complexity

Primitive obsession

leaks to objects

public function setName(string $name): void
{
    $this->name = $name;
}

public function getName(): string
{
    return $this->name;
}

Doesn't matter for small app,

but all apps small in the beginning

CRUD

Sometimes instead of update
you just need new version

Upserts may be handy,

and your ORM can't do that

Referencial integrity

means no unidirectional one-to-many

public function addPhonNumber(string $phoneNumber): void
{
    $this->phones->add(
        new PhoneNumber($this, $phoneNumber)
    );
}

JSON

to the rescue

Even SQLite can do that

Associations

it's often better to share ID rather that reference

Many-to-many

overused in the wild

This is all about writes

but how should I list completed journeys?

We may ignore

references on read operations!

No need for UoW,

no need for identity map,

very simple mapping

Lazy Load

Sometime it's easier to just map several result sets rather than normalize huge one

Lazy Load

Sometime it's easier to just map several result sets rather than normalize huge one

GraphQL

Api Gateways

UI as composition of functions

Portability

SQL is a standart

and you have DBAL for that

Database Views!

is a thing!

CQRS

CQRS

Ref: https://medium.com/eleven-labs/cqrs-pattern-c1d6f8517314

Event sourcing

and you don't care about database

Journey({
   "id": "877c41d5-5677-405d-a19d-73ff2e27e2e1",
   "startingPoint": Location({
     "address": "5 Galvin Street Strongsville, OH 44136"
         "latitude": 42.2123441,
         "longitude": 71.043143
    }),
    "destination": Location({
         "address": "931 Wakefield Street, OH 44136",
         "latitude":42.26524,
         "longitude": 71.18643
    }),
    "passenger": "05737a99-eae6-4a22-bdc3-01a5a6952331",
    "driver": null,
    "status": "pending"
})
Journey({
   "id": "877c41d5-5677-405d-a19d-73ff2e27e2e1",
   "startingPoint": Location({
     "address": "5 Galvin Street Strongsville, OH 44136"
         "latitude": 42.2123441,
         "longitude": 71.043143
    }),
    "destination": Location({
         "address": "931 Wakefield Street, OH 44136",
         "latitude":42.26524,
         "longitude": 71.18643
    }),
    "passenger": "05737a99-eae6-4a22-bdc3-01a5a6952331",
    "driver": "15737a98-eae6-4a22-bdc3-01a5a6952331",
    "status": "arrived"
})
Journey({
   "id": "877c41d5-5677-405d-a19d-73ff2e27e2e1",
   "startingPoint": Location({
     "address": "5 Galvin Street Strongsville, OH 44136"
         "latitude": 42.2123441,
         "longitude": 71.043143
    }),
    "destination": Location({
         "address": "931 Wakefield Street, OH 44136",
         "latitude":42.26524,
         "longitude": 71.18643
    }),
    "passenger": "05737a99-eae6-4a22-bdc3-01a5a6952331",
    "driver": "15737a98-eae6-4a22-bdc3-01a5a6952331",
    "status": "complete"
})

Each UI feature

could have it's own data model

Very sensitive

to decomposition of your domain

and unique constraints requires hacks...

Eventual Consistency

but this is topic for another time

Life without ORM

By Sergey Protko

Life without ORM

  • 237