Counterpoint: Rails and instance variables

A great thing about writing is that it focuses and sharpens one’s thoughts. The great thing about writing in public is that your thoughts, when passed through the brains of others, sometimes yield even better thoughts. The greatest thing about writing is when you hit publish feeling confident about your position and end up with your opinion flipped once the conversation is over.

So it went with A tale of two Rails view that a few hours after I’d published it, my mind was changed.

On the one hand, you can take a permissive stance on views and ivars. Dave Copeland nicely laid this idea out. If you are responsible about minimizing sharing ivars between actions and views, you have a chance. In this case, that means sharing one or two ivars, no more. Placing a little trust in your fellow developers lets you put off the day when you need to isolate state behind helper methods or other restrictive abstractions.

On the other hand, you can take a contractual stance on views and require all data passing between actions and view to do so through a specific object. Tony Pitale’s SimplestView does just this. It unifies views and partials into one name, “templates”, and then provides backing objects (somewhat confusingly called views). Actions create the backing objects and templates consume them. Nothing can leak through, no hunting down the origin of an ivar needed in this template but not yet defined in that one.

Somewhere in the middle are ideas about building a bridge between the action and the view. One could use responds_with as said bridge, but, for me, that felt like it played better with APIs than traditional views[1]. A possible middle ground is to use something like decent_exposure, or this interesting spin on it by Nathan Ladd. I like that Nathan’s approach is basically sugar over the pattern of encapsulating action state behind controller helper methods which are shared between views. I’ve been using the helper method approach so far, but it’s a little awkward to test and confusing for those used to sharing ivars.

If you’re sick of the baby and the bath water, you might find a more extreme approach interesting. Focused Controller and poniard do away with Rails conventions entirely. You still write controllers, but how you load data and model actions is entirely different. Personally, these are interesting sources of ideas. I’m not sure I’d jump on them for a production application.

Of all these approaches, I’m most intrigued by SimplestView. It seems like the Minimum Viable Departure from Rails conventions that could possibly solve the problem of sharing state and defining a contract on that state. That said, I’m likely to try Dave Copeland’s approach first. I like that it’s about talking with teammates, reviewing each other’s work, and making smart decisions. I’m finding that no amount of framework is as good at helping people write good code as review, feedback, and iteration.

  1. I know it works with normal views, but I didn’t like that it nudged me down the path of using conditionals. YMMV.  ↩
At sign

A tale of two Rails views

Why do I prefer to avoid referencing instance variables in view?

I needed to clarify this personal principle to a teammate recently. It was one of those things I’ve internalized so strongly that it was initially difficult for me to do so; one of those things that have become so true to me that teaching someone else about it requires getting past the “well, obviously it’s the best, that’s why” phase of mental tantrum.

An entirely made-up, possibly oversimplified Rails view fragment:

<p>Hi, my name is <%= %></p>

This is a by-the-book Rails view. Set an ivar in an action, use it in views (and helpers), you’re done, get back to thinking about building product.

It’s easy to iterate with this. It’s easy to see data “passed”1 into the view by scanning for the @ sigil; your editor probably does this already. It’s easy to move markup around in templates with a simple cut-paste.

If you stick with ivars long enough, you’re going to end up with two kinds of misadventures.

Most commonly, you’ll wonder why @user is nil for some view or edge case. Maybe you forgot a filter or didn’t set it in an action? Backend developers are sometimes equipped with the curiosity and knowledge to fix this themselves. For front-end developers or those new to the system, this kind of error is basically “womp-womp sad music go interrupt someone who can help you”.

This leads to the second misadventure: where did this @user thing come from2? Maybe it was set in a helper, or a filter, or an action? Well now you’ve painted yourself into a weak spot of a language like Ruby. Your tools probably can’t point you directly at the line of code where a variable came into being. You can do some clever grep’ing around3, probably. At best, you know the system well enough to get to the right file and find it, or there’s some convention you can use to intuit where it might be set.

Of course this way is better, right?

<p>Hi, my name is <%= %></p>

Well, not initially. Already you have to pick a good name for a method because you’re probably going to use it all over the place. Then you have to find a good place to put that method: on a helper method? on a helper object? on a model?, i.e. now you’re making decisions, which is a thing Rails tries to shield you from wherever possible. Personally, I find naming things quite entertaining and hardly one of the hardest problems in computer science4.

A marginal benefit comes from reducing the entry points that the name current_user came to be a thing in this view: it’s a method name, a local variable, or a view-local variable passed into the template5. Thus the search space for “where did this thing come from” is way smaller for typical Rails templates and manageably smaller for unreasonable Rails templates.

This way pays off once the application gets past the point where new code tidily fits into models, views, controllers, or helpers. At that point, you need objects, messages, and experience at building with objects and messages (successes, stalemates, and abject failures)6. If you’re competent at messages (i.e. method calls) in Ruby, you can at this point experience a “this is Unix, I know this!”7 moment and work with this method call like you would any other method/function invocation in a computer program.

Making this investment into a method call yields another long-term benefit: simplicity in experimentation and testing8. I can poke at helper methods and helper objects in a Rails console without breaking a sweat. If that feedback loop doesn’t get the job done, I can write tests against helpers and (some) controller methods to iterate on figuring out why something doesn’t work the way I think it should.

It’s amazing that blogging about programming is so popular. Programming involves a lot of tradeoffs. Tradeoffs make for wordy articles that don’t leave you thinking “yeah, those other guys are SOOOO WRONG” or “YEAHHHH I’m so right”.

If I’ve written this properly, hopefully you felt both of those feelings. Maybe you reminisced about a day when you thought view ivars were great and then regretted it. Perhaps it’s easier to see why you’d start an app or feature off using ivars and then refactor them to method calls later.

With instance variables in views, as with many other grey areas of Rails, the most useful long view is this: you’re always right, and you’re always wrong, it just depends on which “you” (past you, present you, legacy project you, greenfield project you) is being observed.

  1. I’m not using “passed” as scare quotes here. Rails’ choice to take ivars from actions and teleport them into views is oft villified, but I find it more useful to think of them as something that just is. They are incredibly useful at first, but some developers will long for an explicit contract (i.e. a parameter list) between action and view. 
  2. If you’re an object design enthusiast, functional programming aficionado, or Rails contrarian you may be crafting an amazing retort about sharing state in weird ways at this point. Please review the previous footnote. Yes, you’re basically right. No, that’s not going to change how Rails works. 
  3. Regexes, two problems, etc. 
  4. Actual hard problems in computer science: systems connected by unreliable (i.e. any) network, laws and regulations written by humans, working with money. 
  5. When it comes to variables in Rails templates, a short guide by Adam Keys; method names: friend, ivars: foe, local variables: foe, view-local variables (passed via render explicitly or by the framework): both! 
  6. This is the concise version of a seems-really-important-to-me idea I need to express in more words. Remind me to write this, should I forget about it, internet! 
  7. What up, Ariana Richards
  8. You knew the testing thing was coming, didn’t you? I mean it’s like Chekov said about guns in stories: if method calls are mentioned in the first act, you have to mention TDD in the last act. If you headdesk’d, consider that you might be annoyed by TDD because you keep giving yourself a head injury when it’s mentioned. 
The first-stage engines of a Saturn V rocket

Rockets and startups

A venture-funded startup is sort of like a space program. Space programs don’t build airplanes that fly in flat, predictable, safe trajectories. They shouldn’t be concerned with doing something pedestrian. Space programs should be concerned with doing something very unusual, perhaps unnatural.

Like a space program, a funded startup is equal parts propaganda and collection of great minds. During the first few rounds of financing, a startup is completely unlike an actual business. It’s all growth: technical growth, metrics growth, mindshare growth, operational growth, staff growth. It’s about gathering smart, driven people and making something new without the confines of traditional market forces. It’s about showing that new thing off to the world, making everyone think that they either really need to have it or that they’re behind in the race to make something like it.

Startups, like space programs, take a bunch of volatile materials and apply them to make an impossible climb. Quite often, those materials explode on the pad or in the first couple minutes of flight. Sometimes all the systems work together, months of effort by teams coordinated by a few masterminds, and the startup or spaceship gets off the ground.

Even if the startup or spaceship survives it’s first minutes, most of it is discarded as it ascends. A Saturn V weighed millions of pounds on the launch pad; what returns to Earth weight thousands of pounds in the end. Systems are built, used, and discarded many times over. Depending on a startup’s exit, what remains is only one of many ideas or systems built over time, sometimes an idea expressed in the heads of a few key people.

Space programs are great. Startups are great. Keep in mind that they are wholly unlike more commonplace human endeavors and you’ll be fine.

Grow and cultivate

Adding new functionality to software is really exciting. I love poking around the edges of a system, figuring out what’s going on, and looking for that “obvious” place where the first change should happen. But sometimes, it’s hard to know if I’m making the right change. How Should This Work?

The temptation when changing an existing system is to implement the desired behavior within the structure of the current abstractions. Repeat this without adjustment, and you’ll quickly end up contorting existing concepts or working around legacy behaviors. Conditionals pile up, and shotgun surgery becomes standard operating procedure.

Even if you code test first, you can make a mess of a system. What you end up with is a system that moves from local maximum to local maximum while the time of the test suite grows unbounded. There are worse things that could happen, but no one’s going to jot this one down as a “best practice” either.

The counterforce to this temptation is the red-green-refactor cycle. Look at how the system works and figure out how the next bit of work might change how the system works. Refactor to simplify the act of making a change, or make the change and refactor afterwards to a better design.

Software can grow by accretion, but it stays malleable when the team culture is one that balances continuous growth with continuous cultivation of good design.

Currently provoking my thought

The worst NFL announcers, by the numbers (via Kottke). Obviously, this is my jam. To my surprise, Phil Simms didn’t come in last. Simms is a real conundrum; I think he’s great on Inside the NFL, but on live TV he shows frequent ignorance of how NFL games work. Apparently a lot of people don’t like Aikman as an announcer; I think he’s tolerable. I’m surprised Daryl Johnston’s FOX team didn’t show well; I guess Siragusa brings them down something awful.

Mapping Place Pins. The extended story of how the city guide feature on Pinterest came to be. Having worked on the edges of stuff like this in my Gowalla days, this was an intriguing read. Even if you haven’t worked on a location product, stick around and read it for the behind-the-scenes details and the loving treatment of how an idea becomes a product.

Architecture and Agility: Married, Divorced, or Just Good Friends? It starts here…

Does agile development need architecture? Does architecture need agile development? Is it possible to even answer these questions without a polarizing debate typified more by caricature and entrenched cultural views than by clear definitions and open reasoning—a debate more closely resembling two monologues streaming past each other than a dialogue?

…and ends with thinking about the intersection of making things, designing things, and working with people in a different way: holistically. People don’t write great code on schedule because of architecture and process. Architecture and process are what help people learn and create faster. Once a team is learning quickly and creating effectively, then they can write great code and ship it predictably.

Stop me if you’ve heard this one

Lately, I find myself stopping to make sure I haven’t previously written the thing I’m currently writing. For starters, I have a horrible method for moving things out of my “I should finish this idea” folder into the “I wrote about this idea!” folder. It doesn’t help that I often draft articles in my head while I run, shower, or do chores and then forget that I had the thought. It’s kind of a mess in here.

Assuming that I slip up and write the idea down twice, hopefully it’s in a way that doesn’t look like I’m plagiarizing myself. Is it weird to write about the same thing multiple times, if it’s nearly the same idea?

I hate repeating myself, telling the same stories over and over. “Have I told you this one before?” is a frequent prologue to great stories. But is it necessary? Hearing a mediocre story twice is slightly painful, but hearing a great story twice is no chore at all.

If I keep writing an idea, coming back to it, maybe there’s something important there? Perhaps it’s still bouncing around in my brain for a reason. I haven’t fully wrapped my head around it, or articulated the idea in a way I find satisfying and essential.

This is a personal website; the line between “just play the hits” and “stop trying to make fetch happen” doesn’t have to be so strong here as it would on, say, the New York Times. So, stop me if I write about an idea so much I run it into the ground. It’s just that I’m trying to get it out of my head in the right way.

The joy of finishing

Then, the finish. Stain. Wipe. Wait. Stain. Wipe. Wait. Sand. Wipe. Stain. Wipe. Wait. Check. Seal. Wait. Sand. Wipe. Seal. Wait. Sand. Seal. Wait. And that’s if everything goes according to plan.

Finishing. It’s about woodworking. Or everything.  Or sometimes an essay about furniture is just an essay about furniture.

Bridge enroute to Chilas

Let the right something in

There will always be more somethings we want to do than we have time to do. Right? Maybe.

  1. A lot of the right somethings can add up to a great thing, even if the somethings aren’t of the highest quality or express the biggest idea.
  2. A lot of the wrong somethings aren’t that interesting, unless your work is generally of great enough import that historians take an interest in it.
  3. A lot of the wrong somethings may not add up to much at all and are unlikely to attract the interest of historians.
  4. If you don’t care about whether something’s great, you can produce a lot of somethings.
  5. If you don’t care if something expresses a big idea, you can produce a lot of somethings.

A lot of truisms will tell you that quality is the important thing and quantity is secondary. But perhaps there are all sorts of cases where that’s not entirely true.

Mozart wrote way more music than Beethoven; Beethoven’s was more sophisticated but their bodies of work are considered on the same level. There are way more episodes of Law and Order and all its spin-offs than Breaking Bad; one made more money, one gathered more acclaim.

Rather than deciding to pursue quality over quantity, perhaps it’s better to:

  • Choose your somethings with care
  • Execute on the idea central to those somethings
  • Produce as many somethings as possible without hating the quality of your work
Logs from Finland

Not that kind of log

First, read all of this excellent distillation of distributed systems by Jay Kreps,  The Log: What every software engineer should know about real-time data’s unifying abstraction. Now, consider this.

There’s a moment, when you’re building services and web APIs, when you think you’ve pretty much got it under control. You’ve got an endpoint for every query, a resource for every workflow. All the use-cases seem to be under control. And then, the question appears:

“How can I get access to all the updates to all the data? You know, for [REASONS].”

For APIs exposed to external developers over the web, this is where you’d reach for web hooks or PubSubHubbub. It’s not the best solution, but it works. If you’re building an internal system, you could  use the same approaches, or…you could build a log.

No not that kind of log. An event log, like LinkedIn did with Kafka for their internal systems. Every time your data model changes, every create, update, or delete, you drop an event with all the metadata related to the change. The event goes into some kind of single-producer, multiple consumer queue. Then all the clients that want to know about all the changes to all the things can read events off the queue and do whatever it is they need to for those important REASONS.

If you find this intriguing, this is a lot like replication in database systems. Definitely read LinkedIn’s article on this, and definitely read up on how your database of choice handles replication. And if you’ve built this before and have a good answer to initially populating “replicas” of a database, let me know; I haven’t come up with anything better than “just rsync it”.

Synchronize icon

Dear Sync Diary

Brent Simmons is keeping a diary as he works through implementing sync for Vesper, an iOS note-taking app. Building this sort of thing isn’t easy; cf. it took Cultured Code multiple years to implement it for Things. Thus it’s pretty neat that Simmons is breaking it down into understandable chunks:

If you think you need to implement a synchronization system for your application, try to find a shortcut so that you don’t. If you can’t find a shortcut, you could do worse than starting with these notes.