How to recruit great developers

I believe there are 3 ways of recruiting when it comes to technology and startups (ignoring agencies and freelancers):

1.) The HR way: Non-organic recruiting through cold calls and direct search

The “standard” way to do recruiting which probably never works out well for anybody.
Unless you are looking for interns, juniors or freelancers (no offense intended, that’s just the way it is).

There are many reasons why this approach does not work:

  • Developers prefer to be approached by technical guys and not by somebody who thinks that a “javascript” developer easily fits into a “java enterprise” environment.
    I mean, why wouldn’t he, both positions have the word “java” in it!
  • Good developers normally don’t respond to contact requests from xing and linkedin since their inboxes are already flooded with messages
  • It’s hard for a non-technical person to assess the quality of a developer since the CV is useless in most cases. Or rather all cases.
    I have seen great developers with shitty CVs and lame developers with great CVs. The only thing that should matter for a developer is code.
    Oh, and team culture and stuff. But I’ll get to that later


2.) Organic recruiting through team culture

The best way to recruit – it means that your team culture is so great that great developers apply proactively. Great developers rarely have to apply for a job, so this means a lot already (quite a few of them don’t even have a CV because they never had to apply anywhere).

This also means that your team culture is so strong, that your team members proactively start looking for other great team players because they are so convinced of what you’re doing.

Please note that this is not the same thing like “I’m looking in my network because my employer has a ‘refer a friend’ program”, this is something much stronger, since people are not motivated by money, but by passion.

Ok, sounds great, so how do we get there?

* Be polyglot

A lot of companies are focused on one language only. E.g. you started out with ruby and now you are doomed to write ruby forever. This deters good developers. Nobody wants to be locked in the golden ruby cage forever (trust me, I’m the biggest ruby fanboy out there, and even I am convinced of that).
You should drop the “we are doing ruby and you have to know ruby” restriction completely and embrace all modern, sexy languages.
Not to mention that you then can tap into the huge reservoir of great developers out there who haven’t written a single line of ruby in their life.
But in order to do that, you need the appropriate technical architecture. Having a microservice architecture allows you to be polyglot since every microservice is completely independent from each other. Having one monolithic app would probably not work.
Of course this still needs to be at least loosely monitored since certain technologies probably don’t make sense for you (e.g. Java Enterprise when you’re a start-up) or are outdated in the sense that most good developers moved to a different eco system years ago like PHP or Perl (I love Perl, but let’s face it, Perl 6 put the final nail in the coffin).
And of course the teams must commit to maintain and operate it.

* Organize user groups

User groups are a very informal developer meetup.

Normally all you need is:

  • a room with a beamer (easy)
  • couple of beers (easy)
  • people who have a topic they are passionate about (hard to find)
  • a network of great people to invite (see above)

You can either create a user group that hasn’t existed before in your area. Depending on where you are, this might be pretty hard. E.g. in Berlin there are a gazillion of user groups already with all kind of technical topics.
If that doesn’t work, go to existing user groups. Immerse yourself. At one point, people will know and trust you and they might be open to host the next user group at your place.

* Organize internal tech talks

Kind of self-explanatory – your developers get together and talk about tech.
Those talks have more great side effects than I could enumerate here. You increase team spirit. You increase “world knowledge” since those tech talk of revolve around work related problems. You create synergies between teams you hadn’t even thought about before. I could go on and on, but I’ll stop here.

* Create a world class office

Sleeping pods, showers, gym and most important: an up-to-date library (Zappos style. Check it out). That includes encouraging people to read as well.
Ask your team what they want to have in the office.
Some ideas are more of a joke but there will be a lot of good ideas as well ranging from very cheap (“order a new book shelf”) to rather expensive (“A gaming room would be cool”).

* Have open source days

That would be days were people can hack on open source software. This is kind of a difficult thing to get right and warrants a separate blog post later.

* Attend to conferences

Developers want to go to conferences. That’s just something they expect. You should not only grant those requests, but rather encourage people to go there.
Yes, it’s probably not cheap and yes, it might be during working days.

What you get out of this:

  • Motivated developers
  • New ideas how to solve existing problems
  • New impulses
  • A bigger network of talented people

* Establish a mentor program

Seniors mentor juniors. Veterans mentor newbies so that they don’t feel lost and can get productive as fast as possible. This doesn’t mean that juniors can just abuse seniors to get the job done. It’s more of a “ok, when I am totally stuck with something i can at least ask my mentor for an idea” thing. In most cases they don’t even ask anything, but just to know that they can already has an incredible positive effect on them.

* Make recruiting a top priority for every team member

How google works has some great thoughts on how to do that. And more important, how to not do that.

One thing that I love to do is a trial day or two for candidates. After that, both sides know if this will work.
Don’t invite everybody but only people that passed an initial screening. Reject developers who can’t show source code with their application right away, which already weeds out the bad ones.
Include the teams in the decision process. After all, a hire would be good for nothing if you think he / she is a good addition but the team he’d work with rejected him.


3.) Recruiting on steroids through active participation in the tech scene

Even better but requires a lot more of effort.

* Speak at conferences

First of all, its important to understand that those conferences are very different from what a lot people would expect: They are very informal, the agenda is sometimes unclear even days before or changed ad hoc and they often feel more like a meeting with friends. They are mostly non-commercial (in the sense that they only have fees to pay their expenses) and you can’t just buy a speaker slot. You sometimes can buy a slot for a 5 minute lightning talk , but never for a full talk (you have to submit a proposal and this proposal gets reviewed by the organizers if it is interesting enough for the attendees).
Talks must be authentic so you can’t just have a talk about something that somebody else did since most people will notice right away.

* Organize workshops that are free for non-employees

This is basically how a company here in Berlin recruited rare Erlang programmers (Erlang is very popular in northern Europe): They invited Erlang icons, paid them to do workshops and invited every Erlang dev in Berlin to take part. For free (or almost for free).
There are so many idols out there that travel the world and can be booked for workshops. Corey Haines, Eric Ries, Sandi Metz, Yehuda Katz….the list is long.

* Organize Hackathons

Organize a hackathon, give participants an interesting challenge that also solves one of our problems, have some fancy prices and ensure good press coverage.

This is a complicated topic and would require thoughtful planning. I have seen quite a few of those events fail horribly because people thought that providing a room and prize money would be enough.


Get your team culture right. Invest some money. Probably a lot. Build up the best team possible.
Take (early) google, twitter and Zappos as role models. And then go beyond what they did.

And then your recruiting problem will solve itself.

Reek 2 just got released

A couple of days ago we released the new and extremely shiny reek version 2 to the world!

For those of you who don’t know reek, reek is a static code analyzer for Ruby detecting so called code smells. Those code smells range from rather trivial ones like UncommunicativeParameterName or TooManyMethods to high-level code smells like FeatureEnvy or DataClump.

In the most simple use case you can just run

reek my/source/files


echo "def dirty(x,y,z); puts 'hossa!'; end" | reek

So what has happened since 1.*?

There are way too many significant changes to list them all so I restrict this list to my favourite ones (excluding the countless bugfixes):


Parsing with the parser gem allows us to support all major ruby versions:


We deliberately dropped support for 1.8.

New smells

We introduced 2 new smells:

– The ModuleInitialize smell
– The Prima Donna Method smell


We completely revised our configuration handling, basically there are 3 ways of passing reek a configuration file: Using the cli -c switch, having a file ending with .reek either in your current working directory or in a parent directory, or having a file ending with .reek in your HOME directory.
This means that reek no longer tries to nest configuration files, but instead from reek‘s point of view there exists only one configuration file and one configuration.

Another cool feature is support for detecting specific smells like this:

reek lib/ --smell FeatureEnvy

This can be very helpful when refactoring when you want to focus on one group of problems.

And last but not least smell detectors can be configured or disabled in code comments like this (in addition to reek‘s regular configuration mechanism):

# This method smells of :reek:NestedIterators
def smelly_method foo
  foo.each {|bar| bar.each {|baz| baz.qux}}

CLI / Output / UX

We completely restructured and revised the command line interface for reek:

– We now support the yaml and html format besides the standard text format which makes reek great for compiling automated reports and statistics
– We overall revamped the UX when using reek. For instance we added color to reeks output, enabled different sorting options like “sort by issue count” and added a “show-wiki-links” switch that prints out helpful links next to each warning pointing to our github wiki that explains this particular smell and how to possibly fix ist.
– Speaking of the wiki, you now should find an extensive description of each smell reek might detect including possible solutions

rspec matchers

We made the reek_of / reek_only_of rspec matchers a little smarter – you can still just do something like:

expect(src).not_to reek_of(:UncommunicativeParameterName)

but if you really want to be more specific about this you can now add a hash of “smell_details” reek_of will check for as well like this:

expect(src).not_to reek_of(:UncommunicativeParameterName, name: 'x1' )

You can check out the details here.


Personally I’d really like to see a couple of annoying bugs fixed, for instance:

Issue 112
Issue 27
Issue 268

Pair Programming Sucks

For quite some time, a lot of companies have been on the “yes, we do pair programming” bandwagon. Some of them even to the (ridiculous) extent that pair programming was mandatory. So something like “at least 2 days a week”.

I’ve been through that and those were certainly some bad times in my software development career.

I never liked pair programming to begin with.

First of all, it’s synchronous. You have to pay attention that very same time your partner pays attention. But people and their rythm are different and if you do this all day, this gets exhausting very quick.

Second, regardless of what technology you’re using, there will always be artefacts you have to generate and update. If you use languages like Java this might amount to a lot. But even with something concise like ruby this will steal a lot of your time.

And during that time one partner takes care of those artefacts the other drifts off – there’s just nothing you can do about it, this is how most humans work. And if one partner looses focus, he takes the other one down with him ususally.

So, in an nutshell, pair programming sucks hard.

So what are the alternatives?

Pull requests.

They have all the benefits of pair programming but none of the disadvantages. They are asynchronous by design so you can dive into problems when you feel like. Your time, your speed. Very important.

There are a couple of exceptions though where pair programming makes not only a lot of sense, but offers significant benefits:

  1. Learning workflows from your partner. Sure you can read up on git and friends, but nothing makes it easier for you than to see those git workflows in action. Also, seeing how your partner executes those workflows takes the fear away to fuck up things on the remote end when you have to do it yourself: You have not only seen how it’s done, you have seen the result of it. To stick with the git example, a lot of git novices are afraid “cause damage on the remote git repository” – seeing how easy it is to juggle multiple branches and pushing to remote lowers their mental barrier.
  2. Learning how to use tools from your partner. That’s basically how I learned vim. Granted, this only makes sense if you use something obscure and poorly documented as vim.
  3. Onboarding. That probably needs no explanation.

I guess with pair programming it’s like with everything in life: Don’t make up rules just for the sake of having them and follow them without questioning them.
Use pair programming scarcely. In most cases you can achieve the same thing better with pull requests.

My Favourite Books About Products & Programming

Alright, so here’s the list of my favorite books when it comes to product design, product management and programming:



Why you should squash your commits and how to do that

When I look at our bigger pull requests, I can see that they often contain dozens and dozens of commits. With 90% or more of them containing useless commit messages like “Fix.”, “Typo”, and so on.
This implies that this very pull request / branch is not atomic, meaning that “it does not behave like one single entity, but like a lot”.

What’s the problem with this?

1.) git-log is one of the most important git tools and using it properly can make all of our lifes easier.

For instance, with a proper git-log you can just type in “git log” and you can immediately see the last significant changes to the source – something that is utterly impossible when you merge branches with hundreds of commits. If one feature is split across many commits git-log is useless because it can’t tell what belongs where (I am aware that git-log can show you what commits belonged to what branch but this is still useless in most cases because it is just not terse and concise enough for the human brain to operate on)

2.) Bugfixing can be significantly easier if you know what commit introduced this very bug because it gives you context (something that is lost in multiple, meaningless commit messages). Not to mention that you can use git’s finest tools like git-bisect.

3.) If I realize a feature has gone wrong and I need to remove it from master I can’t do that if this feature is spread across multiple commits which are already intertwined with master without a huge, error-prone effort.

4.) If one feature is one commit I can easily play around with, e.g. deploy features in different combinations to staging servers.

How could we improve this?

The canonical git approach to this would be: Squash it.

To give you an example:

Say you have a feature branch called “fancy-feature” with a corresponding pull request where you want to squash the commits before you merge the PR. Here’s what you’d do:

git lp master..fancy-feature  # my alias for log –decorate –pretty=oneline –abbrev-commit
2b2197f (HEAD, fancy-feature) Fix whatever.
5c0ff6b Typo.
1d96940 Fancy Feature.

As you can see, we have 3 commits in this branch that are not in master. Let’s squash that:

git rebase -i master # -i for “interactive”

Now the following edit screen pops up in your favorite editor (whatever `env | grep -i editor`) says:

1 pick 1d96940 Fancy Feature.¬
2 pick 5c0ff6b Typo.¬
3 pick 2b2197f Fix whatever.

Let’s transform this to:

1 pick 1d96940 Fancy Feature.¬
2 f 5c0ff6b Typo.¬
3 f 2b2197f Fix whatever.

I replaced the “pick” in the last 2 lines with “f” for “fixup” which means: “meld into previous commit, but discard it’s commit message” (there’s a helpful explanation in the rebase view as well)

Save the file and exit it. That’s it. Now let’s look at this branch again:

git lp master..fancy-feature 
1e8ae44 (HEAD, fancy-feature) Fancy Feature.

Now it’s just one shiny commit.

The last thing you need to do is update upstream:

git push -f origin fancy-feature

The “-f” flag is the important thing here. You changed history in your branch (which is intentional and ok in a branch) so git requires us to pass this flag to tell git that we really want this.

What’s the downside of this?

– You need to get used to doing that at the end of the lifecycle of each branch. However, once you get used to this you’ll hardly notice it again.

– force pushing. Potentially dangerous if this happens on master. Again, using aliases and sticking to workflows mitigate this. E.g. I have this

  default = tracking

in my .gitconfig, so for me it’s just “git push -f” without even having to specify the branch name (so there’s no potential of screwing up the branch name or whatever)

– We lose the commit history within a pull request. However, I have never seen that this was a problem because after a feature is done and approved you’ll almost never be like “Why again did I go from this to that?”. And even if you were, the git history would be the wrong place for me in any case – such a rationale would be better placed in a changelog entry or a source code comment.

Who else is doing it like this?

Basically every popular open-source project (e.g. Rails, Sinatra, and so on).

Check  out the rails log:

05ab902 Merge pull request #15042 from arthurnn/revert_dirty_transactions
314cbea just call the method and assert the return value
198d9e3 Reverts “Fix bugs with changed attributes tracking when transaction gets rollback”
0a7beb1 Merge pull request #15041 from arthurnn/update_ruby
e019ffa Use ruby 2.1.2 on travis
ea58684 add tests for path based url_for calls

Also notice the “Revert” commit in there. Something impossible for us to do now. Besides that, the git log looks flawless and actually helps you to see what’s going on since one commit == one meaningful addition to the code.

What I expect from a great employer

Alright, so here’s my list.

First of all, I expect any decent employer to pass the “Joel Test”

Now, of to my basics:

  • Salary. Don’t try to start out with cheapest offer you can come up. No virtual shares as incentive. I’ve never seen those work out for anybody.
  • Product. In order to care about it, I need a product that solves a concrete problem and is not sales-driven. Bonus points: It makes the world a better place. This excludes everything that is even remotely connected to ecommerce, marketing or advertisting.
  • Commute / home office. Offer me the possibility to do home office one or two days a week if I live more than 20 minutes away. It’s 2014, not 1976.
  • “The mission”: If you’re just exit-driven, don’t bother to approach me. I want to work with real entrepeneurs – that means people who care about the product, the company and the employees and not about the quickest exit possible.

The intricacies:

  • Overhours. They might be necessary sometimes but they certainly should not be the rule.
  • Don’t try to enforce a company culture. This just happens or …it doesn’t. The only thing you as an employer can do is set up the environment for it. Having semi-automated, semi-mandatory team events every month is not the right way to do it.
  • Company meetings. Only have those when you have something to say. Don’t do them regularly because people will just talk because they have to say something.
  • Meetings in general. Don’t do it unless you a) have an agenda, b) have a moderator and c) have a tight time frame.
  • Managers. The less, the better. Delegators are useless at best, in most cases they are harmful
  • No interruptions. Or at least schedule them properly. You know what happens when you interrupt a programmer, don’t you?
  • Give me time to learn and develop myself. It always puzzles me that in an industry where knowledge and learning is everything you’ll rarely find companies that give you time to learn. You’ll hear crap like “We’d like to do it, but we’re not google”. Guess what, genius, that’s exactly the reason why you’re not google. One day a month for open source work and learning new languages and technologies is a win-win for everybody.
  • Don’t be cheap. Don’t make me explain why I need this ebook which costs you 20 Dollars. Don’t try to find the cheapest accomodation possible for a conference. It’s  disrespectful and it kills my motivation.
  • Involve me in the product. If you treat people like ticket slaves this is exactly what you get: ticket slaves.

git workflows and best practices

Everyday git

Preliminary remark: I use a bunch of shortcuts and abbreviations here for git commands which follow the official “git best practices” and you should configure your environment accordingly as well. See

How to create a feature branch / pull request

  • Create feature branch and switch to it

    git co -b feature_branch

  • Publish it on remote

    git ps -u origin feature_branch

Hint: If you use a tool like:

you can get this done even quicker.

  • Do your changes
  • Stage them

git add -p

Yes, that’s a “-p” there. Please do never use

git add .

  • When you think you’re done commit everything

git ci -m ‘Your meaningfull commit message in proper english.’

  • Publish them

git ps

Now you can open up that pull request on github. Tip: Becomes even easier with the github gem.

This pull request should be reviewed and commented by one of your peers before anything else happens.

What should I do after the pull request has been merged?

  • Close the pull request remotely and delete the branch via github interface (there’s a button showing up after you merged / closed that pull request.)
  • Delete the branch locally via

git b -D your_feature_branch

How to squash all commits from on PR into one?

First of all, you need to understand why it is absolutely necessary that your whole PR is one, atomic pull request:

  1.  git-log is one of the most important git tools and if you’re not familiar with it, you really should learn about it (more to come here soon). However, if one feature is split across several commits git-log is useless because I can’t tell what belongs where.
  2. If I realize a feature has gone wrong and I need to remove it from the mainline I can’t do that if that feature is spread across multiple commits which are already intertwined with master without doing potentially dangerous rebasing. This would also require that I do know exactly what commits belong to what feature which is next to impossible, even after a short time.
  3. If one feature is one commit I can easily play around with, e.g. deploy features in different combinations to staging servers.

So how do I do that?

Ok, so let’s say you have 3 commits in your feature branch that do not exist in master and your feature branch is named “fancy_feature”.

First of all we need to find out how many and what commits that are:

The two most common methods would be:

git log fancy_feature –not master

git log master..fancy_feature

However this gets tedious to repeat so you want to do something similar to what I did and add an alias to your bashrc (or whereever it fits you) like this:

alias sh_exclusive_commits=’git log $(git symbolic-ref -q HEAD) –not master –pretty=oneline –abbrev-commit –decorate’

So now, when I execute


I get (given that I am on the feature branch of course):

9c5ec4b (HEAD, fancy_feature) Finalize feature.

6b24ba0 Fix foobar.

b3210dc Update foo to do bar.

Now let’s squash those commits into one:

Generally you would do it like that:

git rebase -i master

which tells git to take the last commits starting from HEAD (the commit on top of the branch you’re working on) that are not in master.

Now, if you execute this, you’ll see something like this:

  pick b3210dc Update foo to do bar.$

  pick 6b24ba0 Fix foobar.$

  pick 9c5ec4b Finalize feature.$

# Rebase 82ed078..9c5ec4b onto 82ed078

What you want to do now is:

  • Squash those 3 commits into one
  • Give that one commit a proper name
  • Merge it back into master

To do that this is what the menu should look like:

r b3210dc Update foo to do bar.$

f 6b24ba0 Fix foobar.$

f 9c5ec4b Finalize feature.$

This tells git to “fix up” 9c5ec4b and 6b24ba0 into b3210dc and rename b3210dc in the same step. If you save that file now git will perform those operations and then let you rename b3210dc. Now to the last steps:

git co master

git cherry-pick your_final_commit