I work on a lot of little side projects. Many of them are short-lived and small scale. I start them to learn a new technology, to learn a new concept, try an idea, or just to see if I can actually build something cool. I should also mention that my memory is terrible. I “remember” things by figuring them out again. Rote memorization is basically non-existent to me. I've recently come up with a new best practice for my side projects which has saved my butt several times now.
deploy.sh script and I put one in every project that I do which needs
to be built, deployed, or executed beyond the typical compile step. This
very blog has one. There are also a few best practices
I've developed for making this file useful and not just another headache.
This seems like a no-brainer, but hear me out. This file should be executable on
its own. It should not be
deploy.rb. It should not need to be compiled or
otherwise prepared to run. You are writing a script. Script away all of that
tedium. If you need to deploy with ruby, make your
deploy.sh simply contain
ruby deploy.rb. The point here is that you can
cd into your project and run
this script. Period. If you have to remember to initialize your Python
virtualenv first, you've missed the point. Set it and forget it.
Not everything can be scripted away. Sometimes a deploy requires some unique
information, such as an environment or version number. Every microservice I
create is meant to run in a docker container on
kubernetes. In order to automate building, tagging, pushing the
image, and then updating the deployment, the deploy script needs to know the
version number. Since I've deployed 10 times today to “fix” that one bug, I can
easily remember to pass the version to the script:
However, I won't be so hip to that fact tomorrow. Good thing we are writing a
script. Just add some checks and helpful error messages to guide your future
self down the right path. Here's an easy one for requiring an argument to
#!/bin/bash if [ -z "$1" ] then echo "Please provide a version number, like v35" exit 1 fi # other deploy code here
It may seem like a drag, but you'll be so happy that you took the time to take care of your own self now.
Lastly, your deploy script needs to do every step on its own. It's a grown-up
script now and can handle it. If you need to do just one more thing after the
deploy finishes, you might as well just
rm deploy.sh. Even steps which you
might consider “optional” now, need to be included. For example, this blog
is hosted on AWS S3 and CDN'ed by CloudFront. It really is
enough to only upload (read: sync; save those bits) the files. Eventually the
cache will expire and the new content will be shown. However, in just one more
line in the
deploy.sh, I can invalidate the CloudFront distribution and see
this awesome new post right away. If you think it's optional, it's required.
Well, those are my three tips for keeping your side project deployments sane.
P.S. I've recently had a resurgence of shell scripting in general. In the
past, I've certainly been one to (ab)use
zsh's history substring search to re-run the same set of commands
over and again. See also: “Up 12 times then enter. 6 times.” By committing those
~/bin/, it really has made me much more efficient. A practical
example is streamlining my workflow at work. We use Github for code hosting and
reviews. We also use YouTrack for our project management. I wrote a
command line client for YouTrack and combined all the commands I was
doing to checkout branches by story number or create new
branches as well as marking stories In Progress/Under Review/etc. into shell
review_story c-1234 or
$ start_story -t bug -s c-1234 -b this-is-a-heisenbug Applying "Assignee: me In Progress" to story c-1234 Switched to new branch 'bugs/c-1234-this-is-a-heisenbug'
Get creative and really push yourself to save some time. Again, you'll thank yourself, and then me. ;)