-
Rails API Errors
Working on a mobile app? Want to show error field highlighting on signup? Do it the simple way:
unless @user.save render json: {errors: @user.errors}, status: :bad_request and return end
Wasn’t that easy?
-
Rails Tensions
Yehuda Katz recently started a Twitter conversation about the burgeoning tension in Rails between standard html apps and API-based apps. Apparently some people are concerned that rails is superfluous, or at least awkward, when writing web APIs.
I think that Rails does a fine job serving up an API. There’s plenty of work to be done in the model and controller realms of MVC, all of which is served nicely by ruby syntax and Rails conventions.
The view layer has never been Rails’ strong point, and it was always my least favorite part of developing web applications. Now, with the advent of Coffeescript, client-side MVC frameworks and ubiquitous JSON APIs, the client-side has become a first class citizen in its own right. This hasn’t removed the need for Rails; it has merely streamlined an aspect of the framework that was never very good to begin with.
Perhaps the main reason that people see the advent of browser-based API consumers as potentially harmful to Rails is that it diverges so much from the simple program outlined in the Pragmatic Programmers’ Agile Web Development with Rails. The step from server-side templates to web APIs is a natural one, however, and maybe it’s best that people start with the more conceptually simple case before dealing with the slightly increased start-up time needed to make a full fledged API.
-
Rails 3.1 Starting to Crystallize
The Rails 3.1 Hackfest is coming up, and at this stage in development there is a strong focus on ticketing all reproducible issues.
Could this mean that Rails 3.1 is finally approaching prime time? Hopefully we won’t see any tickets about modifying SafeBuffers, an issue that has already delayed the release.
-
Marketing Mysteries
These past few weeks we’ve been doing a soft launch of the new Gojee.com, and, among other things, that has meant that we’ve been hitting the streets trying to market the site to new users. This is a strong departure from the usual routine of an engineer, and it has offered some insights into a completely different type of work.
One of the first things that I realized about street marketing is that my primary value as an employee becomes partially emotional, as opposed to almost exclusively rational. The value that I can bring to the table is a real enthusiasm for the product that others will recognize. It’s one thing to have enthusiasm, which is easy (because Gojee is awesome), but it’s another thing to make that enthusiasm immediately visible for hours on end. I think it should come as no secret that sometimes programming requires a certain amount of drudgery. When that happens, however, there’s no need to maintain intense enthusiasm, you just need to force your way through the uninteresting parts. In that case it doesn’t matter how you feel about the work, only that you finish it. In street marketing, how you feel about the work is the work. This sort of thinking can also be helpful in engineering; sometimes maintaining a consistent positive attitude about your ability to overcome engineering problems can set you on the right path towards solving them.
Another thing that I realized while handing out cards on the street was that you need to cultivate an unshakable cheerfulness the entire time. You have to maintain the same happy attitude when someone politely asks about your company as you do when someone scowls at you and throws your marketing material in the trash. Part of your value as a marketer is to be unshakable in this way. This is somewhat different from programming, where it’s sometimes useful to be frustrated at a problem. In programming, the key is to be relentless in finding solutions, regardless of your emotional motivation. Still, engineers could learn from the sort of mental toughness that marketing requires. If you can stay positive even when things go wrong you’ll usually be quicker to act on fixing them.
Another thing I realized about street marketing is how it differs from online marketing. For one, the personal connection seems to be stronger and more sticky than some faceless plug on the internet. This comes at the expense of detailed analytics, however. On the web you can glean a multitude of data points about where people saw your marketing material, how much of the signup funnel they went on to perform and what your ultimate conversion rate was. If money were no issue, technical solutions could be fitted onto street marketing materials that could answer these questions, but in practice street marketing is something of a mysterious art. People end up coming to your site, but information about why or from where is scarce. Perhaps one day engineers will solve the problem of street team analytics. Until then, street marketing will continue to be a fuzzy yet useful tool.
-
Forbidden Knowledge
One of the more provocative talks at this year’s Goruco conference was Sandi Metz’s talk Less -The Path to Better Design, which dealt with information-sharing and the Law of Demeter. The main point running through the talk was that each object’s knowledge of other objects should be as limited as possible in order to make the code more future-proof. It was a great talk, and it got me thinking about the Law of Demeter in general.
Now, LoD is clearly a good idea. It’s a very bad thing if making a change to the implementation of a single class cascades out so that an entire suite of classes need to change. While this is true in general, I’m not sure if I support strict adherence to LoD where you never allow any object to call any methods on it’s associated objects.
A common case where this comes up is with has_one relationships, where an object might need access to a host of methods of the same name one its associated object. According to LoD, each of these methods must be defined on both objects, where one object delegates the result to the other. Even though Rails provides the delegate method to aid this pattern, I find that in the more agile environments that Rails is commonly used there are usually more pressing concerns than adhering to LoD in every detail.
Also, the point of LoD is to ease the pain of making changes. Well, Rails already makes this easy for us, regardless of our design principles. There’s no waiting around for code to compile, source code is almost always available for everything in the stack, and baked-in unit testing makes refactoring considerably less stressful.
To borrow an idea from Obie Fernandez,I think strict LoD is a case of high-ceremony coding. Deviation from the strict principle is ok so long as the increased velocity is needed. These sort of cost-benefit analyses must be rapidly made in a startup or other agile situation, because market validation is more important than strict adherence to design principles.
Given unlimited time, however, I would always follow LoD in every detail. Because of this I think LoD is a great thing to keep in mind as you code, but more as an ideal towards which you should aspire as you refactor.
-
Spin Doctors
A few weeks ago we had a problem: our feature tests would randomly fail about 2% of the time. Now, 98% might sound like a pretty good success rate for code that will never be touched by consumers, but for feature tests this is a horrible affliction.
Why do we even have feature tests? — to tell, unequivocally, whether or not the code is broken. Randomly failing tests, even if quite rare, completely ruin this function because they desensitize you to failed tests. When you run the suite of feature tests and see red error messages you don’t immediately think “oh man! I broke something!” Instead, you think “ahh, that’s just the normal failure rate for our tests.. I’ll check out the failing tests agian when I have more time.”
Eventually we figured out that the failures always happened in our full javascript tests. For our extremely javascript-heavy site, that basically amounts to all of them (rarely do we have a test that doesn’t include the ubiquitous @javascript tag). So I had a vague sense that it had something to do with timing, that the failures were due to an imperceptible lag between the javascript request and visual results on the page. So I started adding a 3 second sleep before every step that randomly failed. Soon enough nearly every javascript assertion was preceded by a 3 second wait. Needless to say, this didn’t help our already long-running test suite. Now not only were our tests unreliable, they took forever to run.
Then, after some googling for “unreliable cucumber tests” (or something like that), I came across this post from Sauce Labs. They had the answer to all of my problems. The solution is to use “spin” assertions in place of regular assertions when javascript is involved. In a nutshell, spin assertions first check if a particular situation is true. If it is, they continue along with the test. If it isn’t, they sleep for a small amount of time and try again. An assertion is considered failed if it fails many times in a row for several seconds. This way you can have the benefit of my previous “sleep for 3 seconds” solution without unnecessarily waiting around when everything is working fine.
It’s rare in computer science that you find the silver bullet to a chronic problem (usually it takes several bullets). In this case, I did, and it was sweet.
-
To Kill a Mockingbird
RSPec stubs and mocks are a great idea, right? There are built in mechanisms for mocking the behavior of ActiveRecord models, so even the model/controller interaction can be easily isolated. Shouldn’t you always test code modules with the highest degree of isolation, so that code failures provide the most actionable information about what part of your system is at fault?
From my experience, this is not always true. Although mocking can solve some annoying testing issues, it’s best to mock only when absolutely necessary.
Similarly skeptical views of mocking can be found throughout the ruby community. Francis Hwang points out a number of issues with mocks in his Testing Heresies talk. He explains how mocking only provides white-box testing of individual software layers, and that there are entire classes of bugs that can exist between software layers. He also points out that true database abstraction is always presumptuous. Francis generally follows Yehuda Katz’s maxim that you shouldn’t mock anything that you don’t own. In this view, one of the only true candidates for test mocks are external web services that you have no control over.
While I agree with this general sentiment, I think there can be other times when it makes sense to mock, even with its obvious disadvantages. For example, I think it’s a good idea to stub out a local instance of a software service like solr, since maintaining a test environment version of processes outside the rails environment can be time consuming, even if they are on the same machine. In this case it’s worth it to mock out such a separate software piece, even though it means possibly incomplete test coverage.
The other reason to resort to mocks is if your test suite takes too long to run. This should only be used with the most egregious test runtime offenders, however. It’s always best to run full-stack tests (including the database) whenever possible; fewer bugs will slip through the cracks.
One grey area when it comes to mocking is for controller tests. According to standard rails practice, controllers should be “skinny” and relatively single-purpose. In this case there is less room for bugs (at least those that won’t be found by feature tests), so perhaps it’s ok to mock. I think it should still be avoided, however, because even with simple controller methods, bugs arise between software layers and it always makes sense to test those connections.
My stance towards mocking is that it comes with a cost, both in terms of brittle tests and incomplete coverage, so it should only be done when the benefits outweigh the complications.
-
Plugins - The Double-Edged Sword of Rails Development
Plugins are at once Rails’ greatest strength and most glaring weakness.
One of the most common problems with software development is the tendency to reinvent the wheel. A little bit of headache implementing a third party solution usually makes up for hours and hours of hacking together an imperfect solution to an already solved problem.
It’s also bad, however, to rely on hundreds, sometimes thousands of lines of code that you don’t fully understand. Third party plugins aren’t maintained with the same zeal as core rails code. The more plugins and gems you rely on, the greater the pain of keeping up with major rails updates.
That being said, some plugins are in great shape and are constantly being updated with new and improved code. Good plugins are also one of the best ways to learn about programming techniques you may not already know about. Simply keeping up with the best rails plugins is a great source of education and a way of keeping up with the rails community as a whole.
So how to make sure you’re getting all the benefits of rails plugins without the detractions? There is no silver bullet. In general it is true that the more popular a plugin is, the more likely it is that someone has noticed bizarre bugs that could arise from it being used in situations different from what the authors originally had in mind. It is also more probable that a widely used plugin will be continually updated and promptly made compatible with new rails releases. For situations where a lesser-known plugin really does suit your needs, railsplugins.org is a great resource that tracks the status and Rails 3 compatibility of hundreds of plugins.
With a little care and education you can have your cake and eat it too.
-
The Case for Model Testing
Everyone loves Agile. Built from the ashes of the waterfall methodology, it solves so many of the problems that derail conventional development schemes. A well run agile project can add new features, react to changing requirements and fix bugs at a lighting pace. But this quick turnaround requires constant refactoring, which can potentially introduce bugs. The only solution is to obsessively test every aspect of your application. Agile essentially trades time spent dealing with communications and planning for time spent figuring out effective test strategies.
An Agile project should, theoretically speaking, test everything. In practice, however, a line must always be drawn. There comes a point where the value of additional testing fails to justify the time spent writing them. For integration and functional tests it’s almost impossible to be too detailed; model tests are less clear cut. Why? Because in general you should test behavior, not implementation. You don’t want to create in your testing code a perfect facsimile of your model code. This would mean that when you want to change any implementation detail in your model you essentially have to change it twice: once in your model code and once in the failing test. This makes perfect sense in things like custom model methods (state inquiries, calculators, special finders, etc) and complex validations. For example, instead of checking the exact format pattern (implementation) of a validates_format_of you should use actual test strings to check that the validation behaves properly.
Things get somewhat more complicated when you get to extremely simple, declarative activerecord statements, such as validates_presence_of validations and simple associations. Statements like this blur the line between implementation and behavior, especially since activerecord tends to use natural english language for class method names.
The ruby community is hardly of one mind on this issue. Some would argue that testing something like has_many or validates_presence_of amounts to testing the Rails framework itself, and should therefore be avoided altogether. I disagree with this position, however, because at the very least you should test for the existence of these model declarations. What if a section of model code was commented out during refactoring and accidentally left in that state? Without a bare minimum of model testing this problem could take a while to come to the surface.
If we assume, then, that activerecord declarations should be tested, the situation arises where there will be a large number of extremely repetitive tests. Code examples for validates_presence_of validations will generally be the same in all places. Even though testing code is somewhat more “unwound” than application code, such exact repetition begs for refactoring with some sort of macros or custom matchers. This solution leads to a problem, however; tests that use macros will end up matching one to one with their associated activerecord statements. This is an uncomfortable situation for many coders because by creating a parallel copy of our model code we do appear to be breaking the principle outlined earlier regarding testing behavior as opposed to implementation.
At the end of the day I think it makes sense to test all activerecord model declarations. In addition to testing for existence, they serve as a check that the database is connected properly and the schema is set up to support your model code. Also, it’s theoretically possible that there could be a bug in Rails. Without proper model testing this could eventually bubble up to your production application, and I doubt your users will be very understanding when you tell them that it’s pointless to test framework code.