Tim Harvey :: Blog

Icon

I help organizations who feel stuck

Take your workspace seriously

I’ve always been fascinated with creating a proper and efficient working environment. I’ve taken a fair bit of inspiration from the terrific writeup and gallery put together by Mitch Haile on his setup. Key takeaways:

  • Have separate coding and administrative areas
  • For coding, screen real estate is king
  • Bush Series C office furniture rocks
  • Ergotron makes fantastic monitor/laptop mounts
  • I’m not a freak for owning/buying tons of books (in paper form, either)

BookshelfDuring my 5-year stint at a local cabinet shop, I had enjoyed the opportunity to design and install two completely different office setups; one standing-height workstation and the other a traditional L. When I started Literacy5 a year and a half ago, I went through a variety of setups before I settled on something I really liked (some through necessity, and others out of a need to experiment).

Separate coding and administrative spaces

Original layoutOne of the most valuable lessons from reading Mitch’s office FAQ was the way he created different spaces for his coding and administrative/non-computer work. In my original office layout, I used the corner section to setup my Mac Pro and three 22″ screens. The large bowed section functioned as my admin area. This worked REALLY well. My computer workstation area stayed immaculately organized while the admin area was always strewn with papers. That gave me the ability to keep extremely focused on the work at hand while coding, with zero distractions. When working on the business side of things, I could multi-task and juggle whatever I needed. My Macbook accompanied my to the admin area whenever I did my bookkeeping.

I eventually swapped the admin/computer spaces to support pair programming. Two of us could easily sit side-by-side at the large bow-shaped desk and each have our laptops out. While I didn’t use it that way very often, it worked out great!

SquaremouthAt Squaremouth, I keep my desk space as sparse as possible, still maintaining as much screen real estate as possible. As an aside, the Kinesis Advantage Pro has made a huge difference in the trouble I was having with my wrists. It’s a topic for another post, but switching to Dvorak at the same time worked out nicely.

I really like having the two Dell 2209WA monitors on their side…it’s perfect for terminal windows, chat sessions, and Basecamp. The Macbook Pro runs the monitor on the left with the iMac 27″ handling the one on the right. With a little creative SSH action, the left 22″ can tail the Rails logs and it feels like you have three screens natively on the iMac.

New layoutNow that I’m at Squaremouth, my home office needs have changed dramatically. We are selling our 6,000 sq/ft home/office and will share office space with our friends John and Betsy at a converted warehouse. The office will primarily support managing our home, helping out with the non-profit we do accounting for, and my side projects. I may not even keep a computer there full-time, instead relying on my Macbook Pro. The new layout will still have two separate workspaces, but they will likely be split between my wife and I. I may even setup a dedicated podcast/screencast recording area so that I can leave my mic setup and ready to go.

Get a decent chair, please

One of the lessons I learned early was that a crappy chair can ruin your productivity (not to mention your back) by the end of the day. I’m a young guy, so I don’t care to complain about my back for at least another 20-30 years. The office I worked in before starting Literacy5 spent the bare minimum on chairs, so I’ve sat in some doozies. I never thought much of it since I was doing primarily IT support work with some programming sprinkled in. At most, I might be seated for 2 hours at a time with frequent breaks.

After a few more people were added to my staff, I spent considerably more time at my desk managing projects, coding, and handling server support. By this time, I was sitting in my chair for 7+ hours each day with only the occasional break. I realized just how important a decent chair (and having the sense to get up regularly to stretch) was.

So after launching out on my own, one of my major goals was to make sure that I got some decent seating. Like any new business, I didn’t have the stability to drop $1k on a chair right away, so I opted for a standing height work area…no chair needed! I build the desk myself and it worked great for quite some time. About six months in, I found that I was doing fewer meetings to attract new clients and had a lot more long stretches at my desk coding. While I really love a standing desk, I found that I couldn’t be comfortable more than 5-6 hours a day.

When I built a new office, I finally had the client work to justify a decent chair. I got a terrific deal on a top of the line Herman Miller Mirra through eBay, spending about $500. The Mirra is the follow on to the tremendous Aeron (I’ve tried both and prefer the Mirra). That has been the best $500 I ever spent. I’m sitting in it now and a year later it looks new, works perfect and still gives me 9-10 hours a day in perfect comfort.

RVM installation of Ruby Enterprise Edition on Ubuntu Hardy

I decided to try out Rackspace Cloud for a new worker server that Am I Down needed. Since I wanted to keep the system tight on memory usage, I decided to go with Ruby Enterprise Edition. Unfortunately, I ran into a snag getting it installed via RVM (the terrific tool for running multiple versions of Ruby).

I kept getting this error after running “rvm install ree”:

Error running './installer -a /home/username/.rvm/rubies/ree-1.8.7-2010.01  --dont-install-useful-gems ', please check /home/username/.rvm/log/ree-1.8.7-2010.01/install*.log
There has been an error while trying to run the ree installer. Aborting the installation.

I couldn’t find anything on how to fix this as I poked around Google. Since I use zsh (via the amazing Oh My Zsh project), I figured that had to be conflicting with it. I did resolve one issue caused by the old version of zsh installed via “sudo aptitude install zsh” by compiling zsh from source (a newer version).

The Solution: Install Readline headers

But…back to the issue at hand. The solution became clear when I tried to install REE from source. The REE installer complained about missing “GNU Readline development headers”. Running the installation for readline fixed it.

sudo aptitude install libreadline5-dev

From there, RVM installed REE no problem.

Update (3/5/2010): Wayne, the author of RVM kindly wrote to me on Twitter within hours of this post to see if there was some working improperly with RVM. It turns out that I missed a clear set of instructions that indicated the need to install readline5 when using REE. Thanks Wayne!

And now for something completely different

I’ve had the pleasure of spending the last several months working with Squaremouth, the fastest growing travel insurance company in America. They quickly showed themselves to be an ideal client, standing at the intersection of work that I relish and people I enjoy collaborating with. I find myself jumping out of bed each morning, itching to head in to their office and get started on the day.

I’m going all in

Squaremouth Logo 180 I’m pleased to announce that I have accepted a permanent position with the Squaremouth team.

During a trip to the Florida office last week, the owners asked me to consider putting my consulting business aside to partner in their audacious vision for Squaremouth. They really got my attention by asking (even insisting) that in addition to my web coding skills, I offer my business knowledge earned across the last dozen years starting new companies and helping others run theirs.

They had my number

By offering an opportunity to shape both the technology and strategic direction, they had me. My entrepreneurial drive won’t have to die in the transition; if anything, it will get more exercise than ever.

I find this transition especially thrilling because I’m joining a team who prides itself on being the best, doing the best, and giving their customers the best. Owner Chris Harvey recently told me that, “Squaremouth is relentless in its pursuit of quality and perfection.” Having been around a while, I feel the truth in that.

The company is already kicking tail and taking names. Making the leap from independent contractor feels a bit like being asked to move up from the Colts special teams and join the Payton Manning offense. I’m excited at the challenge to further step up my game and make a bigger impact.

Sharp, pointy rocks at the bottom? Bring it on!

(Kuzco, The Emperor’s New Groove)

I can sense that the roller coaster just reached the top of the first hill. It’s time for an awesome ride. I’m throwing my hands up and screaming like a banshee the whole way!

Validate Ruby on Rails model entries with Cucumber

If you use Cucumber, chances are good that at some point in your testing, you needed to verify that a certain set of database records had been created. While this flies in the face of most BDD best practices, I’ve run into a few edge cases the last few months that required this level of minutia. Ideally, you’d use RSpec or Test::Unit for checking database/model level details, and let Cucumber focus on the higher level full stack checking.

In my case, I needed to verify that the admin tool I’m creating builds records necessary for the public side of the site (which hasn’t been built yet). There really wasn’t any visibility in the admin area to this data, except when it’s created. While I did have a solid set of RSpec tests for the model functionality, I felt it necessary to make sure those model methods were called correctly through the controllers and routing that went on.

As a result, I wrote this step:

Then /^I should find these "([^\"]*)" records$/ do |model_name, table|
  model_name.constantize.count.should == table.hashes.count
  table.hashes.each do |record|
    model_name.constantize.find(:first, :conditions => record).should_not be_nil
  end
end

You would use it in your Cucumber feature like this (intentionally bland example):

Then I should find these "Post" records
  | title          | permalink      | category   |
  | A blog article | a-blog-article | Technology |

The first row specifies the fields that will be used as conditions. The following rows will be used to search against. The step will make sure that at least record in the model matches. It will also verify that the number of records in the model matches the number of rows in the Cucumber feature.

Can you be friends with your clients? I think so.

Over the years, talking heads have told us that one should keep your business and personal life carefully separated. While I’ve generally agreed with that approach, recent shifts in my client base towards more ideal clients has given me opportunities to head in a new direction.

Getting our families together

Working with John King from Metta Audio has been my first experience with a truly ideal client. The work we do together has been extremely interesting and engaging, as well as being a joy to build.

20100120 MilesWe enjoy working together so much, and appreciate each other as fun people, that it’s been natural to connect outside of work. Our families have gotten together several times for dinner and play time. I have to admit, it helped a lot that John and his wife Betsy (who is a stellar photographer) are really open and genuine people. Just reading their blogs made me feel like I knew them. Reading about their experiences made it pretty obvious that we had a lot in common.

Building solid foundations

The really amazing thing I’ve found is that as we’ve become friends in addition to business associates, our relationship has strengthened. I suppose that sounds obvious, but it has rather significant implications for the long-term success of any business. While I don’t seek to be friends with John to manipulate him, there are several tangible business outcomes as a result of our growing friendship:

  • Loyalty – Because the business relationship is not based on some fleeting detail like price, I feel more comfortable than ever that John would come to me first when he needs help. I get to spend more time doing the work I love and less time building up my client base. Plus, I’m more loyal to John! I work hard to take care of his needs and have gladly learned some new tools to fit his requests.
  • Profitability – I’ve found that every new client needs some level of training on how you do business and how your services can best meet their needs. By fostering long-term clients, you reduce this non-billable time and effort. Plus, when a client really values what you offer (both in terms of who you are as well as what you do), you can both arrive at a mutually agreeable rate for your services that’s almost sure to be more than what you might feel comfortable asking when doing the first project for a new customer.
  • Fun – Don’t underestimate this one! I’ve had more fun the last six months working for my ideal clients that I ever have before. That’s resulted in me doing some of my best work, feeling less stress, and growing my skills tremendously. I think you’ll find that this does have a measurable financial impact. Clients can tell when you love what you do and they’ll want to be a part of it with you.

Hitting the museum

Spending time with your clients doesn’t have to involve dinner at your home (although the intimacy of that can be powerful). For our latest excursion, my wife Sara and I invited John’s family to join us for a trip to the fabulous Indianapolis Children’s museum.

20100120 JennaA brief side note is in order…spending time with my family is the most important thing on my list when I’m away from work. So the last thing I would do is drag my wife and kids along to some boring business get-together with a client. Instead, we planned something that the family would love and invited John and his family to join us! This is important, too. While your clients will appreciate you for taking care of them, they will adore you when you do special things with their kids. But remember, this all needs to be something you do because you want to and love it, not some cheap to do list to curry favor with a client.

20100120 Miles and John

So we spent several hours at the museum cruising around and playing with the kids. Afterwards, we introduced John to Skyline Chili for lunch. It was a terrific day and everyone had a great time. I think we talked shop for less than 5 minutes the whole day (Which is good! No shop talk would have been fine.).

Getting several clients together

I’m looking forward to going again when John’s wife Betsy can come. Plus, it didn’t work out this time, but for our next trip, I hope that Matt Outten from Squaremouth can bring his family. Matt is my latest ideal client and has been really enthusiastic about getting our families together. He’s even been gracious enough to invite our family to come have lunch at his office each week when his family comes!

If you haven’t picked up the message yet, the critical theme is to share, share, share what you have, whether it’s a fun trip, a friendship, or knowledge. Give it away, you won’t be sorry.

When building web apps, utilize proper indexing

Rails does a lot of crazy wonderful stuff. The downside is that all that awesome power gives you the ability to make some pretty dumb moves. Just because I can get the URL for one of the sites my Am I Down? users get alerts for by using…

current_user.sites[0].host.url

…doesn’t mean that I necessarily should. That command generates some heavy SQL, running a join across several tables (after running a separate query to get the current user):

SELECT "subscriptions"."id" AS t0_r0, "subscriptions"."user_id" AS t0_r1, "subscriptions"."host_id" AS t0_r2, "subscriptions"."alert_id" AS t0_r3, "subscriptions"."created_at" AS t0_r4, "subscriptions"."updated_at" AS t0_r5, "hosts"."id" AS t1_r0, "hosts"."url" AS t1_r1, "hosts"."created_at" AS t1_r2, "hosts"."updated_at" AS t1_r3 FROM "subscriptions" LEFT OUTER JOIN "hosts" ON "hosts".id = "subscriptions".host_id WHERE ("subscriptions".user_id = 35) ORDER BY subscriptions.updated_at DESC, hosts.url ASC

That’s going to take 21ms to run, just for a lookup. Is that a big deal? Perhaps not. Indexes (in the right situations) may make that SQL query run at an acceptable level.

Real world problems

In the case of Am I Down?, my service that alerts you when your web sites go down, I run some pretty slick lookups back through the logs for a web site to see if the change we see in a sites’ status is significant enough to warrant an alert. Since there are thousands of web site checks going on every hour (currently over 20,000 each day), a 21ms SQL statement is seriously bad. You can see the result below:

20100119-db-indexing-screenshot

The solution

The logging table didn’t have an index on the host_id, so it took forever (20ms or so) to find only the log entries for the current host, which for various reasons happens 8-10 times per check. So almost a 1/4 second is taken up by SQL checks every time I checked a site. You do the math and that means you can only sustain about 1,200 sites (240 checks per minute, every 5 min) for each checking worker. Not good.

You’ll see that the there’s a vertical bar towards the right of the graph, after which the bars drop off considerably. That would be the point I added an index for the host_id. Suddenly the time drops to about 3ms. That’s more like 3,600 sites for each checking worker. Much better!

Improving your Rails app

For a Rails app, the Rails_Indexes plugin offers a great way to track down any obvious indexes you may be missing. To speed up queries and reduce the number of queries you make, take a look at Bullet.

Client stats for 2009

As we begin the new year, I would encourage you to review your business and see what unexpected insights you might find. I’m not talking about another look at your products or services, but rather at your processes, finances, and customers.

Starting to work ON your business, not just IN it

It’s easy for me to spend the whole year thinking about code, forgetting that it’s just as important to work on the business as it is in the business (check out the terrific book, The E-Myth for more on this subject).

For me, a major revelation came when I looked at my top customers as a percentage of sales a few months back:

Google Chart

Tail wagging the dog

Wowzers! While it felt like I had a bunch of customer jobs going, the reality was that 3 clients kept everything going. Worst of all, my top client of 2009 was my least profitable and most demanding (It’s worth noting that they had some very good qualities as well: very consistent work and they always paid on-time).

Based on some thoughtful review of these stats, I made a few changes:

Putting long-term relationships first

I saw that too much of my work was provided by clients that needed the services I offered, but had little need for the “Tim-ness” I bring. Partially, that’s because I initially pursued the marketing and design agency niche. Unfortunately, their margins are very tight and for many of the players, web is an afterthought. There’s very little really innovative development going on locally. Clients aren’t asking for it yet.

More than anything else, my work needs to come from organizations that find me irreplaceable. Not in that lame, “I’m the only one who knows how it all works” sort of way. Rather, it’s about finding and working with people who really appreciate the unique talent, perspective, caring, and personality you bring to every project. It’s about brining so much enthusiasm and productivity that the client can’t believe their luck in finding you. Those are things that cannot easily be replaced by anyone else.

My work with John King from Metta Audio has this feel. We both really appreciate what we bring to the relationship. He’s been kind enough to tell me that the chemistry we have as we work together is as much or more valuable than my coding. Plus, I’m always thrilled to work with him on something new!

Demoting the tough client

My favorite book for self-employed consultants, Book Yourself Solid, reminds us that we have to drop our worst clients. They sap our energy and we end up doing poorer work for everyone. I’m not one to fire a client unless there’s something drastically wrong, I’d rather have them fire me. If the work isn’t worth it, I may have to raise my rates significantly to maintain profitability. That way, the client can still get help and I don’t need to complain. If the rate becomes unreasonable for the work they need, the client can replace me. Along those lines…

I’ve known for a while that I needed to change the relationship my top client. 90% of their work was supporting an existing environment, and that’s not really my strength. And because the work is support-related, it’s almost always urgent and interrupts scheduled projects for other clients. My frustration was a clear indication that my rate did not reflect the cost of doing business with this client.

As I mentioned in a previous blog post, I began the transition in October. I completed several open projects and started discussions about eliminating the retainer I was on and associated minimum hours. Since their budget had tightened, it turned out to be a natural move for them, shifting me over to a higher rate that allowed them to only call when I’m urgently needed.

I work hard to protect my time on scheduled client projects, so we also agreed on a minimum billable time when they call. This ensures that I’m compensated for time lost to the interruptions and ensures that they don’t call frivolously. With over a month under our belt with the new agreement, I think it’s been a real success. I’m pleased to take their calls and help when they need it, and they’re spending less. Best of all, I’m freed up to do more of the work that I love.

Increasing the apps available

In addition to client work, I want to add to and continue growing the subscription services I’ve created:

Focusing on larger projects

My business thrives on doing ongoing work for a small number of stellar clients. Part of that is due to my personality. I can really do effective work on one or two projects a day. If I’m pulled away to make calls and juggle 8 projects, trying to move each forward in the course of a day, it feels like a disaster. I enjoy the larger development projects more. They offer a more significant sense of accomplishment that designing lots of little marketing sites.

It looks like I’ll be able to transition over to just a few clients with ongoing needs in 2010. If everything goes as I suspect it will, I’m already completely booked through March, and likely into mid-year. That’s tremendously encouraging. I also had to start a waiting list for a couple potential clients that want some work done and were comfortable waiting for me to free up. It’s a pretty wonderful spot to be in.

Many of the relationships I worked hard to build in 2009 have resulted in requests for work. I’ve been pleased to refer many of these to other independent developers and designers in the area, helping them keep busy while taking care of my contacts. It’s always hard for me to turn down a project as I love to help people, but it’s what I have to do for my current clients.

It’s going to be a stellar 2010!

SOLD: 2.66 Quad Core “Nehalem” Mac Pro

My business has transitioned significantly towards doing work onsite with clients and more frequent travel. Therefore, it no longer makes sense for me to maintain a monster-powered Mac Pro at my office. Heck, I’m only in the office one or two days now.

For Sale – Like-new Mac Pro with AppleCare:

  • 2.66 GHz Quad-Core Intel Xeon “Nehalem” processor
  • 3 GB RAM
  • 640 GB Hard Drive
  • TWO NVIDIA GeForce GT 120 graphics cards (I added one, giving it support for FOUR screens up to 30″ each)
  • AppleCare good until 06/24/2012
  • System just six months old (purchased in June 2009).
  • Comes with original box, power cable, disks, manuals, etc.
  • Sorry, no Keyboard or Mouse

SOLD$2,199

SOLD: 13″ black MacBook

After just over a year of consulting work, I upgraded to a 17″ MacBook Pro. So now I need to sell my original laptop.

For Sale13″ black MacBook with:

  • 2.4 Ghz Core 2 Duo
  • 4 GB of ram (I upgraded it)
  • 250 GB drive
  • 3-year AppleCare protection with over a year left (purchased with the laptop around Aug of 2008)
  • Beautiful Booq Slimcase ($99.95 new) for travel in style. It’s in like-new condition as these cases are tremendously well made

SOLD$800

Interested? Get in touch!

Samantha Joy Harvey joins our family

20091026samanthajoyAt 7:55pm on October 26th, my wife Sara and I welcomed a third little girl to our family. Samantha Joy Harvey weighed 7lbs, 8 oz and was 21 inches long. Jenna and Emmy are thrilled to meet their little sister (while on the phone after Sam was born, Jenna said, “Daddy, I keep laughing when I hear Sammy talking”). Thank goodness for four grandparents in town to encourage us, watch the girls, bring us meals, and visit at the hospital. I can’t express what having friends and family close means to us. The outpouring of support from friends has been incredible.

Crowdcasting via Facebook (and Twitter)

What I find most hilarious about the whole process was the heavy response to the “crowdcasting” I did on Facebook during the day.

While I have a Facebook account, I rarely log in. Mostly, I don’t have time to invest in keeping up with it all. But on baby day, I did more Facebook than I had in the last six months.

For this special event, Facebook became my secret weapon. With our last two girls, I spent WAY too much time on the phone calling people to let them know what was going on, organizing visits, and answering questions. All in all, it was exhausting. I’m not terribly social (preferring to connect more deeply with smaller groups of people), so all of that phone time was overwhelming. Worst of all, I even offended several folks who thought they should have heard from me (and didn’t because of all the chaos). Sorry!

Yesterday, over the course of 10 hours, I posted numerous photos and updates. I ended up making just two calls (thank goodness)…one to each set of grandparents. The result: a significantly larger pool of friends and family were in the know and the whole process was incredibly relaxed. Best of all, with an iPhone by my side, uploading photos was quick and easy. Updates were almost instant as I could post in seconds with the Facebook app. Nice.

I did do a few Twitter posts, but I intentionally kept that light. I use Twitter to connect with other professionals, so I didn’t want to spam them with too much personal detail. I try hard to avoid being the person who posts about what they ate for lunch all the time.

A wonderful journey

I’m certainly a “glass half-full” kind of person. Even still, I’m amazed at how blessed we have been with this pregnancy. Everything went very smoothly. While we always worry about the worst headed into the final stages, things went fine.

After a short meeting with a new client, we showed up at the hospital around 10am. We had several hours of waiting while some meds got going. The staff was looking to keep things slow until enough antibiotics had gone through. By 2 or 3pm, Sara and I made a bet (that I lost). I figured we’d have a baby by 5p, with Sara knowing that it would be much later.

We had a relaxing afternoon of gentle laboring during which I got a fair bit of work done, we watched several episodes of How I Met Your Mother, and a TON of Food Network was enjoyed. Once the evening rolled around, Sam decided that she was ready to make her entrance. Within a half-hour, momma and baby met face to face and our world is forever changed (for the better, of course).

Amazing care from Dupont Hospital

It’s been a great time and the staff at Dupont Hospital has made our stay amazing. Our other two ladies were also born here and our experience was the same. If you are going to have (or planning on) a baby, I can’t recommend Dupont highly enough. All the obvious things (taking care of baby and momma) were perfect. Beyond that, a few highlights:

  • Extremely kind and caring staff, made us feel welcome and supported
  • Special band on the baby that locks down the floor with alarms if anyone (even us) tries to take her out of the birth center
  • Free wifi kept us in touch with family / friends via Facebook and Twitter
  • Rooms are comfortable (even for Dad) and quiet
  • Fantastic “celebration meal” of Filet Mignon w/Shrimp, appetizer, desert, and sparkling grape juice. Very cool.
  • Many meal options, all quite good
  • Nourishment area stocked with a WIDE assortment of complimentary snacks and drinks for mom and dad

All in all, it makes the transition really peaceful. While I’m sure all of the local hospitals offer good care, I think Dupont lives up to their tagline: “Experience the Dupont Difference”. It’s clear that they work hard to stand out from the crowd.

Get updates in your inbox

Enter your email address: