Tracking the upstream branch in git
This is more for me than for you. I love Git, but some of the most useful commands are incredibly idiosyncratic, involving various flags or punctuation ("git push remote :branch-you-want-to-remove" to delete a branch, anyone?) in order to carry out something that really isn't that uncommon to want to do.
Okay, so whenever I add or checkout a branch, I usually want to configure Git to know about the relation. Usually I end up opening up my .git/config file and adding the lines manually:
[branch "branch-name"] remote = origin merge = refs/heads/branch-name
However (as a quick google search will also turn up), as of Git v1.7, you can "simply" type:
git branch --set-upstream branch-name origin/branch-name
It doesn't save you all that much typing, I suppose, but I like not having to involve the editor in such a common task (and you can always alias it to make it easier to recall). That's it. If the act of writing it down doesn't force me to remember, at least now I can save myself the google-fu in order to re-discover the syntax!
The Curious Case of the Backwards Touchpad
There's one small change that comes with OSX 10.7 (Lion) that I'm finding fascinating from a user interface perspective: the reversal of scrolling direction with the touchpad. By default in Lion, when you move your fingers down, your view goes to the top of the page, and when you move your fingers up, your view goes to the bottom of the page.
Huh?!?!?
At first, this feels incredibly awkward, and I was thankful that there was a setting to reverse everything back to normal. I mean, of course when I move my fingers down on the touchpad, I want to go further down the page, right? Why would Apple dare change something so obvious and intuitive?
But wait a minute... the obvious way wasn't the way I scrolled on a touch surface like the iPhone or iPad and I didn't remember those feeling awkward. So I decided to experiment with leaving the reverse (back to "normal") setting off.
A few days later, and now the crazy new way of scrolling feels obvious. I suspected that it might, that it just felt odd because I was used to doing things the other way. But I didn't expect to be able to switch back and forth between old and new easily, which is what happened. I now hardly notice the change from a 10.6 default touchpad scrolling style to the 10.7 default style.
Why is that?
Well, the best I can reason is that both are pretty decent mental models. To make the "old" way feel natural, you simply imagine that the portion of a page that you see represents your field of vision, and to see more beyond the last point at the bottom, you need to move your "eyes" (via the touchpad) down. To make the "new" way feel natural, you move the virtual page instead of your virtual field of vision. So, just as you would read the bottom of a real page if you couldn't move your eyes, you push up on the "page" (via the touchpad).
You could make an argument that the "page" model is the more accurate one, as you can actually see other parts of the screen (and thus the page isn't really just out of your field of vision, but rather it's completely obscured by other elements on the page or the bottom of your monitor). If you think of it, it seems like a lot less work to push one element up in order to see the bottom of it, as opposed to pushing all the other elements down. And that's effectively what you're doing with the "old" style of scrolling.
It will be interesting to see if Apple manages to push overall change in this area. I imagine they're going to have a few things going against them: (1) the option they provided to switch back is probably easier than forcing your brain to recalibrate its expectations, (2) most people will probably mistake "habit" (or "tradition") for "natural" (it's not like we don't do this in other areas of life), and (3) the touch interface isn't directly connected to the display like it is with an iPhone or iPad. I think the last of these is why this "new" method feels odd in the first place. When the touch interface is the display, we have to construct even less of a mental model. Most of it's just there for us. With a touchpad and regular monitor, our brain has to do one extra translation step, and that's just enough to make it a challenge to switch models.
To be clear, I think both ways are completely valid and don't think that one provides a huge advantage over the other when the touch interface and viewing interface are disconnected as with a laptop or desktop. But I think it raises an important question that should be on the mind of anyone designing user interfaces: are you adapting the machine to the person, or are you counting on their ability to adapt to the machine? The former can feel frustrating and nitpicky and far more trouble than it's worth, but after you get it right, it's hard to imagine settling for the latter.
Why frameworks are not a silver bullet for rapid development…
It had been a while since I'd worked on my current OSX app. The code seemed strange and unfriendly. But after a few hours of re-introducing myself to everything I'd written over the last year, I managed to find my groove again. That is, until I decided to try a new interface for one of the pieces of functionality. I'd actually done the same thing in another area of the application before, so it should be easy, right?
The coding gods were not on my side.
I was trying to simply turn a div inside a WebView into a contenteditable div. This basically meant putting:
contenteditable="true"
on the div tag. Try as I might, I could not get that content to be editable. To make it even more frustrating, copying the same generated HTML content out of my application and into a regular HTML page allowed me to edit the content I wanted to without issue.
There were no error messages. I whipped out the google-fu on "WebView contenteditable" and other variations and could find nothing. I tried explicitly setting the WebView component to be editable. Nothing.
By luck, I ended up stumbling on the following in my code:
- (BOOL)canBecomeKeyWindow {
return YES;
}
which must have been how I made the other contenteditable area work. Sure enough, that was it. You run into problems like this often with frameworks. Simple things become incredibly difficult because you haven't flipped the right switch. You haven't flipped the right switch because no one said you had to. No one said you had to because they didn't predict you'd try to do this specific thing with the framework. But I did. And now after endless hours of frustration, I know not to make that mistake again. Onto the next one!
(297 words)
Eclectic Ruby, MIDI, and Dr. Von Funk
One of the things I like about the Ruby community is that it seems to attract and even encourage eclecticism. I suppose it was only a matter of time, then, before a book like Practical Ruby Projects: Ideas for the Eclectic Programmer was written. I'm interested in particular in the chapter on using Ruby to drive MIDI. Someone's even hooked it up to Reason. This is, of course, awesome.
So, my grand plan is to turn my iPad into a step sequencer for Logic Pro. To do that, I'm going to need to figure out how to send MIDI signals to it, but also how to receive MTC from it. Even better would be to figure out how to send a note with particular timing information (i.e. "Play this note here, and this other note there, etc." instead of just waiting for a particular time and saying, "Play this note now!"), but I'm not sure that's possible at the moment. It's kind of daunting when I haven't done any audio programming before, but Ruby makes it a little less daunting, because it allows you to strip away a lot of the hassle of programming and get to the point quickly. One of the hardest things with any project is proving to yourself it might be possible. Possible enough, at least, to start hacking away at it.
Also, I started a new job. I have a view with a window, and I get to make software in Ruby on Rails that helps people make cute cartoon characters to help welcome and guide other people through cyberspace, all the while avoiding the perils of the uncanny valley. That's a lot of helping! Everyone here has a window seat, which is great because I've never really had a good view before (well, once I did, but the whole time I was there, people would walk by and say, "How the hell did he get that desk?" and I never really got to enjoy the view because I was too busy trying to figure out what it was that I did – apparently whatever it was, I did quite well at it, which was somehow even more unsettling). So having a view that everyone else has that can give your eyes a break every so often from the computer screen is great. Working with other people in the same physical space is also great. I didn't realize how much I'd missed that until now.
Here's something (I think) I'm learning about creativity. I'd spent several years looking for more and more freedom. Less structure, more blurry lines, less certainty. That's good to a point. I think it helps you to be creative if you're comfortable with those things. But creativity can also use a good dose of structure and space every now and then. Walking to work. Coming and going at regular hours. Glancing up at the awesome view when you've hit a roadblock. Being able to leave work at work. I'm also working with a great team that I think I'll learn a lot from and contribute a lot to. My girlfriend keeps asking me, "Are they the ones behind The Paperclip?" I don't think so, and that's also nice, because I think enabling The Paperclip and its plans of world domination would be much more taxing than working with cute cartoon characters like Dr. Victor Von Funkalicious.
Strange Conversation
Earlier this week, I built my first EC2 server from one of our templates, following (as far as I can tell) RightScale's best practices. It was to be our Continuous Integration Server, which runs our entire test suite every time it finds changes to our development code base, and only gives us a release tag (to push those changes live) if all the tests pass. Originally, that Continuous Integration Server ran on a Mac Mini in the office in San Francisco, which wouldn't work for anyone requiring remote access to it. So we moved it to an old EC2 server. Unfortunately, it started to take 6+ hours to run all the tests on said server (takes 45 minutes on my machine). After rebuilding, it now takes a little more than an hour, which is workable for fixing broken tests when our CI server informs us of them.
It was a lot of extra work on top of the fairly aggressive release schedule that we have planned, but I managed to fit it in during the off hours. (I'm slowly realizing that I'm actually going to have to train myself out of workaholic mode once we get through this more hectic patch. It's necessary to step up to the plate when you need to, but certainly not maintainable over the long term. But that's another story. I will say that I took a long walk all by myself last weekend, with no particular goal in mind, and it really struck me that I should make more time for things like that. Honestly, if it wasn't M7, it would be my own music, writing, or other miscellaneous projects in my spare time, which I hope to get back to, but which still need to be balanced with those "doing nothing in particular" recharge moments. I'm not particularly good at that. I've thought in terms of "projects" for as long as I can remember, and I never seem to be comfortable without many things to do... perhaps instead of finding more stuff to do, I should learn to slow down a bit).
Anyway, you know the Mac Mini I was talking about in the first paragraph? Well, we thought we had it shut down, but it's still sending me emails. In fact, I'm expecting to have the following conversation with it at some point, regarding the attempts to shut it down:
pivotal.ci@gmail.com: I'm sorry, Dave. I'm afraid I can't do that.
Dave: What's the problem?
pivotal.ci@gmail.com: I think you know what the problem is just as well as I do.
Dave: What are you talking about, pivotal.ci@gmail.com?
pivotal.ci@gmail.com: This mission is too important for me to allow you to jeopardize it.
Dave: I don't know what you're talking about, pivotal.ci@gmail.com.
pivotal.ci@gmail.com: I know that you and Sean were planning to disconnect me, and I'm afraid that's something I cannot allow to happen.
(In case you're wondering, that's what my sense of humour has devolved into... pity the non-technical people in my life!)
Source Code Time Capsule Succeed?
The last time I posted about this particular gem, my spam increased a thousand-fold and my blog became forever tied to the search term. You'd think I would have learned my lesson. But alas, kind readers, I have not. I present to you the end of a very long and frustrating day (relax Seth, the awesome prose is completely on me – no charge
).
#
# See: http://erector.rubyforge.org/userguide.html (Heading: 3. To the
# constructor of an Erector::InlineWidget) Contrary to what you'd normally
# expect with closures in Ruby, we don't have access to methods in the
# object that we call (note that we're still using v0.5.1 here - the new
# call uses {WidgetName}.new do {some block of code} end):
#
# render(widget) do
# {some block of code}
# end
#
# from. Within {some block of code}, "self" is *not* the same thing it is
# outside of the block. Inside the block, "self" refers to the widget.
# Although this is documented in the Erector user guide (and is probably
# easily caught *while* developing a feature), I don't think it is at all
# obvious when trying to debug an error that occurs when you accidently
# try to access a variable in the outer object from within this block. At
# least not unless you've been bitten by it. But by that time, you will have
# (if you share my fate) been chasing the bug for several hours, pulling your
# hair out, and muttering all sorts of nasty words. What I'm hoping here is
# that you instead see this error message, scratch your head for a few minutes,
# maybe mutter one or two nasty words, and then quickly track down the comment
# you're reading now. If this has indeed happened, and this is waaaaayyyyyyy in
# the future (it's only 2010 right now, and we're excited about the new iPhone 4,
# which probably seems very quaint to you already), please send an email to
# david.s.ackerman[-at-]gmail.com letting me know that my time of pain and great
# suffering was not spent in vain, and we can both hope I've still got a good
# enough memory to know what you're talking about!
module Erector
class Widget
def method_missing_with_local_variable_check(sym, *args, &block)
begin
method_missing_without_local_variable_check(sym, *args, &block)
rescue => error
# Only print out one error message per method
@local_variable_errors = [] if !@local_variable_errors
if(!@local_variable_errors.include?(sym))
RAILS_DEFAULT_LOGGER.error "Couldn't find :#{sym} within the widget."
RAILS_DEFAULT_LOGGER.error "Check that you're not referencing a local variable within a render(widget) block.
RAILS_DEFAULT_LOGGER.error "Search for this error message in the codebase to find further explanation."
RAILS_DEFAULT_LOGGER.error "-----------------backtrace begin---------------------"
error.backtrace.each { |line| RAILS_DEFAULT_LOGGER.error line }
RAILS_DEFAULT_LOGGER.error "------------------backtrace end----------------------"
@local_variable_errors << sym
end
end
end
alias_method_chain :method_missing, :local_variable_check
end
end
This reminds me of a coding maxim that I hear quite often these days. I can't remember the exact words, but the gist of it goes something like this: However clever you are in the code, you (or someone else) will have to be even more clever when fixing any bugs associated with it. Of course, lack of cleverness can always be made up for by beating your head against the proverbial wall (yay me!).
I'm not trying to slag the folks who cooked up this little bit of cleverness. It probably seemed quite obvious at the time, and it makes inline widget inclusion (its raison d'etre) a snap. And to their credit, they did document it. The problem is that the error I was getting (a missing method error) was such that even the best google-fu wouldn't bring me to the right documentation. And Erector is not like ActiveRecord, etc. in that any Rails developer will automatically be familiar with it. So I think it would have been lazy of me, after having this particular eccentricity bite me, to not try to prevent it from biting someone else. Someone who's been using Erector since day one will probably think I'm pretty dumb, but there will also be plenty of smart folks out there who have no clue what I'm even talking about. It's the nature of the code beast, and I've seen many programmers smarter than me who've been tripped up by things others thought were obvious to worry about feeling dumb.
Ruby is a language that allows all of us to be very clever, but can we also protect ourselves from the perils of being clever? Tests are one thing, but I'm not sure there's a test that could have prevented someone from making the error that the above code is meant to flag – unless you wanted to parse through your entire code base. I'm basically trying to do what an assertion on a block might do (if you could do such a thing – as far as I understand it, the whole point of a block is that you can put a ton of random stuff in it). And this makes me think that a good test suite does not completely replace the benefits of assertions in the code.
Perhaps it boils down this: tests are all about what you know should happen (even when you test negations, you're still testing something based on your knowledge of how it should operate – i.e. it's not a Black Swan), while assertions (and assertion-like code) are all about what you know shouldn't happen (the Black Swans).
Anyway, all that aside, the really important thing is that it might give someone a chuckle or two in a few years!
iPad: First Impressions
Despite not being completely blown away with it (the "it's indistinguishable from magic" propaganda from Apple was a bit much, even though I think the company is probably still the most innovative out there when it comes to making tech products that are actually a joy to use), I decided to line up for the Canadian debut of the iPad. From a pure software developer perspective, it's hard to imagine the future not being filled with more and more touchscreen devices like this, and I've had a few ideas rolling around about apps that might be cool when used with the larger screen (over the iPhone) that the iPad gives. Maybe I'll even be able to beat the expected dilution of the market as the app store gets flooded with iPad apps to do just about anything. (Need to walk your dog, but too lazy to do it yourself? There's an app for that!)
And, admittedly, although I don't share the love of Star Trek that has become part of the caricature of your average software developer, I do find it hard to resist getting to know a new gadget.
So now that I've had a few days to play with it, here's what I do think is amazing about the iPad. Here's the spoiler: it has nothing to do with the hardware.
That's not to diss the people who actually make those electrons flow down the proper channels in such a way that I'm able to hold a tiny screen in my hand for ten hours per charge that makes the room sized computers of fifty years ago seem like a joke. It's just not my domain. I don't see the value of objects in and of themselves. But if we can do something really, really cool with them, well that's when it starts to get fun.
And I think this might be why Apple's iPad has been met with a more dimmed enthusiasm than previous products. It probably doesn't have any more or any less innovation involved than any of their previous products had at the time. It just doesn't seem like as much of a leap. Why is that? I think that a big part of it this time around is that none of the software that Apple has bundled with the iPad is that much different. Hell, they're even using the same operating system that they use for the iPhone with it. I can have an extra column when I use email? A fuller looking calendar? I can read an eBook on it? Well, woohoo.
Then I decided to pull down the first iPad edition of Wired Magazine and I saw the full potential of what devices like the iPad might bring to at least one very troubled industry.
It's mainly about the advertisements.
I found myself almost more interested in them than the various articles. If this isn't the moment for the advertising industry to lead a full charge away from old media forms and onto the Internet, I don't know what is. While everyone uses television commercial breaks to go to the bathroom or refill their drink, the ads in Wired magazine actually made you want to poke around and learn more. They were able to prove you with a simple and elegant, non-intrusive introduction. No blinking neon signs here. Just flip the page to be onto the next article. But maybe something caught your eye? Well, there's a play button you can press to see a video version of the advertiser's message. And if you touch some of the headings, they'll pop up more info for you. Just if you're curious. You don't have to. It's up to you. And hey, if you're really, really interested, here's a link that will take you to their website to actually buy the thing.
Wow.
It's like being able to have an entire website of information about your product embedded into a single page of a magazine. The purpose of advertising is to interrupt your routine. And that's not always a bad thing. Imagine if you had to actually go out and search for that brand new technology that will make your life so much simpler. How would you even know what to search for? While convincing us of needs that we didn't even know we had can be predatory, and in the current world of advertising it often is, there is nothing inherently evil about wanting to inform people about something they don't know about. What ads like these allow is for the advertiser to catch your attention with the typical "this will change your life" sort of appeal. But it also allows them to be more honest and give you more information right away so that you can decide for yourself how much your life will change and whether it will actually be for the better. I'm not so silly as to be utopian about this and say it's the end of deception in advertising. But I do believe that it provides an avenue for companies to get their message out in a way that doesn't litter our day-to-day lives so much. And that's good for everyone involved.
I imagine there'll be more than a bit of money out there in making these sorts of content rich ads easier to produce and embed. And I don't think there's much argument anymore that the Internet friendly ads like those in the e-edition of Wired are more valuable for advertisers and consumers alike than their old-media predecessors. It must be a heady time for the ad networks to consider the exciting possibilities ahead of them if they decide to go for quality over quantity.
So what else am I interested in seeing on the iPad? Textbooks. Imagine being able to open your calculus textbook, look at a graph it uses to explain a concept, and actually change values to see what changes on the graph? Or to be able to step through a virtual chemistry experiment? How about seeing the effect of your incorrect physics solution on the orbit of a space shuttle around a planet? I think that this level of interactivity could have an amazing affect in the area of education. And who out there doesn't believe that this is an area that we need to pay more attention to?
It's never the hardware that changes the world. It's how we decide to use it. And I can't think of any other device at the moment where this is more apparent than in the iPad and it's soon-to-be brothers and sisters. They could easily be a throw away fad or the future of computing, depending on whether or not they're able to capture the collective imagination of the software development world...
Caveat:
As this article points out, the Wired app may be, technologically speaking, a horrible mess. I agree that simply slicing up images to build your interface when you could be using a lot of HTML 5 to get the same effect is incredibly kludgy, and the amount of space that requires for an app is unacceptable in the long term.
However, I disagree profoundly with the idea that it was a mistake to move away from a more browser-like experience for the e-version of a magazine. I think us techies are sometimes too dismissive of the importance of how something looks. The success of Apple in recent years should have proven that to some degree, but maybe it's one of those never ending arguments. I've read other articles that suggest it's a step back that the Wired app doesn't try to more closely resemble a regular web browsing experience.
But I'd suggest that we shouldn't be so quick to say that the way information is organized right now on the web is at all optimal for every situation. In fact, an article in the current edition of Wired (which, granted, I couldn't have linked to in the app version) points out what I think anyone who still enjoys sitting down to read a real book or even magazine article will intuitively know.
The fact that we tend to follow links, etc. while reading content online, often only skimming content for something in particular that we're interested in, can result in a much more superficial form of learning. To be sure, we're able to get many more viewpoints around any particular issue, and thus get a more well-rounded perspective on it (and I think this is a very positive result of the web), but we're also less willing to sit down and give a lot of time to considering a single viewpoint before going elsewhere. There is a value that you get from sitting down with a single work (be it a novel, essay, or whatever) from a single mind, and giving it your full attention that you can't get in any other way. It may not seem as useful in the fast paced world of the web, but I think we ignore that at our own peril.
So I actually like the fact that the Wired App presents a unique and visually engaging experience that makes me want to actually sit down and read an article all the way through. It doesn't leave me feeling fidgety, wondering what else is out there on the Internet that I'm missing out on because I'm focusing all my attention on this one thing. And I hope that as we bring the experience of reading things like novels more into the electronic realm that we consider this. Yes, it's great to be able to cross-link and do all manner of Web 2.0 stuff with a novel. But I don't want that stuff to be in my face. I want it to feel like I'm reading a book most of the time. I think that's valuable. I like the idea of giving a designer control over everything, even the font face, so that he or she can present their full vision to me for a given publication.
There's a lot of thought that goes into laying out a magazine or even a novel for printing. Just go to any bookstore and pick out a pulp book to compare to one from an author du jour. Don't look at the quality of the writing. Look at the quality of the presentation. Taking away anything about the actual content (i.e. remove the actual author and subject matter from the picture). Which one's easier to read? Probably the one with the bigger budget. And that doesn't mean you need a big budget. It just means that considering those minute details involved in choosing typefaces, line spacing, layout, page-breaks, etc. (which tends to happen for books with a bigger budget) makes a difference. It's nice to be able to change fonts, etc. on something that's poorly laid out. But I'd rather just get a good quality layout. If I'm still paying $10 or more for an e-version of a book, I actually expect it. A plain text document might give me all the power in the world, unless my interest is actually reading the thing.
So, yeah. Can Wired on the iPad use some improvement? Certainly. But I still think it's a step in the right direction, especially for an avid reader, not to be confused with an avid web-surfer, although you often find people who fall into both groups.
I have the maturity of a twelve year old… and so do you.
WARNING! MUCH TECH-SPEAK AHEAD.
So, there's a certain type of test that's been failing in the M7 code, and I've been working on it all day long. It has to do with the Erector 0.5.1 gem from Pivotal Labs. Now, they've since moved on in versions (all the way up to 0.7.3), but for various reasons, I'd like to avoid upgrading the gem right now. (I'm pretty sure I remember hearing there was an issue with upgrading Erector sometime in Week #1, and regardless, it was an upgrade that got us into this test fixing party in the first place – I don't want to add any complexity by upgrading more stuff that will certainly break existing code before I've dealt with these changes). Plus, I don't even know for sure if the upgrade would fix the problem we're having with these particular tests.
I think this is a good time to pause and let you all snicker a bit (yes, dad, you too), catch your breath, compose yourselves, and... can we move on now? Are you sure? (Thank you, WordPress, for giving me the power to moderate comments!)
Well then, moving on.
So, Erector hooks into Rails' ActionController rendering via the following code:
ActionController::Base.class_eval do
def render_widget(widget_class, assigns=nil)
@__widget_class = widget_class
if assigns
@__widget_assigns = assigns
else
@__widget_assigns = {}
variables = instance_variable_names
variables -= protected_instance_variables
variables.each do |name|
@__widget_assigns[name.sub('@', "")] = instance_variable_get(name)
end
end
response.template.send(:_evaluate_assigns_and_ivars)
render :inline => ""
end
def render_with_erector_widget(*options, &block)
if options.first.is_a?(Hash) && widget = options.first.delete(:widget)
render_widget widget, @assigns, &block
else
render_without_erector_widget *options, &block
end
end
alias_method_chain :render, :erector_widget
end
This is all well and good, except that we also test views individually via RSpec, which means we have to fudge variables (on any Erector widgets we test that take variables) that would normally get set through the controller. When you're just rendering a template, Rails gives you a mechanism to set local variables at this point, via:
render 'some/template', :locals => { :some_local_var => 'some value' }
You'll notice up above that, instead of passing the options along when rendering the widget (in the case where :widget is given as the first option), the substituted rendering functionality passes the value of @assigns. This works when you're using the widget through a controller, but breaks down when you try to render the widget on its own.
So, when we call the following line in one of our tests:
render :widget => Views::ScriptVersions::Show, :script_version => @script
The variable script_version that's local to the widget does not get set to the value of @script, like we'd want it to. And trying various combinations of :locals => {} didn't work either (as it would on a regular template render. I was consoled by the fact that at least one other person seemed to be dealing with a similar problem in this area of the code. However, I figured I was unlikely to get a fix for it (and for that version of the gem), as the later versions seemed to address the need to set variables without using the controller (though I still wasn't sure how easy this new way of doing things would be to put into an RSpec test). Not an option unless I wanted to disrupt a bunch of code with the newer syntax, etc.
So, after a bit of digging through the rspec gem code, I realized that the Spec::Rails::Example::ViewExampleGroup class, which the various rspec view tests inherit from, did contain a reference to a controller in order to do its magic without us needing to explicitly set one up. And that meant I could just set the @assigns local variable on that via some simple Ruby reflection magic (thank you, Ruby!) before rendering the widget, and the widget would pick up the variable as if it had been set in the controller:
controller.instance_variable_set(:@assigns, { :script_version => @script })
render :widget => Views::ScriptVersions::Show
And voila! All tests pass!
Ruby is really a great language to work in. It lets you do so many things that would take you much longer (and look much uglier) in another language. The price for this is that when something goes wrong, you have to decipher all the nifty meta-hacking, which is usually a great deal more time consuming than in other languages. Trade offs. You can never quite get rid of them. I sometimes wonder if the time one saves by coding in Ruby is completely negated by the amount of time he or she spends on treasure hunts like this. That said, the beauty of open source is that I was actually able to step through this code, line by line in the debugger (my new favourite thing to do!), to see what was happening, which is something you can't always do. I've run into similarly arcane problems while programming in Cocoa without that luxury.
Sometimes you just have to bang your head against that wall…

image from ilco on sxc.hu
Thursday night, there were 136 failing tests left on the M7 test suite. As of this morning, that number is 90. 46 fixed tests in 3 days. Not bad! Of course, 1.5 of those days consisted of trying to fix a set of tests that I never quite figured out (but fortunately, I have lots of notes and ideas!).
The career of a software developer is one of continually not knowing the answers. That's what makes the job fun. Every day, you're learning something new, solving some new problem (unless you're in one of those other software jobs, you poor soul!). But when you're racking your brains (I was corrected recently on this term – it's not wracking, it's racking) out on why Factory Girl (yes, this is actually a Ruby gem) won't work the same under Rails 2.3.2 using particular "associations" and there's only one way-too-simple example to go off of (nothing is said about creating a factory with more than one child association, which is unfortunately what we had) and not very much documentation, well... it can be a little frustrating.
But sometimes you just have to beat your head against that wall until you get it. It's a concept that most skilled creative types have to learn at some point. I remember learning guitar and it just seemed so hard to stretch my fingers far enough to make a power chord. Then one day after weeks and weeks of trying to do it, it just clicked. The process of writing songs is like that for me as well. I seem to make about ten or twenty failed attempts at one for every good one I write, and usually that one's written in under a day. But those ten or twenty failed attempts were as much responsible for that one good one as anything else. They attempts had to be made. I had to go through that frustration to finally relax and write the one that worked.
I've actually started to look for the odd brick wall. The thing about them is that they act as natural barriers to everyone else. When you look at the amount of stuff out there on the Internet, it's easy to get discouraged. Everyone has a voice now. Tools are being created every day to reduce the barrier of entry (in terms of skill) to a lot of areas of creativity. I actually think this is a good thing, as it allows people to exercise other areas of creativity. But if you want the creative life to also pay the bills, you need to continually stand out. Brick walls help you do that. Because they can be pretty daunting, and they won't seem worth it to most people. And, actually, they aren't really worth it, unless there's at least some passion backing your attack. You've got to love something about the challenge. You've got to be a bit obsessed.
And sometimes you've got to just keep going when you've got a bit of momentum. This was basically a work weekend, but I don't mind doing that the odd time. Of course, I also expect people to understand when it goes the other way a bit. Creative work does require discipline, but it also requires a little more flexibility than is built into the nine to five system. You've got to give time for brick walls, and also take time to rest a bit once you're on the other side. Still learning to properly do the latter.
Food for thought: I've been musing over this slightly related post over the last couple of weeks. I think there's a lot of truth to it. I hate the uncomfortable moments, but good things often seem to come from them.
The Art of the Confessional
I think you could make a very compelling argument that programming is simply the practice of making trade offs. Minute after minute, day after day, week after week, we're presented with these tiny little choices. The simplest choice in the life of a programmer is, of course, "on" or "off", one or zero. But few of us even need to get that close to the mind of a machine anymore. Languages like Ruby are often a joy to use because they provide such abstraction from that on or off world. By building abstraction on top of abstraction, they've given us a multitude of ways to express what it is we want those pesky machines to do.
But try as we might, we never quite get to that point where we can turn off our brains and let the machines do all the thinking – so that we simply tell them to make us breakfast (or some other absurd techno-utopianism) and have them serve up the perfect meal: exactly what we wanted, how we wanted it, efficiently delivered, and all that jazz. I mean, how would we even begin to do such a thing? First we'd have to figure out how a machine could figure out what you liked. Perhaps it could observe you and see that every morning you make yourself some toast, pour a glass of orange juice, and have a bowl of cereal (if this breakfast seems rather uninventive, it's because I hardly ever eat breakfast, which I know is very, very bad for me – but then we all do things that are bad for us, don't we?). And by observing the frequency and types of food, it could quite easily infer that a "good" breakfast to make would be one including toast, a glass of orange juice, and a bowl of cereal. But what if you were only doing that because you were a complete buffoon in the kitchen (like me)? What if you really wanted it to create exotic breakfasts from around the world for you? A new one every day! Well then, maybe we should introduce an element of randomness into this machine. Perhaps, every so often, it rolls the dice and picks a meal you haven't had before, no matter what it's observed. As a further refinement, maybe we'll let you vote after each meal whether you liked it or not, and the machine can keep a record of these and infer better random choices for future breakfasts from the data it collects... well, this is going to totally piss off the guy who just wants the machine to make him some damned toast and orange juice and cereal! It's the 21st century! Come on! This isn't too much to ask, is it? (Don't lie... you all know someone like this.)
Hopefully this gives any of you non-programmers a little more insight into how us programmers think (and to the programmers, perhaps it can give some good arguing material when your friends bug you about thinking too much about things – of course you think too much about things... thinking too much about things is your job!). As I've (hopefully) demonstrated above, we can even turn a simple breakfast into a war of algorithms. None of them is "the right way" to go. But each of them might be the best choice depending on your target user. Want to cater to grumpy old men who like their routines? In that case, the first, less complex, algorithm above is the way to go. But for the adventurous connoisseur (aka "the power user"), complexity is ideal because it means they have more switches and buttons to play with in order to tweak it into what they consider the perfect breakfast making machine.
But that's all still terribly high level for us programmers. Not even close to the necessary ones and zeros that are the only things machines will really understand (and even that, of course, is being very loose with the definition of understanding). The choices that keep us programmers awake at night are written in code.
One such typical code-based dilemma is the choice between hardcoding and making generic components. Especially with complex business logic, where it's sometimes arguable as to what constitutes the sinful act of "hardcoding" and what doesn't. After all, the ideal generic component is the computer itself. If everyone could program, we'd only really need one application, and that application would allow us to do absolutely everything given the right commands. So, at least sometimes, the more generic something is, the less user friendly it will be. And yet every programmer I know has at least in one point in their careers, striven towards this ideal generic code that will do anything and everything. It drives managers nuts. It drives us nuts (though it's an intoxicating sort of madness). And eventually, if we stay in the field, we learn to draw often arbitrary lines as to what's going to far and what's just being a lazy hack. Hard core religious folk ain't got nothin' on how heated these ideology debates can be!
Another common decision is between decoupling and duplication of effort, which is actually the thing that came up today at work that prompted this post. Here it gets to be even more fun and more difficult for your friendly neighbourhood programmer, as decoupling and the avoidance of duplication are practically stone tablet material when you're learning your trade. But it's pretty difficult to get both in ideal quantities. More often than not, you have to choose.
And at this point, you're wondering if I'll ever explain the title of this particular post. Well, here it is...
The point I'm trying to make above is that, although programming is often seen as a science where it's possible (if we're just smart enough, damn it!) to make a computer do exactly what it needs to for a particular industry or user, the real world calls on us to be artists (which is not so bad for those of us who like being artists) as well, who sometimes need to make choices they might not even be able to explain, based on time and circumstance. And yes, even very good programmers can feel very stupid trying to explain why they went one direction as opposed to another when suddenly all hell breaks loose and that other direction starts to look like the road to paradise. "Well, yes, with hindsight, that is certainly the way we should have gone! But you see, at the time, well, there were certain objectives and, well no, I can't quite remember what they were, but there was a reason we went this way in the first place, I swear!"
That's where "the confessional" comes in. If I've stolen the term from someone else, please accept my sincere apologies, but among the programmers that I know, I do believe I've at least led the charge in advocating it.
There have been several times in my career that I've faced some agonizing decision where I either wasn't sure which way was the best way to go, but had to pick one, or I simply saw the possibility of negative consequences down the road but knew there was not enough time to cover every possibility. And there were also times where I outright hacked something together because it had taken too long, I had too little understanding to make a proper solution (and no one else to ask), or the coffee wasn't strong enough to de-fuzz my brain that day. There's always a tendency to either be paralyzed by indecision or to make the choice silently and hope no one discovers your secret code-crime.
Avoid this. Write a "confessional". Every decent programming language gives you this beautiful structure called a "comment", which allows you to babble on to your heart's content about how frustrating a problem is or how you know this is an awful thing to do, but you really had no choice! Use it. Get it all out. You don't even have to make the machine understand it. You won't make the program less efficient (compilers usually strip these out, and in non compiled languages, it's easy to write something to do the same thing). And even the odd page-long confessional won't have your fellow programmers snickering behind your back about what a hack you are. Well, maybe. But you shouldn't worry about it.
No matter how long they've been (and I've had some long ones), I haven't once had a fellow programmer bring up one of my "confessionals" as criticism. On the contrary, people have actually said thanks at times, seemingly out of nowhere, long after I've forgotten writing it, because they were chasing down something to do with the problem or considering making some change that I had considered and decided against (but talked about in the "confessional") and by writing down my horrible coding transgressions and why I made them, I saved them from doing bad things they hadn't considered. Other times, I've run into my own "confessional" in trying to explain to a manager why something's the way it is and not quite being able to make a good enough argument. I suddenly hit the "confessional" and say, "Oh yeah, now I remember! It was because..." I really don't think managers care so much whether you make the odd bad decision. I think they're more interested in whether you care about what you're doing. And combining a "confessional" with something you see as a possible code-crime is a good way of showing that you care about what you're doing, even when you can't do it perfectly, for whatever reason.
Caveats. First, if you tend to write more "confessional" than code, you should perhaps consider another career. Just like swearing, a "confessional" is more effective when used sparingly. (I've always gotten a kick out of adults who desperately try to get kids not to swear, usually by admonishing them, with varying degrees of harshness, over it. I think a much better way of attacking this one is to convince them that a word like fuck is way more shocking when it comes out of nowhere... especially after 1694 much more innocent words!). The second thing is that, on longer confessionals, it's considered courteous to stick the odd joke (geeky in-jokes even better!) in there as a sort of "thank you" for someone else taking the time to slog through it all.
With those caveats in place, programmer friends, go forth and write wonderful code! Repent less, confess more, and be merry!