For a long time I’ve had the idea in my head of doing a Rails app-building walkthrough that emphasizes classic Object Oriented Programming techniques. For instance, building out domain models as regular ole’ objects, and then adding persistence in as an implementation detail later on.
Over the weekend I started writing it. I thought it was just going to be a sort of maxi-article, but I’m at 37 pages and I’m only 2/3 done at best. So far I’ve covered stuff like adding ActiveModel bits as-needed, Dependency Injection, and the Presenter pattern, but I’m sure there’s stuff I’ve missed. So I thought that while I’m in the process of brain-dumping all of this stuff I might as well open up the floor.
SO! What would you like to know about OOP on Rails?
“For instance, building out domain models as regular ole’ objects, and then adding persistence in as an implementation detail later on.”
Frightening that anyone would approach application design this way. Your data is more important than your application and should therefore be given primacy-of-design.
Is your data more important than your business logic? I think the answer depends on the application.
I don’t think the question is which is more important. In the majority of cases, the data is very important, and should be carefully considered from the start.
That has nothing to do with the choice of moving the business logic outside of the persistence classes though.
I’m trying to find a way that allows the data to be first class until it shouldn’t be. My domain may be very data-centric. There are points in an application where the data will evolve to something more…not sure how to evolve incrementally under test.
Any non-trivial data is ALWAYS more important than your business logic.
For Twitter, Stack Overflow, OKCupid, Gmail, Mint, or basically any web app you can think of that has data at all, you could scrap the entire front-end and middle tier tomorrow and replace it with something new and improved. In fact we expect web apps to do this, though usually in bits and pieces, over time as they evolve. Interfaces and business logic are ephemeral.
But could ANY of these apps survive discarding their data? Not a single one. Data has permanence, it endures. Make mistakes with your UI and logic and you can always improve them. Make mistakes with your data and they will likely be with you forever.
I think it really depends on the app. Data tends to be important in web apps, it’s true. But Twitter could decide to start throwing tweets away after 24 hours and they’d still be wildly popular. Their business value lies more in the ability to distribute messages to a great deal of people very quickly than it does in either their schema OR their logic. And then of course I’ve worked apps which had no persistent data at all, although most of them were off the web.
In any case, the approach to program design I’m talking about is, if anything, more aligned with your aims than the “orthodox” Rails approach. In typical Rails development the data model is completely dictated by the model classes – when the classes change, the data has to change. When you start your app thinking about business models only and delay persistence until later, you are able to take more care in mapping models to a sensible schema instead of simply accepting whatever defaults ActiveRecord gives you.
If you design your domain model without ActiveRecord, you are free the to persist that data in the best way for your app and your data. You are able to design your data store separately from your business logic. Given them equal billing if you wish.
Agree completely. Wanna see this done for a rails app.
I’m definitely looking forward to this!
But to say what you’ve missed; I fear that I might be second order ignorant on that part. I would love to see something that makes DI less tedious though.
I think I would benefit mostly with some heuristics when to go all the way instead of just adding this one or two little methods to a model.
I’m super excited at this announcement. I’m not sure if these ideas fit in with your intention, but here are a few: Using observers and decorators, ideas for modeling events/requests that aren’t simple DTO requests, Command/Query separation, Composition, Polymorphism, Null Objects. Also, I recently read “Object Thinking” and was looking for ways to decouple objects more and remove control in favor of cooperation.
I’m also super-excited about this. One question I’ve been pondering: when a model inherits from ActiveRecord::Base, is that already fulfilling one responsibility, in the sense of the Single Responsibility Principle sense? This would imply very thin models, with most/all logic completely separated into other classes and modules. What are the benefits and drawbacks to this?
Models don’t have to inherit from AR. Anything that models a domain concept is a model.
Ok, so, to phrase it differently: when a class inherits from ActiveRecord::Base, is that already fulfilling one responsibility? I agree the answer is still yes. But then that suggests that things like scopes, validations, associations, and everything else belong elsewhere. Is that too extreme?
I remember seeing a tweet positing that not encapsulating Rails associations is the cause of some very high percentage of slow tests/design problems/societal collapse, etc. I found that intriguing. Maybe you can write a bit on that topic.
Sounds great Avdi, I look forward to reading this.
While I usually know how to apply these design patterns, I more often struggle with when to apply them. Splitting a class into more classes can increase the complexity by adding indirection, abstraction, and just plain line count. What is the tipping point of a single model class that requires one to take this action? That question is hard to give a generic answer to, so maybe some specific examples would work well.
It looks promising. I get a question how to extract business logics from models and put them in other classes by domain modeling?
In .NET land, their is a contingent that likes DI, the Repository Pattern, and the Unit of Work pattern. I’d like to see how something like that works in Ruby/Rails.
DI is especially hard to bring over, for me, as I think I confuse it with the Adapter Pattern (like ActiveRecord adapters) when looking at Rails.
You don’t need DI in Ruby: http://weblog.jamisbuck.org/2008/11/9/legos-play-doh-and-programming
I think you mean “you don’t need DI frameworks in Ruby”.
There has never been a well fleshed-out example of a Rails Presenter, especially one that can handle a form. I would love to see an example of a Presenter with complex (or more than naive, at least) business logic.
I think this is a good idea, but only if you present the why for doing this. What are the benefits of using a presenter here, vs this other case where it’s not worth doing. In my opinion, honest, solid advice from an experienced developer on why always trumps how.
I cannot abide by patterns for the sake of patterns. I think OO is one approach, and an approach that isn’t always the best approach. If I know the “why”, I can make better choices.
Why should I keep my ActiveRecord objects separate from my business objects? So I can, one day, theoretically switch to MongoDB? What if I have no intention of doing that? These are all things that warrant good discussion. I’d love to see that in what you produce. I think it would be quite helpful.
I think that such application written with Apotomo, while explaining all the reasons for this organization and what design patterns are being used in those situations, would be of great appreciation for those willing to write good web 2.0 applications, covering topics like components organization and components testing.
Talking about those JS MVC frameworks (there’s tons of them now) would also help people evaluating them as well as deciding if they’re worth. In the same situation, there are several JS templating frameworks that would worth talking about too…
I’m not saying that you should really compare them all, but just illustrate those concepts and give some examples in one or more similar frameworks explaining their reasoning…
I really think that the topic that needs more love currently are those concerning server-side and client-side integration. Specially, JS testing.
I would love to read from you about implementing DCI with Rails, I believe that is a pattern which could improve a lot the way we are writing business logic in every Rails application.
I discover an exemple of implementation in the blog post http://andrzejonsoftware.blogspot.com/2011/02/dci-and-rails.html which looks really interesting and I would like to hear you voice about this subject.
I hear what you’re saying – but I come from the pre-OO days where we would do detail data models first, then identify the GUI to work with that model. I tend to start from Active Record and BDD the model to death, then work out to the GUI – it works for me, and feels much simpler and protects you from doing naive stuff with the model. Rails lends itself to this – when OO became popular I kept coming across systems where the model was absolute crap and full of holes because da kids just out of college didn’t understand data or integrity, so essentially your SQL database may as well have been an ISAM store with some indexes. But you couldn’t write reports that weren’t nonsense and sometimes it was damn hard to find out where the money was going too, or bill people properly.
I’m not convinced that doing the persistence layer later is a good idea, unless you already really understand how to do it “properly” in the first place – which I know you do, but less experienced folk may not, Rails protects you from your ignorance by making you think of the data first. I think this has made it a real step forward, compared with the bizarre Java-based systems I used to come across where weird class structures are the norm, but not useful or maintainable.
Patterns too – I like Bob Martin’s concept of “backing into” patterns – as you do your (T/B)DD you recognise a pattern and see its utility, then you refactor into it. Again in Javaland 10 or so years ago there used to be a lot of “patternitis”, where there would be utterly sterile arguments about which pattern to use instead of what the customer actually needed. It used to drive me nuts and was a total waste of time.
So, I’m really interested in what you do and how you explain it, but would caution people who don’t have that visceral grasp of the “why” not to treat it like some kind of gospel. Personally, I always start from the business processes and move out to the data needed to support it, then I worry about the other stuff. It gives you a solid base to build on. But I’ll try any approach if it speeds things up or makes the resulting code cleaner.
When I saw this title, I thought it was going to be a snarky post saying that Rails isn’t really Object-Oriented. You disappoint me!
Thank you for putting this out Avdi, I’m really looking forward to it!
I would love to see an article that walks through the design of an app using OOP principles (or any other principled approach, for that matter) that (1) does not start by assuming the presence of all the Rails stuff, and (2) provides a legitimate justification for introducing (some or all of) the Rails stuff as it goes along. Almost every Rails walkthrough I see starts by assuming I want a bunch of CRUD screens ‘for free’ – as I almost invariably don’t, I tend to reach for Sinatra+Sequel+random html library instead just because I get to nicer places faster by integrating libraries one at a time than by trying to fit into someone else’s monolith.
But perhaps it’s not really a monolith, perhaps it’s a marble veneer on a tower of bricks. If you’re planning something that exposes the bricks, I’m watching avidly.