the next five years of rails
DESCRIPTION
Yehuda Katz - "The Nex Five Years"TRANSCRIPT
![Page 1: The Next Five Years of Rails](https://reader034.vdocuments.mx/reader034/viewer/2022052619/555eba9cd8b42a08408b58f9/html5/thumbnails/1.jpg)
The Next Five Years
RAILS
![Page 2: The Next Five Years of Rails](https://reader034.vdocuments.mx/reader034/viewer/2022052619/555eba9cd8b42a08408b58f9/html5/thumbnails/2.jpg)
THE LAST FIVE YEARS
![Page 3: The Next Five Years of Rails](https://reader034.vdocuments.mx/reader034/viewer/2022052619/555eba9cd8b42a08408b58f9/html5/thumbnails/3.jpg)
WHY DO WELIKE RAILS?
![Page 4: The Next Five Years of Rails](https://reader034.vdocuments.mx/reader034/viewer/2022052619/555eba9cd8b42a08408b58f9/html5/thumbnails/4.jpg)
"CONVENTION OVER CONFIGURATION"
![Page 5: The Next Five Years of Rails](https://reader034.vdocuments.mx/reader034/viewer/2022052619/555eba9cd8b42a08408b58f9/html5/thumbnails/5.jpg)
TRIVIAL CHOICES.
When we say "convention over configuration", we mostly mean eliminating trivial choices.
![Page 6: The Next Five Years of Rails](https://reader034.vdocuments.mx/reader034/viewer/2022052619/555eba9cd8b42a08408b58f9/html5/thumbnails/6.jpg)
■ Naming
■ Asset compilation
■ To test or not to test
■ Routing HTTP to controllers
■ File structure and architecture
TRIVIAL CHOICES.
![Page 7: The Next Five Years of Rails](https://reader034.vdocuments.mx/reader034/viewer/2022052619/555eba9cd8b42a08408b58f9/html5/thumbnails/7.jpg)
MORE COMMON CONCERNS REQUIRE FEWER DECISIONS.
![Page 8: The Next Five Years of Rails](https://reader034.vdocuments.mx/reader034/viewer/2022052619/555eba9cd8b42a08408b58f9/html5/thumbnails/8.jpg)
Rails takes a very hard line on conventions, which forces us to solve problems very completely. There's little room for us to punt problems onto Rails users.
![Page 9: The Next Five Years of Rails](https://reader034.vdocuments.mx/reader034/viewer/2022052619/555eba9cd8b42a08408b58f9/html5/thumbnails/9.jpg)
CSRF PROTECTION
![Page 10: The Next Five Years of Rails](https://reader034.vdocuments.mx/reader034/viewer/2022052619/555eba9cd8b42a08408b58f9/html5/thumbnails/10.jpg)
100% MANUAL.
![Page 11: The Next Five Years of Rails](https://reader034.vdocuments.mx/reader034/viewer/2022052619/555eba9cd8b42a08408b58f9/html5/thumbnails/11.jpg)
<form action="/cash_transfer">{% csrf_token %}
SEMIAUTOMATIC.
![Page 12: The Next Five Years of Rails](https://reader034.vdocuments.mx/reader034/viewer/2022052619/555eba9cd8b42a08408b58f9/html5/thumbnails/12.jpg)
<%= form_for @cash_transfer do |f| %> <%= f.text_field :from %> <%= f.text_field :to %> <%= f.text_field :amount %> <%= button "Transfer!" %><% end %> Enter Text here
AUTOMATIC.
![Page 13: The Next Five Years of Rails](https://reader034.vdocuments.mx/reader034/viewer/2022052619/555eba9cd8b42a08408b58f9/html5/thumbnails/13.jpg)
Cognitive Overhead
Conventions Tools Hand-Rolled
Conventions allow you to avoid thinking about the problem at all while working on features.
Tools make the problem easier to solve, but still make you think about it.
When we don't have a convention for something, we end up forcing the developer to learn about the problem and choose a solution, which is most of the cognitive overhead of solving it yourself.
![Page 14: The Next Five Years of Rails](https://reader034.vdocuments.mx/reader034/viewer/2022052619/555eba9cd8b42a08408b58f9/html5/thumbnails/14.jpg)
The common conventions of Rails applications provide a foundation for additional abstractions.
![Page 15: The Next Five Years of Rails](https://reader034.vdocuments.mx/reader034/viewer/2022052619/555eba9cd8b42a08408b58f9/html5/thumbnails/15.jpg)
COURSE CORRECTIONS
No interest in cosmetic, no time for refactoring.
Interested in figuring out why my clients don't want me to use Rails.
![Page 16: The Next Five Years of Rails](https://reader034.vdocuments.mx/reader034/viewer/2022052619/555eba9cd8b42a08408b58f9/html5/thumbnails/16.jpg)
MANY PEOPLEHAVE A PROBLEM.
Criteria for course corrections
![Page 17: The Next Five Years of Rails](https://reader034.vdocuments.mx/reader034/viewer/2022052619/555eba9cd8b42a08408b58f9/html5/thumbnails/17.jpg)
MANY PARTS OF THE SOLUTION ARE TRIVIAL.REST:
What HTTP structure should I use?What names should I give my methods?How should I generate URLs?
![Page 18: The Next Five Years of Rails](https://reader034.vdocuments.mx/reader034/viewer/2022052619/555eba9cd8b42a08408b58f9/html5/thumbnails/18.jpg)
THERE IS BENEFIT IN A SHARED SOLUTION.
Asset pipeline:
* Works out of the box* Reduces cost of entering a project* Concept of "Rails asset processor"
![Page 19: The Next Five Years of Rails](https://reader034.vdocuments.mx/reader034/viewer/2022052619/555eba9cd8b42a08408b58f9/html5/thumbnails/19.jpg)
LEARNING ABOUT THE PROBLEM IS HARD. Encodings, Security, ETags
![Page 20: The Next Five Years of Rails](https://reader034.vdocuments.mx/reader034/viewer/2022052619/555eba9cd8b42a08408b58f9/html5/thumbnails/20.jpg)
FAILURE TO SOLVEIN RAILS CORE.
What are the problems for failing to provide solutions in Rails core.
Flip side of what I just said.
![Page 21: The Next Five Years of Rails](https://reader034.vdocuments.mx/reader034/viewer/2022052619/555eba9cd8b42a08408b58f9/html5/thumbnails/21.jpg)
CRITICAL MASS.Having multiple competing solutions robs any one solution of the critical mass it needs to rapidly improve.
No initial implementation is perfect, and Rails provides eyeballs and hands.
![Page 22: The Next Five Years of Rails](https://reader034.vdocuments.mx/reader034/viewer/2022052619/555eba9cd8b42a08408b58f9/html5/thumbnails/22.jpg)
USAGE.
It's tempting to say "let this feature be a plugin, and we'll let our users flesh it out before we include it"
This often results in several competing solutions, each languishing with few users, all of which have major issues.
The lack of usage can also hide conceptual problems with an approach (heroku deployment?)
![Page 23: The Next Five Years of Rails](https://reader034.vdocuments.mx/reader034/viewer/2022052619/555eba9cd8b42a08408b58f9/html5/thumbnails/23.jpg)
INTEGRATION.When users pick a solution on their own, they are willing to put up with a lot of manual work. The process of integrating a feature into Rails to automate it often brings fundamental problems to light.
![Page 24: The Next Five Years of Rails](https://reader034.vdocuments.mx/reader034/viewer/2022052619/555eba9cd8b42a08408b58f9/html5/thumbnails/24.jpg)
ECHO CHAMBER.The people most likely to choose a plugin solution to a problem also understand it the most. This means that there is little impetus to provide completely transparent solutions that work without complete (or any) knowledge of the underlying problems. By making something a Rails concern, it immediately busts the echo chamber of those who already understand the problem.
![Page 25: The Next Five Years of Rails](https://reader034.vdocuments.mx/reader034/viewer/2022052619/555eba9cd8b42a08408b58f9/html5/thumbnails/25.jpg)
TECHNICAL DEBT.As Aaron said yesterday, when solving these larger issues, we have a larger tolerance for technical debt.
That said, we shouldn't throw caution to the wind and take on unlimited debt. At this point, we're still paying back our last emergency loan, so let's be more prudent now.
![Page 26: The Next Five Years of Rails](https://reader034.vdocuments.mx/reader034/viewer/2022052619/555eba9cd8b42a08408b58f9/html5/thumbnails/26.jpg)
GOOD ARCHITECTURE ENABLES FUTURE FEATURES.
Architecting well means that we can easily improve the feature in the future. Many of the good things in the Rails 3 architecture (notifications) have only come to fruition now.
![Page 27: The Next Five Years of Rails](https://reader034.vdocuments.mx/reader034/viewer/2022052619/555eba9cd8b42a08408b58f9/html5/thumbnails/27.jpg)
FEATURES NOW + FEATURES LATER
COST NOW + MAINTENANCE÷
![Page 28: The Next Five Years of Rails](https://reader034.vdocuments.mx/reader034/viewer/2022052619/555eba9cd8b42a08408b58f9/html5/thumbnails/28.jpg)
FEATURES NOW + FEATURES LATER
COST NOW + MAINTENANCE÷
Building a feature right lets us extend it easily in the future with lower maintenance costs. This allows us to make necessary investments more easily in the future.
![Page 29: The Next Five Years of Rails](https://reader034.vdocuments.mx/reader034/viewer/2022052619/555eba9cd8b42a08408b58f9/html5/thumbnails/29.jpg)
BETS
When we correct course, we are placing a bet about the future of our industry.
![Page 30: The Next Five Years of Rails](https://reader034.vdocuments.mx/reader034/viewer/2022052619/555eba9cd8b42a08408b58f9/html5/thumbnails/30.jpg)
BETTING ON REST.
![Page 31: The Next Five Years of Rails](https://reader034.vdocuments.mx/reader034/viewer/2022052619/555eba9cd8b42a08408b58f9/html5/thumbnails/31.jpg)
■ Early support for rich HTTP semantics
■ Powerful router (request constraints, ...)
■ Content negotiation (Accept, $.getJSON)
■ Baked-in MIME types
■ HTTP caching ("Conditional GET")
■ JSON parameters
■ Security (e.g. IP spoo!ng)
WINS OF REST.
![Page 32: The Next Five Years of Rails](https://reader034.vdocuments.mx/reader034/viewer/2022052619/555eba9cd8b42a08408b58f9/html5/thumbnails/32.jpg)
RAILS HAS A GREAT HTTP FOUNDATION.
![Page 33: The Next Five Years of Rails](https://reader034.vdocuments.mx/reader034/viewer/2022052619/555eba9cd8b42a08408b58f9/html5/thumbnails/33.jpg)
BUT...
![Page 34: The Next Five Years of Rails](https://reader034.vdocuments.mx/reader034/viewer/2022052619/555eba9cd8b42a08408b58f9/html5/thumbnails/34.jpg)
DATA TRANSPORT
![Page 35: The Next Five Years of Rails](https://reader034.vdocuments.mx/reader034/viewer/2022052619/555eba9cd8b42a08408b58f9/html5/thumbnails/35.jpg)
SQL DATABASE
![Page 36: The Next Five Years of Rails](https://reader034.vdocuments.mx/reader034/viewer/2022052619/555eba9cd8b42a08408b58f9/html5/thumbnails/36.jpg)
■ Primary key: chosen per table
■ Table name: chosen per table
■ Timestamps: chosen per timestamp
■ Polymorphic tables: ad hoc setup
■ Foreign keys: chosen per relationship
■ Camel/Underscore: chosen per !eld
BEFORE RAILS.
![Page 37: The Next Five Years of Rails](https://reader034.vdocuments.mx/reader034/viewer/2022052619/555eba9cd8b42a08408b58f9/html5/thumbnails/37.jpg)
Because of all of these discrepancies, you end up needing to build a map of your database for your application.
![Page 38: The Next Five Years of Rails](https://reader034.vdocuments.mx/reader034/viewer/2022052619/555eba9cd8b42a08408b58f9/html5/thumbnails/38.jpg)
"DATABASES ARE TOO DIFFERENT"
In the early days of Rails, we heard a lot of arguments that databases were simply too different for AR to be more than just a toy. We hear similar arguments today with APIs.
![Page 39: The Next Five Years of Rails](https://reader034.vdocuments.mx/reader034/viewer/2022052619/555eba9cd8b42a08408b58f9/html5/thumbnails/39.jpg)
JSON APIS.
![Page 40: The Next Five Years of Rails](https://reader034.vdocuments.mx/reader034/viewer/2022052619/555eba9cd8b42a08408b58f9/html5/thumbnails/40.jpg)
■ Should responses include a root?
■ How to embed associations?
■ Include the identi!er? In what form?
■ id or href?
■ Include additional/associated resources?
■ How to update in bulk?
■ Primary key de!ned on server or client?
■ Moving a belongs_to record?
JSON APIS.
Just like there were questions in SQL, there are questions in JSON APIs.
![Page 41: The Next Five Years of Rails](https://reader034.vdocuments.mx/reader034/viewer/2022052619/555eba9cd8b42a08408b58f9/html5/thumbnails/41.jpg)
STANDARDIZED CLIENT CODE.
Without standardization, we cannot easily build standardized code on the client.
![Page 42: The Next Five Years of Rails](https://reader034.vdocuments.mx/reader034/viewer/2022052619/555eba9cd8b42a08408b58f9/html5/thumbnails/42.jpg)
We're also back to making the same trivial decisions over and over again, if we even realize that we are making decisions.
![Page 43: The Next Five Years of Rails](https://reader034.vdocuments.mx/reader034/viewer/2022052619/555eba9cd8b42a08408b58f9/html5/thumbnails/43.jpg)
And because we're not taking on the problem, we're pushing the concerns onto every client.
![Page 44: The Next Five Years of Rails](https://reader034.vdocuments.mx/reader034/viewer/2022052619/555eba9cd8b42a08408b58f9/html5/thumbnails/44.jpg)
IS RAILS WORTH IT?
Since Rails doesn't provide these conventions, people are asking "Is Rails the right tool for the job"
Even though other tools don't provide conventions, Rails is all about CoC, so the lack of conventions makes *Rails* feel like the wrong tool for the job, even though much of Rails is still useful.
Rails starts feeling more like a very polished library and less like a framework.
![Page 45: The Next Five Years of Rails](https://reader034.vdocuments.mx/reader034/viewer/2022052619/555eba9cd8b42a08408b58f9/html5/thumbnails/45.jpg)
ACTIVEMODEL SERIALIZERS.
![Page 46: The Next Five Years of Rails](https://reader034.vdocuments.mx/reader034/viewer/2022052619/555eba9cd8b42a08408b58f9/html5/thumbnails/46.jpg)
What to Serialize
• Which attributes• Which associations
How to Serialize
• Include a root?• Associations?• Extra data?• Avoid duplication!
![Page 47: The Next Five Years of Rails](https://reader034.vdocuments.mx/reader034/viewer/2022052619/555eba9cd8b42a08408b58f9/html5/thumbnails/47.jpg)
class PostSerializer < ApplicationSerializer attributes :title, :body belongs_to :author has_many :commentsend
WHAT TO SERIALIZE.
![Page 48: The Next Five Years of Rails](https://reader034.vdocuments.mx/reader034/viewer/2022052619/555eba9cd8b42a08408b58f9/html5/thumbnails/48.jpg)
class PostSerializer < ApplicationSerializer attributes :title, :body belongs_to :author has_many :comments def comments comments = post.comments return comments if scope.admin? comments.where(hidden: false) endend
CUSTOMIZE.
![Page 49: The Next Five Years of Rails](https://reader034.vdocuments.mx/reader034/viewer/2022052619/555eba9cd8b42a08408b58f9/html5/thumbnails/49.jpg)
class ApplicationController embed :ids, include: trueend
HOW TO SERIALIZE.
![Page 50: The Next Five Years of Rails](https://reader034.vdocuments.mx/reader034/viewer/2022052619/555eba9cd8b42a08408b58f9/html5/thumbnails/50.jpg)
{ posts: [ { "id": 1, "title": "First", "person_id": 1 }, { "id": 2, "title": "Next", "person_id": 1 }, { "id": 3, "title": "More!", "person_id": 1 } ], people: [ { "id": 1, "name": "Yehuda Katz" } ]}
AVOID DUPLICATION.
![Page 51: The Next Five Years of Rails](https://reader034.vdocuments.mx/reader034/viewer/2022052619/555eba9cd8b42a08408b58f9/html5/thumbnails/51.jpg)
ANY CONVENTION IS BETTER THAN NO CONVENTION.
![Page 52: The Next Five Years of Rails](https://reader034.vdocuments.mx/reader034/viewer/2022052619/555eba9cd8b42a08408b58f9/html5/thumbnails/52.jpg)
DEMO.
![Page 53: The Next Five Years of Rails](https://reader034.vdocuments.mx/reader034/viewer/2022052619/555eba9cd8b42a08408b58f9/html5/thumbnails/53.jpg)
![Page 54: The Next Five Years of Rails](https://reader034.vdocuments.mx/reader034/viewer/2022052619/555eba9cd8b42a08408b58f9/html5/thumbnails/54.jpg)
![Page 55: The Next Five Years of Rails](https://reader034.vdocuments.mx/reader034/viewer/2022052619/555eba9cd8b42a08408b58f9/html5/thumbnails/55.jpg)
AVOID MIXING COMMON AND UNCOMMON.
The advantage of serializers is that it avoids mixing the common (representation) with the unique (attributes, associations)
This is in contrast with builders, which put the common and unique things in one place, so we have no place for conventions.
![Page 56: The Next Five Years of Rails](https://reader034.vdocuments.mx/reader034/viewer/2022052619/555eba9cd8b42a08408b58f9/html5/thumbnails/56.jpg)
CONFIGURABLE.
Especially for authorization, there is a need to be able to poke under the declarative hood. It's not all documented, but it works.
![Page 57: The Next Five Years of Rails](https://reader034.vdocuments.mx/reader034/viewer/2022052619/555eba9cd8b42a08408b58f9/html5/thumbnails/57.jpg)
class PostSerializer < ApplicationSerializer attributes :title, :body has_many :comments has_many :troll_ratings
# override just default association inclusion def include_associations! comments = post.comments unless scope.can(:see_hidden, post) comments = comments.where(visible: true) end # override default value, but not embedding rules, etc. include! :comments, value: comments # conditionally include an association include! :troll_ratings if scope.can(:troll_rate, post) endend
AUTHORIZATION.
![Page 58: The Next Five Years of Rails](https://reader034.vdocuments.mx/reader034/viewer/2022052619/555eba9cd8b42a08408b58f9/html5/thumbnails/58.jpg)
WAS IN RAILS.
![Page 59: The Next Five Years of Rails](https://reader034.vdocuments.mx/reader034/viewer/2022052619/555eba9cd8b42a08408b58f9/html5/thumbnails/59.jpg)
REVERTED. WHY?
![Page 60: The Next Five Years of Rails](https://reader034.vdocuments.mx/reader034/viewer/2022052619/555eba9cd8b42a08408b58f9/html5/thumbnails/60.jpg)
EMBER-RAILS.
ember-rails was trying to build a transparent data transport and it was hard for arbitrary Rails applications.
![Page 61: The Next Five Years of Rails](https://reader034.vdocuments.mx/reader034/viewer/2022052619/555eba9cd8b42a08408b58f9/html5/thumbnails/61.jpg)
GENERATE A MODEL, GET A SERIALIZER AND EMBER-DATA MODEL.
![Page 62: The Next Five Years of Rails](https://reader034.vdocuments.mx/reader034/viewer/2022052619/555eba9cd8b42a08408b58f9/html5/thumbnails/62.jpg)
REST ADAPTER.
![Page 63: The Next Five Years of Rails](https://reader034.vdocuments.mx/reader034/viewer/2022052619/555eba9cd8b42a08408b58f9/html5/thumbnails/63.jpg)
App.store = DS.Store.create({ revision: 4, adapter: "DS.RESTAdapter"});
REST ADAPTER.
![Page 64: The Next Five Years of Rails](https://reader034.vdocuments.mx/reader034/viewer/2022052619/555eba9cd8b42a08408b58f9/html5/thumbnails/64.jpg)
App.Post = DS.Model.extend({ title: DS.attr('string'), body: DS.attr('string'), comments: DS.hasMany(App.Comment) }); App.Comment = DS.Model.extend({ body: DS.attr('string'),
post: DS.belongsTo(App.Post) });
MODELS.
![Page 65: The Next Five Years of Rails](https://reader034.vdocuments.mx/reader034/viewer/2022052619/555eba9cd8b42a08408b58f9/html5/thumbnails/65.jpg)
var people = App.Person.all();/* GET /people */ // later...
var first = people.objectAt(0);first.set('firstName', "Brohuda"); App.store.commit();/* POST /person/1 { ... } */
TRANSPARENT.
![Page 66: The Next Five Years of Rails](https://reader034.vdocuments.mx/reader034/viewer/2022052619/555eba9cd8b42a08408b58f9/html5/thumbnails/66.jpg)
Transport
Client Side
Serialization
AMo::Serializers solve serialization, but I think we need a general solution for all three.
![Page 67: The Next Five Years of Rails](https://reader034.vdocuments.mx/reader034/viewer/2022052619/555eba9cd8b42a08408b58f9/html5/thumbnails/67.jpg)
BULK.Serializers doesn't solve this, but there is a need to define conventions around bulk updates.
ember-data defines conventions that, if implemented in Rails, "just work"
![Page 68: The Next Five Years of Rails](https://reader034.vdocuments.mx/reader034/viewer/2022052619/555eba9cd8b42a08408b58f9/html5/thumbnails/68.jpg)
OTHER DATA FEATURES.
Identity map; data binding to the view; associations (including create parent=>child=>persist)
![Page 69: The Next Five Years of Rails](https://reader034.vdocuments.mx/reader034/viewer/2022052619/555eba9cd8b42a08408b58f9/html5/thumbnails/69.jpg)
CONVENTIONS FOR APPLICATION STRUCTURE.
Beyond "put your JS here"
![Page 70: The Next Five Years of Rails](https://reader034.vdocuments.mx/reader034/viewer/2022052619/555eba9cd8b42a08408b58f9/html5/thumbnails/70.jpg)
TRIVIAL CHOICES ARE THE ENEMY.
![Page 71: The Next Five Years of Rails](https://reader034.vdocuments.mx/reader034/viewer/2022052619/555eba9cd8b42a08408b58f9/html5/thumbnails/71.jpg)
NODE?
![Page 72: The Next Five Years of Rails](https://reader034.vdocuments.mx/reader034/viewer/2022052619/555eba9cd8b42a08408b58f9/html5/thumbnails/72.jpg)
Back in 1995, we knew something that I don't think our competitors understood, and few understand even now: when you're writing software that only has to run on your own servers, you can use any language you want. When you're writing desktop software, there's a strong bias toward writing applications in the same language as the operating system. But with Web-based software, you can use whatever language you want.
“PAUL GRAHAM
![Page 73: The Next Five Years of Rails](https://reader034.vdocuments.mx/reader034/viewer/2022052619/555eba9cd8b42a08408b58f9/html5/thumbnails/73.jpg)
This new freedom is a double-edged sword, however. Now that you can use any language, you have to think about which one to use. Companies that try to pretend nothing has changed risk !nding that their competitors do not.“
PAUL GRAHAM
![Page 74: The Next Five Years of Rails](https://reader034.vdocuments.mx/reader034/viewer/2022052619/555eba9cd8b42a08408b58f9/html5/thumbnails/74.jpg)
TRANSPORT.
Standards and Conventions
• HTML• ActiveRecord
Same Language Everywhere
• JMS• DRb
Thinking "I need to talk with JS, therefore I need to write JS on the server" is pretty lazy thinking. We can get seamlessness without insisting on the same language everywhere.
![Page 75: The Next Five Years of Rails](https://reader034.vdocuments.mx/reader034/viewer/2022052619/555eba9cd8b42a08408b58f9/html5/thumbnails/75.jpg)
TRANSPORT.
Standards and Conventions
• HTML• ActiveRecord
Same Language Everywhere
• JMS• DRb
>Thinking "I need to talk with JS, therefore I need to write JS on the server" is pretty lazy thinking. We can get seamlessness without insisting on the same language everywhere.
![Page 76: The Next Five Years of Rails](https://reader034.vdocuments.mx/reader034/viewer/2022052619/555eba9cd8b42a08408b58f9/html5/thumbnails/76.jpg)
RECAP
![Page 77: The Next Five Years of Rails](https://reader034.vdocuments.mx/reader034/viewer/2022052619/555eba9cd8b42a08408b58f9/html5/thumbnails/77.jpg)
■ Good conventions save developers from having to agonize over common problems.
■ Rails' bet on REST gave it a leg up in many areas that are relevant to rich client apps.
■ There is still room for improvement: we can make APIs as transparent as ActiveRecord.
■ ActiveModel::Serializers is one approach we are looking at to get us there.
■ We can also make browser frameworks better through the same conventions.
RECAP.
![Page 78: The Next Five Years of Rails](https://reader034.vdocuments.mx/reader034/viewer/2022052619/555eba9cd8b42a08408b58f9/html5/thumbnails/78.jpg)
THANKS!
@WYCATS