Large scale Rails applications
Florian Dutey
www.strikingly.com
Fat Models Skinny Controllers
If it’s not a controller job, leave it to the model.
If the screwdriver can’t solve it, use the hammer.
Business complexity
Technical complexity
Solution = Complexity²
Rails doesn't scale!
ApplicationHttp
RequestResponse
Request Router Controller
ResponseView
Models
Request Router Controller
ResponseView
Models
Application
Principles• Modularity
• Single Responsibility Object
• Plain Old Ruby Objects
• Inversion Of Control
• Stateless Objects
• Domain Specific Language
• Controller
• Test
• Rake tasks
• Jobs
• Daemons
• …
Single Responsibility Principle (SRP)
Useremail
password
first_name
last_name
address_1
address_2
zip_code
city
country
User
email
password
User::Profileuser_id
first_name
last_name
User::Addressuser_idaddress_1
address_2
zip_code
city
country
Break things downminimalist objects
“Make everything as simple as possible, but not simpler.”
Albert Einstein
Plain Old Ruby Objects (PORO)
Inversion of controls
Separate what and when
Why?
• Separate responsibilities
• Remove strong dependencies
• Easier to test
• Write highly abstract processes
Stateless objects
Why?
• No setup
• Predictable
Domain Specific Language
Router Controller
Domain
API language
Domain Specific Language
View API language
Request Router Controller
ResponseView
Application
?
??
??
Models
Services
Application
Forms Policies
Queries Adapters Models
Services Forms Policies
Queries Adapters Models
Application
Services (1)
Describe processes
Services (4)
Create != Signup
Services (8)
User::SignupService
Payment::SignupService
user/signup_service_spec
Payment::SignupService
payment/signup_service_spec
Services Forms Policies
Queries Adapters Models
Application
Forms (1)
Convert inputs in Domain language
Forms (2)
USERemail
password
Forms (6)
User
email
password
User::Profileuser_id
first_name
last_name
Useremail
password
first_name
last_name
Forms (7)
accepts_nested_attributes_for
Services Forms Policies
Queries Adapters Models
Application
Policies (1)
Describe permissions
Services Forms Policies
Queries Adapters Models
Application
Queries (1)
Describe how to access data
Services Forms Policies
Queries Adapters Models
Application
Adapters (1)
Translate DSL into another
Adapters (2)
Useremail
password
first_name
last_name
Recurly
Adapters (4)
It’s about languages
Adapters (5)
3rd party API language
Client
Http request
Ruby method
Adapters (6)
Client
API Language
Adapter
DSL
Application
Adapters (8)
PaymentManager
RecurlyAdapter StripeAdapter
Benefits
• Easy to test (mock client responses)
• New provider => new adapter
• Easy to migrate
• Fake adapters for integration servers
Services Forms Policies
Queries Adapters Models
Application
Models (1)
Data (& persistency)
Models (2)
If it doesn’t fit in models …
Models (3)
Then it doesn’t fit in models!
It’s not a perfect solution, just a guide
Pros
• Easier to browse and discover
• More flexible
• Easier to test
• Easier to debug
• Agnostic (from ActiveRecord)
Cons
• Harder to design
• More time on code architecture
• Write more code, more tests
• Write integration tests (IOC)
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
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
Rails is a fantastic prototyping tool!
Rails is NOT an application framework
Rails is a fantastic web framework!