Nik Kantar 2020-10-21T00:00:00Z Nik Kantar Hire Me! (v.2020.10) Back on the job market again, so here’s my updated “dating profile”. 2020-10-21T00:00:00Z Update: I'm no longer looking. :) Everything below is for reference/posterity.



I really like Python and someone ought to pay me to make things with it.

The Full Story

I wrote my first lines of code in the early 90s, when I was about 7. Don’t let this fool you, though—what followed was a cool decade and a half of not doing anything noteworthy with computers, until my first real computer-related job in 2006.

At that time I was in early college, rediscovering programming, and I started writing PHP and maintaining Linux servers part-time. Shortly thereafter I went off to get a design degree before going back to programming in 2011.

I then did more PHP than I ever really wanted to, until discovering Python sometime in 2014 or so. I immediately fell in love and dove into it pretty heavily. Ever since, I’ve thought of myself as a Python programmer first and foremost. Much of that time I’ve spent wrangling Django and Flask backed by PostgreSQL, deployed either on Heroku or plain ol’ Linux boxes. Lately I’ve been building systems comprised by smaller services and deployed on AWS, thus relying not on web frameworks but the glue available in that ecosystem.

A notable part of the last few years has involved working with an entirely different stack. It’s been a bit more of a stack du jour, based primarily on TypeScript, with accompaniment consisting of DynamoDB, SQS, Kinesis, and AWS Lambda, and the whole symphony managed by Terraform.

While the learning experience has been fascinating and valuable, I frankly miss working primarily with Python. Ideally, I’d like to work on projects which are predominantly or at least largely reliant on it. Not a whole lot of serious software is single-language these days, but this preference is still important to me.

If you’re looking for my résumé, you can find it here.


You’re probably a small company, or a fairly independent team in a larger one. You use something resembling a sane methodology for producing quality software, and it’s shown itself to work well in this instance (or you’re open to change). You don’t like pointless meetings and are happy to reconsider any that are thought of as such by team members.

You use Python pretty heavily—if not exclusively—and plan on continuing to do so in the foreseeable future. Its role in the organization isn’t tied exclusively to data science/engineering, ops, or light scripting. You probably use it for something web related, be it good ol’ page loading web apps or APIs powering external clients.

If I’m lucky, you’re heavily invested into open source in some manner. Maybe your main product is open, or you share some ancillary tools with the world. Dare I dream about your developers being allowed (or even encouraged) to contribute back to the software they use for their work?

You support your staff in attending conferences, and perhaps even sponsor some as a way to give back to the community. Ditto for relevant meetups and other local events.

You believe in work-life balance, or however you refer to the idea that happy, well rested employees live better lives and do better work.

You’re not an adtech company and your products and services aren’t primarily harmful to anyone. You don’t have contracts with law enforcement agencies, nor plans to enter any.

You’re currently fully remote and plan on being remote-only or at least remote-first if and when it’s at all safe to go back to the office. Asynchronous work is either the norm or a possibility.


If the above sections have you feeling like it might be a match, you can email me at Do us both a favor and mention this post in the email, so I know you’re not entirely random. ;)

Note to recruiters: I’m not opposed to working with independent recruiters, but I tend to be very selective. If you choose to get in touch, please make sure what you send me makes sense based on the above. If you respect my time, I will respect yours, and quite likely remember you in the future for doing so.

Introducing Autohook I made a little Git hook manager and some people even use it! 2020-10-16T00:00:00Z Note: Autohook isn’t new at all—the first release was published on January 31st, 2017, and the most recent on August 26th, 2018. I just never wrote a proper introduction post about it, and given its popularity—92 stargazers, some users, and even 4 co-maintainers—it certainly feels warranted.

Way, way back in early 2017, I wanted to implement some Git hooks in a repository at SimpleLegal. Being my usual self, I decided to both overengineer the solution and not use any existing tooling, because that would be entirely too sensible.

So I wrote a relatively simple tool to automagically run Git hooks that can be added to the repo itself. It’s basically a simple shell script that replaces the various hook files in .git/hooks/ and then looks for scripts to run in appropriately named directories in hooks/.

An example tree is probably clearer than my description:

my_project/ ├── .git/ │ ├── post-checkout # symlink to hooks/ │ ├── pre-commit # symlink to hooks/ │ └── ... # other symlinks to hooks/ ├── hooks/ │ ├── │ ├── post-checkout/ │ │ └── 01-delete-pyc-files # symlink to hooks/scripts/ │ ├── pre-commit/ │ │ ├── 01-delete-pyc-files # symlink to hooks/scripts/ │ │ └── 02-run-tests # symlink to hooks/scripts/ │ └── scripts/ │ ├── │ └── └── ...

Why did I do it this way? Well, I wanted to be able to enforce the running of said scripts across the team. Furthermore, I didn’t really give other existing solutions (e.g., pre-commit) an honest look, likely because I wanted to do it myself. That said, I vaguely remember not quickly finding anything that didn’t have to be installed on a POSIX system, and Autohook was always intended to be just a portable shell script with no dependencies other than a compatible shell.

Anyway, now it’s gaining a bit of a life of its own. I haven’t used it in years, but others still seem to, so I’ve moved it to a GitHub organization. It’ll likely get more love than it has from me in quite a while.

And now you know about it too! :)

Introducing sus I made a URL shortener with a static site generator. 2020-10-15T00:00:00Z Before we begin, it’s pronounced “suss”. There’s a whole section about it in the documentation.

URL shorteners can be pretty useful. Static site generators are awesome. Why not combine the two?

That isn’t what inspired sus, but doesn’t it read well?

What did inspire my newest project was—of all things—Instagram…sorta. Ugh, I know!

Instagram doesn’t really allow tappable links in a whole lot of places. It especially doesn’t let users link Stories unless they have a business account. I don’t, so two years ago I bought to use for a URL shortener of my own. The “pub” part is meant to stand for “public”, but I’m not sure that comes across.

Anyway, I first made Publinker and used it for a while. Please don’t look at the project—it’s neither good nor complete. But it did the trick! The whole time I wanted something simpler, but couldn’t be bothered to change anything.

Recently I ran into di’s corvid project and switched to it for this very site just about immediately. It was nice to finally get off the thoroughly outdated Flask-based horror it was before, and I was exceedingly pleased with myself for being back on a static site. Shortly thereafter I made an http redirect page for another site and it hit me that an entire URL shortener could be build based on that. A flurry of commits later, here we are.

See, an http redirect is just this:

html <meta http-equiv="refresh" content="0;url=" />

On a static site, going to will load, and if that index.html has an http redirect, it’ll work like a charm! So that’s exactly what sus outputs.

In essence, you feed it an input file that looks something like this:

foo | bar |

and it spits out an output/ directory that looks something like this:

output/ ├── bar/ │   └── index.html └── foo/    └── index.html

with output/foo/index.html that look something like this:

html <meta http-equiv="refresh" content="0;url=" />

and output/bar/index.html that looks something like this:

html <meta http-equiv="refresh" content="0;url=" />

which means that going to will redirect the user to" and going to will redirect the user to".

Bonus: if you feed sus a home.html file, it’ll copy it to output/index.html, giving you a homepage. Brilliant, if I may say so myself!

There’s an example site at and the source is on is on GitHub.

Happy redirecting!

P.S.: This project contains what may very well be my most pretentious commit ever. No, I’m not sorry.

Black Lives Matter: Venice Beach and Santa Monica Painted boards from Venice Beach and Santa Monica on the morning of June 8th, 2020 2020-06-18T00:00:00Z Ten days ago I rode my bicycle through Venice Beach and Santa Monica. The only painted surfaces were boards put up to protect storefronts. They were mostly of faces.

Black Lives Matter

George Floyd

George Floyd's last words

Shelly Frey

Tony McDade

BLM names

Toni Morrison

BLM - Liberty and Justice for All!

Black lives matter. Defund the police.

# TODO: add comments 5 Tips for Winning at Code Comments 2020-05-06T00:00:00Z I've given this talk at several meetups and a conference, and thought it might be worth writing down as well. The conference recording is embedded here at the top (the link is here), and the wall of text follows below. You can find the slides here.

Why should we care anyway?

The motivation for this piece comes from something I consider downright frustratingly true:

"Bad documentation is worse than no documentation."
— some wise people (and also me)

When you have no documentation, you're left with the code itself. While quite possibly subpar in any number of ways, at the very least it's honest, in the sense that it simply does what it does.

When you have poor documentation—especially if it's incorrect—you may find yourself misled and your time otherwise wasted.

As such, I'm a big believer in having either useful documentation or none at all. Since the former is far preferable to the latter, here we are.

The basics

To make sure we're on the same page, let's review some basics.

What are code comments?

They're # this stuff in Python, // this stuff in many other languages, and /* this stuff */ in others. They're annotations sprinkled throughout your source code meant to provide some form of context to the reader.

Why are they important?

"Programs must be written for people to read, and only incidentally for machines to execute."
— Harold Abelson, Structure and Interpretation of Computer Programs (1979)

Comments are part of code, so the above quip holds doubly true for them.

Who are they for specifically?

They're for everyone except you at the time of writing them—me, you in six months, and everyone else. Humans are pretty terrible at reading minds, and this really helps.

The 5 tips

Here's the list before we go into detail about each one:

  1. Make comments stand out in your editor.
  2. Explain the why, not the what.
  3. Don't fear the paragraph.
  4. Read what you wrote out loud.
  5. Ask for help!

1. Make comments stand out.

Here's a screenshot of my editor with the theme I use:

invisible comments 1

Here are a few more screenshots of various themes:

invisible comments 2 invisible comments 3 invisible comments 4 invisible comments 5 invisible comments 6 invisible comments 7

The one thing they all have in common is that they don't make comments very prominent. In fact, they very intentionally hide them quite a bit. This is a problem, because invisibility is bad.

Invisible things are easy to ignore. Thus, invisible comments get ignored. As a result, these ignored comments suffer in quality. The two most common problems this causes are outdated comments and commented-out blocks of code.

Making comments more prominent doesn't magically fix them, but it does motivate you to consider them more often. If you're forced to read outdated comments because you can't gloss over them, you'll update them. If you have to scroll past giant blocks of commented-out code, you'll delete it.

I fix this problem rather simply:

visible comments 1

visible comments 2

I make comments the most prominent thing on screen. This has made me far more eager to improve them in my day-to-day work.

2. Why, not what.

Things may get a little uncomfortable here, but we need to dispell a surprisingly popular myth:

"Code is self-documenting."

In reality, the best-case scenario is that code can self-document what happens. The comments answer the "why" questions, such as why is this here (as opposed to somewhere else), why is this done this way (as opposed to any number of other ways), and why is it done at all.

As an example, here's a line of code yours truly wrote a few years ago:

python file_data = file_data.replace("\\\\\\\\", "\\\\")

You don't even need to know any real Python to get the gist of what's going on there—we're replacing every instance of eight backslashes with four in some variable file_data. Simple enough.

If I were to document this poorly, I'd write this:


replace 8 backslashes with 4

file_data = file_data.replace("\\\\", "\\") ```

While technically correct—the best kind of correct—the comment adds no value and is thus useless.

If I were to try and be clever while investigating this later, with no context, I may end up with something like this:


wat? why. just why.

file_data = file_data.replace("\\\\", "\\") ```

And if I were a bit younger, perhaps I'd write this:


y tho

file_data = file_data.replace("\\\\", "\\") ```

But what I should write is something like this:


This file is submitted with backslashes escaped,

the validator escapes them again, and the first

round of processing does it again, so here we

remove the last layer we don't actually want.

file_data = file_data.replace("\\\\", "\\") ```

Now the code explains what happens and the comment explains why it happens. At this point the whole thing seems a bit weird, so we can add a little feel-good note at the top:


TODO: clean up this whole escaping mess

This file is submitted with backslashes escaped,

the validator escapes them again, and the first

round of processing does it again, so here we

remove the last layer we don't actually want.

file_data = file_data.replace("\\\\", "\\") ```

3. Don't fear the paragraph.

This may seem shocking, but there are no points awarded for brevity at the expense of thoroughness. Yes, rambling is bad and there absolutely is such a thing as too much documentation, but the opposite is more frequently the case.

This also may seem shocking, but it's perfectly OK to have more comments than code. This goes for any single section and even entire projects. The extra bytes of text really shouldn't be an issue in this day and age.

4. Read what you wrote out loud.

With apologies to everyone working in an open office, I suggest that you at least sometimes take the time to read your comments out loud. You'd be amazed at what you can hear!

Language matters, and how we consume it affects our perception of it. When you read something silently to yourself—especially if it's something you wrote recently—you'll skim more than you'll actually read. Reading it out loud forces you to slow down and pay closer attention.

You'll catch typos much more effectively. Bad grammar will stick out like a sore thumb. When writing that last bit of documentation after a particularly long day, you'll stand a better chance at not writing gibberish.

5. Ask for help!

You already ask for feedback on your code, likely through code reviews. Your comments shouldn't get a pass on this.

Getting experts to read your comments lets them verify correctness and completeness. Getting those unfamiliar with the code, language, or problem domain lets them verify clarity. And everyone can point out obvious issues.

If you're wondering whether this is really necessary, keep in mind that great writers have great editors. Or listen to Kurt Vonnegut at least:

"Be a good editor. The Universe needs more good editors, God knows."
— Kurt Vonnegut, Letters (2014)

Quick recap

To save you scrolling back to the top, here's the list again, as my parting gift to you:

  1. Make comments stand out in your editor.
  2. Explain the why, not the what.
  3. Don't fear the paragraph.
  4. Read what you wrote out loud.
  5. Ask for help!

Now go forth and comment!

PyBeach 2020 Tickets Are on Sale! You should attend! 2020-02-13T00:00:00Z PyBeach 2020 tickets are on sale now!

Talk and speaker details are also available.

Come hang out. :)

DogTown CrossFit Blog — Member Feature: Me! I lost a buttload of weight and got a cool shoutout on my gym's blog, and it's hard not to brag. 2020-01-16T00:00:00Z I lost a buttload of weight in 2019 (dedicated post forthcoming) and I got featured on my gym's blog, so I thought I'd brag a bit.


Goals for 2020 Ahead of the curve this time, a look forward at what I'm hoping to accomplish professionally in 2020. 2019-12-20T00:00:00Z I've been publishing professional goals and review for four years now, and 2020 shall be no different.

1. Make PyBeach Happen

A reprise of the only 2018 goal, this time for realsies! Check out for details!

2. Migrate My Projects

I have a few projects out in the wild and most of them need to be updated and migrated. I already wrote about how I plan on doing it and got started, and should be able to complete it all by the end of the year. Fingers crossed!

3. Actually Start a Newsletter

This will probably come as a surprise to the vast majority reading this, but I actually have a newsletter. Well, I have something you can sign up for—joining the eight fine individuals who already have—but I've never sent one, ever. Hey, at least you can't reasonably accuse me of spamming.

Anyway, I'd like to get this thing off the ground this year. Now that I'm writing more in general, the reflext to compile content for it should come fairly easily. The aforementioned site rewrite might bring along a bit of tooling to help as well.

4. Complete a Hardware Project

I've built a fair bit of software at this point. A lot of it is dead (for various definitions of "dead"), much of it was for work (and thus proprietary), and I've got some living projects out in the wild. My GitHub profile has some of the open source highlights and is constantly growing. But it has nothing about hardware whatsoever, predictably.

I've gotten some CircuitPython goodies from Adafruit the last two PyCons, and they've been a lot of fun right from the start. I've had a number of ideas of varying degrees of silliness, but haven't followed through on any. 2020 is the year I build a thing—may the good FSM help us all…

5. Explore a New Sphere Within Software

In the past I've fairly explicitly defined what I wanted to learn:

  • In 2016 I wanted to pick up a new language, and it—accidentally!—ended up being Vimscript.
  • In 2017 I decided to learn how to properly touch type, and that didn't really happen.
  • In 2017 I wanted to learn a new programming paradigm, but didn't get to it.
  • In 2017 I also wanted to specifically significantly improve my Python skillset, and that I accomplished.
  • In 2019 I hoped to learn a useful amount of frontend, and that absolutely didn't happen.

For 2020 I want to be less specific, largely because nothing comes to mind as a particular to-do item. Sure, I could pick up one of the previous misses—except touch typing, which getting an ErgoDox EZ earlier this year solved—but where's the fun in that? I'd rather do something fresh and exciting instead.

Perhaps this year I'll spend some time looking at this whole machine learning thing. Or maybe I'll end up becoming a cloud expert (likely thanks to work). Or I might finally spend more than five minutes with Rust, turning me into a low-level programmer out of nowhere. Or I may write a native mobile app. ~~The world~~ Software is my oyster.

In Conclusion

2020 is going to be a great year.

Goals for 2019 in Review 2019 is just about done—let's wrap it up. 2019-12-17T00:00:00Z I thought I'd mix things up for change by doing this before the year is over. After all, it's already December 17th, and little is likely to change at this point. You can find the original goals here.

First, the scorecard:

  1. Get Back into Open Source: ✓
  2. Write More!: ✓
  3. Read Some Tech Books: ✗
  4. Learn a Useful Amount of Frontend: ✗
  5. Give More Talks: ✓

Score: 3/5

1. Get Back into Open Source: ✓

It happened!

I didn't make quite as much progress as I had hoped I would, but some forward movement did occur:

  • Parsenvy got Windows CI and v3 is nearly done.
  • Starminder v2 is in progress (I've started sketching out the redesigned flow, but have written no code yet.)
  • I launched Wendlerizer.
  • I submitted some minor PRs to a few projects, but—somewhat notably—some of that work was done on my employer's dime. Hooray for sweetgreen!

It's not quite the mad flurry I was hoping—if not expecting—to achieve, but I'm glad to have completed something of consequence. Honestly, I'm perhaps most excited about having gotten to do some of it at work, starting to give back to the world on which I and all my employers have built so much.

2. Write More!: ✓

Oh, this definitely happened!

I've got at least one other post slated for publishing before the year is up. That will break past the previous record of ten in 2015, 2017, and 2018. I think they've been more worthwhile on average, too.

I've also written elsewhere, namely in a journal I started keeping. It had been a long while since I last did something like that, so I thought I'd see if I can get the habit going, and whether I then care to continue it. Results were great at first, but I've lately fallen off the train. I think I'll get back to it, starting tonight.

3. Read Some Tech Books: ✗

Nope. I even bought some (more).

4. Learn a Useful Amount of Frontend: ✗

It should come as no surprise that this one went absolutely nowhere.

In 2019 I made a mental switch from "web dev" to "software dev", which only pushed me further away from any notion of "full-stack" in the traditional web sense. With this disappeared much of my desire to keep up with frontend tech (i.e., the JS ecosystem), so this is no longer really a relevant goal.

I expect I'll actually tick this box when I need it for a real project I truly care about, be it for work or otherwise.

5. Give More Talks: ✓

We've come to the crown jewel of this year('s goals).

In 2018, I gave one talk at one meetup. In 2019, I gave that same talk at another meetup and a conference. I also gave a lightning talk at the same conference, totally on a whim (and bombing spectacularly). I'll share the links soon, I promise.

Past Years

Simple Is Funner than Complex I think I've figured out why I've been having such a hard time starting to migrate my projects to the cloud. 2019-12-10T00:00:00Z About half a decade ago, I distinctly remember wishing I had my own side projects that other people used. These days that's my reality, as I've got some tools and a few living deployed web applications out in the wild. Here are the ones relevent to this post:

Since I'm v. lazy, these are all currently deployed on Heroku, which is a wonderful, exceedingly painless hosting service. It's also quite expensive for my particular use case.

The above projects cost me a total of $42 per month:

  • requires one web dyno to run the Flask app
  • Starminder requires two dynos—one for the Flask app, and one for the task runner
  • SendOtterLove is a single-dyno Django app
  • is a single-dyno micro-app
  • is also a single-dyno Django app

Heroku charges $7 per dyno per month for the base paid tier ("Hobby"), which is required for constant uptime (free dynos sleep 6 hours per day) and SSL (https is a hard requirement for some of the above apps, and I'm quite fond of it anyway). I find this to be a very reasonable pricing model, if you want to deploy things that, uhh, get used.

But my projects don't really get all that much attention. Traffic on all of the above is nearly nonexistent, averaging less than one request per second:

Heroku stats

But I like them all, and don't want them to go away. I'm also unwilling to compromise uptime or SSL to drop down to the free dyno tier.

Given that the performance requirements for all of the above are also nearly nonexistent, I've always thought something as minimal as AWS Lambda would make for a perfect hosting platform. Now that I use Lambda at work a fair bit, that belief has only been reinforced. Relatedly, I have some AWS credit I'd like to use, especially as I'd wager that everything I have would fit into the free tier for most services I'd harness, giving me oodles of free hosting.

So why, then, have I struggled so much to carve out the reasonably small amount of time and energy required to migrate these—or even just one of them—over?

I think the answer is a bit deeper than the reflexive and superficial guess of "well, I am lazy" or "if it ain't broke, don't fix it".

Side Projects vs. Day Job

Software I write on my own time generally doesn't serve any work related purpose and isn't expected or even meant to get me paid directly. Most of it is open source, and it's a mix of web apps, libraries, and other miscellaneous stuff. It's all at least somewhat important to me.

A side project is by necessity of lower priority than the work I do at my day job. I quite like said job and find the work itself very rewarding. While I'm unwilling to compromise my ability to write software on my own time, I don't subject my job to any negative effects that could have. In short, work always comes first.

sweetgreen lives on AWS, so my work involves thinking through a lot of cloud related things. I'm no longer contributing to monoliths deployed on servers, but orchestrating services running on some combination of Lambda, containers, and managed services. Much of my job now is understanding the landscape of available tools and how to best glue them together to get the built-in advantages. I spend less time than ever actually writing application code.

This isn't necessarily a bad thing at all. I enjoy systems design and architecture—it's very challenging and rewarding work. The benefits of the cloud approach are pretty stellar much of the time as well—AWS really provides an awful lot services I don't have to manage at all, and that's great. But it doesn't feel playful or simple just about ever. And I miss that.

Work vs. Play

Many moons ago, when I still very much called myself a web developer, I generally thought of myself as "full-stack". Even though I'd done enough SysAdmin work to get things up and running, this mostly referred to my ability and desire to write code for both the server and the client in the context of web apps. Depending on which one I was working with for the most part at my day job at any given time, I tended to play with the other after hours. This kept me engaged and fulfilled without feeling negatively about work, which may have slanted heavily on occasion.

It's now been some time since I've thought of myself as a web dev, and much longer since I last used the phrase "full-stack" to describe what I do—or want to do. Lately I've invested energy into organizing events instead of writing software, which has left work as the only place where the engineering parts of my mind get a workout. I haven't felt like that in and of itself is a problem, but I do think that a different kind of separation is something I miss.

With the complexity I already tackle daily, I think I may be craving simplicity.

Now What?

I bet this explains why I've been so reluctant to dive into migrating my projects to AWS: I don't really want to deal with the complexity of rearchitecting everything and then managing that over time. I just want to write some Python and share the results with other people. To paraphrase the third line of my favorite PEP, simple is ~~better~~ funner than complex.

In light of this, I think I'm going to adopt an anti-cloud approach for these apps. I can probably rearchitect them all as fairly simple Django projects and deploy them on Lambda or ECS (if it turns out to be simple enough), or even EC2s (if it doesn't). Not flashy, cool, or full of new things to learn, no. But likely to be simple, enjoyable, and easy to maintain. Given that these are products that cost me time while netting very little in return, this feels like the correct trade-off.

We'll see if I'm right soon enough.

Computer cat

"Black Cat Holding Persons Arm" by Ruca Souza on Pexels