Happiness is DRY Code, or "Programming Language Stratification"

Cryptic prologue

As George Burns may or may not have said:

Happiness is DRY code in a good shell script

Your code—directed by Matthew Vaughn


In the age of devops and the full-stack developer, it’s common to have many layers of programming in your life. These layers are often treated as classes in sociological sense, where an implicit hierarchy of resource allocation and standards are applied subconciously.

To everything, there is a season


As in sociology, the hierarchy shifts, unshifts, pushes and pops over time.
JavaScript code could be said to be higher up in 2016 than in 2004.
Objective-C might be lower in 2016 than 2010.
Throughout the ages though, it’s been prevalent to see the same programmers that give incredible attention-to-detail in their code throw all caution and decorum to the wind when writing shell scripts.

Shell scripts—no longer just for 90s cyberpunk movies

As the Perl, Ruby and Node.js communities subsequently lowered the barrier to CLIs further and further, you’ve seen the types of devs willing to consume and create CLIs expand. I credit this change with a renewed interest in pure shell programs written for bash and zsh. Alongside this, even within the shell script sphere there’s been a stratification—between public (OSS) and private (proprietary or personal) shell scripts. While proprietary Java code often receives similar scrutiny to OSS Java code, the same doesn’t hold true for scripts. It doesn’t have to, and shouldn’t, be this way though.

Walk the talk

I was compelled to write this post because of the immense benefit I’ve received over time from treating my zsh scripts much like I would JS packages. I put them in version control and all that jazz. But most importantly I endeavor to make the code as readable and DRY as possible. An example of how this benefits me in the day-to-day can be seen in the following real-life example. I had a script like this that’s part of the zsh setup I sync across multiple machines. This piece is a set of aliases for moving into directories I commonly develop within.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
source $ZSH_SCRIPTS_DIR/bootstrap.zsh
alias gpom="git push origin master"
alias zscripts="c $ZSH_SCRIPTS_DIR"
# Personal / OSS
alias ghub="c $GHUB_DIR"
alias bitb="c $BITB_DIR"
alias ghjw="c $GHUB_DIR/jameswomack"
alias exti="c $GHUB_DIR/jameswomack/exploding-video-tiles"
# Netflix
alias stash="c $STASH_DIR"
# Netflix DEA
alias ignite="c $STASH_DIR/dseplat/ignite"
alias nmdash="c $STASH_DIR/nmdash/nmdash"
alias abacuse="c $STASH_DIR/abacus/abacus-editor"
alias abacusa="c $STASH_DIR/abacus/abacus-editor-app"

Now yesterday I migrated a couple of Abacus repos from Stash to Github. That affects my aliases across several machines, and also affects scripts outside the above example. But because I’ve carefully put common paths into variables and already setup syncing across each of my machines, it’s a simple matter of find-and-replace (in one file) + commit and push. If I hadn’t broken out my common paths into variables… if I hadn’t modularized my scripts… if I hadn’t setup up version control and syncing… this seemingly simple task would be rife with room for error. In the end I simply changed this

1
2
alias abacuse="c $STASH_DIR/abacus/abacus-editor"
alias abacusa="c $STASH_DIR/abacus/abacus-editor-app"

to this

1
2
alias abacuse="c $GHUB_DIR/abacus/abacus-editor"
alias abacusa="c $GHUB_DIR/abacus/abacus-editor-app"

and then

1
2
git commit -am "refactor(aka): Abacus Github migration"
ggpush

It’s the little things :)