Fat chunky ugly bloated “models”
I’m not referring to the runway model variety, I’m talking about code.
Observation
I’ve had the opportunity to work with many Ruby code bases the past few years. One reoccurring theme I keep seeing is bloated models. Fat chunky ugly bloated models. Literally thousands of lines, mixing in of modules, and extensions galore. All of which are convoluting the notion of two completely separate things, data access and business logic. The phrase “fat models” has been taken too literally. I have one question. Why?
I am officially declaring it an anti-pattern for the Ruby community. A “model” is supposed to be an object representation of the underlying data your application needs. So when working with a _data_ model, you ought to stay laser focused on the DML behavior. Get your data and get out. Move on to the next set of objects that are responsible for determining, strategizing, composing, decorating, and displaying (these action verbs should sound familiar) the object representations of your data.
Remarkably most Java projects I’ve seen get this one right. Typically there is DAO, there is an entity, and beyond those two objects that are focused on DML, there are other objects that responsible for doing “things” with that data. I say “things”, but I am referring to whatever your business or domain does with the data beyond creating, reading, updating, or deleting it.
Real World Example
Here’s a solid example for the sake of discussion. Every e-commerce site has some notion of a product or service. Suppose you are modeling a “Product”. Your product has some attributes regarding description, size, weight, color, etc. You get the gist. Let’s not forget pricing, every product has some type of pricing. I see pricing go sideways almost every time. Pricing always starts out simple. You might have a “base” price and “selling” price. The “base” price is your company’s cost, and the “selling” price is your customers cost. Shortly after you deliver that functionality your product development team will undoubtedly come up with all kinds of pricing strategies.
These should all sound familiar:
- site wide sales
- single use coupons
- volume discounts
- bundling discounts
- affiliate pricing tiers
- employee discounts
Wrong
This is where it goes sideways. It’s so easy, right? Just fetch the “selling” price within an instance of the “Product” model and being applying the business rules inside your model.
Right
I hinted a couple times in that this is a perfect application for the strategy pattern. Not familiar? Each individual pricing type should have it’s own strategy. It is safe to let a “Price” object flow though the strategies. The pricing strategies classes can then apply the discounts and the appropriate pricing separately. One of the golden rules is that composition is almost always better than inheritance and that is the construct the strategy pattern embraces.
That should look and feel better on many different levels. You should observe the freedom to add or remove pricing features without the tight coupling to any particular model. In the case that your business evolves, and it inevitable does, your pricing strategies should be flexible enough to handle any sort of pricing irrespective of whether it has anything to do with a “Product” or not. It should also be easier to test. There are no worries about the creation of database objects or fixtures, simply assert the strategies of pricing with a “Pricing” object. Also as the pricing strategies grow in size and complexity it will certainly be easier to abstract away into a separate library.
Facetious Wonderment
Here is where my “wonderment” comes into action. How is it possible that so many “Rubyists” are ignoring traditional OO programming techniques and patterns when coding at the data access layer? Is it possible that the suggestive nature of the most popular and opinionated Ruby framework has created some psychological voodoo on developers making them believe that classes only come in 4 flavors (models, views, controllers, and helpers)? Is it really that scary to add new directories or categorize your classes differently? Perhaps it is the dynamic nature of the language? Can it be the power and “expressiveness” of the language? A language wherein the lack of true interfaces, strict type checking, and the magical injection of behaviors and methods has lead its developers down a path of wicked and corrupt habits. Gosh…why should I create a new class when I can just inject a few unrelated wacky ass methods to the String class? Is it laziness? Could it be that Ruby has given way and lowered the barrier to entry for people who shouldn’t be programming at all? Or perhaps it is a lack of classic OO programming training?
Conclusion
Draw your own conclusions. The major takeaway for me is that I’m sick of it; or rather I’m sickened by it. Unwavering I will remain steadfast on an ever-quest to right the wrong where ever my fingertips land regarding this matter. You should too. There are some great code katas that focus on this very problem set. Give the Gilded Rose kata a whirl. You might be surprised by the harshness of my befuddlement and/or the generalizations I’ve made about the Ruby community. Don’t get me wrong. There are many super intelligent people out there that swear by Ruby, who are doing the right thing, and you know who you are. I am just saying based on my observations and experiences there are many more people doing the wrong thing, specifically in the data access realm, that outweigh the right-doers. But hey that’s the case with most things in life, isn’t it?
Follow me on Twitter
My github repository
My LinkedIn Profile
Stephen Sloan
Great post. I think the “Facetious Wonderment” phrase is appropriate. Ruby is wonderful. Rails is wonderful. It’s fun, it’s opinionated, it’s right! When I learned Ruby and Rails I learned OOP design at the same time. Okay, not really, I mostly just learned MVC. There are other patterns, other entities out there. Unfortunately I learned the most about OO design from Java books. Ruby is awesome enough that we shouldn’t need to learn Java. There are a few books (now) that probably fill in that void, but I’d guess that the Rails community is somewhat burdened by excessive appreciation of just one implementation.
Sep 06, 2011 @ 11:48 am