I don't know about you, but I'm an absolute sucker for productivity systems. Cards, pomodoro, todo lists -- I've tried 'em all, and stuck with a few. But the only thing I've found that actually encourages me to get shit done and doesn't encourage me to waste time organising lists and making plans is keeping a done list.
What's a done list? Think of it as an anti-TODO list: your DONE list is where you write down everything that you've, well, done. You know that little dopamine kick you get from filing a neatly-tagged TODO or marking off something that you've finished? A done list is just that, and the only way to use it is to train yourself to stop organising and just get stuff done.
Try keeping your own done list for a week, and you'll be amazed at how you can hack your brain into actively looking for projects you can finish and tasks you can check off, just so you can write down one more thing as DONE. You don't need fancy tools to write down a list, but if you're like me and you like having fancy tools check out https://donel.ist -- the fast, easy-to-use done list tracker I built for myself. It's 100% free (no ads, "pro" tiers, or feature unlocks). And if you want to automate your done list or use it to automate other things, there's an easy-to-use REST API too.
Way back in the halcyon days of September 2010, I threw my hat in the ring for the first Ludum Dare October Challenge, where a bunch of hobbyist gamedevs built indie games in public, for a month, with the end goal of getting them out for sale before the end of October. The idea was to turn a bunch of hobbyists (i.e., us) into professionals (i.e., what we wanted to be) -- and if the definition of a "professional" is "someone who gets paid for their work", well, all we had to do was make a game, release it, and earn at least $1 from it.
Fast forward to 2020, and even though I've been out of the games industry for almost a decade (I did, in fact, win my own personal October challenge) that idea of the October challenge has stuck with me ever since. After leaving Palantir (I was, ahem, fired -- let's not mince words, there) I spent the next year getting, well, basically nothing done. I kept Quail ticking over, responded to a zillion bug reports and requests for help, and generally kept things on an even keel. But no new projects really made it out into the world.
Turns out being fired, even from a job you hate, can really knock the professional/creative stuffing out of you. Who knew?
But from March 2021, that's changing! To kick myself back into entrepreneurial thinking I'm setting myself a possibly-unrealistic goal of launching 12 projects in the next year, one per month from April 2021 until at least April 2022. I'm two months into this meta-project, and so far I'm two for two:
Are these amazing business ideas? No, not really. Are they flawlessly executed, investor-ready products with product-market fit and a knockout marketing story? Of course not. But designing them, building them, and getting them out the door (plus marketing, feedback, maintenance, &c) is forcing me to work out muscles that I've let atrophy for far, far too long. Forward to 2021 -- let's mint some new Founders, shall we?
When I started at my last-but-one job, my very first task was to take a whole bunch of internal coding “best practice” formalisms and find a way to gently enforce them on new projects. For my first pass at this I set up a couple of git repositories: one frontend, one backend. Whenever you started a new project, the rule was that you started off by forking from the relevant “standard” repo. This…worked, but that tedious rename-and-update-everything step never really sat right with me, or the rest of my team.
A couple of years later we came across Yeoman, a general-purpose tool for scaffolding new projects. It made our cumbersome git repos look amazingly cumbersome by comparison — and just a few months after I refactored our standard repositories into Yeoman generators, we were getting serious results. People were experimenting with new projects, structuring code in a sane way instead of cutting corners and just sticking it in some place that already worked. We started moving faster, and — true miracle — we noticed a few months later that we weren’t getting bogged down in anything like as much technical debt as before.
Ever since then, I’ve tried to maintain a similar set of standard generators for myself. At the moment, my preferred tech stack for personal projects is deeply boring: Java+Dropwizard on the backend, and Typescript+React on the frontend. Pretty much any new project I start, or new idea I want to play around with, starts with either:
…for a backend service that’s turnkey-deployable, or:
…for a bare-bones single-page web app that’s ready for hacking. If either of those sound like your cup of (instant) tea, you can grab respective Yeoman generators from doches/generator-dropwizard-gradle and doches/generator-tfountain-webstack, or just install ‘em with
yarn global add generator-dropwizard-gradle generator-tfountain-webstack.
But what I’d really suggest you do is look at ‘em as meta-templates, and maintain your own personal generator. Just the act of keeping these two up to date has forced me to stay on top of upgrades, changing trends, and new technologies that I might have missed otherwise. And those changes get more-or-less automatically rolled into everything I do over time.
Also, Yeoman’s just a dude.
_-----_ | | ╭──────────────────────────╮ |--(o)--| │ Welcome to │ `---------´ │ tfountain-webstack │ ( _´U`_ ) ╰──────────────────────────╯ /___A___\ / | ~ | __'.___.'__ ´ ` |° ´ Y `
One of the tricks that helps me move super fast on Quail and related projects is a continuous delivery setup that I use to iterate quickly (on the browser-based portions, anyway). And what’s great about this workflow is that once you’ve got it set up then publishing a release fits exactly into your already-existing workflow, and setting it up requires tools you’re already using.
The trick, of course, is to rely on
This first bit is optional, but I like to maintain a
master branch that always reflects what’s actually deployed in production. Pushing commits to this master branch logically means that those commits should be immediately deployed, but programmers are lazy and I realised long ago that if I could simply automate away the devops-y step of “ssh into the host, build a distribution of static files, and update nginx” then I’d never forget to deploy a finished release again.
So. Let’s automate this puppy.
First, you’ll need a git host running on your production server (I like Gitolite because it also relies on a git-push-to-deploy model, but your mileage may vary). In the project you want to auto-deploy with git, add this host as a new remote:
git remote add production git@<your production host>:<repo>.git
In your remote repository (e.g.
<repo>.git/ wherever you’ve set up Gitolite on your host) you’ll find a directory called
hooks. Git hooks are an incredibly powerful tool that I won’t go into the details of, but basically they’re scripts that are triggered by events happening in your repository. Create a file called
post-receive in your
<repo>.git/hooks directory with the following (obviously replacing
<repo> with a more helpful name!):
#!/bin/bash sudo -u integration /home/integration/<repo>.sh
sudoing, we’ll need to add an exception to
/etc/sudoers to allow our
git user to execute this script (and only this script!) as the
integration user. Add the following to the end of
git ALL=(integration) NOPASSWD: /home/integration/<repo>.sh
I like to keep my git hooks super-simple, so the above simply runs another script as a lower-privilege user that we’ll use to actually do the work of deploying our pushed application. Go ahead and create that user (
sudo useradd integration) , then become them (
su integration; cd ~). Clone the repository you just created (
git clone git@localhost:<repo>.git — you may need to set up key authentication for the integration user in Gitolite), then create the script we referenced in your
post-receive hook at
#!/bin/bash REPO=<repo> INTEGRATION=/home/integration PUBLISH_DIR=/srv/www/<deploy directory>/public_html # Publish master branch to <deploy directory> cd $INTEGRATION/$REPO # Fetch the latest production push git checkout master git pull origin master # Compile a distribution yarn install yarn compile # Remove the existing distribution rm -rf $PUBLISH_DIR/* # Copy the compiled static files into a place where nginx can serve them cp -R dist/* $PUBLISH_DIR # Update permissions on the published files chgrp -R nginx $PUBLISH_DIR/* chmod -R 775 $PUBLISH_DIR/*
Obviously your commands to turn your uncompiled code into static assets will differ.
And that’s it! Work happily on your
develop branch, and when it comes time to push code to production just commit on
git push production master. You’ll see the forwarded output from your
<repo>.sh above (in my case, the output of
yarn install and
yarn compile, and — assuming everything compiles properly — your production-ready assets will be pushed out all the way to where your web server can serve ‘em.