architecting your models

Download Architecting Your Models

If you can't read please download the document

Upload: matthew-weier-ophinney

Post on 16-Apr-2017

33.612 views

Category:

Technology


0 download

TRANSCRIPT

Architecting Your Models

Matthew Weier O'PhinneyProject LeadZend Framework

Goals

Learn to recognize why old habits may be bad

Learn several design patterns that can help you write testable, maintainable code

Learn some techniques for altering existing behavior without rewriting existing code

What We've Learned and What We Do

Oooh! Let's create the schema!

Write code that uses the DB

Plain Old Mysql (POM)

ActiveRecord

Table/Row Data Gateway

And then

We start lamenting about performance.

We end up refactoring for every new feature (e.g. caching, logging).

We need to go to a Service Oriented Architecture, and effectively refactor twice.

STOP
THE
MADNESS!

Step One

Models are just classes.
Create classes.

Models have metadata and behavior;
create properties and methods.

class Person implements PersonInterface{ // Metadata protected $_email; protected $_password; protected $_username;

// Cheat: use overloading to
// provide setters/getters public function __get($name) { } public function __set($name, $value) { }

// Behaviors public function authenticate() { } public function logout() { } public function ban() { }}

Step Two

Now start thinking
about data persistence.

Identify what data you need to persist

Identify how you'll persist the data

Write code for persisting data
(Data Access Layer)

CREATE TABLE person( username VARCHAR PRIMARY KEY, password VARCHAR, email VARCHAR,);

class PersonTable
extends Zend_Db_Table_Abstract{ protected $_name = 'person'; protected $_primary = 'username';}

Step Three

Map your model
to your data.

Common approaches

Transaction Script (can even use POM)

Table Module (often with ActiveRecord or Table Data Gateway)

Data Mapper / ORM

class PersonMapper
implements PersonMapperInterface{ public function save(PersonInterface $person) { $data = array( 'username' => $person->username, 'password' => $person->password, 'email' => $person->email, ); $this->getTable()->save($data); }

public function fetch($username); public function getTable(); public function setTable($table);}

Some notes:

Data !== Relational Database.

Data could come from a document database, filesystem, cache, or web service.

Choose an ORM that allows you to generate your schema from your entities; allows you to easily model first, and persistence comes for free.

Step Four

Move business and
application logic to
a Service Layer.

Applications
are like onions;
they have layers.

Photo 2008, Mike Chaput-Branson

The Service Layer
provides application logic
on top of your models

Service Layer
in perspective

Data Access Objects and Data store(s)

Data Mappers

Domain Models

Service Layer

Benefits to a Service Layer

Allows easy consumption of the application
via your MVC layer

Allows easy re-use of your application
via services

Write CLI scripts that consume the
Service Layer

What kind of application logic?

Validation and filtering

Authentication and Authorization

Transactions and interactions between model entities

class PersonService{ public function create(array $data) { $person = new Person(); if (!$data = $this->getValidator()
->isValid($data)
) { throw new InvalidArgumentException(); } $person->username = $data['username']; $person->password = $data['password']; $person->email = $data['email']; $this->getMapper()->save($person); return $person; }}

Decorating for
fun and profit

Decorators allow you
to add or alter functionality
of an existing class.

Typical decorators

Implement the same interface(s) of the class being decorated

Often use overloading to proxy to the decorated class

Override specific behavior(s) you wish to modify or enhance

Add new behaviors that use existing behaviors in the decorated class

Refactor to add caching?
No!
Decorate!

class CachingPersonMapper
implements PersonMapperInterface{ public function __construct(
PersonMapperInterface $mapper) { $this->_mapper = $mapper; }

public function fetch($username) { $cache = $this->getCache(); if (!$person = $cache->load($username)) { $person = $this->_mapper
->fetch($username); $cache->save($person, $username); } return $person; }}

Refactor to provide alternate
return formats? (e.g., JSON, XML, etc.)
No!
Decorate!

class JsonPerson implements PersonInterface{ public function __construct(
PersonInterface $person
) { $this->_person = $person; }

public function __toString() { $data = array( 'username' => $this->_person->username, 'email' => $this->_person->email, ); return json_encode($data); }}

Nicely Formed
Objects

Rebuilding and refactoring is costly and painful

Good OOP and encapsulation CAN make your life easier

Testing is easier than debugging

Choose a good ORM to expedite development. (Doctrine, Object Freezer, Zend_Entity, etc.)

Think beyond
the DB!

Thank you!

Feedback: http://joind.in/918

Twitter: @weierophinney

Blog: http://weierophinney.net/matthew/

Click to edit the title text format

Click to edit the outline text formatSecond Outline LevelThird Outline LevelFourth Outline LevelFifth Outline LevelSixth Outline LevelSeventh Outline LevelEighth Outline LevelNinth Outline Level

All rights reserved. Zend Technologies, Inc.

Click to edit the title text format

Click to edit the outline text formatSecond Outline LevelThird Outline LevelFourth Outline LevelFifth Outline LevelSixth Outline LevelSeventh Outline LevelEighth Outline LevelNinth Outline Level

All rights reserved. Zend Technologies, Inc.

Click to edit the title text format

Click to edit the outline text formatSecond Outline LevelThird Outline LevelFourth Outline LevelFifth Outline LevelSixth Outline LevelSeventh Outline LevelEighth Outline LevelNinth Outline Level

All rights reserved. Zend Technologies, Inc.