There was a debate a few months back on Twitter about 10x developers, if they really exist, what is the definition of such unicorn, or even if 10x developers are only bad developers who look good to some management.
The truth is, if we assume that "effectiveness" can be measured (whatever definition you want to put in that word), without prior assumptions, it will most likely follow a bell curve. You the reader and I the writer are mathematically most likely to be in the middle of the curve. In other words: an average developer.
$P(avg_dev) > P(10x_dev)$
If we, the average developer, want to get more effective, instead of only looking up at highly effective developers, we need to define the characteristics of an average developer. This allows us to overcome the Survivor bias.
In that case, what would be an average developer? Depending on your definition of "effective" it could be:
A developer that makes mistakes regularly, probably mostly stupid errors: forgetting to push a file, adding a typo when fixing another typo, forgetting to refresh the Github page when going through the review comments
An average developer deliver average code: code that does the job but no more, code that doesn't handle most error cases, code that is readable but not necessarily straight forward
An average developer reads, reviews, and edits code written by other average developers: code that should have been refactored 10 years ago, that was designed in a rush for its initial use case and is now stretched out to its inflection point
An average developer works in an average company that doesn't follow every best practice, needs every new feature for yesterday,
A hypothetical human, calling themselves a developer, that shares all the arithmetic mean values of all measurable "effectiveness" metrics over the set of every developer
If you recognize yourself in one of those bullet points, congratulation, you are an average developer! (Spoiler: everybody is average, just select your metric accordingly).
That said, there are heuristics that you can follow to look less average, these tips won't make you make fewer mistakes or make you smarter per se, but following them will help you introspect those biases.
I've tried to make them as practical as possible.
This is probably the most important one, doing pair-coding with junior developers, I've seen so many instances of the following:
*make a change* :wq git add -A git commit -m "Fix typo" git push *Click on re-request review on github*
This is probably the worse thing you can do, 95% percent of the time you will look fast and swift, but in the 5 other percent, you will look like a fool in front of your colleague reviewing your pull request.
Let's break down to a more careful and methodic way to create commits.
The first advice is to never, ever, use
git add -A. With
-A you don't know what you are committing, you could still have a debug statement remaining, forgot to clean up the last issue you were working on, or simply staging files you don't mean to commit.
When you create a commit, not only make sure to know exactly which file you are committing, but also make sure you have read each line before staging them. A great tool to use is
# Short form git add -p # Long form git add --patch
-p parameter allows you to see each patch of a commit you are going to create. This way you know exactly which change you are going to commit, and make sure you read every single line of each patch!
In particular, before adding a patch, look carefully for:
Once you have staged your changes, don't hesitate to have a quick glance at the changes you made with:
# Changes staged for commit: git diff --staged # Changes not staged for commit: git diff
Make sure that you did not forget any new file in the staging area!
Now on to actually create the commit. Here again, I advise against using
git commit -m. Even if
-m is swift, it encourages the developer to write unhelpful commit messages.
Prefer to use
git commit in verbose mode:
git commit -v
When creating the commit message, you will then see the full change that will be created. This serves two functions:
There are already a ton of articles on how to write a great commit message, so I won't spend too much time on that. Basically, those good ideas can be summarized to:
When creating the commit message, especially for trivial changes, resist the urge to set an irrelevant commit title like:
You don't need to have a long commit message with a body each time, especially if the changes are trivial. But try to force yourself to always write a relevant commit message. This might take 5 seconds more than simply writing
fix, but this will save countless times when another team-mate will find the source of a bug in a tree of 10 000 commits.
Here are examples of better commit titles for trivial changes:
scheduler: typo rename actionHander to actionHandler
PROJ-12031 core: simplify deduplicate_str() implementation
TODO: add links to relevant pieces of advice on creating good commit messages
Once your commit is created you can now push your changes with
git push or
git push -u origin <branch-name> if you are creating a new branch.
If you need to push force (after a
git commit -v --amend or a
git rebase) prefer
git push --force-with-lease over
git push --force.
The difference being if the remote branch is different from your local one, git won't override it. This is a great failsafe to avoid overwriting one of your colleagues' work.
If your team is using Github when creating the Pull Request don't hesitate to give a last glance at the diff, seeing your change in another context than your text editor is a great way to catch last minutes typos.
Depending on which language you are developing in, the compiler might not be bundled with static analysis that could catch common pitfalls. For those languages, you might already rely on a linter on top of your test suite.
Linters not only serve the role of catching code errors or style violations, but they are also a great source of information for learning to write idiomatic code.
This article is not about linters (that a topic for another day), however, integrating linting and testing to your git workflow allows you to catch linter errors rather sooner.
Git has a feature called hooks that allows a developer to do actions based on different events. Those events could be creating a new commit, pulling or pushing some changes, etc...
For example, to run your lint suite before each commit:
cat << EOF > .git/hooks/pre-commit #!/usr/bin/env bash exec make lint EOF chmod +x .git/hooks/pre-commit
With this hook, from now on your lint suite will be run each time you create a new commit.
There are some cases when you don't want to run the lint suite. This can be if you know it will fail, or only want to create a temporary commit. You can skip the hook by adding
git commit -v -n
If your test suite is fast enough, you can also add it to a git pre-commit hook.
You might have noticed, all those pieces of advice are here to slow you down and try to give your system 2 more chances to engage. Most mistakes we do are because we are overconfidently relying on our system 1, however, we are only human.
That said, you need to slow down your mind, but not necessarily your fingers. And to avoid that and help build these habits I suggest you create aliases for all those git commands. Here is an excerpt of my shell configuration for example:
# ~/.bashrc alias gs="git status" alias gd="git diff" alias gds="git diff --staged" alias ga="git add --patch" alias gc="git commit --verbose" alias gp="git push" alias gpf="git push --force-with-lease" # Push a new branch: alias gpu="git push --set-upstream origin \`git rev-parse --abbrev-ref HEAD\`"
Note the use of long-form parameters in scripts, this is a great way to self-document each parameter.
Even if code should be written for humans first, the ultimate juge if a piece of code is correct or incorrect is a machine. Proof-reading a code a thousand time, by a thousand human eyes won't change the fact can't prove that the code is correct.
The smaller the change, the more likely you will think it is a trivial, and the more likely you'll do a typo or forget a trivial case.
Spend 5 minutes at the end of your day, before you close your work laptop to write down at least a sentence on what you worked today.
New feature? bug fix? use the Red, Green, Blue technique: