Slide 1

Slide 1 text

Beyond the ORM an introduction to DataMapper 2 RuLu 2012 Sunday, June 24, 12

Slide 2

Slide 2 text

Piotr Solnica • codebenders.com • solnic.eu • github.com/solnic • @_solnic_ Sunday, June 24, 12

Slide 3

Slide 3 text

4 Facts about This Talk • It has 2 sections: “ActiveRecord Retrospective” and “DataMapper 2” • It has 2 obligatory pictures of a cat • It has only 1 quote from Martin Fowler’s PoEAA book • It has only 16 code examples Sunday, June 24, 12

Slide 4

Slide 4 text

ActiveRecord Retrospective Sunday, June 24, 12

Slide 5

Slide 5 text

ActiveRecord Pattern Facts Sunday, June 24, 12

Slide 6

Slide 6 text

Active Record Pattern Facts • Simple ORM Pattern • Designed for simple usecases where the business domain is simple. ie. basic CRUD • Mixes together data & behavior • 1:1 mapping between database schema & objects (means tight coupling with the db) Sunday, June 24, 12

Slide 7

Slide 7 text

ActiveRecord in Rails Sunday, June 24, 12

Slide 8

Slide 8 text

class User < ActiveRecord::Base end Active Record in Rails Sunday, June 24, 12

Slide 9

Slide 9 text

Active Record in Rails (User.methods.sort - Object.methods.sort).count # => 391 391 new public class methods... Sunday, June 24, 12

Slide 10

Slide 10 text

WHAT??!! I’m perfectly fine!!! Sunday, June 24, 12

Slide 11

Slide 11 text

• Persistence • Validations • Associations • Life cycle hooks • Typecasting • Mass-assignment security • ...and much much more! Active Record retrospective Sunday, June 24, 12

Slide 12

Slide 12 text

Active Record retrospective • Slow test suites • Lack of real unit tests • God objects • Code hard to reuse and extend • Code hard to refactor Sunday, June 24, 12

Slide 13

Slide 13 text

I don’t think I can take it Anymore! Sunday, June 24, 12

Slide 14

Slide 14 text

I don’t care if we can create a blog in 15 minutes Sunday, June 24, 12

Slide 15

Slide 15 text

but I do care if we can work on a project for 15 months and keep it in a good shape Sunday, June 24, 12

Slide 16

Slide 16 text

DataMapper 2 Sunday, June 24, 12

Slide 17

Slide 17 text

DataMapper 2 “A layer of Mappers that moves data between objects and a database while keeping them independent of each other and the mapper itself.” Martin Fowler Sunday, June 24, 12

Slide 18

Slide 18 text

DataMapper 2 Repository Mapper & Session Domain Model Validation Serialization Extensions Sunday, June 24, 12

Slide 19

Slide 19 text

Domain Model Sunday, June 24, 12

Slide 20

Slide 20 text

Domain Model class City attr_reader :name, :lat, :lng def initialize(attributes) @name, @lat, @lng = attributes.values_at( :name, :lat, :lng ) end end Sunday, June 24, 12

Slide 21

Slide 21 text

Domain Model class CityMapper < DataMapper::Mapper map :name, :lat, :lng end Sunday, June 24, 12

Slide 22

Slide 22 text

Domain Model city = City.new( name: 'Kraków', lat: 123456.789, lng: 987654.321 ) Sunday, June 24, 12

Slide 23

Slide 23 text

Domain Model class GeoLocation include Virtus::ValueObject attribute :lat, Float attribute :lng, Float end class City include Virtus attribute :name, String attribute :location, GeoLocation end Sunday, June 24, 12

Slide 24

Slide 24 text

Domain Model class CityMapper < DataMapper::Mapper map :name map :location, to: [ :lat, :lng ] end Sunday, June 24, 12

Slide 25

Slide 25 text

Session Sunday, June 24, 12

Slide 26

Slide 26 text

Session class Person include Virtus attribute :name, String attribute :city, City end Sunday, June 24, 12

Slide 27

Slide 27 text

Session class PersonMapper < DataMapper::Mapper map :name has 1, :city end Sunday, June 24, 12

Slide 28

Slide 28 text

Session city = City.new( name: 'Kraków', location: { lat: 123456789.123, lng: 987654321.987 } ) person = Person.new(name: 'Piotr') Sunday, June 24, 12

Slide 29

Slide 29 text

Session DataMapper.session do |session| session.track(city) session.track(person) person.city = city session.insert(person) session.commit end Sunday, June 24, 12

Slide 30

Slide 30 text

Repository Sunday, June 24, 12

Slide 31

Slide 31 text

Repository Repository Relation Optimizer Datastore Adapter Sunday, June 24, 12

Slide 32

Slide 32 text

Repository • Complete support for all relational algebra operations • All operations can be run in-memory • Can be extended to support any kind of a datastore • Can be used with multiple different databases • Designed to support per database optimizations Sunday, June 24, 12

Slide 33

Slide 33 text

Repository relation = Veritas::Relation.new([ [ :id, Integer ], [ :name, String ], [ :color, String ] ], [ [ 1, 'Nut', 'Red' ], [ 2, 'Bolt', 'Green' ], [ 3, 'Screw', 'Blue' ], [ 4, 'Screw', 'Red' ], [ 5, 'Cam', 'Blue' ], [ 6, 'Cog', 'Red' ], ] ) Sunday, June 24, 12

Slide 34

Slide 34 text

Repository # projection new_relation = relation.project([ :id ]) # removal new_relation = relation.remove([ :name ]) # rename new_relation = relation.rename(id: :other_id, name: :other_name) # restriction new_relation = relation.restrict { |r| r.color.eq('Red').or(r.color.eq('Blue')) } # natural join new_relation = relation.join(other) Sunday, June 24, 12

Slide 35

Slide 35 text

Repository include Veritas adapter = Adapter::DataObjects.new( "postgres://localhost/test") header = [ [ :id, Integer ], [ :name, String ], [ :color, String ] ] relation = Relation::Base.new( 'items', header) gateway = Relation::Gateway.new( adapter, relation) Sunday, June 24, 12

Slide 36

Slide 36 text

Repository new_relation = gateway.restrict { |r| r.color.eq('Red').or(r.color.eq('Blue')) } new_relation.to_a # SELECT "id", "name", "color" # FROM items # WHERE ( # "color" = 'Red' OR "color" = 'Blue' # ) Sunday, June 24, 12

Slide 37

Slide 37 text

What’s Done Sunday, June 24, 12

Slide 38

Slide 38 text

What’s Done • Veritas • Veritas DataObject Adapter for PostgreSQL • Veritas Optimizer • Virtus (Domain Model features) Sunday, June 24, 12

Slide 39

Slide 39 text

Work in Progress Sunday, June 24, 12

Slide 40

Slide 40 text

Work in Progress • “write” support for Veritas • Mapper • Session/Unit of Work Sunday, June 24, 12

Slide 41

Slide 41 text

Work in Progress • Validations • Migrations • Constraints • Extension Interfaces • More Veritas adapters (sqlite, MySQL, MongoDB, Riak etc.) Sunday, June 24, 12

Slide 42

Slide 42 text

Development Process Sunday, June 24, 12

Slide 43

Slide 43 text

Development Process • All “levels” of API are treated with the same amount of care & love • Using metric tools to verify code quality • Mutation testing with Heckle • 100% YARD documentation coverage Sunday, June 24, 12

Slide 44

Slide 44 text

Virtus Project on CodeClimate Sunday, June 24, 12

Slide 45

Slide 45 text

Resources • https://github.com/datamapper/dm- core/wiki/Roadmap • https://github.com/dkubb/veritas • https://github.com/dkubb/veritas-do- adapter • https://github.com/solnic/virtus • https://github.com/solnic/dm-mapper Sunday, June 24, 12

Slide 46

Slide 46 text

THANKS! Sunday, June 24, 12