Balancing Performance and Convention
markmcb writes "My development team was recently brainstorming over finding a practical solution to the problem that's haunted anyone who's ever used a framework: convention vs. customization. We specifically use Rails, and like most frameworks, it's great for 95% of our situations, but it's creating big bottlenecks for the other 5%. Our biggest worry isn't necessarily that we don't know how to customize, but rather that we won't have the resources to maintain customized code going forward; it's quite simple to update Rails as it matures versus the alternative. What have your experiences been with this problem? Have you found any best practices to avoid digging custom holes you can't climb out of?"
I worked in a small shop that used rails, we found that rails is... constricting, just for the reasons you posted to slashdot for. We looked at our options and switched to django+python. Maintenance wasn't a problem after that. I'd suggest investigating a switch now while you have an opportunity.
The customization is what is going to keep you employed. That's the specialization that keeps the customers from going overseas - even if you're Indian yourself. There's always someone willing to do it for less. No exceptions. So, develop those resources if you want to keep doing what you're doing.
Would it be out of the question to assess the needs of the troublesome 5% (and perhaps the other 10% that were shoehorned into Rails) and add a framework that's more in line with those needs?
Data exchange is sufficiently mature that interaction between applications in different environments is not an issue, so all you are left with is the added overhead of supporting two frameworks; not a bad thing if you consider the added flexibility of using the framework best suited to each application. Having options is usually a good thing.
I'm a Programmer. That's one level above Software Engineer and one level below Engineer.
It really depends on the complexity of the problems you're trying to solve.
If you have complex business processes they won't be easily modelled by rails, or any other framework.
So horses for courses, really. It's a judgement call, and depends on the specifics of your application.
Making this sort of decision really requires more technical details than you provided in the summary or the linked article.
If you do choose to make custom modifications to Rails (or any other third party dependency in your system), make them very carefully. Keep notes about what you changed, and why. Comment the modified source code with a consistent, searchable tag, like
Also, check the third party source into your own version control system so that you can track the changes explicitly.
Since you are talking about making changes for performance reasons, be sure to follow good optimization practices. Measure first, optimize only the true bottlenecks. Measure under realistic scenarios. If optimizations are even slightly confusing or subtle, comment them thoroughly. Keep the original, unoptimized code, maybe just in comments next to the new code, or maybe in a separate "reference implementation" function so that you can fall back to a known reliable version.
/...
The poster states they have resources for making the customizations but not for maintaining them. Why not just use the same resources that made the customizations for the maintenance?
In a band? Use WheresTheGig for free.
First off, I totally agree with Samschnooks that as a development team, that 5% is your responsibility, and what you're really getting paid for. But given your concerns about maintainability, and what I'm reading as your concern that custom code that you create may end up being addressed by the framework, I do have some advice.
See what of your own code can be crafted into a plugin to extend the framework. Rails plugins are quite easy to create and insanely easy to use.
Be diligent about abstracting the functionality that you need, keeping domain-specific business logic out of the plugin and in the application instead. You'll find that plugins are easy to write test cases for and will keep your custom logic very modular.
If someone else ends up releasing a plugin that addresses your needs, you can simply swap it out; the same applies if the framework gets extended to include what you need.
If maintenance is a real issue for you, release the plugin yourself as open source and recruit some assistance from the community. Chances are, you're not the only one in the world who needs the functionality.
Ruby on Rails resources and more at idolhands.com
I don't quite see how using django solves your problems. If you want to use a particular vesion of rails and not upgrade, there's of course: rake rails:freeze:gems No updates means that your software will be out of date eventually. That's like saying, I have an ActiveX plugin that works only in IE7. What can I do to make it work with IE8 without doing anything?
Lots of tools have the property that they make the first 95% or so of the solution really easy and the remaining 5% nearly impossible. On balance, you're worse off than if you had done the whole project in another tool.
What you call "convention vs. customization" is really just a special case of "build vs. buy". You can research the standard factors that go into such a decision, but the most important one is whether the part you intend to build is both a) essential to the business and b) something that would give you a competitive advantage over buying.
What have your experiences been with this problem? Have you found any best practices to avoid digging custom holes you can't climb out of?
What's your perspective here?
If you're looking at this from the financial point of view, I'd say that you now have enough experience to plan carefully. Also, the customer should know about and pay for maintenance.
From the manpower point of view, you might need more junior developers who can start with maintenance issues.
If you're just looking for engineering elegance, I'd say that's solved in the maintenance (tail) of the project as well. Be sure to have a senior developer keep track of the big picture in the maintenance phase.
8 of 13 people found this answer helpful. Did you?
I work on a major website, all done in Ruby/Rails. We, in contrast, have found that the tremendous ability to customize the framework is liberating, rather than constrictive.
Without knowing much more detail about your problem, it is difficult to give advice. Having created large, complex websites, and maintained them for long periods of time, we have yet to run into intractible problems as a result of the language or framework themselves. The fact that there are many large, complex Ruby on Rails websites being created and maintained by Fortune 500 companies also contradicts the idea that Ruby and Rails have serious, show-stopping shortcomings.
I strongly suspect that part of the problem is that you do not know your platform (in particular, Ruby) as well as you perhaps could. Ruby is very extensible via Gems that are freely available or that you can write yourself, or even just code modules. Rails is similarly, wonderfully extensible via plugins. Plugins are also freely available for just about every situation you can imagine, or again you can write your own.
Ruby is one of the most flexible languages in existence. Rails is hardly perfect, but any shortcomings are easy to code around by adding your own extensions. But expecting any framework to be complete for your purposes, before you begin, is pretty much wishful thinking.
Once again, I do not know enough about your situation. But if you expect any framework to be "plug and play" for very complex tasks, like an erector set, you will be disappointed. There is no substitute for knowledge of your platform, and programming ability.
The general answer is to manage the change you suffer, so as to keep it from getting ahead of you.
You can do this several ways, but the best requires you be the creator of the interfaces that are to change. If you are, you can make it easy for your customers (and your own team) to change asynchronously, basically by version-numbering your interfaces. Paul Stachour has a good talk on this at multicians.org.
A primitive form of this is freezing your interfaces: once they're in the Application Binary Interface (ABI), don't change then until the hardware changes so much that everyone has to recompile (e.g., when switching to 64-bit). This is heavily used in operating systems, but not in the world of programming languages.
Finally, if you're the consumer of someone else's changes, steal a technique from the porting/migration community and automate your changes when your supplier forces you into them. One tools, aimed at Vim/Emacs users is "port", described at Strength-Reducing the Task of Porting. It only takes about 10 minutes to create a change-database entry and optionally a sed script, so you can make a controlled change of all your sources to match a vendor's newest brainstorm.
--dave
davecb@spamcop.net
My company started writing a big app in Rails. We hit limitations (for us) fairly quickly so just started replacing the bits we wanted to work differently. The great thing about Ruby is you can just switch stuff in and out. The great thing about Rails is that it's well-designed enough that you can do that fairly easily.
Sessions, for example. We wanted to share sessions between sites, so just stopped using the Rails one and started using ours. We just put a new session class system in a gem, require it, and talk to that instead of the built-in. Works brilliantly and with a little finesse you can make it totally transparent.
I think the key is to think of Rails as a framework - as in, a literal scaffolding that you place things in. The basic structure is sound enough and very useful. It's filled with some useful default code, but if that doesn't meet your needs, feel free to start replacing it wih things that do.
Let my new 7-digit UID be a lesson to all - write down your passwords.
[test!]
A good test suite == "best practice to avoid digging custom holes you can't climb out of"
I work at a Rails shop too and, when I/we need to do something highly custom, we create it as a gem (or a Rails plugin) and post it somewhere incase someone else finds it useful. None of the plugins/gems I've released have required any maintenance to speak of, unless I've wanted to add additional features.
Be sure to write tests for your customizations (gem/plugin)! This will make it really easy to discover if your plugin no longer works for the next version of Rails/ActiveRecord/whatever it is you're extending.
[open source!]
If your changes might help other developers (they're not very, very specific to your product), open source them as a gem and let people know how to use it.
Not only can others benefit from your changes, but they can commit back too! Put the gem up on github[1], as it's the current de facto standard home for such things.
[rack it up!]
If you really need crazy performance out of Rails, look into using Rack[2]. Rails 2.3 (currently Rails Edge, will be released this month) *finally* uses Rack. Something like Rails Metal[3] makes it easy to return directly from Rack, letting you *highly* optimize certain requests. This is like rewriting some of your Ruby as C extensions to speed it up - Rack is really easy to use.
Good luck!
[1]: http://github.com/
[2]: http://rack.rubyforge.org/
[3]: http://weblog.rubyonrails.org/2008/12/17/introducing-rails-metal
Why not deploy your app on JRuby, and if there are still performance bottlenecks, write those parts in real Java ?
``Our biggest worry isn't necessarily that we don't know how to customize, but rather that we won't have the resources to maintain customized code going forward; it's quite simple to update Rails as it matures versus the alternative.''
As Alan Kay said, the best way to predict the future is to invent it. If you are worried about your useful code being broken by a future version of Rails, contribute it to Rails so that that future version will include it. Or, if you can't get it into the framework, make it available as a separate plugin.
Assuming that it's ok to share the code and that the code is useful outside your project, this will allow open source to work for you and ease your maintenance burden. If it's not ok to share the code or it isn't useful outside your project, then it's part of the project and the project will have to carry the cost.
Please correct me if I got my facts wrong.
Maintaining custom patches for a foreign codebase is going to be painful, proportionally to the number of patches, and how badly spread out they are through the codebase.
Consider this: every time the Rails team changes things, you'll have to go through your patches and make sure they still apply correctly. And if, heavens forbid, they do some major refactoring, you'll have to spend the time figuring out what functionality got moved where, and re-apply the patches as necessary.
My project was maintaining a custom set of patches for a major open source library for a while, and it was fairly labor-intensive: every time the library provider released a new version, a senior engineer spent a good part of a day going through the codebase and repatching it, testing the new version, etc. The problem was, however, that they released new versions frequently, and we needed them as soon as they were released.
If your patches aren't going to migrate upstream, I'd be very wary of spending a lot of time maintaining them as the core library keeps evolving. Try to measure how much time it would take to update your local patched Rails when they release a new version (especially a major one, if you can), and project future work estimates from that.
For us, we ended up sacrificing functionality for development speed, and we switched to a less capable library that worked right out of the box without endless patching.
My other car is a cons.
Since you are benefiting from the open source nature of ruby on rails shouldn't you simply provide your customizations back to the ruby on rails project so they can be maintained as part of the the framework or start an open source project separate from ruby on rails where the community can assist in maintaining it?
As the evolution of browsers is going right now you should not need a framework anymore. Just a good js/as3 custom team and a rails/python server team. My example http://code.google.com/p/appwsgi/source/browse/trunk
the site is large, in size AND traffic, and it has many complex functions.
We DO use it under real load, and we have no problems that have been directly traceable to either our chosen language or web framework!
On the contrary: most of our serious problems have been traceable to problems with our commercial host, EngineYard.
When you know the true cost of customization, then charge what it is worth + x%. Allow the true cost to fund the resources necessary to keep it in order.
that the other serious problems we have had have been programming bugs; but those bugs were due to our own coding or design lapses, not framework limitations.
Most people who speak of "limitations" to their framework are people who expect the framework to do all their work for them: this is simply unrealistic. If that were how it worked, it would not be called a "framework", but rather a "product".
He never called anyone "stupid". He merely stated that the saying "sounds stupid". There's a difference between being stupid and doing something stupid.
If the framework is good,
And your team is good,
And they have thought hard about how to express their design problem in terms of the framework, and found it wanting,
Then perhaps it is not The Best Framework for your team.
If that seems like an oversimplification, consider it another way:
What is your product, and how many resources do you have?
How much time you do you want to be spending tweaking frameworks?
There are no karma whores, only moderation johns
After 25 years in the architecture and development of application frameworks and transaction processing systems (used by major manufacturers world-wide) I have come to the conclusion that selection of a language is not the answer to software (and framework) entropy. Over the past several (10) years, I have been exploring MDA (Model Driven Development) as a possible solution to this problem, with some positive results. Long term, I see that robust modeling tools with advanced code generation capabilities as a much more robust means of dealing with environmental and process changes. Unfortunately, current tools are just becoming useful in this regard. My current preferred tool set is Sparx Enterprise Architect, but it is still too difficult to generate a domain-specific framework model that can reflect an adaptive approach to the problem.
Sometimes, real fast is almost as good as real-time.
.
Best Practice #1 - don't use Ruby on Rails. It is a dead end.
ergo
We are well into a project that has JBoss SEAM as its basis, but required significant mods to give us multi-database capability and a FLEX front end. So instead of a community maintained opinionated meta-framework, we now have our own super complex, fragile framework cluster(****).
It is also effectively a dense, opaque yarnball. The stack traces of exceptions are so long, due to the interceptor architecture, that the Java stack trace displaying algorithm gives up and prints ...
So my advice would be, at the risk of trolling, but I intend it as a serious debate position, don't start with something as excessively complex as JEE technology.
Because JEE technology is barely manageable, maybe, if you stick EXACTLY to the most popular opinionated meta-framework for it, but if you deviate off the straight and narrow path, you are on your own in a dense jungle with a dull machete.
Where are we going and why are we in a handbasket?
One has to take the name "framework" literally... it provides a foundation, YOU provide the structure. Expecting your framework to be a complete solution in itself is like expecting a building foundation to be a complete home: you will be disappointed. And you will have nobody to blame.
Haha. This is the first time in a long time I have seen anyone seriously suggest using Java for better performance...
First, PLEASE no more going forward. It's silly and makes any words after sound like... I don't know. I just tune out after I hear that. It's filler. Where else would one be going in that sentence? Are we in fact going anywhere?
Second, trying to answer your question-
1. Don't write custom code. Find some other more generic way to do it or someone that already has. Blame them when it breaks with any framework upgrade- see the horrors of Drupal upgrades.
2. Write it and write it well with documentation. I just re-read some notes on programming philosophy that I always repeat in mantra- program to the interface (or abstraction). Write it portable so the maintenance is actually in the implementation as opposed to the library. As one poster suggested- submit your lib to the repository for other to perfect and use- especially with Rails which is built on submissions like this.
3. Write it in Logo. This ensures job security if it is used. More likely they will shout and throw little turtle icons at you.
Personally, I am still in the camp of writing more internally than using libraries outside the framework core. It keeps the app unique and just buggy enough to have a job to come back to :) There are other more serious reasons such as the family aspect that self authorship bring to a team- "We did that" really makes the team feel very good at the end of the day.
quis custodiet ipsos custodes
Hardware is Cheap, Programmers are Expensive:
Read my blog: HansMast.com
You could have just forked the library, and kept your own code (and version) rather than updating to the latest of their version. Your "solution" puzzles me, as it seems to be shooting yourself in the foot.
Chances are, someone in the community has experienced your very problem, and it's likely someone has a solution already. At the very least, you'll get some ideas from people who actually use the product.
Pluginize, git them out, outfactor. You are kidding, right?
Just deal with the other 5% in the 'old fashioned' way; using CGI or C - doing everything from the ground up. And if somehow you can't - because you can't just get the session state from the ruby framework, or you can't get the style sheets from it, then you have to wonder why not. And blame ruby for it, not yourself or CGI.
Religion is what happens when nature strikes and groupthink goes wrong.
I hate code full of company comment cruft.
Use a good VersionControl system, git, murcurial or Subversion if you must, __but__ keep the meta-data out of the code. If you use sensible tools you get all that, and its much easier to work with the upstream,
Keep your code and use Rack to factor out the last 5%. You can keep you code base, and still get your performance. Merb is a an excellent tool for this. It is similar enough to rails to be easy to pick up, but it is light weight and has the ability to run a small application in a single file.
Without knowing how tightly coupled that 5% is it is hard to be more specific, but definatly look into Rack.
Strive to make your client happy, not necessarly give them what they ask for
Ruby is a very dynamic language, that makes it easy to extends and to customize classes. Rails itself is designed to be extended using plugins. You can write a plugin that won't define any new class, but that will just add or replace methods from Ruby, Rails or other plugins. This is really a great feature of Ruby, that avoids a lot of hassle.
{{.sig}}
With over ten years under its belt, WebObjects has proven very beneficial to our company. Of course, Java developers are sometimes hard to find, and the learning curve for WebObjects can be steep, but the community is tight-knit, and the Wonder (open source) frameworks have addressed that persnickety 5% you describe...
After all, iTunes, UPS and other enterprise solutions show that a core set of frameworks, scalable architecture, and talented developers can yield a business model that works.
- Ubique, Tom Termini www.bluedog.net - WebObjects / J2EE SOA / iPhone solutions for knowledge workers
Integrate the rails hacking into your release process.
* import rails into your scm -- one that has good branching and merging
* regularly update your scm rails trunk to recent upstream release
* branch rails locally as part of your release process. that includes using the branched release in QA.
* get as much of your local changes as possible merged upstream! it's a pita to start, but your effort will be rewarded.
Use the right tool for the job.
* use standard APIs so you can switch back and forth between your implementation and others' easily. when possible, of course; not all commonly used APIs are well thought out.
* if rails doesn't do something well, use another tool that does. examples:
** regenerating content all the time? look at memcached.
** need local disk-backed storage? sqlite, not mysql/pg/etc.
* are you sure rails is your bottleneck? not disk-wait for your database?
The true differences between frameworks are inevitably revealed as soon as you try to build a product of significant complexity. A truly flexible framework makes it easy to override, overload, or otherwise replace functionality WITHOUT having to modify the framework itself. This has long been my issue with a number of web frameworks implemented in a variety of frameworks. There are many frameworks that will make a fairly simple form based web application come together very quickly. If you've got 5-10 forms, a simple data model, and low enough load to run on a single host, there are lots of frameworks that will let you churn out an app in the blink of an eye. But as soon as you have a sophisticated and complex data model, loads that require scaling not just the web layer, but also the persistence layer, across multiple hosts and even multiple data centers, and you have to support a variety of views (html, web services, json for ajax, iphone, pdf, etc), a lot of frameworks fall completely flat and are unable to help and, in many cases, become an active obstruction.
It has been a number of years since I seriously investigate RoR for a web project because the vast majority of my work involves very high performance and high volume sites and when I looked into RoR, it offered no easy mechanism to work cooperatively in a cluster with any more sophistication than sticky load balancing and a single shared db. I'm sure it is much improved since then, but every time I take a quick look-see, it still seems to be very lacking - not just in scalability, but in extensibility in general, and I just can't tolerate that.
There aren't many frameworks that I've encountered that offer the kind of flexibility to really allow you to take our app any direction you want to go. The one that does requires a fair bit more work up front, but boy does it pay off as soon as you have to get sophisticated. Of course, it is native to the language everyone round here loves to hate, Java, but I highly recommend you look into Spring and SpringMVC. Plug in any persistence mechanism you like, including a mixed persistence layer. Plug in any view technology you like. Use AOP to handle cross cutting concerns. You have the flexibility to replace any built-in component with an implementation of your own, so you are never required to modify the source code of the framework itself.
At every turn, SPring has provided the flexibility I've need to build very sophisticated applications for a number of years now. It will take quite a bit to move me to another platform for anything but the simplest of apps. I recommend you check it out. The fact that it runs in a language that is 25x faster than Ruby doesn't hurt any, either. And the ecosystem of useful code is larger for Java than for any other language I'm familiar with. JEE is needlessly complex, but you can do just about everything JEE does via Spring with a tiny fraction of the complexity, and for the very few things spring won't do, Spring will happily expose JEE directly to you. Oh, and I gather it runs in .NET, too, though I have no idea if it is quite as functional, since it is developed from a java-centric paradigm.
How are you customizing?
Early on with Rails we had all sorts of issues - usually with the database drivers - that we "fixed" by using mixins. It meant that we didn't touch core code, but we could slot in alternative functionality wherever it was required. Our code tended to break with each new release of Rails, but our tests showed up the weak spots straightaway.
I could be wrong, but I believe that with mixins Ruby itself gives you a mechanism, while not perfect, gives you something of what you need - the ability to break convention where you have to.
The easiest solution I have found is to build side web pages out using whatever your server supports, utilizing the same cookies or sessions as the main pages.
I am a chef and my kitchen is a Rails® kitchen.
My freezer is a Rails® freezer.
My cupboard is a Rails® cupboard.
-- stocked with cans of Rails®.
Rails® can-opener.
Rails® microwave.
I've never been more efficient. I could have put some ratatouille on faster than it took to type the above, and it would have been done before I finished this post.
So can you guess where I'm a chef?
--
I guess what I'm getting at is that even though you can roll a to-do list with a can opener, microwave, and three and a half minutes of spare time while you're coding, if you really are a chef you probably shouldn't. A professional chef shouldn't be microwaving things from a can or reheating frozen cordon bleu from the supermarket, and you shouldn't either.
Forget the framework: get some fresh vegetables (yes, you will have to write database queries by hand, boo-hoo) -- and start dicing.
Since you're developing solutions for the 5%, but you don't want to maintain it, maybe you should consider open sourcing that 5%. Or maybe you don't really have a solution, just a hack?
If it's just a hack, let's face it, nobody wants to maintain that crap.
Ah, you spend 95% of your time on the first 95%, and 95% of the rest on the last 5%.
Everything your code does is something the framework doesn't do for you: the real problem is not customization, but how cleanly the framework allows you to extend it, how stable the interface (between the framework core and your extensions) is, and so on.
That's why I'm surprised to hear people recommend switching from Rails to Django. My experience in going through that route is that Django is less flexible and harder to customize than Rails. For example, in both frameworks you can write custom SQL queries, but while find_by_sql in Rails returns fully-formed model objects (as long as you fetch all the needed attributes in the query), raw SQL queries in Django only return raw data tuples. You cannot integrate your custom SQL with Django's ORM (ie, you cannot get a Django model object from cursor.execute), so you end up getting a bunch of IDs from your custom SQL, and then passing them to Django so it can query the database again for the same objects, using two queries to do the work of one.
Next time I want to make a web application in Python, I'm going to skip Django and look into Pylons instead.
If your problem is that it is a bottleneck, you could just slow all the other software down, have it count to pi every once in a while, randomly.
Yes, I do work in management.
And "Rails" isn't a framework? And by "as3" I assume you mean ActionScript3, presumably for Flex, which one might reasonably assume is a framework, no?
creation science book
Those you know me, know me a lot. I had the same problem five years ago. And it started to turn working for clients and revenue-generating work into working for the framework and framework-customizing work.
So I built my own framework, from the ground up.
Now it's all my conventions, and no one else's. I customize in ways that I know will be compatible for future upgrades. Of course, I get to make those upgrades myself too.
But it means that I do everything "for the last time". If it's something that seems valuable, it gets thrown into a framework-compatible routine, and I never need worry about it ever again.
A lot more work early on. A lot more work for quite a while. And then, blissful no work for anything. Seven of the nine things in the "essentials" section of my invoices -- that every client project needs just to start -- amount to 90% of the essentials dollar amount, and amount to, no kidding, the twenty seconds to install hte framework for teh new client -- and by that I mean run the script that copies files, migrates databases, and changes passcodes. From then on, approximately 75% of the work is remembering the name of the existing function -- or looking at another client project to find it; writing documentation simply hasn't made it to the top of the list in five years.
I spend about 85% of my effort dealing with client content/sales/training/trust, and only 15% on the actual programming.
The .Net platform is where its at for professional development.
If you go back and read it again, you may see that my comment was perfectly honest and accurate.
Of course, you have no way of knowing exactly what I have heard; but neither do you have any real reason to doubt my statement.
Aldo I probably was mistaken about rails as just a ruby interpreter. ActionScript3 is a language that you can compile with the flex compiler. ActionScript3 and mxml are different things. My point was it can be done for web apps. You just need to learn both web client and server world. Frameworks are for people that do not have the time or knowledge to implement both.
But come Monday, I can ask the guy who does our load testing.
You have identified the key problem nicely in your question. How to maintain your changes when the base changes underneath you.
The first thing I recommend is to go back to your basic OOP structures. If you can, inherit and extend rather than modify their code. The interface will change far less than the internals.
If you have to modify the internals try and keep it as contained as possible. Consider creating new functions rather than modifying theirs. Try and collect as many changes together as you can, each function changed is a pile more work.
When you are updating to the newer versions try and do a three way merge, it makes it far simpler. Many of the distributed VCS like git have it built in or you can use tools like kdiff3 to do it manually.
>will you disqualify fifty really smart guys for
>five mediocre ones who happen to know Django?
You don't hire developers because they "know" django, or any other framework or language. You hire them because they are good developers.
Real developers learn how to use new libraries and languages all the time. Only HR drones concern themselves with "X years of experience with Y technology".
It sounds to me like the OP is complaining that his hammer won't work with every nail.
No tool is perfect and each has limitations.
Use each tool as appropriate and do not prescribe to purism over functionality.