Page 1
Large scale Rails applications
Florian Dutey
Page 2
www.strikingly.com
Page 5
Fat Models Skinny Controllers
Page 6
If it’s not a controller job, leave it to the model.
Page 9
If the screwdriver can’t solve it, use the hammer.
Page 13
Business complexity
Page 14
Technical complexity
Page 15
Solution = Complexity²
Page 16
Rails doesn't scale!
Page 18
ApplicationHttp
RequestResponse
Page 19
Request Router Controller
ResponseView
Models
Page 20
Request Router Controller
ResponseView
Models
Application
Page 21
Principles• Modularity
• Single Responsibility Object
• Plain Old Ruby Objects
• Inversion Of Control
• Stateless Objects
• Domain Specific Language
Page 23
• Controller
• Test
• Rake tasks
• Jobs
• Daemons
• …
Page 24
Single Responsibility Principle (SRP)
Page 27
Useremail
password
first_name
last_name
address_1
address_2
zip_code
city
country
Page 28
User
email
password
User::Profileuser_id
first_name
last_name
User::Addressuser_idaddress_1
address_2
zip_code
city
country
Page 29
Break things downminimalist objects
Page 30
“Make everything as simple as possible, but not simpler.”
Albert Einstein
Page 31
Plain Old Ruby Objects (PORO)
Page 35
Inversion of controls
Page 36
Separate what and when
Page 39
Why?
• Separate responsibilities
• Remove strong dependencies
• Easier to test
• Write highly abstract processes
Page 40
Stateless objects
Page 43
Why?
• No setup
• Predictable
Page 44
Domain Specific Language
Page 45
Router Controller
Domain
API language
Domain Specific Language
View API language
Page 47
Request Router Controller
ResponseView
Application
?
??
??
Models
Page 48
Services
Application
Forms Policies
Queries Adapters Models
Page 49
Services Forms Policies
Queries Adapters Models
Application
Page 50
Services (1)
Describe processes
Page 53
Services (4)
Create != Signup
Page 57
Services (8)
User::SignupService
Payment::SignupService
user/signup_service_spec
Payment::SignupService
payment/signup_service_spec
Page 58
Services Forms Policies
Queries Adapters Models
Application
Page 59
Forms (1)
Convert inputs in Domain language
Page 60
Forms (2)
USERemail
password
Page 64
Forms (6)
User
email
password
User::Profileuser_id
first_name
last_name
Useremail
password
first_name
last_name
Page 65
Forms (7)
accepts_nested_attributes_for
Page 69
Services Forms Policies
Queries Adapters Models
Application
Page 70
Policies (1)
Describe permissions
Page 74
Services Forms Policies
Queries Adapters Models
Application
Page 75
Queries (1)
Describe how to access data
Page 78
Services Forms Policies
Queries Adapters Models
Application
Page 79
Adapters (1)
Translate DSL into another
Page 80
Adapters (2)
Useremail
password
first_name
last_name
Recurly
Page 82
Adapters (4)
It’s about languages
Page 83
Adapters (5)
3rd party API language
Client
Http request
Ruby method
Page 84
Adapters (6)
Client
API Language
Adapter
DSL
Application
Page 86
Adapters (8)
PaymentManager
RecurlyAdapter StripeAdapter
Page 87
Benefits
• Easy to test (mock client responses)
• New provider => new adapter
• Easy to migrate
• Fake adapters for integration servers
Page 88
Services Forms Policies
Queries Adapters Models
Application
Page 89
Models (1)
Data (& persistency)
Page 90
Models (2)
If it doesn’t fit in models …
Page 91
Models (3)
Then it doesn’t fit in models!
Page 94
It’s not a perfect solution, just a guide
Page 95
Pros
• Easier to browse and discover
• More flexible
• Easier to test
• Easier to debug
• Agnostic (from ActiveRecord)
Page 97
Cons
• Harder to design
• More time on code architecture
• Write more code, more tests
• Write integration tests (IOC)
Page 99
Soft transition
• Code convention
• Focus on data and API
• Express everything in DSL
• Write adapters early
• Drop assets pipeline
• Split FE / BE in different projects
Page 101
More tips
• If it doesn’t fit anywhere, think twice
• If it still doesn’t fit anywhere, you need a new layer
• Check what Java / React community does
Page 102
Rails is a fantastic prototyping tool!
Page 103
Rails is NOT an application framework
Page 104
Rails is a fantastic web framework!