rupicon 2014 single table inheritance

22
Single Table Inheritance (STI) Raul Pristopan 1 / 22

Upload: rupicon

Post on 31-Jul-2015

240 views

Category:

Technology


2 download

TRANSCRIPT

Page 1: Rupicon 2014 Single table inheritance

Single Table Inheritance (STI)

Raul Pristopan

1 / 22

Page 2: Rupicon 2014 Single table inheritance

Agenda1. Introduction2. What is STI?3. When should we use STI?4. How do we implement STI?5. Reasons why you shouldn't use STI6. Demo

2 / 22

Page 3: Rupicon 2014 Single table inheritance

Introduction

3 / 22

Page 4: Rupicon 2014 Single table inheritance

IntroductionIn the beginning everything always works. Things get complicated withtime when you start adding new features.

Some weeks ago I had to refactor some parts of a project and also addsome new features to it.

After some hours of reviewing the actual code I run into some problems:

1. Same code in multiple places2. Same data stored in 2 or more tables

create_table "users", :force => true do |t|... t.string "image_file_name" t.string "image_content_type" t.integer "image_file_size" t.datetime "image_updated_at"...

4 / 22

Page 5: Rupicon 2014 Single table inheritance

Introductioncreate_table "activities", :force => true do |t|... t.string "image_file_name" t.string "image_content_type" t.integer "image_file_size" t.datetime "image_updated_at"...

create_table "image_attachments", :force => true do |t| t.string "image_file_name" t.string "image_content_type" t.integer "image_file_size" t.datetime "image_updated_at" t.datetime "created_at", :null => false t.datetime "updated_at", :null => false t.integer "used_by_count", :default => 1 t.text "original_url"end

5 / 22

Page 6: Rupicon 2014 Single table inheritance

What is STI?STI is basically the idea of using a single table to reflect multiple modelsthat inherit from a base model, which itself inherits fromActiveRecord::Base.

In the database schema, sub-models are indicated by a single "type"column.

In other words we have:

a base classdescendant classes

6 / 22

Page 7: Rupicon 2014 Single table inheritance

When should we use STI?Should be considered when dealing with model classes that share much ofthe same functionality and data fields (granular control over extending oradding to each class individually)

When you have duplicate code over and over for multiple tables (and notbeing DRY)

STI permits you to use keep your data in a single table while writingspecialized functionality.

7 / 22

Page 8: Rupicon 2014 Single table inheritance

When should we use STI?Suppose you have three classes in your application which model similarthings. To make this easier to think about I’ll be referring to some hypotheticalclasses by name: Business and Employee. Let’s consider three choices formodeling this situation:

1. Polymorphic Associations (separate classes, multiple tables)2. Single Table Inheritance (separate classes, one table)3. Single Class with conditionals (one class, one table)

8 / 22

Page 9: Rupicon 2014 Single table inheritance

When should we use STI?

Polymorphic Associations (separate classes, multiple tables)

With Polymorphic Associations we use modules to share code amongclasses.

We have the following active record models for a “Business” and an“Employee”.

class Business < ActiveRecord::Base # Methods, variables and constantsend

class Employee < ActiveRecord::Base # Methods, variables and constantsend

9 / 22

Page 10: Rupicon 2014 Single table inheritance

When should we use STI?

Polymorphic Associations (separate classes, multiple tables)

For the contact information, we have the following active record models:

class PhoneNumber < ActiveRecord::Base # Methods, variables and constantsend

class Website < ActiveRecord::Base # Methods, variables and constantsend

10 / 22

Page 11: Rupicon 2014 Single table inheritance

When should we use STI?

Polymorphic Associations (separate classes, multiple tables)

Now, for the associations, Business and Employee models can have manyphone numbers and websites. And conversely, Phone Number/Website canbelong to either a Business model or an Employee model.

class Business < ActiveRecord::Base has_many :phone_numbers, :as => phonable has_many :websites, :as => webableend

class Employee < ActiveRecord::Base has_many :phone_numbers, :as => phonable has_many :websites, :as => webableend

11 / 22

Page 12: Rupicon 2014 Single table inheritance

When should we use STI?

Polymorphic Associations (separate classes, multiple tables)

class PhoneNumber < ActiveRecord::Base belongs_to :phonable, :polymorphic => trueend

class Website < ActiveRecord::Base belongs_to :webable, :polymorphic => trueend

Having the above setup, you can get a collection of phone numbers for abusiness instance via the call “@business.phone_numbers.

Similarly, you can get a collection of phone numbers for an employee instancevia “@employee.phone_numbers”.

12 / 22

Page 13: Rupicon 2014 Single table inheritance

When should we use STI?

Single Class with conditionals (one class, one table)

A Single Class is not exactly a design pattern, or anything particularlyinteresting.

I’m thinking of a model with a type-like attribute (maybe called kind) andsome if statements in methods where you need different behavior fordifferent kinds of objects.

13 / 22

Page 14: Rupicon 2014 Single table inheritance

When should we use STI?

Questions to ask yourself

When deciding how to design your data models, here are some questions toask yourself:

1. Are the objects, conceptually, children of a single parent?

2. Do you need to do database queries on all objects together?

3. Do the objects have similar data but different behavior?

14 / 22

Page 15: Rupicon 2014 Single table inheritance

How do we implement STI?

Create the base class

Model: Employee

Attributes:

Name - String

Age - Integer

Department - String

$ rails generate model Employee name:string age:integer department:string

# /app/models/employee.rbclass Employee < ActiveRecord::Base # Methods, variables and constantsend

15 / 22

Page 16: Rupicon 2014 Single table inheritance

How do we implement STI?

Add a :type attribute as a string to the base class

$ rails generate migration add_type_to_employee type:string

16 / 22

Page 17: Rupicon 2014 Single table inheritance

How do we implement STI?

Create any necessary descendant classes

# /app/models/developer.rbclass Developer < Employee # Methods, variables and constantsend

# /app/models/tester.rbclass Tester < Employee # Methods, variables and constantsend

17 / 22

Page 18: Rupicon 2014 Single table inheritance

Reasons why you shouldn't use STI

It creates a cluttered data model

Why don’t we just have one table called objects and store everything asSTI?

STI tables have a tendency to grow and expand as an application develops,and become intimidating and unweildy as it isn’t clear which columnsbelong to which models.

18 / 22

Page 19: Rupicon 2014 Single table inheritance

Reasons why you shouldn't use STI

It forces you to use nullable columns

If sub-classes that you intend to use for STI have many different datafields, then including them all in the same table would result in a lot ofnull values and make it difficult to scale over time. In this case, you mayend up with so much code in your model sub-classes that the sharedfunctionality between sub-classes is minimal and warrants separatetables.

A comic book must have an illustrator, but regular books don’t have anillustrator.

Subclassing Book with Comic using STI forces you to allow illustrator to benull at the database level (for books that aren’t comics), and pushes yourdata integrity up into the application layer, which is not ideal.

19 / 22

Page 20: Rupicon 2014 Single table inheritance

Reasons why you shouldn't use STI

It prevents you from efficiently indexing your data

Every index has to reference the type column, and you end up withindexes that are only relevant for a certain type.

20 / 22

Page 21: Rupicon 2014 Single table inheritance

Reasons why you shouldn't use STI

Two objects types have similar attributes

Both airplanes and bicycles have wheels, but it probalby doesn’t makesense to group them into the same table, given that intuitively, they’redifferent objects that will have vastly different functionality and datafields in an application.

Demo

21 / 22

Page 22: Rupicon 2014 Single table inheritance

Thank you!

22 / 22