Your development environment has a big influence on how good you can perform as a software engineer. So you should try to optimize it to increase your productivity. This post lays out some strategies on how you could do that.
As a software engineer you probably agree that the most productive time is when you are in that state called flow. Flow allows you to give all your focus to the specific problem you are solving. Flow is a real multiplier of your performance. It is fair to say that when you are programming and not in flow, you are wasting time. You will not get anything significant done compared to being in flow.
As flow is the biggest multiplier of your performance, you should strive to optimize it.
Optimizing for flow
You usually need around 15 minutes to get into flow. A great way to speed this overhead up is listening to music. Music is a great catalyst for flow
When you are already in flow the biggest issue you are having is to stay in flow. Once you get interrupted you have to waste 15 minutes again to get back in flow. So make sure you will not get interrupted when you want to get something done. This includes putting the internet and your smartphone on stand-by. Also make sure email is turned off.
Try to allocate a single slot of multiple hours for programming. Three one-hour sessions are not as effective as a single 3 hour session. Make sure meetings are allocated around your programming sessions and not in between your programming sessions.
If your application always needs 30 seconds to build you will get distracted during these 30 seconds. Distraction is a flow killer, so make sure you get feedback as fast as possible. This means fast build times or - even better - live reloading. Slow feedback can really destroy your performance, so make sure you are never waiting for your computer. The computer should wait for you, not the other way around. Remember that computer time is cheap, human time is not.
This also includes unit and functional tests and other common tasks. These processes better be fast, otherwise you are getting distracted. If the unit tests are not running fast you will just push your commits. You will let the CI server run the tests in the background, in the meantime you will switch branches. Five minutes later the CI is reporting back: The tests are failing. But you are already working on something else. Now you have to switch back the context and fix the bug. With fast tests you can save the time of these context switches.
As your project gets more complex you will inenvitable introduce some processes. Some of these are automated (e.g. running CI before merging a commit), some others are not.
A great way to increase productivity is to transform the non-automated processes into automated processes.
bundler need to be updated after you have changed the
If these tasks cannot be done by running a single command, these are not automated processes. They are very human error prone: if a developer forgets about one step he might get stuck. For example when not running
bundler before starting your ruby application, the application might crash because some library is missing. Then he might get stuck and lose flow. By automating these processes (e.g. with a build system like
gulp) you will make these errors impossible by design.
Make sure your processes actually work. When your CI server randomly let’s the tests fail, people will not trust the CI server anymore. Then the whole process is needless.
When some of your automated processes requires a specific tool to be installed, make sure the error message shown when the tool is not installed is not a show stopper. Let’s say you have a git hook running facebooks flow type checker before you can commit. When the tool is not installed you will get something along the lines of
zsh: command not found: flow. This is not helpful, it will not tell the developer how to proceed. Error messages should always help the user to recover by providing a possible solution. In our example we could just show an error like
flow binary not found: Just execute 'brew update && brew install flow' and you can proceed to help out. So before running the
flow tool we just run
which -s flow || (echo "flow binary not found: Just execute 'brew update && brew install flow' and you can proceed" && exit 1) which will print out the error message and exits when the
flow binary is not in the
Debugging is wasting time
As an engineer your goal is to build a great application. So when you are debugging you are not moving closer to the goal of getting it done. A good way to increase productivity is to make bugs impossible by design. It’s not possible all the time, and sometimes debugging is necessary, but many bugs can be avoided.
Let’s say we have a function
findUser which finds a user by id and returns it or returns
null if the user cannot be found. An example call in php could look like this:
Do you see the mistake? The code will fail when the user cannot be found because then the value of
null. The php interpreter will say the error has happend on the
$user->getName() call, altough the error is caused by not handling the error case somewhere above. You now have to find the real root cause (not handling the error case above) of this bug first, before you can fix it. With exceptions you could have avoided this. Just let
findUser throw an exception and use a generic not-found-error handler somewhere at the entry point of the application. Then the
null-check cannot be forgotten by humans because there is no need for it. We have successfully avoided bugs here by design. Take a look on how this looks in real world code if you are interested.
Another good way to avoid debugging is to place some
asserts in your code. Debugging is a process in which you validate your hypothesis of what the state of your program should be against what it really is, so why not write down these hypotheses in form of
The key goal of a great development environment is to increase your flow time. You can archieve this by removing distractions and possible source of interruptions. Make sure your processes are as automated as possible to avoid human errors. Make sure your tools and processes are fast and actually work. Make sure your error messages are helpful. Avoid bugs by design to avoid spending too much time on fixing them.
Thanks for reading :) Follow me on twitter if you’re interested in more of this stuff!
If you want to read more about flow check out my friend Alex Gonçalves blog post, which is a response to this post.
 Obviously this is designed for just one package manager. Just pick the package manager you are recommending to your junior developers. More experienced developers will just use their favorite package manager of choice when they read this error message.
 Take a look at the manual of
which. It’s really helpful for tasks like this.
If you liked this post feel free to subscribe to my mailing list.