Frequent changes and deprecations to technology you rely upon cause dependencies to break
if you want to upgrade. In many cases, you'll find yourself hacking through someone else's code
to try to fix it, because a new version has yet to be release (and probably never will). That can be
a chore.
I get embarrassed when something I've recommended falls prey to this cycle. Backwards compatibility
is one way to deal with the issue, but in the Rails world, few seem worried about it. It doesn't bother
me that code and interface quality is a high priority, but it does cause extra work.
There's a trick you can use to help isolate the pain, decrease the work involved in keeping your app up to date,
and improve your code in general. You've probably heard of it, but you might not be using it to help you
out in this area: encapsulation.
What I'm about to describe talks heavily about Ruby on Rails, but that's only because it was the focus
of what got me thinking about this. I think it really applies in general.
Problem
Rails changes frequently. Some people think it
changes too frequently. I'll leave it for you to decide whether or not that's the case.
One consequence of change is that plugins and gems designed to work with Rails break. Perhaps as a result
of frequent changes (in Rails or just the whims of the community about which project in a similar area does
the job best), the authors of those packages become disillusioned and abandon the project. They could
just be lacking time, of course.
Now you get to fix their code (which doesn't have to be a bad thing, if you contribute it back and someone
else is sparred the trouble), use a new project that does the same thing, roll your own, or sit on an old
version of Rails that time forgot, and everyone else forgot how to use.
Don't you get at least a little embarrassed that you have to recommend large changes to your
customer or product owner or manager as a result of upgrading to the latest version of a technology you
recommended using?
It reminds me of a quote from Harry Browne I heard as part of his year 2000 United States
Presidential election campaign:
Government is good at only one thing. It knows how to break your legs, hand you a crutch, and say,
"See if it weren't for the government, you couldn't walk."
I'm likening programmers to the government of that quote, except we don't
pretend to
give the crutch away. We tell them "you can't walk without our crutch, so pay up." We sell people
on a technology which they build their business around, and then tell them they have to choose between
keeping a substandard version of it, or spending a lot of money to upgrade all the components.
(Understand that I'm talking about how it feels overall as a result of what happens in the community of
programmers, not a particular instance of particular decisions by any particular well-defined group of programmers.)
I just got done migrating a Rails 2.3 app to Rails 3.1 that was heavily dependent on several plugins and gems.
After writing a ton of missing tests, I made the switch and ran them. As expected, there were loads of errors.
More than half of them were due to the application's own code, but those failures were fixed with very little
effort. By far the most excruciating and time consuming task (even longer than writing all of the tests) was
spent getting the plugins to work (or in some cases, using new plugins and changing the application to use them
instead).
I acknowledge that I'm doing something wrong, because surely not everyone has this problem.
So tell me,
how can I improve my experience?
A Solution?
Something I'd like to see more of in this area is to encapsulate your plugin usage. Rather than
include NoneSuch
,
why don't you take the time to wrap it in your own code? In doing so, I see a couple of benefits:
-
You document which features you're using by only writing methods for those in use. That means
you have something specific to test against in your app, and something specific to run those
tests agains when you trade one dependency for another. It also means you know exactly what you
need to implement when you swap dependencies.
-
You ensure a consistent interface for your app to use, as opposed to having to change it when you
swap out which plugin you're using. Also, all your changes to that interface are localized, instead
of spread throughout your source code.
That means you can change one external dependency for another with greater ease, which means you'll be a
lot less likely to get off in the weeds trying to make something fundamentally unworkable work.
Thoughts?
Hey! Why don't you make your life easier and subscribe to the full post
or short blurb RSS feed? I'm so confident you'll love my smelly pasta plate
wisdom that I'm offering a no-strings-attached, lifetime money back guarantee!
Leave a comment
That's nothing new. Encapsulating 3rd party dependencies has always been a good idea. With the rise of more and more powerful frameworks this get's more and more difficult. And somehow I've the feeling it's less popular nowadays than it should be, esp. with defacto standards like Rails or Spring. Go ahead. This is the right way.
Posted by
Peter Kofler
on Sep 04, 2011 at 06:44 AM UTC - 5 hrs
It makes sense to me that it would be a good idea, but I don't know that I've seen it done very often, and I didn't think about doing it myself until it was a major problem on this codebase I was contracted to bring up to the latest version of Rails.
Thanks for the comment -- it's good to have some validation that my thoughts are not unique. It would be scary if I was the only person to have this idea. =)
Posted by
Sammy Larbi
on Sep 08, 2011 at 09:24 AM UTC - 5 hrs
this has been a consistent problem for rails since the start. i strive to use as few gems/plugins as possible because most of my apps are expected to last more than six months.
Posted by billstickers
on Sep 08, 2011 at 11:56 AM UTC - 5 hrs
IMO, if the 3rd party plugin is simple enough, you're better off writing your code for the functionality to eliminate a dependency. If it is quite complex, then you have the "don't reinvent the wheel" (DRTW) forces working against you.
I think the considerations to balance include:
- the life expectancy of the project,
- the relationship of developers to the project (hired guns, internal employees)
- the value of any one plugin to the app.
Long-term projects should invest in themselves by depending less on 3rd party plugins. They should limit themselves to only the most popular add-ons that save considerable time, or would otherwise require considerable expertise the team does not have.
Applications created by developers external to the company might have an inverse perspective. Depending a great deal on 3rd party plugins might help future developers with maintenance because there is less custom code to understand--assuming the plugins are popular enough to be well known. This, of course, raises your very scenario of broken libraries though. IMO, the application owner needs to be fully informed--use 3rd party code for expediancy and be aware of the potential maintenance costs later. Assuming there's equal potential for incompatibility of 3rd party and DIY code with future versions of Rails or Ruby (or whatever), I don't think it is fair to say spending more now on custom code will have savings in the long run. It's more a question of ownership and control at a cost.
The more valuable the function of a plugin is to an application, the more inclined I am to write it myself. I don't like the idea of core functionality being the responsibility of someone I don't have some control over. Sure, open source allows you to take on repsonsibility, and that's an alternative option. Go ahead and use the 3rd party code, but study it deeply and know how it works so that you can maintain it yourself.
I think you'll find that many of the originators of the agile movement suggest the latter. Go ahead and use 3rd party code, but not before you completely understand how it works interally so that you're fully informed as to whether there's any functional, security, or reliability things that need improved.
Whether it makes sense at that point to wrap it, I think that depends on whether you're convinced that any one of a few different options could easily replace each other. But it smells an aweful lot like YAGNI to me as an up-front exercise.
Plugins by definition imply a certain commonly-used functionality. If it's that common, then personally, I choose to write it myself and invest in building my own code base which is reuseable in other projects. For 3rd party plugins, I try to use only those which have reached a very broad ubiquity. I've been doing that for 10 years, and it doesn't seem to have failed me yet as a strategy.
Posted by
Greg Willits
on Sep 08, 2011 at 04:48 PM UTC - 5 hrs
Leave a comment