In a Hacker News comment thread about a lawsuit against Bank of America for lying to homeowners about their eligibility for refinancing:
I've dealt with similar institutions before. They have to be seen to be playing by the rules, but they use every possible lie and excuse to wriggle out of their obligations. Here's how to beat them:
- Understand that your relationship is entirely adversarial. Play by the rules, but be an asshole.
- Your adversaries will mostly consider themselves decent people, who are forced into a corrupt role. Use the cognitive dissonance against them.
- Create a cross-referenced paper trail so strong that it is impossible for them to pretend that they don't have every document they need.
- Hound them relentlessly on every promise and every lie.
By the time you're done with them, they won't care about their performance bonus. They'll just want you to leave them alone.
For example, here's how you send them an important package of documents:
- Add cross-referenced meta-data to the package so that, if anything gets "lost", it will be immediately, undeniably obvious.
- Send the package by registered mail.
- After the package has arrived, call them to confirm that they've received it.
- They'll probably "lose" it the first time, so go back to step 1. (Eventually they'll catch on, and stop "losing" things so often.)
- When they confirm receipt, also ask them to confirm what will happen next, and when. If they don't give a date, tell them that you'll call them back every week for progress reports.
- Send them a follow-up letter in which you tell them exactly what you sent them (repeat the meta-data), when they confirmed receipt, what they said they'd do, what you said you'd do, a summary of previous correspondence, and so on.
If you catch them telling lies on the phone, you have a golden opportunity. Ask them whether they'd be willing to confirm their statement in writing. When they say, "Yes." grab a pen and get them to agree an exact wording with you. Send them a copy of the wording, remind them that they agreed to these exact words, and ask them to sign it and send it back to you.
Of course, you won't get your signed statement, but they're not going to admit that they lied to you either, and the cognitive dissonance will make them deeply miserable. Hound them.
Replacing a class with a test double with Rspec
Say you want to write a test that verifies no class methods are called (i.e., a class isn't being used). With Rspec's mocking library, you can easily replace methods with message expectations that verify a method is called, but making sure no methods are called takes a little doing.
What you need is an object that will raise an error if there are any unexpected messages. Rspec's test double will do this by default. Combining this with stub_const to replace the class will allow you to replace the class with a test double:
stub_const("ClassName", double("my test double"))
Now, it will only respond to messages you've defined on the test double (in this example, none), so any use of the class you haven't anticipated will cause the test to fail.
For more examples of replacing a constants with stub_const, read Myron Marston's post Constant Stubbing in RSpec 2.11.
Video for my RailsConf 2013 talk is now available, thanks to Confreaks.
How to send a String as an attachment with the Mailgun API and RestClient
Sometimes at work, I run one-off reports on the server console and generate CSVs. I need an easy way to get the data off the server so I can look at it. Naturally, I decided to email it to myself. We use Mailgun for email, so I looked for a way to email a String as an attachment using RestClient.
Mailgun attachments must be multipart/form-encoded in the POST body. However, RestClient will only encode multipart if the argument responds to
path, like a
File object would.
StringIO but responds to
read but not
path in Ruby 1.9, so it won't work.
Monkey patching to the rescue! Defining a fake
path method on the
StringIO instance will allow sending it as an multipart/form-encoded file field.
my_string = "foobar" string_io = StringIO.new(my_string) def string_io.path "string_io.txt" end RestClient.post(Mailgun::API_ENDPOINT_URL, :from => 'email@example.com', :to => 'firstname.lastname@example.org', :subject => 'hi', :text => 'hi. again.', :attachment => string_io, :multipart => true)
You are responsible for you
I flew back to Minnesota last week for the 2013 Almanzo 100 gravel road race. Maybe it seems stupid to fly across the country for a free bike race, but since I started riding it in 2009, the Almanzo has been one of my favorite things to do. It's hard, really hard. The challenge changes you, and you come out stronger. It's also one of the most beautiful bike rides I've ever been on -- it rolls past farmland and trout streams, under limestone bluffs and up hills, all almost entirely free of traffic. In January, I decided I would travel to Minnesota to test myself again and sent in the necessary post card.
Since my bike is in San Francisco, I looked into borrowing a bike, but decided to ride my 1983 Trek 500 because I wanted to ride a road bike.
I was apprehensive about riding the old Trek because it has downtube shifters and I'd never ridden it more than 10 miles. My friend Ben had it checked out and was told "It wouldn't be my first choice, but it should be fine." He got me a new seat tube, and we put on my SPD pedals and the (nicer) front wheel from his 1980s Trek. I bought another water bottle cage and a frame bag.
The race almost ended for me on the first minor hill 5 miles into the ride. I shifted into a high gear to build up speed on the descent and bore down as I started climbing. Suddenly my legs were spinning freely: the chain broke. I thought I was done, but a fellow rider and total stranger named Andrew stopped to help, and he had a chain tool. He and my friend Garrick helped pop out a link and get me going again.
After that, I stayed in my small front cog to avoid any further problems. I spun out at about 25 mph on the descents but it was a good gearing for cruising on the rolling hills of the Almanzo. I rode conservatively, aware that I was making good time, but might not finish at all. In the end, I finished in about 10:35, my fastest Almanzo yet. Andrew was there at the finish and I was able to thank him again for helping me and allowing me to finish.
The #1 rule of Almanzo is "You are responsible for you". This year, I learned that's true -- but you don't ride alone.
In response to a post about burnout, commenter Isaac Yonemoto, who once dated a neuroscientist -- which totally makes him an expert -- argues that burnout is caused by making large amounts of effort for something that fails.
No. Burnout is caused when you repeatedly make large amounts of sacrifice and or effort into high-risk problems that fail. It's the result of a negative prediction error in the nucleus accumbens. You effectively condition your brain to associate work with failure.
Subconsciously, then eventually, consciously, you wonder if it's worth it. The best way to prevent burnout is to follow up a serious failure with doing small things that you know are going to work. As a biologist, I frequently put in 50-70 and sometimes 100 hour workweeks. The very nature of experimental science (lots of unkowns) means that failure happens. The nature of the culture means that grad students are "groomed" by sticking them on low-probability of success, high reward fishing expeditions (gotta get those nature, science papers) I used to burn out for months after accumulating many many hours of work on high-risk projects. I saw other grad students get it really bad, and burn out for years.
During my first postdoc, I dated a neuroscientist and reprogrammed my work habits. On the heels of the failure of a project where I have spent weeks building up for, I will quickly force myself to do routine molecular biology, or general lab tasks, or a repeat of an experiment that I have gotten to work in the past. These all have an immediate reward. Now I don't burn out anymore, and find it easier to re-attempt very difficult things, with a clearer mindset.
For coders, I would posit that most burnout comes on the heels of failure that is not in the hands of the coder (management decisions, market realities, etc). My suggested remedy would be to reassociate work with success by doing routine things such as debugging or code testing that will restore the act of working with the little "pops" of endorphins.
That is not to say that having a healthy life schedule makes burnout less likely (I think it does; and one should have a healthy lifestyle for its own sake) but I don't think it addresses the main issue.
Speaking at RailsConf 2013: Front-end testing for Skeptics
On Monday, I'll be speaking at RailsConf 2013 in Portland. I'm excited about this because I'll be able to share some of the cool stuff I've learned at Swiftype. Also, I've never gotten a chance to speak at RailsConf before, so that is exciting in itself.
My talk abstract is below. I speak at 2:50 on Monday, April 29. After I give the talk, I will most some material from it. Also, if you're going to be at RailsConf, check out the bike ride I'm organizing.
Front-end Testing for Skeptics
Obama Blend: A blend of Kenyan, Indonesian, and Hawaiian coffee. Amazing.
This is a great story about creative thinking and launching smart phones into orbit:
"It was sort of a whimsical notion," Cockrell says. But it also made sense. Modern satellites are used for communication and navigation, and so are smartphones. And the phones have things that satellites have, too, like accelerometers, gyroscopes and cameras.
How Hipmunk saved me from an agonizing day of travel
The night before we flew home, everything was in order. Our taxi was arranged, our bags were packed, and our bording passes printed. We set our alarm and went to sleep.
The next morning, we calmly wheeled our bags into the airport, ready to go through the security checkpoint. There weren't many people around, but that didn't worry us. My mom lives in State College, Pennsylvania and the airport there is really small. But when the TSA agent checked our boarding passes, there was a problem: we'd arrived an hour late.
The reason for that is another story: my wife had entered the flight details in her phone in Central time, and when we arrived in the Eastern time zone, all her details were shifted up one hour. Check your event time zones, folks!
University Park Airport is not the kind of place where you can just hop on the next flight. It's serviced by only three airlines with a few flights per day. The gate agent was helpful but it took him a long time to find us a new option, and the new itinerary he put us on was terrible. Instead of flying from State College to Philadelphia to Minneapolis, we'd have to fly from State College to Philadelphia to Charlottle to Minneapolis with long lay overs at Philadelphia and Charlottle. We'd be traveling all day.
At this point, I'd like to say I whipped out my phone and showed him a better itinerary on Hipmunk and asked him to book us on that, but I didn't. We took our tickets and sat down to wait for the next flight. In the meanwhile, I looked on Hipmunk to see what it would suggest for a trip to Minneapolis.
I quickly found a flight from State College to Philadelphia to Minneapolis. I was too anxious to try to get the gate agent to re-book us, but resolved to see if we could get our flight changed in Philadelphia.
Once we arrived in Philadelphia, we went to the customer service desk and I showed the itinerary to one of the agents. He was skeptical about why we should be allowed to change flights (In retrospect, the gate agents were much friendlier in State College. I should have just talked to them.). Finally, we convinced him he could change our itinerary because we'd missed our flight and were being rebooked. He went away for a while, then came back out and booked us on the direct flight to Minneapolis. Victory!
Hipmunk saved us from an unnecessary flight to Charlotte and hours of waiting around in airports. The incredible thing about this is that the itinerary was there the entire time, but with the terrible green screen terminal interface, the gate agent working for the airline wasn't able to find it. Whereas, I, just a guy with a web browser on his phone was able to locate a superior alternative. Now that demonstrates the transformative power of user experience.