Jake McCrary

Using Bash-Preexec for monitoring the runtime of your last command

My article on putting the runtime of your last command into your bash prompt is one of my most surfaced-by-google articles. Why is this a great to your prompt? To quote my previous article:

I’m fairly certain the following scenario has happened to every terminal user. You run a command and, while it is running, realize you should have prefixed it with time. You momentarily struggle with the thought of killing the command and rerunning it with time. You decide not to and the command finishes without you knowing how long it took. You debate running it again.

For the last year I’ve lived in a world without this problem. Upon completion, a command’s approximate run time is displayed in my prompt. It is awesome.

I’ve been living without the above problem since sometime in 2014 and not having that problem is still awesome.

I have made some changes since 2014.

One change was switching to using Bash-Preexec instead of directly using trap and $PROMPT_COMMAND for calling functions to start and stop tracking runtime. Bash-Preexec lets you trigger a function (or multiple) right after a command has been read and right before each prompt.

The usage is pretty straight forward. In the most basic case, you source bash-preexec.sh and then provide functions named preexec, which is invoked right before a command is executed, and/or precmd, which is invoked just before each prompt. bash-preexec.sh can be downloaded from its repo. The changes required to move to Bash-Preexec pretty pretty minimal.

The other change was introducing the script, format-duration by Gary Fredericks, to humanely format the time. This script converts seconds into a more readable string (example: 310 to 5m10s)

Here is a screenshot of everything in action (with a reduced prompt, my normal one includes git and other info).

Command line prompt showing runtimes of previous commands

Below is a simplified snippet from my .bashrc that provides runtimes using both of these additions.

preexec() {
  if [ "UNSET" == "${timer}" ]; then

precmd() {
  if [ "UNSET" == "${timer}" ]; then
    the_seconds=$((SECONDS - timer))
    # use format-duration to make time more human readable
    timer_show="$(format-duration seconds $the_seconds)"

# Add $last_show to the prompt.
PS1='[last: ${timer_show}s][\w]$ '

# a bunch more lines until the end of my .bashrc
# where I include .bash-preexec.sh
[[ -f "$HOME/.bash-preexec.sh" ]] && source "$HOME/.bash-preexec.sh"

No more wondering about the runtime of commands is great. Introducing format-duration made reading the time easier while Bash-Preexec made reading the implementation easier. I highly recommend setting up something similar for your shell.

A retrospective format for remote or co-located teams

See all of my remote/working-from-home articles here.

Retrospectives are a useful type of meeting to have periodically with your team. There are many different formats of retrospectives.

One of them can be summarized in the following steps:

  1. Gather the team together
  2. Set the stage
  3. Brainstorm answers to the questions What went well? and What needs improvement?
  4. Discuss the answers

Let’s talk about each step and see how each works with an co-located or remote team.

Step 1: Gather the team

This step is self explanatory. If you are an in-person team, then this is gathering everyone together in a room for some allotted about of time. If you are a remote team, or have remote folks on your team, then this is gathering everyone together in a video conference.

Preferably everyone in the retro is communicating in same way. This means if anyone is remote, it is preferable that everyone join the video conference from their own computer instead of using a single screen and video from a shared conference room. My earlier article about tips for remote meetings goes into more details on this topic.

Everyone using the same communication method puts everyone on the same page and dramatically improves the experience for the remote folks. With a mixed group, we’ll want to use some remote collaboration tools anyway, so it is useful for everyone to have their own computer with them. They might as well use it for video communication as well.

Step 2: Set the stage

This part doesn’t differ between an entirely in-person meeting, mixed, or entirely remote meeting.

Take the time to set the stage for the meeting. Remind everyone that we’re here to improve and to listen with an open mind. Remind everyone to try to not make things personal and not take things personally. This is a good time to read the Prime Directive.

This is also a good time to set the boundaries of the discussion. What is the retrospective covering? Is it covering the last few weeks? The last quarter? The new working from home experience? Pick a topic so everyone in the meeting focuses on the same things.

Step 3: Answer the questions

In this step, we will answer the questions What went well? and What needs improvement? and use those answers for discussion in the remainder of the meeting. Timebox this step to 5 to 10 minutes.

In an in-person setting, this is often done through the use of Post-it notes. Give each attendee a marker and a stack of notes and have each person write down as many answers as they can come up with, one per post-it note, to the two questions. Dedicate a section of a whiteboard or wall for each question and have people bring the generated answers to the respective sections. Try to group the answers by topics.

With a remote meeting, you don’t have the physical whiteboard and cards. That is perfectly fine! Once you figure out your remote collaboration tools, this part of the retrospective isn’t difficult.

I’ve mostly done remote retrospectives using Trello. Trello works great for this as it is multi-user and does a great job of presenting lists to a group. Here is how previous teams I’ve worked with setup Trello for remote retrospectives.

First, make a Trello board and make sure everyone has an invite to view and edit the board. Second, add the following columns to the board.

First three columns before any cards

The first column is for Step 2 of the process and is there to remind everyone why we’re all spending time in this meeting.

Columns two and three are used in this step. Have attendees add cards to these columns as they come up with answers If anyone notices duplicates during this time frame, move them near each other by dragging them up or down in the column. If you notice someone else has already put a card that you’d put up there, don’t bother putting it down again (this differs from the in-person meeting).

First three columns with cards before voting

[remote only] Step 3.5: Vote on cards

This step sneaks into the remote retrospective and is missing from the in-person retro. In the in-person retro, duplication of post-it notes serves as this voting stage.

Once all the answers have been generated, or time is up, it is time to vote on what will be discussed in the next step. Only have people vote on the What needs improvement? answers.

There are at least two ways of doing this in Trello but my favorite is having attendees hover their mouse cursor over the card and then hit space bar1. This sticks their avatar on the card (in Trello speak, I believe this is called joining a card). You can either restrict folks to a certain number of votes, say 3, or let them go wild and vote as many times as they want. I haven’t found the outcomes to be much different and find infinite votes more fun.

First three columns with votes

Once voting is finished (again, timer or when it seems to have reached an end), have one person sort the cards by number of votes with the highest votes at the top of the list.

First three columns with cards sorted by votes

Step 4: Discuss the answers

With in-person or remote retros, go over the answers to What went well? first. This starts the discussion with positive feelings. This part usually goes pretty fast as we’re just celebrating wins and not having a long discussions about them.

Next, start discussing the answers to What needs improvement?

For each topic being discussed, set a five minute timer. At the end of the five minutes, do a quick poll of the attendees on if the topic should be continued or not. If it should be continued, start a three minute timer and continue discussion. At the end of those three minutes, repeat the vote for continuing or not.

Throughout the discussion, try to be mindful of people dominating conversation and give everyone a chance to voice their thoughts. Try to figure out some next steps to take to actually start making improvements on what needs to be improved.

The above is generic advice for remote or in-person retros. When you’re running a remote retro using Trello, it can be useful to do the following as well.

You should add two more columns, Next Steps and Discussed, to the right of the What needs improvement? column.

Additional columns added to board

Since your cards are sorted in the What needs improvement? column, you’ll always be talking about the top card. As discussion finishes, move it from the top of the What needs improvement? column into the Discussed column. As Next Steps are discovered, add cards to the Next Steps column and assign the people responsible for following up to the card. Below is an example of those three columns after discussing two cards.

Final state of last three columns

When voting on continuing discussion or not, it can be useful to have a hand signal for taking the vote and for continuing or ending the discussion. We’d do a quick thumbs up or thumbs down and if half the team wants to keep going then we’d seamlessly start the next timer.


Retrospectives can be a very handy tool for a team’s continuous improvement. If time isn’t provided for reflecting, then reflecting does not happen and this makes improving harder.

Remote retrospectives provide a challenge since most of us only have experience using physical sticky notes or whiteboards for collecting answers. We don’t need to recreate the same form factor for remote retrospectives. Using remote collaboration tools, such as Trello, that don’t recreate the sticky-note-on-wall experience can lead to initial confusion but, once familiar with them, the experience is pleasant and allows for greater participation.

How is participation increased? Well, in an in-person retrospective you often are unable to read what everyone else has stuck up on the wall because of physical distance. With a remote retro, you’re able to read every answer added to the lists.

Don’t be afraid of running a remote retrospective. They can be incredibly useful.

  1. The alternative method I’m aware of is to use a Trello Power-up to enable voting on cards. But why bother doing this when you can just stick faces on cards.

More working from home tips

See all of my remote/working-from-home articles here.

With the the new coronavirus spreading through the world, more people are either choosing or are being forced to work from home. From 2013 to 2018, the companies I worked for were entirely remote. For the rest of my professional career, 2007 to 2013 and 2018 to now (March 2020), I’ve also frequently worked from home.

I’ve managed to be very effective at it and I think others can be as well.

After years of working in an office, transitioning to working from home isn’t easy. I had difficulty with the transition and people I’ve mentored have as well. I think most people will be able to be effective at home, assuming their workplace is supportive, if they try to get better at it. With a supportive company or team, once you get used to working from home you probably find yourself getting more done.

The key word in the sentence “I’m working from home” is working. You are going to be working where you spend a lot of your non-work time. This can be a difficult mental transition. Physically switching to an office environment can help switch your brain into work mode and now you no longer have that. Don’t worry, it might feel rough in the beginning but you will get better at it.

I’ve written more articles about working remotely and I’d recommend you read those as well. This article is primarily targeted at the person not making a permanent change in their work from home status. My Guide to Distributed Work is a bit more targeted at someone that is permanently choosing to work at home or in a position of power to influence work from home policies at a company. I’d recommend that you read it as well as many of the subjects it talks about are generally applicable. It steps through some of the pros and cons of remote work and links to other writing on the topic.

Below is a hodgepodge of tips for working from home.

Setup a home workspace

In my years of remote work, I’ve always managed to have a dedicated space for work. In some apartments, this was a corner of a room where I put a desk and faced a wall. In other apartments, I’ve been privileged enough to have a dedicated room for an office.

If you aren’t planning on working from home permanently, or very frequently, then you probably don’t want to spend a significant amount of money setting up a work area. This probably means you don’t want to find a home with a dedicated office and you may not want or be able to dedicate a portion of a room to a desk1.

Whatever your living arrangement is, I’d encourage you to figure a way to have a regular spot to work at while you are working. Having a regular spot to work from will help your brain turn on and off from work mode.

Setting up a home workspace can be as low cost as using a tv tray or folding table2 with a chair. Your setup could be as elaborate as getting a height adjustable desk with large monitors. It could be something else entirely.

Find something that works for you and stick with it.

Beyond a dedicated space to work, make sure you have a reliable internet connection. If you can, use Ethernet as it is generally better than WiFi. I’ve never had a situation where I could use Ethernet and have found that having a good router is enough to make my WiFi reliable.

Discuss boundaries and expectations with your cohabitants

If you live with others that will be at home while you need to work, you should have a discussion with them about boundaries. You are at home to do work and that expectation needs to be set. You may be able to do some household chores during breaks or take other breaks with cohabitants but everyone in your living area needs to understand you are at home to work.

If you have children that might have a particularly hard time with this, it can be useful to use some sort of physical signaling device (examples: a closed door, a light bulb being on, a closed curtain, headphones on) that you should not be interrupted.

Minimize distractions

This one is obvious but try to minimize distractions. Don’t try to sit on your couch with the TV on and do work. You won’t be doing great work.

If your home is loud and you have difficulty in a loud space, wear some ear plugs or noise canceling headphones.

If cohabitants are distractions, refer to the above section and have that discussion with them about needing space. One technique for dealing with interrupting cohabitants is to schedule time throughout your day for them. You can use these scheduled times as breaks through out your working day.

If you try to get some household chores done while working at home, make sure you schedule time for doing them. This could be putting the time on your calendar or simply setting a timer when taking a break. Regardless of the method, when your time is up, get back to work.

I’ve often found that finishing a short, simple household task can actually jump-start finishing more complicated work tasks. Using that momentum from the household chore can make accomplishing work tasks easier.

Having difficulty starting a work task?

Sometimes it is hard to start a task. It can be especially hard if you are new to working at home and not used to working in your environment.

One technique I’ve found useful is the Pomodoro technique. The steps to this technique are below.

  1. Pick a task.
  2. Set and start a timer (usually for 25 minutes).
  3. Focus intensely on the task for the duration of the timer.
  4. Make a mark on a piece of paper
  5. If you have fewer than four marks on the paper, take a 5 minute break and then go back to step 2.
  6. If you have four marks on the paper, then take a 15 minute break and go back to step 1.

I don’t follow those steps strictly and mostly use the trick of setting a timer for focused work. If at the end of the timer I feel like continuing, I’ll reset the timer. If I need a break, I’ll set the timer for a short period of time and take a break.

It was mentioned above, but sometimes doing a small, easy task can jump-start knocking out TODOs. This small, easy task could be something work related or some simple chore around the house.

Be mindful of your communication

Text communication is hard. It is often taken more negative than intended. Be mindful of that.

Try to take what your coworkers write in the most positive way possible.

Try to be careful with your own written communication. It sounds ridiculous but emojis can help make you look like less of a jerk and set a friendly tone.

Don’t hesitate to jump on a video or voice call with someone (or a group). Video is a much higher quality interaction than voice and both are much higher quality than text. The downside is the communication isn’t persistent so be sure to write down outcomes of conversations.

Sync up with your team

Try to sync up with your team (if you don’t have a team, sync up with someone else from the company) at a regular interval. This should probably be at least once every couple days but it can be more regularly. I usually once a day.

It can be easy to feel like an island when you are part of a remote group. Regular sync-ups help reduce that feeling.

Collaborate remotely

Most video conference software allows you to share your screen with others. Some of them even allow others to take control of your machine or treat your screen as a whiteboard.

Take advantage of these features. After learning how to use them, these features can often make remote collaboration as productive as in-person collaboration.

Using technology, you can even pair program with someone from another city.

Google Docs is another great remote collaboration tool. The best meetings I have been part of were meetings where every attendee was editing a shared Google Doc.

Video Meetings

When possible, have video meetings over voice only conference calls. The addition of body language through video makes remote conversations much better.

You might want to introduce hand gestures for signaling during video meetings3. On a former team, we had the practice of raising a finger4 when you wanted to speak. This practice helped prevent people from interrupting and speaking over each other. It also let quieter people jump into conversations easier.

As far as I can tell, Zoom is still the winner in terms of video conferencing.

I also recommend using a headset with dedicated microphone for talking through your computer. The sound quality is usually better than using the built-in microphone.


It can be difficult to get good at working from home. It is definitely a skill that is learned through experience and reflection. If you have any questions about working remotely, feel free to reach out on twitter or through email.

Working from home can be a great experience.

  1. A desk can be any table that you can work on that is comfortable for a reasonable amount of time. It doesn’t have to be what someone would typically think of as a desk.

  2. I used a table like this for years in college and when working an internship.

  3. These are also useful for in-person meetings.

  4. No, not the middle finger.

Auto-syncing a git repository

I’m currently keep notes on my computer using plain text and Org mode.

I keep my notes in a git repository in my home directory, ~/org/. I want my notes to be synced between my computers without me thinking about it. Historically, I’ve reached for something like Google Drive or Dropbox to do this but this time I reached for git and GitHub.

Below is the script that I ended up cobbling together from various sources found online. The script pushes and pulls changes from a remote repository and works on my macOS and linux machines.

The loop starting on line 38 does the work. Whenever a file-watcher notices a change or 10 minutes passes, the loop pulls changes from a remote repository, commits any local changes, and pushes to the remote repository. The lines before this are mostly checking that needed programs exist on the host.

I keep this running in a background terminal and I check periodically to confirm it is still running. I could do something fancier but this isn’t a critical system and the overhead of checking every couple days is nearly zero. Most of the time checking happens by accident when I accidentally maximize the terminal that runs the script.

I’ve been using this script for a long time now and I’ve found it quite useful. I hope you do too.


set -e


stderr () {
    echo "$1" >&2

is_command() {
    command -v "$1" &>/dev/null

if [ "$(uname)" != "Darwin" ]; then
    INCOMMAND="\"$INW\" -qr -e \"$EVENTS\" --exclude \"\.git\" \"$TARGETDIR\""
else # if Mac, use fswatch
    # default events specified via a mask, see
    # https://emcrisostomo.github.io/fswatch/doc/1.14.0/fswatch.html/Invoking-fswatch.html#Numeric-Event-Flags
    # default of 414 = MovedTo + MovedFrom + Renamed + Removed + Updated + Created
    #                = 256 + 128+ 16 + 8 + 4 + 2
    INCOMMAND="\"$INW\" --recursive \"$EVENTS\" --exclude \"\.git\" --one-event \"$TARGETDIR\""

for cmd in "git" "$INW" "timeout"; do
    # in OSX: `timeout` => brew install coreutils
    # in OSX: `fswatch` => brew install fswatch
    is_command "$cmd" || { stderr "Error: Required command '$cmd' not found"; exit 1; }


while true; do
    eval "timeout 600 $INCOMMAND" || true
    git pull
    sleep 5
    STATUS=$(git status -s)
    if [ -n "$STATUS" ]; then
        echo "$STATUS"
        echo "commit!"
        git add .
        git commit -m "autocommit"
        git push origin

Reading in 2019

At the beginning of every year I reflect on the previous year of reading. I take a look at my records, fix errors, and think about reading goals for the upcoming year.

Here are links to my previous end-of-year reflections: 2013, 2014, 2015, 2016, 2017, and 2018.

I’ve continued to keep track of my reading using Goodreads. My profile has nearly the full list of the books I’ve read since 2010. This is my 2019.

2019 Goal

I have a stack of software and process books and I’d like to read through at least some of them (others are more reference books). I’m also going to bring over the 2018 goal of reading at least one book on writing. In a more general sense, I’m hoping to put some practices together that help me gain more from the books I’m reading. I’m still thinking through what that means. - Me last year

That was my goal for 2019. In list form it looks like this:

  1. Read some software or process books
  2. Read at least one book on writing
  3. Try to develop practices for getting more from books I’ve read

I read eight books related to the first goal and two (or three if I count an iffy one) related to the second. That is enough where I feel pretty good about claiming I accomplished the first two goals.

I mostly failed on the third goal. I was more aggressive about highlighting notes in my Kindle and I did occasionally look back at them. Beyond that I didn’t do anything.


Here are my five star books from 2019. The titles are affiliate links to Amazon, so if you click one of those and make a purchase I get a small kickback1.

Accelerate: Building and Scaling High-Performing Technology Organizations by Nicole Forsgren, Jez Humble, and Gene Kim

This is a stellar book on practices of technology organizations that help build high performing companies. If you work at a company that produces software in any capacity, I’d highly recommend this book. This is a book that I’ve recommended to any coworker looking, and some not looking, for book recommendations.

Elements of Clojure by Zachary Tellman

This book has Clojure in the title but it is applicable to more than that language. The book was published a section at a time and as a result I’ve read parts of it many times. The content clearly shows that Zach has put a lot of thought into the topic.

A Tour of C++ by Bjarne Stroustrup

I’ve written C++ off and on since I started programming nearly 20 years ago. Over those years, I’ve seen C++ transform as new versions were released. Earlier in 2019, I was starting to write C++ again and this book was recommended by a coworker. I had last written C++ back in 2013 and this book was a perfect way to refresh my stuck in early 2013 knowledge. There is no fluff in this book and it is full of useful information.

Developer Hegemony: The Future of Labor

This is a tough read. It isn’t tough because of difficult writing. It is tough because it makes you depressed until you power through and reach the end.

This book delivers a very cynical look at corporations. It provides guidelines for getting ahead and climbing the corporate ladder.

Then the book promotes an alternative approach, that of doing your own thing and going independent. It makes a good case of it.

Beware of this one, it might make you question what you are doing with your career and life.

Digital Minimalism: Choosing a Focused Life in a Noisy World by Cal Newport

There is a common theme of awareness throughout many of the books I read and this book hits that theme. This book can help you become a more thoughtful user of technology. There are many useful recommendations in this book. One of them is the suggestion that you can use social media and other technology differently than how the creators want you to use it. In 2019 I wrote about how I use social media which shows how I apply this idea.

Effective Java by Joshua Bloch

I’ve read earlier editions in the past and decided to read the latest edition when it seemed like I’d be writing Java again. This book is still good and a must read if you work with Java.

21 Lessons for the 21st Century by Yuval Noah Harari

This book covers a lot of ground.

Here is a quote from my friend Steven Deobald about this book.

Through stories and anecdotes woven into his almost unbelievably extensive research as a historian, “21 Lessons” is perhaps as entertaining and insightful as any other book I’ve read. It is accessible to anyone and the ideas presented regarding the fate of our species are stitched together beautifully. The arc of the 21 chapters has a progressive, almost orchestral, quality to it. Each chapter builds on all those which precede it and although some chapters have surprisingly variable writing styles, none feels like Harari is attempting to showboat or to force his medium into the overly artistic.

Draft No. 4: On the Writing Process by John McPhee

This was a pleasure to read. I like reading books about writing and this is a good one that talks about McPhee’s approach towards creative non-fiction.

The Push: A Climber’s Journey of Endurance, Risk and Going Beyond Limits by Tommy Caldwell

What can I say? I’m a sucker for books on climbing and learning more about the icons of the sport I love. If you’ve watched the movie The Dawn Wall then some of this will be familiar to you.

The Nickel Boys by Colson Whitehead

This is a great book. Go read the Goodreads page and pick it up.

The Great Believers by Rebecca Makkai

A friend of mine gave me a copy of this book and I’m glad she did. It tells the story of the AIDs epidemic in Chicago. This is a great piece of writing. I’m not surprised at all that it has won many awards.

The Bonfire of the Vanities by Tom Wolfe

This book is great. The satire just drips off the pages. There are passages in this book where you can just feel the anxiety of the characters.

Every character is despicable and it is wonderful.

The Paper Menagerie and Other Stories by Ken Liu

This was my second time reading this book. It is an excellent collection of short stories.

The first time I read this book, in 2016, I read the stories in order. This time I took advantage of the Kindle’s estimate of how long a chapter would take and I jumped around, picking out stories that fit how long I wanted to read. Both ways of reading this collection were excellent.

Exhalation: Stories by Ted Chiang

I absolutely loved Ted Chiang’s Stories of Your Life and Others and was excited when this collection of stories was published. I had high hopes for this collection and I was not disappointed.

Some of the stories I had read prior to them being included in this collection but that didn’t matter. I enjoyed reading the new stories and revisiting the previously published ones.

We don’t normally think of it as such, but writing is a technology, which means that a literate person is someone whose thought processes are technologically mediated. We became cognitive cyborgs as soon as we became fluent readers, and the consequences of that were profound.

That is a quote from a story in this collection. It felt right to include it in an article about reading.

Golden Son, Morning Star, Iron Gold, and Dark Age by Pierce Brown

The four titles above are books two through five in Pierce Brown’s Red Rising saga. I also read the first book in the series, Red Rising, in 2019 but it only earned a four star rating from me. I obviously enjoyed this series and devoured it.

The books tell the story of a world full of inequality. The world created is full of interesting characters and dilemmas.

Animal Farm by George Orwell

This was either my second or third time reading Animal Farm. It is still good. Reading it in 2019 and mapping in book behavior to the modern political climate was interesting.

Non-Five Star highlights

Irresistible: The Rise of Addictive Technology and the Business of Keeping Us Hooked by Adam Alter

Yet another book that is at least somewhat about awareness. This book talks about behavioral addiction but not just addictive technology.

Is it the single book out of the handful of books I’ve read in this space that I’d recommend? No, but it is a good addition to my collection on the topic.

Permanent Record by Edward Snowden

I consider myself fairly knowledgeable about Snowden and what he did but I still learned more through this book. One part I particularly enjoyed was Snowden reflecting on what has changed since his actions.

Another part I particularly enjoyed was Snowden’s telling of the early Internet. This was an Internet where identities online weren’t necessarily tied to a real one. I’m approximately the same age as Snowden and had similar experiences with being a young person during the early Internet days. It was interesting to be reminded of that time while reading this book.

I highlighted a lot of passages and there are probably more I should have highlighted.

Atonement by Ian McEwan

This book was so close to being five stars. I started reading this book because I mistook the title for that of a science fiction book I’ve been intending to read. I’m glad I did.

It took me a little while to get into the book but once I did I was hooked.

Here is a review from one of my friends that captures some of what I felt about this book.

I Hear You by Michael S. Sorensen

It provides some guidance towards being a more validating person. The book is short and to the point. I’ve managed to take some of its advice and I think it has been useful.

Recursion by Blake Crouch

This was really good. It is action packed and an interesting concept.

Version Control by Dexter Palmer

I really enjoy this book. It tells the story of a relationship with bits of science fiction. I really enjoyed my friend Dan’s review.


The page count numbers for 2019 books are a bit screwed up so I’m only doing a books per month graph this year.

Book and pages count by month

Unsurprisingly, electronic books continue to be the dominate format.

|           | 2019 | 2018 | 2017 | 2016 | 2015 |
| ebook     |   43 |   37 |   37 |   56 |   47 |
| hardcover |    1 |    1 |    7 |    0 |    1 |
| paperback |    7 |    5 |    5 |    3 |    3 |

This year I read a noticeably higher amount of non-fiction books than in 2018.

|             | 2019 | 2018 |
| fiction     |   28 |   29 |
| non-fiction |   23 |   14 |

2020 Goals

I was encouraged by how many non-fiction books I read this year and how many of them ended up earning a five star rating. I’d like to continue that trend of reading high-quality non-fiction books.

I’ve also been reading a lot of books but I haven’t always been the best at trying to consciously apply the lessons from those books. I’m going to try to improve that this year.

Those are pretty fuzzy goals but I’m alright with that.

  1. I’m not really sure why I bother doing this. I’d write these posts without this incentive and I think my lifetime earnings are maybe in the double digits.

Building an Atreus keyboard

I recently built an Atreus keyboard. This keyboard is an extremely small keyboard with only 42 keys. Below is the photo of my result.

My completed Atreus keyboard

As you can see, it has a split layout and the keys are aligned vertically and staggered. Thanks to using Ergodox keyboards since 2014, I’m very used to this key layout and find it superior to traditional keyboards.

The keyboard is very small. To give you an idea of how small it is, here is a photo of it next to one of my Ergodox keyboards and with a bit of my fingers in the shot.

Atreus size comparison

Building the keyboard was pretty straight forward. The included instructions are thorough and include plenty of photos. All of the components are through-hole so the soldering is not difficult. This would be a good first keyboard project.

I already had USB cable, key switches, key caps, and a micro-controller so I purchased the partial kit from Phil. It came with everything else, except for something to coat the wood, that you need to build the keyboard. I wanted to connect the keyboard to USB C ports, so I used a micro to USB C cable.

I enjoyed the color of the laser cut wood and appreciated the burn marks. I didn’t want to lose the color or burns so I coated the wood with a water based clear polyurethane with a satin finish. This was probably the most difficult part of the build, and it was pretty easy, simply because I lack experience finishing wood.

When reading other build logs I noticed that someone else put a zip tie on their USB cable to help prevent it from tugging on the micro-controller. I have no idea how helpful this is but it seemed like a good thing to do so I also did it. To do this you basically just wrap the cable with a zip tie and cram it against the case so that the zip tie prevents tugging on the micro-controller. You can see it in the picture below.

My completed Atreus keyboard

I’ve only been typing on the keyboard for basically this blog post but I’ve already found myself adapting to it pretty quickly. I don’t intend for it to replace my Ergodox for normal usage but I think it will be a great portable keyboard.

Overall it was a fun project and I’m glad I did it. I look forward to customizing the firmware to make the key layout fit my usage.

Building a Onewheel stand

I’ve owned a Onewheel XR for about a year now. It is a one-wheeled electric skateboard-like device that is super fun for zipping around Chicago.

When I first got it, I purchased a small guitar stand. It worked but it was always a bit finicky and I was never satisfied with it. I had to sit the Onewheel on it just right to have it stay on it without causing the legs of the stand to spread too wide.

This resulted in me buying a second guitar stand and trying that out. This one was even worse.

I grew frustrated with these non-purpose built stands and started looking into purchasing a Onewheel stand. There are plenty of beautiful stands out there, both officially from Future Motion and from third party vendors like The Float Life.

Then I remembered that my old coworker, Tom Marsh, built his own and put the plans online. This inspired me to go the DIY route.

I thought that a stand made out of pipe would look pretty good and be easy to construct. It also gave me a good excuse to ride my Onewheel to Home Depot.

I explored the plumbing section of Home Depot and bought a variety of pipe and pipe fittings and took them back home to experiment with putting them together.

I ended up building the stand below.

onewheel pipe stand

onewheel in pipe stand

I think the above stand looks great and it was easy to build.

Here is the part list:

  • 2 ½ inch x 8 inch nipple
  • 1 ½ inch x 6 inch nipple
  • 2 ½ inch x 3 inch nipple
  • 2 ½ inch 90 degree elbow
  • 2 ½ inch 3-way side outlet
  • 2 ½ inch cap

I washed off the black coating using Goo Gone and then assembled the stand. This ups the risk of rust but I think that might actually look cool so I’m not too worried about it. You could optionally coat the pipes for some protection.

Once you have the parts the assembly is very straight forward. The only additional work I might do is to put some rubber feet on the bottom to prevent scratches to my floor.

Switching my Ergodox to QMK firmware

Last fall I started to work in an office again. I’ve used a hand-built Ergodox for years now and really prefer working on it. This meant I needed another ergodox for the office. Luckily, now you don’t have to build your own. I bought an Ergodox EZ1.

The Ergodox EZ uses the QMK firmware. This has a lot of fancier options than the firmware I had been using on my hand-built ergodox.

This mostly didn’t matter and I just configured the Ergodox EZ to match my original Ergodox’s layout. Then I started a new job and found myself programming in Scala using IntelliJ IDEA.

Shockingly, after not using IntelliJ for years, I still remembered many of the keyboard shortcuts. This was great! Unfortunately, in my years since last using IntelliJ, I created some conflicting keyboard shortcuts for managing my window layout. These were mostly shortcuts that involved holding Command + Alt and pushing an arrow key. Luckily, the QMK firmware supports a Meh key.

What is the Meh key? It is a key that presses Control + Alt + Shift all at the same time.

This is great for setting up shortcuts that don’t conflict with ones found in most normal programs. This let me change my window manger shortcuts to use the Meh key and I was then conflict free.

I can’t handle having different shortcuts across different machines with the same OS, so I needed to needed to update my original Ergodox to use the QMK firmware so I could also have a Meh key at home. Luckily, the QMK firmware also works on it and, maybe even more luckily, the Ergodox EZ firmware just works with my original Ergodox.

This actually means I can simply take the compiled Ergodox EZ firmware and flash it straight to my Ergodox. Any time I’ve done this the keyboard keeps working.

Unfortunately, the LEDs in my original Ergodox are mostly hidden by non-translucent keys. These LEDs indicate when I’m not main layer and I find them really useful. I only have a single translucent keycap and would prefer only that LED to be used.

Here are the steps I took to make that change.

  1. Use the graphical QMK Configurator to visually configure my keyboard layout. In the Keymap Name field, put jakemcc.
  2. Click the Compile button in the above configurator.
  3. Download the full source.
  4. Unzip the source and edit qmk_firmware/keyboards/ergodox_ez/keymaps/jakemcc/keymap.c to include snippet of code below this list.
  5. In qmk_firmware run make ergodox_ez:jakemcc.
  6. Find ergodox_ez_jakemcc.hex and flash my original Ergodox.
uint32_t layer_state_set_user(uint32_t state) {
  if (biton32(state) == 0) {
  } else {
  return state;

This snippet gets added to the bottom of the keymap.c. It only turns on led 1, which is the one under my translucent key, whenever my keyboard isn’t on layer 0.

Now, I can use the fancy Meh key to be conflict free and easily tell when I’m not on my main layer. This is wonderful.

  1. I bought one with Cherry MX Clear switches. I’ve since switched them to Cherry MX Browns. The clears were too firm for me. I did not get Cherry MX Blues because I didn’t want my fellow coworkers to be annoyed by the glorious clickty-clack of those switches.

How I use social media

Over the years, I’ve read many articles about the negative aspects of social media. You’ve probably read articles extolling the benefits of cutting social media out of your life. These articles are abundant and easy to find through a search for “stop social media” or “quit social media”.

Social media hasn’t played a significant role in my life for a couple of years. I first started being more mindful of how I consumed social media in 2013. Back then, I temporarily switched to using a feature phone (a non-smart phone) for a month and a half. This really reset my relationship with consuming media on a phone. Since my phone was my primary entry point into Twitter and Facebook, my usage of both plummeted.

Since then, I’ve continued to take a careful look at how I use social media and have made tweaks to get maximum enjoyment with minimal downsides. This has involved changing how I use the desktop web applications for both Twitter and Facebook1.

The following books have helped shape my thinking towards digital distractions. They’ve put into words some of the practices I stumbled into. They’ve affected how I use smart phones and how I approach social media.

One of the ideas in both Digital Minimalism and Essentialism is that you can pick and choose what you add to your life. This extends to individual features of products you use. This is something I arrived at prior to reading these books and it was nice hearing others putting this idea into words.

Below is how I’ve chosen to use various social media platforms.


I only consume Twitter on my computer and I read it through Tweetdeck.

I don’t check my entire feed. Instead, I have Tweetdeck setup to display a few curated lists of accounts along with mentions and direct messages. One list is composed of close friends, another highlights some people in the software development space, and another contains some Twitter art projects.

Because I focus on a limited number of accounts, I don’t have an infinite list to scroll through. This focus keeps Twitter useful to me and allows me to check it every few days and still stay up to date on topics I care about.

I rarely tweet but when I do it is usually to promote my own or another person’s writing. I also occasionally tweet as an art bot.


I only consume Facebook on my computer and mostly stopped using the website in 2016. The 2016 US presidential election made me realize I didn’t find the Facebook news feed useful. It did not add positive value to my life.

That is when I found the News Feed Eradicator Chrome extension. This extension gets rid of the news feed. It is great.

Without the news feed, I no longer open the site and mindlessly scroll through the firehose of updates. I no longer know what is going on in the curated lives of my friends that still use Facebook. That is ok. Now when I run into them in real life, I can catch up and learn about their kids and their lives. I can have an honest reaction to learning that someone got married instead of sort of already knowing it. Someone can tell me about a trip they took and can show me photos I’ve never seen before.

I haven’t completely deleted my Facebook account because it does add value to my life through a couple of groups and Facebook messenger. Only using these features has reduced the frequency I visit Facebook to once every few days. That is more than enough to keep up with what is going in in the Chicago climbing community and events going on at local climbing gyms.

I rarely post to Facebook but when I do it is often to promote something I’ve written.


I’m not really sure if Goodreads counts as a social media site. I use it to keep track books I want to read and books I’ve already read. It isn’t something that consumes any amount of my time mindlessly.


I’m not sure if you can consider my usage of LinkedIn to be actual usage. It mostly results in email in my inbox that almost immediately gets archived. It does keep me somewhat informed about what job opportunities are out there though recruiter outreach.

I very rarely post anything to LinkedIn.


I’ll completely admit that this is the social media platform that I waste time on. It is the only social media app on my phone and that increases how frequently I use it.

I signed up for Instagram in order to follow tattoo artists. This helped me learn what tattoo styles I enjoyed the most. This was a huge success and now I have a much better appreciation and eye for this art.

Eventually, my usage of Instagram expanded to follow some friends, local Chicago artists, and professional rock climbers. Following each of these groups is slightly beneficial but I’m not sure if it is an overall positive impact compared to the temptation to fill downtime with Instagram scrolling.

I’m approaching the point of deleting Instagram from my phone and experiencing that.

I post occasionally to Instagram both using the story feature and normal posts. These are usually photos of some street art or stickers put up in Chicago. It is very infrequent.


So that is how I consume social media. It mostly happens on my computer and I use a subset of features a platform offers. I’ve reached a point where I feel like I’m getting a lot of the pros without too many of the cons.

It is an area in which I’ll keep experimenting. I’d encourage you to as well. Try a different usage pattern for an extended period of time and then reflect on your changed behavior. Keep the changes that have made a positive impact.

  1. Ignoring LinkedIn and Goodreads, I think Facebook and Twitter were the only social media platforms I used back then.

Breaking change and more in lein-test-refresh 0.24.1

Today I released lein-test-refresh 0.24.11. I don’t always announce new lein-test-refresh versions with an article but this release breaks some existing behavior so I thought it was worth it.

Each of these changes is the direct result of interacting with four different lein-test-refresh users. Some of this took place on GitHub and others through email. Thanks to all of you for taking the time to think about improvements and notice oddities and bring them to my attention.

Breaking change: Monitoring keystrokes to perform actions

Prior to this release, if you hit Ctrl-D then STDIN reads an EOF and test-refresh would quit. With version 0.24.1, test-refresh no longer does that. Instead, it stops monitoring for input and just keeps running tests. Since it stops monitoring for input it no longer notices when you hit Enter to cause your tests to rerun. You can still stop lein test-refresh by sending a SIGINT with Ctrl-C.

This change was made because there is some combination of environments where if test-refresh execs /bin/bash then it receives an EOF on STDIN. Before this change, that means test-refresh would quit unexpectedly. Now it will keep going.

Thanks Alan Thompson for bringing this to my attention and taking the time to help diagnose the problem.

You can supply your own narrowing test selector

Being able to tell test-refresh to narrow its focus by adding :test-refresh/focus as metadata on a test or namespace has quickly become a favorite feature of many users. Now you can configure a shorter keyword by specifying configuration in your profile. See the sample project.clj for how to set this up.

Thanks Yuri Govorushchenko for the suggestion.

Experimental: Run in a repl

I’ve turned down this feature in the past but a narrower request came up and I thought it seemed useful. test-refresh now exposes a function you can call in a repl to run test-refresh in that repl. This makes the repl useless for any other task. To do this, first add lein-test-refresh as a dependency instead of a plugin to your project.clj. Then, require the namespace and call the function passing in one or more paths to your test directories. Example below.

user=> (require 'com.jakemccrary.test-refresh)
user=> (com.jakemccrary.test-refresh/run-in-repl "test")
*************** Running tests ***************

This request was done so that you can run it in Cursive’s repl and gain the ability to click on stacktraces. Thanks Klaus Wuestefeld for bringing this up again with a really solid and focused use case.

Better output on exceptions while reloading

This was a pull request from Minh Tuan Nguyen. Now figuring out where to look for the error will be a little easier.

Thank you

Thanks to all the users of lein-test-refresh. I’ve found it to be very valuable to the way I work and I’m very happy that others do as well.

  1. This was originally 0.24.0 but that had a bug in it. Sorry about that.