b.kocik

what I should have said was nothing

About

Sometimes I write things here. Even when I shouldn't.

Stupid caching tricks #804

June 29th, 2009

Suppose you have a number of endpoints in your app, such as /user/private_data and /user/secret_stuff, where logged-in users see information that’s only meant for them. Suppose further that you have a number of other endpoints like /user/1/quotes and /user/1/book_collection that are accessible by all users of the app, logged-in or otherwise. You want to cache the responses to all of these endpoints, but you have to be careful not to serve one user some other user’s cached private data. You also don’t want to do all of your caching in each controller action, because there are a lot of them, and we like our applications to be DRY.

Going a step further, wouldn’t it be nice to support Etags so that if the document is in the cache, we can consider it unmodified and just return an HTTP 304 (Not Modified) instead of a full response? Even if it is a memcache response, it’ll be even faster to not pull it out of memcache and spend the bandwidth returning it when we can just tell the browser “It’s the same as it was the last time you saw it”.

My approach, inspired by Michael Koziarski:

  around_filter :cache_for_user, :only => [:private_data, :secret_stuff]
  around_filter :cache_public, :only => [:quotes, :book_collection]

  # Cache something that's specfic to a logged-in user
  def cache_for_user
    cache_response(request.request_uri, @user.auth_token) { yield }
  end

  # Cache something for the general public
  def cache_public
    cache_response(request.request_uri) { yield }
  end

  private
  # Cache a response, using the passed-in values to create
  # the key.
  def cache_response(*keys)

    # If it's still in the cache, return a 304.
    # NEVER let a user retrieve something by Etag!!!
    if etag = request.env['HTTP_IF_NONE_MATCH']
      if CACHE.exists?(etag)
        headers["X-Cache"] = "HTTP"
        head :not_modified
        return
      end
    end

    # Set the etag for next time.
    response.headers["ETag"] = etag

    # Check memcache
    key = keys * ':'
    etag = MD5.hexdigest(key)
    if data = CACHE.get(etag)
      # render from the cached values
      headers["Content-Type"] = data[:content_type]
      headers["X-Cache"] = "HIT"
      render :text=>data[:content], :status=>data[:status]
    else
      # Yield, note the cache miss, then cache the response
      headers["X-Cache"] = "MISS"
      yield
      CACHE.set(etag, {:content=>response.body, :status=>headers["Status"].to_i, :content_type=> (response.content_type || "text/html")})
    end
  end

Note the stern warning on line 20. Although we’re using Etags as keys into our memcache store, don’t ever retrieve something from memcache that you looked up by an Etag header in an HTTP request. This would allow users to retrieve one another’s data by learning the Etags used to validate it. Only use the Etag in the request to see if the document is in the cache, and return a 304 if it is. Our generated Etags, however, are specific to the logged-in user, and should be safe so long as your security model is sound in general.

You might also have spotted an unfamiliar method - on line 20 I’m calling exists? on a MemCached object from the memcache-client Ruby gem. But out of the box, that class defines no such method. I put this in my memcached initializer (the same one that creates the CACHE constant in the first place):

# Attempt to add an object at the given key.
# Just the number 0, expiring in the past, (-1),
# and without marshaling (false). Memcached
# returns "NOT_STORED" if there's already
# something in that slot.
class MemCache
  def exists?(key)
    CACHE.add(key, 0, -1, false) =~ /NOT_STORED/
  end
end

Credit goes to David McCormick for that idea.

I’ve recently seen folks asking questions about how to do acceptance testing with Cucumber on an application that authenticates using Twitter’s OAuth service. Since I’ve recently done exactly that, I thought I’d share my technique with the world. I’ll walk you through it step-by-step here, from creating a new Rails app all the way to the bitter end, but if you’re impatient and just want to see the code you can download the example app here. I would encourage you to take a walk through this tutorial, though, because the example app isn’t entirely self-explanatory.

Credit where credit is due: I shamelessly stole the ideas of creating the methods “stub_get”, “stub_post” and friends, as well that of as storing API responses in fixture files, from John Nunemaker’s tests for his excellent Twitter gem,  which my application uses.

This example app also uses that gem, but because I’m essentially stubbing the Twitter API itself, they should work with whatever you’re using to talk to Twitter (so long as it understands Twitter’s JSON responses).

Finally, I’m aware that my blog’s layout isn’t really friendly to code files, and it tends to smush them. If the code below looks strange (and some of it will, I promise) hit the “view plain” button found at the top of each code box to get a better look at it. Sorry about that.

Let’s start by creating a new Rails project to play with:

Read the rest of this entry »

Top 5 Covers

November 2nd, 2008

The other day I complained on Twitter about the cover of David Bowie’s “Space Oddity” that Lincoln is using in their commercials for the MKS. This elicited a response from a friend of mine whom I’m guessing is a fan of Chan Marshall - who for some reason calls herself “Cat Power” on stage, and is responsible for the aforementioned abominable cover - coming to her defense. He included the question, “Besides, since when are covers ever good?”

The truth there is that there are many, many examples of very well-done covers in the music world. I listed off a handful of them for him. Since then I’ve been thinking about which are the truly great covers in the history of music, and decided to come up with a list of what I consider to be the 5 best covers (in the spirit of the John Cusack/Jack Black movie “Hi-Fidelity”). These are only from the ones I’m currently able to recall off the top of my head, and is with a couple of exceptions really more a list of my favorites than what might be called “great”. No doubt later on I’ll think of 10 more that should have made my list (I really wanted to include Alien Ant Farm’s cover of Michael Jackson’s “Smooth Criminal”, Johnny Cash’s cover of Nine Inch Nails’ “Hurt”, and Dynamite Hack’s cover of Eazy-E’s “Boyz-n-the-Hood”). Right now, though, my 5 are these:

  • 5. Pearl Jam, Love Reign O’er Me (The Who)
  • 4. Garbage, Wild Horses (The Rolling Stones)
  • 3. The Lemonheads, Mrs. Robinson (Simon and Garfunkel)
  • 2. Jimmy Cliff, I Can See Clearly Now (Johnny Nash)
  • 1. Jimi Hendrix, All Along The Watchtower (Bob Dylan)

Raise your hand if you didn’t know my #1 cover even was a cover until just now. It was born of the genius of Bob Dylan, who wrote it and recorded it in 1967. But Jimi made it famous by recording his unforgettable version of it in 1968.

What are your 5?

Finally Leaving AOL

September 16th, 2008

Some of you might be confused by the title of this post, since I haven’t worked at AOL since October of 2007. But even though I don’t work there anymore, I haven’t really left. I went from AOL to Mixx, largely because it was an opportunity to continue working with some of my favorite AOLers (Joe Dzikiewicz, Kerry Parkins, Jason Garber, Nathaniel Collinsworth, Mike Golay and Kori Hill - neither of whom I knew at AOL, but am glad I know now - and Will Kern, who joined us later). Although I no longer spend my days on the AOL campus in Dulles, coming to Mixx wasn’t like leaving AOL at all. It was like moving to a smaller part of the company which happened to be located off-campus.

But now I am leaving AOL. For the first time since April of 2001 I’m taking a new job where I don’t already know everyone, and importantly, everyone doesn’t already know me. I’m nervous about having to get used to a whole new group of folks and a whole new environment. At the same time I’m looking forward to being in a place where people have no preconceived notions about who or what I am. It’s an opportunity to start anew.

For the curious, I’ll be joining the team at CustomInk.com. CustomInk has been around for more than 8 years, and has a reputation for being fanatical about customer service, as well as being an outstanding place to work. They are consistently found on “best places to work” and “fastest growing companies” lists in these parts, and I’m excited about joining them. They’re also located right down the street from Mixx, so I’ll still be in the neighborhood. I may finally be moving out of the house, but I’m not going across the country just yet.

Onward and upward.

I’ve been using the word “no” an awful lot lately. For some reason over the past few months there’s been a lot of interest shown in my resume (which apparently is out there somewhere, though I don’t remember where) and my LinkedIn profile. I get all sorts of random emails, LinkedIn messages, and even phone calls from recruiters. My favorites are the ones who call me to ask if it’s okay to email me a job description. You know what? Take a chance, skip the phone call. I’d much rather deal with an unwanted email.

Most of them get a very quick “no” out of me. Like, for example, Google. I got an email from a Google recruiter a while back, something along the lines of “We have some great opportunities here at Google, and I just wanted to see if you have any interest!”

He actually used an exclamation point, as if as soon as I saw the words “Google” and “opportunities” used in the same sentence I would nearly wet myself with excitement. Finally, the great GOOG is calling on me, after all these years of quiet desparation and yearning! My actual response was, and I quote, “No, thanks.” Google has a reputation for not paying very well, and for having something of an elitist, hipper-than-thou culture that I want no part of. I can’t imagine the shock this recruiter experienced when he discovered–probably for the first time–that everyone isn’t dying to go to work there.

Another didn’t survive past the first question. “How much experience do you have writing web apps in Perl?” “None. I know better.” Where on my resume does it say I have ever written a web application in Perl? I think the very act of being willing to admit I ever had would show a significant lack of judgment that would turn any potential suitor away.

A few recruiters get a little further with me than that. But almost inevitably, they (or the company they represent) find some creative way to lose my interest shortly thereafter. Like the company I won’t name that hounded me more than a year ago. I had occasion to be in the same room with one of their employees on a semi-regular basis, and every time I did he would try to get me to talk to one of their recruiters. Finally I caved, and a technical interview was set up. Fair warning to all recruiters: I’m a terribly lazy person (it’s part of why I write software), and if I’m really not interested in your position I am going to half-ass your interview. Just so you know.

Oh, and if you set me up with someone who has no business conducting interviews I am not going to rise to the occasion and shine like a pro, I’m going to toy with him. That’s what this company did. Within two minutes of the start of the interview I could tell the interviewer had no idea what he was doing. He’d ask me questions like, “So, do you know how to use threads?” and I would respond with informative, thorough, clearly thought-out responses like, “Yes.” About ten minutes into the thing I was about to terminate the interview myself (which I will do–and have done–if I get bored enough), when he beat me to the punch. Later I got a phone call from the recruiter telling me, “Yeah, we’re looking for someone with some stronger Java skills.”

I replied, “Given who you have now, I would be, too.”

I have walked out of interviews, like I did when an interviewer asked me to come up with an algorithm to solve a sudoku board. With a marker. On a whiteboard. Seriously. In that case I was already squarely on the fence about the position anyways for other reasons (if you’re trying to woo a potential employee, try not telling them that you’re not sure if you have a sustainable business, or if you yourself will even be sticking around), and that question shoved me right off of it on the side of “I’m going home now.” They had even paid for plane fare to get me there, which I sort of felt guilty about.

That last mistake was actually a pretty common one, it turns out, and at its core it is this: Do not ask me to jump through hoops until you’ve given me really good reason to want to jump through them. That sounds snobby, but I honestly get anywhere from five to nine random inquiries per week from different recruiters. If you’re one of them, you need to remember that I’m not looking for you, you were apparently looking for me. If you give me the slightest reason to turn you down I’m going to do it, because there’s a whole line of recruiters right behind you and I have to weed through you somehow. One of the surest ways to get me to terminate the process is to make the mistake of thinking that I need (or want) a job, and am therefore motivated to go through a bunch of process to get to an interview. I’m not, and I won’t.

I don’t really like to interview to begin with, so if you happen to get me to agree to an interview, for heaven’s sake do NOT blow it by sending me a job application with instructions to “make sure I fill it out before the interview.” I’m not going to. You know what I will take the time to do, though? Compose a short email cancelling the interview, and making it clear that I will not be seeking to reschedule it. (Don’t believe me? I did exactly that not two hours ago. I’ll give you the recruiter’s contact information if you want to verify.)

It’s not that I’m a prima donna, nor do I have illusions of grandeur concerning my worth as an engineer. Please. I know my station. But since you came to me, it’s really sort of unrealistic (maybe even rude) to expect me to do a bunch of leg work in order to talk to you when I really didn’t ask to in the first place. And besides, a job application? Really? What is this, Arby’s? Sometimes I’m tempted to fill them out with a bunch of fictitious babysitting and fast-food jobs. Reason for leaving: Mom said if my grades didn’t improve I couldn’t work school nights anymore.

I have a carefully-constructed resume and an even more carefully-constructed 11-year track record in the industry. Don’t ask me to write out my employment history in long hand, outlining my “responsibilities” for a 6.5-year position in a tiny little box. It’s just not going to happen.

I found out recently that people actually do read this blog (which made me briefly consider taking it down and letting the domain expire). I don’t know how many of them are recruiters (though some of them have told me this is how they found me; why on earth anyone would read my drivel and still want to contact me afterward is a profound mystery). But if you’re a recruiter and you see yourself or your company reflected in this post, do me a big favor: Don’t call me. I’d appreciate it.

Monsters are real

June 24th, 2008

On July 23, 2007, two career criminals broke into the home of a prominent Connecticut doctor, intent on robbing it. When they entered, they discovered the family was at home - the doctor, his wife, and their two daughters, 11 and 17. They beat the doctor. They tied the 11-year-old girl to her bed, and raped her. They raped and strangled the wife. Then they poured gasoline on their victims, and set the house on fire with three people still alive inside. The doctor is the only survivor.1

On December 18, 2005, a 37-year-old woman who was mother to three children answered her door, and was greeted by a man who claimed he was having car trouble, and needed to use her phone. She was later found shot and hanged to death in the basement of her home, near Culpeper, VA.

On New Year’s Day, 2006, a family of four were found beaten, stabbed, and bound in the basement of their house in Richmond, VA. The two daughters were 9 and 4 years of age. None of them survived. One of the two men who slaughtered them was the same man who had killed the woman near Culpeper. The pair went on to kill another family of three only five days later.2

Monsters are real.

I tell you this because, of late, I’ve been hearing from a lot of people who seem genuinely puzzled as to why I feel the need to own a gun. Some have made me the subject of jokes about “violent tendencies” (which I do not have, and as a matter of fact, those of you who do not possess concealed carry permits are statistically 5.5 times more likely to be arrested for a violent crime than those of us who do3). Some have even gone so far as to pay me the insult of questioning my intelligence, my background, and my mental competence. Since so many of you have been so forthright in sharing your opinions about my choice to keep a firearm, I’m going to be very blunt about one of my own:

I am completely dumbfounded that any of you seem to have to have this explained to you. I am shocked that so many of you who are otherwise sharp, intelligent, reasonable people have been so snowed by the anti-gun crowd that you appear to actually believe their myths, when the truth is so easily discovered. I am honestly disconcerted to have found that several of you are so naive as to believe that in this day and age, no one needs to possess or conceal such a weapon.

Following are some of the fallacies I have heard put forth by some that honestly causes me to question their own intelligence and mental competence.
Read the rest of this entry »

As many of you know (because I have no internal filter), I was recently in talks with Yahoo, who were talking about relocating me to California to go to work for them. The title of this post refers to an interview question they asked me, which was, “Can you think of an efficient algorithm to detect the first repeated character in this string?” My answer was, essentially, not really. I’ve made my career writing web applications in Java, Ruby on Rails, and even occasionally PHP (I’m not proud). I’ve never had to find an efficient way to detect the first repeated character in an arbitrary string, except maybe in some college class I no longer remember. If it ever comes up, then I’ll know that Yahoo was wise to try to make sure I could do it, and I’ll turn in my developer’s cap and take up carpentry or something. At least until someone asks me if I can dream up a clever way to build bookcases using only a pipe wrench and toothpaste, and exposes me for the non-carpenter that I am.

But that I couldn’t satisfactorily answer that question is not why I don’t work for Yahoo (and I don’t really begrudge them asking such algorithmic questions, even if I think they’re mostly contrived and silly). In fact, almost all of my interviews could not have gone better than they did. There was one at the end of the day that completely derailed, but it was actually unimportant (long story). My first interview, which was with the lead architect of the group, ended with her saying “Well, I like you. I’m gonna tell them to hire you.” Much of the rest of them went about as well.
Read the rest of this entry »

I recently learned that people in Virginia - that’s people in general, certainly not every one of them - have a keen distaste for the state of Maryland and its contents. I don’t know why this is, much as I cannot explain to you why people from Michigan look south to Ohio with disdain, even though I myself hail from Michigan. In Ann Arbor, directions to Toledo are typically given as “South until you smell it, then east until you step in it.”

What I find more amusing, though, is the animosity between Virginia and West Virginia. I hear a lot about this, given that I have now lived in West Virginia and worked in Virginia for years. When Virginians hear that I live in West Virginia, they often have all manner of hilarious comments for me. I’m sometimes asked if I have a “yard car” or not (I don’t). Once, on a business conference call (yes, really) a woman who shall remain nameless (though who I’ll tell you I secretly referred to as “Scout Finch”, because that’s who she reminded me of) took a shot at West Virginia. I told her, as I’ve told others, “Being from the north, the thing I don’t understand is why you Virginians act like there’s some sort of a difference.” Clearly, this touched a nerve, because she shot back with some hostility, “There is a difference - we don’t chase our brothers and sisters around.” In a fit of quick thinking the likes of which I have experienced neither before nor since that moment, I replied “That’s only because they don’t run.”

She didn’t even try to recover. Someone tried to come to her aid with some dumb comment about ice fishing in Michigan that sort of fell flat, the awkward silence passed, and the world moved on.

You see, the thing is, I really work in Northern Virginia, most of the inhabitants of which it would seem consider themselves a completely separate state from not only West Virginia (which they are), but also from the rest of Virginia (which, of course, they are not). You will almost never hear anyone from Northern Virginia say they live in Virginia; they almost invariably will tell you they’re from Northern Virginia. But I remember in 5th grade having to learn all the states in alphabetical order - you know, for that song? - and I’m pretty certain there’s no Northern Virginia anywhere on it. Just plain old Virginia. In fact, there’s no Northern anything on the list. It goes straight from North Dakota to Ohio, with no stops in between.

When I think about Northern Virginia’s identity crisis, I’m both saddened and amused. Northern Virginia is like the south’s very own Quebec. If you’re not familiar, Quebec is the province of Canada where everyone speaks French, acts French, thinks of themselves as French, and looks down upon the rest of the country for not being as French as they are. As far as Quebec is concerned, they’re more French than they are Canadian. What they don’t seem to grasp, though, is that France doesn’t claim them. France will happily tell them they are, in fact, a bunch of Canadians in denial. Similarly, Northern Virginians seem to fancy themselves part of the north (hence the Northern).

Sadly, as a genuine, bona fide, dyed-in-the-wool, has-forgotten-more-about-being-cold-than-Northern-Virginians-will-ever-know northerner, I’m afraid I have some bad news. If you’re reading this and you’re from Northern Virgina, first, sorry for all the multi-syllabic words and complex sentence structures, and second: You’re southern. No, really. I know news like this is hard for you to hear, but you had to hear it. You are southern. The north does not claim you. Never has, never will. Our collective advice to you is to embrace your southern brethren before it’s too late and they refuse to take you back. You don’t want to be a land-locked island nation all on your own, do you? Probably not. You’ve got a pretty nice place here, actually. It would be a shame to see it wind up that way.

Besides, the only thing worse than a southern redneck is a southern redneck disguised in a 3-series BMW or Mercedes C-class. So embrace your southernness. Do what comes natural, whether it be buying a pickup truck with huge wheels and CB antennae tall enough to hit traffic lights as you pass beneath them, or wearing one of those tight tank-top style undershirts (commonly referred to as a “wife beater”) while you peruse the aisles of Wal-Mart in search of such trendy home decor items as Billy Bass, the singing fish. Go ahead, drink Budweiser from the can, I know you want to. Free yourselves from these senseless charades!

I mentioned that in addition to being saddened by the plight of the indigenous peoples of Northern Virginia, I’m also amused. It’s because - and it took me a while to realize this - their shots at West Virginia (which, by the way, is a real state separate from the rest of Virginia (lucky them); I looked it up) are really just self-deprecating humor. It used to bother me a little when Northern Virginians waxed disparagingly about the state I now live in (even though it’s not my home), but not now that I’ve realized they’re just lashing out at what they see in themselves like chickens attacking a mirror. Whenever a Northern Virginian asks me if I have a yard car yet, I know it’s because he secretly yearns for one of his own, and wishes to live vicariously through me. I also now realize this is why Scout Finch so vehemently reacted to my gentle suggestion that, from the viewpoint of real northerners, there’s not much difference between the hillbillies from West Virginia and the hillbillies from Virginia (nor those from Northern Virginia, since we’re on the subject).

I wonder if it was a brother or a sister she’d have chased after, if only they’d had the decency to run.

Sometimes you run across someone so profoundly dumb you do a mental double-take before realizing that, yes, they really did just do something that stupid.

Case in point: Today I was browsing around doing a little research on a Bluetooth headset I’ve had my eye on when I stumbled across a site belonging to a company called Bluetooth Imports. Like so many online retailers, Bluetooth Imports purports to bring you and me “the best products at the lowest prices possible”. I love a good deal as much as anyone, so I thought I’d check their price on the particular device I’m interested in.

According to their site, they do offer a pretty good deal on the Aliph Jawbone I’m pondering. According to their site, they’ve knocked $30 off the regular price of $169.95, and will part with it for a paltry $139.95.

That is, according to their site. And I say “according to their site” because according to reality, that unit retails for $119.99, and can be had for significantly less than that all over the web.

Also according to their site, they offer the $169.99 Plantronics Discovery 665 for a mere $149.95. What a bargain! Except . . . the Discovery 665 is not regularly $169.99, it’s $149.95 at full retail, and can also be found for a lot less than that at dozens of sites around the web. Puzzled why a site that boasts “the lowest prices possible” would be so ridiculously overpriced, I wrote them a note. Unfortunately I used their web form to send the note, so I don’t have what I sent to them verbatim, but I recall pointing out these pricing disrepancies and asking the question, “Why are online sites that say they offer the lowest prices always the most expensive?”

They had an answer. They wrote me back, using a subject line of “Becuase” (their spelling, not mine), and this pubic relations pearl as the entire body of the message - save for their boiler-plate signature:

“We are online stores trying to make money please get over it and choose the cheapest.”

There you have it, folks. If you’re an online store trying to make money, it’s okay to mislead the public into thinking you’re giving them a discounted price on merchandise you’re actually charging full retail - or more - for. Bluetooth Imports said so. The thing that I love most about this response is that, essentially I asked them why they are among the most expensive merchandisers on the web for the products they’re selling, and they actually provided a reason. They didn’t refute it, they explained it. Oh, sure, they explained it with all the tact and language skills of a 7th grade drop-out, but the point is they explained it. They agree that they are amongst the most expensive out there; they have a reason for being so.

Yes, they really did just do something that stupid.

8 Things

September 6th, 2007

I’ve been tagged. I’m supposed to tell you (in case there is a you) eight things you (probably) don’t know about me.

  1. I first attended college at the ripe old age of 12. I thought I was 14, but last Christmas the topic came up and my parents convinced me I was 12 (and of course they’re right; it was 1987).
  2. I can sing.
  3. I used to be a locksmith.
  4. I grew up in a house on a lake in Michigan. I’ve forgotten more about being cold than many of you will ever know, I believe that hockey is a religion, not a sport, and every once in a while you can still catch my accent (I’m told it sounds vaguely Canadian).
  5. I am very mechanically inclined, and can fix all kinds of stuff.
  6. I can do a killer Arlo Guthrie impression. I didn’t know this about myself until today.
  7. I am staunchly opposed to capital punishment. If you want to know why, ask me.
  8. I have been with my wife since we were teenagers. We both turned 32 this year (her 3.5 months more recently than I).

I’m supposed to tag 8 people, but I only know so many people with personal blogs, and some of them are already tagged. So I’m tagging Alan, Kevin, Jason, Randy, and Will. I have no idea how I’m supposed to alert them.