At the beginning of every year, I take the time to update my records of what I've read the previous year and write up a summary. Previous summaries: 2013 , 2014 , 2015 , 2016 , 2017 , 2018 , 2019 , 2020 , 2021 , 2022 , 2023 , and 2024 . 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. 2025 Goals For…
If you've got a ridiculously good memory and you've been reading my writing for a while, you know I'm a fan of processes notifying you when they are done. I often have some task running in a hidden terminal that performs actions when files change. This is most often running Clojure tests whenever a file changes using either test-refresh or lein-autoexpect . Another common watch task…
I'm a big fan of making small (sometimes silly) programs . As a software developer, you have a superpower: you can identify problems in your life and fix them by creating some specific software that solves for exactly what you need. When scoped small enough, creating these tiny programs takes minimal time investment. When you develop the practice of recognizing when a bit of software would be…
Warning: There are minor spoilers of parts of A Deepness in the Sky in this article. I was reading Vernor Vinge's A Deepness in the Sky when a paragraph made me think of today's AI tools. In A Deepness in the Sky , one of the groups of humans, the Emergents, has figured out how to take advantage of a "mindrot" virus that was a plague on their homeland. Once a person is infected, the…
Keeping code consistently formatted is important for readability and maintainability. Once you get used to having a computer format your code for you, manually formatting code can feel tedious. For the last few years, my team has been using zprint to keep our Clojure codebase formatted to our specifications. zprint is great because it runs fast and is extremely customizable. This flexibility is…
I've been using Emacs for nearly twenty years but find it challenging to craft even tiny elisp functions to enhance my workflow. Despite that, I've written elisp to enhance my Emacs experience but I often don't bother fixing small annoyances that are solved relatively easily in other ways. Now that LLMs exist and are reasonably good, they have lowered the bar for creating small…
At the beginning of every year, I take the time to update my records of what I've read the previous year and write up a summary. Previous summaries: 2013 , 2014 , 2015 , 2016 , 2017 , 2018 , 2019 , 2020 , 2021 , 2022 , 2023 . 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. 2024 Goals I'd like to…
Have you ever needed to schedule a repeating task on a Linux host? If so, you've probably reached for cron. cron is widely available and reliable; it is a great choice for scheduling tasks. Sometimes you find yourself scheduling a task and, ideally, you'd be scheduling that task referencing a different time zone. This is a common need if your programs are interacting with systems hosted…
At the beginning of every year (not so much the beginning this year), I take the time to update my records of what I've read the previous year and write up a summary. Previous summaries: 2013 , 2014 , 2015 , 2016 , 2017 , 2018 , 2019 , 2020 , 2021 , 2022 . 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…
At the beginning of every year, I look back at my records and reflect on the books I read the previous year. Previous years: 2013 , 2014 , 2015 , 2016 , 2017 , 2018 , 2019 , 2020 , 2021 . 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 year I did a poor job of keeping Goodreads updated. I had…
Bookmarklets, little snippets of JavaScript that you keep around as a bookmark, are useful. They let you execute some JavaScript to perform almost any action you want on a website. Some bookmarklets I use on my desktop browser include: A collection of bookmarklets that let you change the playback speed of most embedded videos. A bookmarklet to manipulate the URL of the page you're visiting. A…
At the beginning of every year, I reflect on books I've read in the previous year. 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 , 2018 , 2019 , and 2020 . I've continued to keep track of my reading using Goodreads . My profile has nearly the full list…
Tests can serve many purposes. You might write tests as a way of driving the design of your software. Other tests might be written in response to a discovered bug and, if written first, those tests you know when you've fixed the bug and act as guardrails preventing the reintroduction of that bug. Tests can also be used to confirm you haven't changed behavior while refactoring. Tests can…
The constants you use in unit tests matter. Like test and variable names, they can improve the readability of your code and make it easier to understand test failures. Imagine the following. A new developer joins your team and asks a question about how the code resolves config values. You are unsure of the details so you pair up with the new teammate to dig into the code. You know the codebase…
At the beginning of every year I reflect on my reading from the previous year. 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 , 2018 , and 2019 . I've continued to keep track of my reading using Goodreads . My profile has nearly the full list of the books…
In my last article, Speeding up Magit , I showed how removing elements from Magit's status buffer drastically reduces the time it takes to refresh this buffer when working in a large repository (from 4 seconds to around 0.348 seconds). In a comment on r/emacs , someone wondered if the native-comp feature of Emacs might improve the Magit status refresh time. This reddit thread was the first…
Magit is a great Emacs tool and by far my favorite way of interacting with git repositories. I use Magit nearly every day. Unfortunately, refreshing the magit-status buffer is sluggish when you are working in a large repository. A few months ago, I became sick of waiting and investigated how to speed up refreshing the status buffer. After doing some research, I learned about the…
Back in April 2013, I created and published a custom Kindle dictionary for the book Dune . As far as I can tell, my Dune dictionary was the very first custom Kindle dictionary for a fiction book. I created it because I was reading Dune for the first time and there were many unfamiliar words. These words could not be looked up by my Kindle because they were not found in any of on-device…
Over the summer, I developed a couple of small, sort of silly programs. One, Photo Fit , is a little tool that runs in a web browser and resizes photos to fit as your phone's background. The other, Default Equipment , runs on Heroku and automates changing the "bike" of my Strava-tracked e-bike rides to be my onewheel . These weren't created to solve large problems in the world. There is…
Selecta is a command-line utility that gives you the power to fuzzy select items from a list of text. What does that mean? It means you pipe selecta a list of text on stdin, it helps you make a choice from items in that list, and then selecta prints that choice to stdout. Here is an example of me using it to help me narrow in on what file I'd like to pass to wc . In this example, I search for…
Earlier this year, I wanted to use a landscape photo as my background on my phone. It wasn't the photo below but we can use it as an example. When I made it my background, my phone 1 zoomed in to make it fit the portrait orientation of the phone. This is not great. I don't want a zoomed in version that fits my vertical phone. I want to see the whole photo with black bars at the top and…
Flaky tests are terrible. These are tests that pass or fail without anything changing in the code. They often pass the majority of the time and fail rarely. This makes them hard to detect and cause developers to often just run the tests again. Flaky tests erode your team's confidence in your system. They cause folks to get in the habit of not trusting the output of tests. This discourages…
Let me set the stage. I kick off the compilation of a large Scala codebase. This will take minutes to finish, so I switch to Slack and catch up on what coworkers have posted. Someone posted an interesting link and I follow it to an article. Fifteen minutes later, I notice the compilation finished twelve minutes ago. I silently grumble at myself, disappointed that I didn't start the next step…
If you've browsed the adventure section of my website you know I'm a climber. Currently, the climbing gyms in Chicago are closed due to COVID-19 concerns. This has put a damper on my training but I own a hangboard and have been able to keep training my fingers at home. A hangboard allows you to apply stress to your fingers in a measured and controlled fashion. It is a vital tool for a…
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…
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: Gather the team together Set the stage Brainstorm answers to the questions What went well? and What needs improvement? Discuss the answers Let's talk…
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…
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…
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…
I recently built an Atreus keyboard . This keyboard is an extremely small keyboard with only 42 keys. Below is the photo of my result. 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…
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…
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 EZ 1 . 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…
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…
Today I released lein-test-refresh 0.24.1 1 . 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…
I was recently adding a feature to an internal web UI that caught all unhandled JavaScript errors and reported them to the backend service. The implementation went smoothly with most of the effort spent figuring out how to test the code that was reporting the errors. If the error reporting failed, I didn't want to trigger reporting another error or completely lose that error. I decided to log…
Leiningen test selectors are great. They allow you to filter what tests run by applying a function to the test's metadata. If that function returns a truthy value then that test will run. lein-test-refresh supports them and even includes a built in one for its focus feature . I was recently asked if test-refresh could support filtering tests using a regular expression against the name of a…
Lately, I've been using tmux a lot. This resulted in me figuring out how to get lein-test-refresh to send notifications using tmux . The setup linked above works great for when I'm doing work all by myself. It showed a problem when using ssh and tmux to pair with another developer. Instead of both developers receiving a notification, only one did. One is better than none but not ideal.…
At the beginning of every year I like to take the time to reflect on my previous year's reading. It gives me a time to correct my data and think about where I want my reading to go in the upcoming year. Here are links to my previous end-of-year reflections: 2013 , 2014 , 2015 , 2016 , and 2017 . I've continued to keep track of my reading using Goodreads . My profile continues to have the…
I've been using Emacs in a remote tmux session lately and I've been missing lein-test-refresh notifications when my Clojure tests pass or fail. Luckily, it only took me a little bit of searching to figure out a solution for when I'm working inside of tmux. Below is a GIF of the notifications I get as my tests run and pass or fail. With the above notifications, I can keep my focus on…
In an older article of mine I extolled the virtues of having unified interfaces for interacting with your projects. I recently started working at Coinbase and the group I'm working with is mostly using makefiles as that common interface. We still have some more work to do to unify the makefile targets of the various projects but I've picked up one tip that makes switching between…
If you follow my work you probably know that I value fast feedback cycles. Most of the open-source I maintain was developed to enable faster feedback cycles. This is why lein-test-refresh and lein-autoexpect were originally created. Leiningen supports test selectors and lein-test-refresh does as well . This lets you start-up a testing session and only run tests or namespaces with certain metadata…
I was recently having some difficulty debugging a problem in a ClojureScript single page application. The SPA was implemented using reagent 1 . This interface stores most of its state in a global reagent.core/atom called db . To debug the problem, I thought it would be useful to track how the global state changed as I interacted with the interface. How do we do that? For the rest of this article,…
A couple months ago I was looking into a problem and noticed that there was a situation where an expensive operation could be running simultaneously multiple times. This was wasteful. This operation happened on a timer and could also be triggered by a power user through the UI. A power user could accidentally (or purposefully) mash on a UI button and cause the instance they're interacting…
I typically like to reflect on my previous years reading closer to the beginning of the next year. We are just entering March, so I've missed doing that. Here are links to my previous end-of-year reflections: 2013 , 2014 , 2015 , 2016 . I've continued to keep track of my reading using Goodreads . My profile continues to have the full list of the books I've read since 2010. Here is…
Earlier this year, I traveled to India and gave a presentation at IN/Clojure . I talked about building serverless ClojureScript applications that use Firebase to persist and sync data between clients. I was pretty pleased with how the talk went. The people who talked to me after seemed to enjoy the presentation and were inspired to try out some of the techniques and tools I mentioned. Here is the…
In July 2017, I found myself editing some Clojure code that looked approximately like this. (defn validate-required-fields [params] (when-not (contains? params :source) "Missing source field")) (defn validate-invariants [params] (when (>= (:lower params) (:higher params)) "lower field must be smaller than higher")) ;; route handler taken out of other routes (GET "/event-redirect/:event_type"…
I recently needed to optimize the speed of some Clojure code. After investigating, I identified that a huge number of exceptions were being thrown and handling these was slowing down the process. The code throwing the exceptions was parsing strings into Joda-Time DateTime objects using the clj-time library. The code was calling clj-time.coerce/from-string which calls clj-time.format/parse .…
See all of my remote/working-from-home articles here . Whether it is working as the one remote employee at a traditional company or being one of many at a distributed company, remote work is becoming an option for many of us. The number of employees that work remotely is growing 1 . Technology improvements, pervasive Internet, and mindset changes are some of the drivers for this change. The…
Last time I needed to speed up some code, I wrote a Clojure macro that recorded the aggregate time spent executing the code wrapped by the macro. Aggregate timings were useful since the same functions were called multiple times in the code path we were trying to optimize. Seeing total times made it easier to identify where we should spend our time. Below is the namespace I temporarily introduced…
Nearly three years ago I wrote an overview of my Leiningen profiles.clj . That post is one of my most visited articles, so I thought I'd give an update on what I currently keep in ~/.lein/profiles.clj . {:user {:plugin-repositories [["private-plugins" {:url "private url"}]] :dependencies [[pjstadig/humane-test-output "0.8.2"]] :injections [(require 'pjstadig.humane-test-output)…