Articles Feed

Authors

Categories

Walk and Code

by: doug | February 25th, 2010 | 43 comments »

Treadmill 1

The Motivation

A few years ago when we were buying furniture for the first 8th Light office I came across a piece called the WalkStation. It was an adjustable height desk with a treadmill underneath. I had just started to get myself into better physical shape, and thought this would be a unique way to change a sedentary job into an active one. The price tag turned out to be way to high ($4500+).

Fast forward to January 30th, 2010. At ORDCamp, Zach Kaplan, founder of Inventables, gave a presentation about Dr. James Levine and the research he's done creating active computer workstations. It turns out that Dr. Levine is the guy behind the WalkStation that I had seen earlier. Zach had thrown together a treadmill and a laptop desk to try out the concept and was raving about the benefits. It was the motivation that I needed to finally get to building my own treadmill desk.

Acquisition

Using Craigslist, I found a treadmill just blocks from my house. It is a ProForm 830QT. Sears sells this brand, and I think this one retailed for around $900. I paid my neighbor $140 for this one.

My next stop was Ikea. Somewhere in the back of my brain I remembered seeing a desk at Ikea that was adjustable on-the-fly. I went searching, but found nothing that could be adjusted without tools and without unloading the desk first. I had done a bit of a web search earlier for adjustable surfaces, but hadn't come across anything in a reasonable price range. I headed downstairs to the "as-is" section of Ikea and snatched a Gallant table, frame, and T-Leg combo for $60. The legs alone cost that much new. The combo had been a display model and we a little bit dinged up, but the price was right.

Construction

My first concept was to build a free standing table that would sit over the top the treadmill. The table I picked up was wide enough, but the Gallant legs maxed out at around 36" and I knew that wouldn't be enough. I began envisioning ways to make the legs longer.

In the meantime I started to take apart the treadmill. I just started unscrewing and unplugging everything I found until I was left with just the touch-panel unit and circuit board in my hand. There was one cable running through a leg of the treadmill that was pretty obviously the main control cable back down to the motor below. There was also an audio cable, a cable running to the hand-grip heart rate monitor, and an extra heart rate cable leading to nothing. After a look at the manual, I discovered that this cable can be connected to an optional sensor for heart rate chest straps. The whole idea of this setup is to walk slowly and keep the heart rate down, so I just yanked out all the heart rate cables and sensors.

With all of the electronics off of the treadmill, it was back to figuring out how to mount the desk. This treadmill has hand grips on either side. I yanked furiously on these for several minutes trying to pull them off to see what was underneath. After consulting the assembly manual, I saw there was nothing holding them on, so I got out a pry bar and went to town. They eventually gave way and revealed the horizontal supports that were to become the foundation of the table mount.

A 2x4 set across the hand grip post put the work surface at just about the right height, so I drilled a hole through the posts and bolted on the 2x4. The Gallant table frame has lots of mounting holes, so after removing the frame from the desktop, I chose two holes and bolted the frame on top of the 2x4.

Things were looking good, but for the two post that would prevent the table top from being installed. At first I thought that I could cut the uprights off. But my dremel cutting wheel and hack saw were no match for the thick posts. Without the right tools or know-how to deal with metal, I resigned myself to notching out the table top to fit around the posts. This operation was a measure twice, start over, measure twice again kind of affair. But with some care, I was able to cut the notches with a drill and a jigsaw. A quick tip here. When you cut through a laminated surface like most Ikea stuff, masking or packing tape on your cut line will prevent the laminate from chipping.

Amazingly, I had measured and cut the notches right and the table top slid in place and the old holes to the frame lined up nicely.

With the table top mounted, it was time to get control of the treadmill back. First the touch-panel and circuit boards needed to be contained. I didn't want to spend more money on a project box, so I started hacking away at the plastic enclosure that I had disassembled earlier. I was able to cut away everything but a box the just enclosed all the pieces and was even left with two screw holes for mounting. The problem was where to mount it. I wanted the controls accessible, but out of the way most of the time. They couldn't interfere with walking or typing.

I settled on a keyboard tray that would mount underneath the desktop. It could slide under most of the time, and then pull out easily to start and stop the treadmill or change the speed. Ikea has a tray for just under $10, so it was back to Ikea for the Summera Pull-out keyboard shelf. With the touch-panel mounted on the keyboard tray, there was just not quite enough slack in the control line to be able to pull the controls out far enough to see the entire display. I took the cover off on the base of the treadmill to investigate the control cable and see if I could create any slack. I was able to free up enough cable so that the tray could come out far enough, but it came at the cost of the treadmill's incline feature. The cable will bind now because of the re-routing when the incline it pushed up.

Results

So it's been about 3 weeks with the treadmill desk. Here are some of the question I've received: Q: Don't you get tired?
A: Sure, then I sit down for a while.

Q: Isn't it distracting to your work?
A: I'll admit it took a little while to get over the novelty of walking and coding. Once the meta-conversation in my head stopped ("Look at me, I'm on a treadmill, and I'm writing code!") then I think that low level physical activity has actually helped to keep me focused. Walking engages a completely different part of my brain. I compare it to how some people will pace when they are making a decision.

Q: What about pair-programming?
A: Colin and I have been experimenting with pairing on the treadmill. We've integrated it into our normal ping-pong rhythm. The one coding is the one walking. One green-red cycle, and then we switch. It's a little bit hard to stand and look over the walkers shoulder, so we've been using a second laptop sharing the screen of the first. With both laptops on the same network, the point-to-point screen sharing is pretty responsive. We've had the best luck with Skype. A second screen also allows the pair to sit for a while. I'm still imagining how two treadmills could come together for a fully-walking pair station.

Q: How fast do you walk?
A: 1 MPH for the most part. We've done okay at 1.3 - 1.5 too. I can stay pretty stable even up to 2.0, but I start to get overheated at that speed.

Q: What effect has it had on you?
A: My knee hurts a bit after being on all day. Colin and I have both noticed that we get hungry sooner when walking. I think that mean that our metabolisms are running faster. So I make sure to eat a good breakfast everyday, and we are really ready for lunch at noon now.

References:

Dr. James Levine talk about treadmill desks
The Mayo Clinic's Non-Exercise Activity Thermogenesis Lab
Jay Buster's Treadmill Desk
Treadmill Sensei - Good reviews and info and treadmills

Photos

From the Side:
Treadmill 2

The touch panel mounted beneath the work surface:
Treadmill 3

From the Front:
Treadmill 4

Underneath / Mounting detail:
Treadmill 5

Update 2/28/2010: Here is some video footage.

Stubbing :new Considered Harmful

by: eric | February 8th, 2010 | 1 comments »

Hi my name is Eric, and I have made a mess.

There I said it. I’m not proud of it, but I believe a couple very loosely related things:

It is in the process of cleaning up the mess that I’ve been trying to evaluate the messy code in the first place. How is the code messy? Was it Test-Driven? It was - or at least it attempted to be (we’ll get back to that). Was I lazy? Certainly not. Am I stupid? Crap I hope not. So how did we end up in this mess?

What’s the mess nimrod?

Recently Justin, our latest apprentice, wrote about attending a code review here. The feature he is referring to is part of one of our best client’s systems, where we integrated with several webservices, making them look seamless in our application. This was an extremely difficult problem, and our code bent in a dozen painful ways for a solution, and has since become rigid. Changes have stopped being done in the nice Test-Code-Refactor mode, and instead are being done by trying a change, trying the product, then backing out the change and making the test pass. While we identified several ways to improve the code, such as better naming and adding a facade between some of our interfaces, one stated goal was to “make the tests readable.” See the problem isn’t that it’s not tested - it’s that you can’t follow the tests at all. Let’s look at an example, modified to protect the guilty:

  1. it "should call a webservice when its complete" do
  2. @caller.should_receive(:call_webservice)
  3. typedObj = mock("Obj", :no_follow_ups? => false, :null_object => true)
  4. ProprietaryObject.stub!(:create_typed_obj).and_return(typedObj)
  5. @page.stub!(:widget_id).and_return(@widget.id)
  6. @page.stub!(:previous_page_id).and_return(nil)
  7. @product.page_cache = [@page]
  8. @widget.follow_ups({}, {:application_id => "123", :group => "group"})
  9. end

This probably isn’t the worst example - if you look closely you can see that we’re testing that call_webservice needs to get called when ‘its complete.’ But what complete? I don’t see a stubbed object that returns complete. Also I have no idea what @page, @widget, @product or :createtypedobj are doing here. When I want to write the next test I have to guess at intent, and start playing with variables. What this is trying to test is that a webservice caller object receives call_webservice when the widget (an object on the screen) is called with certain variables. I’d tell you what those variables are, but I truly don’t know.

It doesn’t get better. Let’s look at where some of those variables are coming from. These are excerpts from a setup method that is too long.*

  1. Context.stub!(:find_by_widget_and_application_form).and_return(@context)
  2. Page.stub!(:new).and_return(@page)
  3. ...
  4. @caller = mock('caller', :call_webservice => nil)
  5. WebserviceCaller.stub!(:new).and_return(@caller)
  6. ...
  7. @page_factory = mock_model(PageFactory, :acquire => @page)
  8. PageFactory.stub!(:new).and_return(@page_factory)

So by my count we’ve stubbed new three times, two finders, and an acquire all of which inject yet another dependency into the code. Thus the premise of the article stubbing new considered harmful.

Is it really harmful?

Dependencies in static languages are generally more onerous than what we’ve got here, sometimes extremely painful although usually it can be accomplished with simple setters and constructors. In Ruby this isn’t the case - you can just stub new and create the object the way the user intended, thereby continuing to test. This can be a VERY BAD THING because it’s a moment where you need to pause. Do you need this dependency? Should you be wrapping dependencies? Do you need a facade or wrapper object for a couple dependencies? The difficulty of DI in other languages enforces that pause, but Ruby does not. It lets you stub anything, only to one day wonder why you have such a mess on your hands.

It’s important to remember that Dependency Inversion existed before Unit Testing, and isn’t just a Unit Testing technique. Indeed we often sell TDD as a way to make you have better designs, and yet here it failed me because I can so simply call new and continue testing. This is a mistake. To paraphrase Jurassic Park, just because you can easily stub new doesn’t mean you should. Would you create a constructor that took five objects? Then why would you stub :new (or finders, or factory methods) five times. Would you pass in an object to the constructor that’s only used in one method? No - that’s not cohesive. By stubbing :new you can slowly, and easily, introduce dependency after dependency creating an indecipherable mess despite writing tests. Worse you can do this easily, without suffering the traditional pain of tightly coupled code. It’s only later that you’ll feel the awful, horrible, indescribable pain. Trust me it’s bad.

Am I really advocating stopping stubbing :new? No not really. It makes perfect since to just call :new when you can, and in many cases factories are a way to get around the limitations of a static language. What I am saying is that each time you do stub!(:new) THINK! You have a dependency to manage, so manage it. It’s your job you know.

*This is also a smell. Allow me to quote “The Art of Unit Testing”, an excellent book on Unit Testing by Roy Osherove

Don’t use [SetUp] and [TearDown] to initialize or destroy objects that aren’t shared throughout the test class in all the tests, because it makes the tests less understandable. Someone reading your code won’t know which tests use the logic inside the setup method and which don’t.

##