Should I Work For Free?

In one of the Slack organizations I am in, some of the people in the design channel were talking about how spec work permeates their industry and how it is harmful. They talked about how this came to be and the effects of it. I stayed out of the discussion for a while, but I finally posted this to try to help understand what they were saying and state my perspective. Since I thought it might be valuable to you if you are a freelancer or consultant, wanted to share it here.

The Post

I have worked more in a software development capacity, so I am not steeped in the “spec work” culture as much, but I basically would not give work away for free for someone who is able to pay money. I think part of our responsibility as people who take on clients is to verify the following before engaging to learn more:

  • what is the significant business problem you have?
  • why are you trying to solve it today?
  • have you had and solved problems like this before?
  • do you have a budget for this project, and is it at least $X0000 dollars?
  • are you the project owner?

I will admit to mostly lifting this from Brennan Dunn’s Double Your Freelancing Rate book and related materials. But I think it is a good list to qualify leads that will prevent a lot of headache. There are certainly clients that will filter out of the process at this point, and the best case would be for you to be able to direct them to someone else that would be able to help or to a good resource to learn more. I think we have all run across someone who wants a MailChimp clone for $500, and we just have to say that this is almost certainly unreasonable, and here is why, and here are other resources that you can investigate and the potential advantages or pitfalls of going that route. Sometimes people just have an unrealistic or uninformed expectation, and at least we can tell them why we think this is incorrect and help them on their journey.

A business might think they need a new website, when in reality they have a product or positioning issue, or they are not getting enough traffic to their existing website, or other problems. So I think it is our responsibility to understand the underlying problems the client has and to make sure that we are solving the actual problem they have. That is a lot more valuable than just saying “yep, you specify it, I code it.” Or, “you give me a design, and I design it.” At that point you are a commodity, and will be able to charge accordingly. If you can provide more value than that, then you are not in the same market segment and can justify a higher rate as a result.

I think it’s easy to blame the industry or norms, but I think it’s important to say “what can I do to ensure that the projects that I take on are going to be the kind of projects that I want to work on?” Part of it is working with clients to establish better default communication and expectations.

It’s interesting though. I think that there likely some “free” work involved in most consulting industries. If you write a blog post or go to a conference or a networking event, or learn a new technology or process, or meeting with leads, this is time that you are not charging clients. But it is probably really important to ensuring that you get new work in the door. If you were turning away good work every week, would you have any incentive to do spec work?

Thanks for reading, and I’d actually love to hear more about this. I think it is an interesting topic.

Consistently Snake- and Camel-Casing

I am working on a couple of projects that use Ruby on the back end and JavaScript on the front end. The Ruby convention for variables is snake_case, while JavaScript variables are camelCased. This causes friction when we pass things between the front end and the back end.

An ad-hoc solution might result in the Ruby code handling some camel-cased variables when reading in JSON or when sending a response. Otherwise, the JavaScript code has underscores all over the place, which is also undesirable. It has the effect of cluttering up our front end code.

Overall, this discrepancy makes it harder to derive the right variable name each time on both the server and the client. Languages have conventions primarily to make it easier to remember what to call things. However, this breaks down when there are two or more languages in play that have different conventions.

A solution that I implemented that I’m pretty happy with so far is to consistently snake- and camel-case on the server. This can be done with two steps. First, we create a middleware that intercepts requests with a JSON body and converts the keys to snake-case. Then, whenever we send a JSON response, we convert the response to camel-case for the client to consume.

There are a few advantages to doing it this way. We will have consistent snake-casing on the back end and consistent camel-casing on the front end. Our linters will have fewer false positives. In addition, our tests are also generally easier to write because they can use the correct case (except for server-side controller tests, since these require camel-case input.)

For the specific project that I’m working on, I used a pair of gems written by the same author. The plissken gem turns camel-cased hash keys into their snake-case equivalent, and even works recursively for arrays of hashes. The awrence gem does the reverse, going from snake-case to camel-case. So if we were using Sinatra and ActiveSupport, a middleware might look like:

  ...
  use Rack::Parser, parsers: {
    'application/json' => -> (data) do
      JSON.parse(data).to_snake_keys.with_indifferent_access
    end
  }
  ...

Which will load the JSON body into the params hash, and we can access it with symbols or strings.

Our JSON responses can be automatically camel-cased with the following middleware:

class CamelizeJsonResponseMiddleware < Sinatra::Base
  after do
    pass unless content_type == 'application/json'
    if response.body.length > 0
      body response.body.to_camelback_keys.to_json
    end
  end
end

The nice thing about using middlewares is that we don’t have to remember to convert for each request. Our application is more consistent as a result.

One potential downside is if the gems don’t work as expected or if the input or output is particularly complicated and our expectations are violated. The other would be if someone new came onto the project and doesn’t understand the middlewares. They might be quite confused until they figured out what was going on. I think documentation and logging would help address most of the issues here.

I’m pretty happy with how this worked out, and think that it makes the code a lot cleaner. Hope this helps you on your projects!

The Cross-Country RV Trip I Didn't Take

At HealthPro, we recently started having some company culture discussions. The general idea is that a company will always have some culture, and that you can influence what it becomes by being aware of it and proactively discussing it. After a general brainstorming session together, we started discussing things in Slack (“Work As If Remote”, right?)

The value that we were discussing was “Try new things / Don’t be afraid to make mistakes”. One of Kyle’s questions that seemed to get a lot of response was “What’s the most spectacular failure you’ve been a part of? What did you learn from it?”

I liked my response, so thought I would share it with everyone now.

My Story

One thing that I did in 2011 that was a pretty big failure in my mind was unsuccessfully trying to go on a cross-country RV trip.

I had some money saved up and the startup I was working for had folded (which is probably a failure story itself), and thought it would be good to get away from everything and travel out west and try to play a lot of Ultimate. I thought that I would need a small RV to make living work (and could maybe code or something in there), so traveled several hours to Kentucky based on a Craigslist ad to buy a 22-foot 1987 Winnebago Minnie Winnie. My (now) wife drove me there and followed me back in one very long day.

When driving back, we stopped at a gas station, and the RV wouldn’t start! We waited a bit and it started up again, but I was loath to stop it again. When we got home after about ten hours of driving round-trip in the summer, I was pretty exhausted.

I am not mechanically inclined, so considering driving across the country in a 25-year-old RV was not really that exciting. I kind of freaked out and sat in the basement for a day or two. I signed up for a conference in Colorado that I was going to drive to that week, but didn’t end up going and so lost out on the money that I put into it.

The RV sat in the driveway through the winter. After nine months I put it up for sale.

The woman who ended up buying it has the foresight to have a mechanic appraise it, which seems like a smart thing to do. They said it had some roof damage, so I ended up selling it to her for about $2000 less than what I bought it for. The mechanic also said that there was essentially no oil in the thing, so it was lucky that I didn’t burn up the engine with the several hour drive from Kentucky. I was glad to be finally rid of it, but it was a fairly expensive mistake.

Obviously in the grand scheme of things, it was not that big of a deal. Instead of going on the trip I used the rest of the savings to start some independent work, which launched my consulting business. If that is the worst thing that happens to me, then I would consider myself very fortunate.

Lessons Learned

First, get vehicles checked out if you aren’t sure about them.

I realized that there were easier and cheaper ways to make the trip that I wanted to take. I could have taken my pretty well-functioning car and bought a tent and camped out. The gas certainly would have been cheaper (30 MPG vs 10 MPG.) Plus, I would have saved the capital outlay and potentially loan interest of purchasing another vehicle.

Do the simplest thing that could possibly work. Instead of making the big trip first, make smaller trips to figure out if I like it or not and I can come back easily if there are any complications. While having the conference as a deadline pushed me to action, I might have made worse decisions because I tried overcomplicating things early.

Last, play to your strengths. Buying a super-old RV that I didn’t know much about and that I would need to maintain was not in my wheelhouse.

Work As If Remote

At Haven, one of the unwritten values we had was “work as if remote”. In this post I’ll explain what this means and why it is important.

What does it mean?

“Work as if remote” means we always pretend that there are people working remotely, and behave accordingly. Even if everyone on the team is in the same room, or at the same meeting, we operate like there are people that are across the country. We do this by documenting:

  • the plans that we have
  • the decisions we make
  • the things we do
  • the things we learn
  • meetings or conversations we have

The tools

We implemented this at Haven by using Slack for most communication, and Trello for capturing story-specific details in line with the cards that they were related to.

Also, MeetingHero (now the inferiorly named WorkLife) allowed us to record meetings in a collaborative way, although a shared Google Drive document could achieve the same goal.

Benefits

There are usually people working remotely, even if you don’t think they are. First, there may actually be remote people that you have just forgotten about. :) We had a designer working in San Francisco, and while he didn’t chime in often, writing as much as we could likely gave him more context for designs.

You might think that everyone who cares about a given subject is in the current room, but often there are other people that would benefit from having conversations written down.

Working as if remote allows us to bring new people up to speed more quickly, because we document what we are doing and how we do it. Asking a question in a shared channel enables anyone to answer it without interrupting everyone. Everyone can search back through history for the discussion and resolution of problems.

Writing out what we are doing forces our thinking to be sharper and our decisions more explicit. We get a chance to look back at the decisions we make along the way and introspect when things go well or go poorly. We make it clearer what we are planning on doing and can hold ourselves accountable. Coworkers understand what we do on a daily basis and where they might be able to help.

In today’s software development environment, being able to work remotely some of the time is more and more common. I doubt that I will consider future work that isn’t partially remote, and there are or will likely be more people like me. Most people expect to be able to run errands or take care of their kids or have a more flexible schedule, but our communication patterns need to change if we are to be successful and have this be a possibility. To this end, I would argue that working as if remote is one of the foundations of a healthy culture around taking vacations and traveling. In my opinion, it should not matter if I am across the street or across the country if we are getting work done effectively as a team.

Tradeoffs

Communicating in this way may seem like a lot of extra work. In reality, it doesn’t take much more time than having the conversations that we are already having. Also, it can actually save us time. When I try to remember something I did yesterday and I wrote something about it, it saves time and effort.

Four people getting together in a room for two hours is an expensive thing. We have an obligation to make sure that meeting time is well spent and that we are clear on what comes out of the meeting. By typing up good notes, we give people who weren’t in the meeting the benefit of being in the meeting without needing to devote the entire time to be there.

Good practices

Be asynchronous

From code review to meetings to doing standups, there are many activities that can be made asynchronous or location-independent. You may start a process that works synchronously (perhaps a recurring meeting), but once the team understands the parameters, consider how can it be distributed over time and location.

Overcommunicate

This is probably a good principle in general, but write more and about more topics than seems necessary. If you feel like someone might say, “TMI (too much information)!”, then you are probably headed in the right direction.

Record synchronous communication

If you have a useful conversation with someone, post a summary so that others can learn from it. Also, this helps document what you talked about to ensure that you actually heard it right.

Embrace the firehose

Posting everything that happens can be a little overwhelming. Personally, I’d rather have more information than less, so I think this is worth it. But when everything is a priority, nothing is. It is useful to mark things as “FYI” or “important” so that others understand the priority and can effectively filter the firehose of information. You also need to set up your channels and policies to be responsive but also not get overwhelmed.

Don’t be afraid to sync up

Even when remote, be willing to have a Skype / Hangout to sync up. Synchronous communication allows you to hash things out much more quickly. Then, of course, write down what you talked about and the main decisions or clarifications made. :)

Conclusion

I wanted to share this because I think it was a really useful philosophy that we had. I will definitely be trying to do things along these lines going forward.

Debugging An Issue With Should.js

Quick post today about something that I was debugging that I thought might help someone out.

We were using should.js for Mocha assertions. In some of the tests, I was suddenly getting warnings like:

WARN Strict version of eql return different result for this comparison
WARN it means that e.g { a: 10 } is equal to { a: "10" }, make sure it is expected
WARN To disable any warnings add should.warn = false
WARN If you think that is not right, raise issue on github https://github.com/shouldjs/should.js/issues

I tried adding the should.warn = false but that did not seem to have an effect. Plus, this code would have been required in each file that had the problem, so it is an unsatisfactory solution.

The solution is to change things like the following:

response.status.should.eql('404');

in the tests to:

response.status.should.equal(404);

Basically should.js tries to ensure that we are doing what we expect when matching equality. Since the types don’t exactly match, it issues a warning so that we take a cloer look. This behavior must have changed recently when I saw it, since it previously seemed to work. Happily, the new way of doing this is more correct as a side effect.