The Right Abstraction Matters
Last week DHH wrote about his love for implicit code, and held up Rails as an example of the benefits. As someone who has been working with Ruby on Rails since 2006, I appreciate a lot of the benefits that Rails offers. However, I have also run up against some less pleasant implications of the “Rails Way.”
But, the problem is not really Rails’ fault — it’s an inherent weakness of the MVC architecture.
I’ll follow DHH’s example and use ActiveRecord as an example. In new applications ActiveRecord makes standing things up incredibly easy. The assumptions that are baked right in are helpful and improve developer velocity immensely in the early days. But, as the number of models in a system grows certain tendencies can emerge that are not good for the long-term ease of development.
Several months ago I wrote about what I believe is a clear anti-pattern present in many large Rails applications: Domain-Data Overcoupling. Rails encourages this anti-pattern implicitly because there are no conventions provided by the framework to do anything else. A mantra in the Rails community for a long time was “Fat Models, Skinny Controllers, and Dumb Views.” That simple, and popular, approach made things worse. But, the problem is not really Rails’ fault—it’s an inherent weakness of the MVC architecture.
MVC, as an architectural pattern only provides three layers where logic can live. And, Rails implements the MVC architecture better than any other framework I know of. But, Rails implements MVC so well that at a certain size of application, and with certain problem domains, the weaknesses of MVC reveal themselves. If your Domain Model and Data Model don’t match each other in a very close one-to-one correspondence, then you are going to experience some degree of discomfort. But, that would be true of any MVC framework.
So, what does all this have to do with implicit coding versus explicit coding? Well, it’s because all of this eventually comes back to the idea of abstraction. MVC represents an abstraction for how to structure an application. ActiveRecord is an abstraction for working with relational databases. And, all abstractions rely on a degree of implicitness, because that is the nature of an abstraction. In the post I cited at the beginning DHH, had this to say:
To carve out a meaningful, effective belief system, you must be willing to give up something. To embrace explicit code, you must be willing to accept laborious ceremony and the boilerplate. To embrace implicit code, you must teach the context and unpack its at-first bewildering magic.
And, it is here that I am drawn to disagree with DHH to a degree. Preference for implicit or explicit code should not come down to a belief system, or even a preference. The decision to accept code powered by implicit behavior, to accept Convention over Configuration, ought to start with a question, “is the abstraction correct?” Or, at least with the question, “is the abstraction suitable?”
Implicit versus explicit is not nearly as meaningful as correct and suitable.
ActiveRecord is a really powerful abstraction, and it has a lot to offer. But, it is not the correct abstraction all the time. It took years of explicit, boilerplate-laden, code for the abstraction that ActiveRecord provides to be sufficiently obvious to be implemented effectively. But, just because we have a powerful abstraction available to us does not mean we have to use it, especially if it is not correct or suitable for our needs.
So, to put as fine a point as I can muster on this: prefer explicit code until you understand it well enough to make more of it implicit via abstraction. And, don’t assume that the available abstractions are correct or suitable. Test them and confirm them for your own needs. Implicit versus explicit is not nearly as meaningful as correct and suitable.