2018 Media Reviews

I’ve appreciated when people take the time to write reviews and highlight connections to other good works. This is an in-progress list that I’ll update over the course of the year. Previously: 2014 2015 2016 2017


Surgeon’s Mate: Patrick O’Brian; historical
More Napoleonic-era nautical adventures. Very fun reads.
Fire and Fury: Michael Wolff; politics
I look forward to the inevitable libel suits to see if there’s support for the unbelievable anecdotes in this book.

Tabletop Games

Pandemic Legacy: Season 2: Rob Daviau, Matt Leacock; strategy
Only played the prologue twice, but it feels like a nice balance of old and new mechanics. Really looking forwarding to playing through this.
Unearth: Jason Harner, Matthew Ransom; worker placement
Fun, quick strategy game with a nice amount of variance. Rules are a little unclear, seems like almost every action card has a corner case).

Last update: 2017-01-07

Posted in Life at 2018-01-07 22:01 | No comments | Tags: , , ,

2017 Media Reviews

I’ve appreciated when people take the time to write reviews and highlight connections to other good works. This post was written in one go at the end of 2017. I didn’t keep good track of the games, so that’s spotty and may be updated in 2018 as I’m reminded of them, but is otherwise complete. Previously: 2014 2015 2016

Continue this post…
Posted in Life at 2017-12-27 16:51 | No comments | Tags: , , , ,

Return Statement

I’ve finished my time at Recurse Center, and a small tradition is to write a “return statement” about what you did in your time there.

Attending Recurse Center was a very rewarding time for me, personally and professionally. I succeeded at studying some difficult topics, I learned about a number of things I’d never have thought to look for, and even more important I got to spend three months with a group of curious, kind, smart, generous developers. I am both proud and humbled to be a part of the Recurse community.

I was a bit unusual among Recurse attendees in how narrowly I focused on studying Haskell, so most of this list of things I did is other stuff:

  • Finished a solver for Shenzen Solitaire, a Haskell program to tell me how bad I should feel about my results at the game (very bad, around 99% of games are winnable). I got practical experience in Haskell modeling data, managing state, testing, property-based testing, debugging, and tooling. I’d been working on this for a few months at Code and Coffee before I started.
  • Soldered and assmbled a Planck keyboard, then configured it using the very nice QMK firmware with a Norman layout, then trained that up to an acceptable 75wpm. I’ll write a longer post about keyboards at some point, but for anyone who gets curious to buy a kit and might buy from MassDrop, let me mention that I ended up deleting my account over how badly they mismanaged the process and how dishonestly they communicated about it.
  • Became the sysop of Lobsters. This wasn’t because of Recurse, but it was a big life event that happened during my time at RC. I planned the migration, learned ansible to help administrate the new servers, and started writing Rails code again for the first time in a year to maintain and improve the site.
  • Met with a twice-weekly Haskell study group to work through Haskell Programming from First Principles. I was mostly ahead of the group from prior study, but still learned from all the discussion and helping others. The group split up around Thanksgiving as folks decided to focus on various personal projects.
  • Got an introduction to MetaMath and had a multi-day conversation about isomorphisms between different branches of mathematics and computer science, as well as a number of related topics like the role of git in collaborative projects.
  • Attended a reading with Q&A by Ellen Ullman, whose book “Close to the Machine” is a cornerstone in my understanding of the experience of programming and its effects on programmers and the world at large.
  • Had an interesting experience in sleep deprivation: I started to do some system administration, but quickly recognized that I was too tired to be logged into anything as root. I changed gears to refactoring Haskell and was able to make real improvements by leaning on the type system. Usually I would’ve been writing the commits that featured in the ‘git blame`s of next week’s debugging, but when I looked back they were all solid. The maxim “if it compiles, if works” seems to be true of Haskell refactoring.
  • Learned about symbolic execution and concolic testing, an exciting new field of research in program correctness. It’s very academic now and I want to try my hand at writing a practical tool; if it can scale to real-world code it could be tremendously valuable.
  • Gave a 5-minute lightning talk introducing functors. I’ll probably record this and put it up on my talks page before the new year. Came in under my usual ratio of one hour of prep time to one minute of presentation.
  • Helped a family member’s small WordPress hosting company recover from being defaced by an Albanian script kiddie. I miss when helping older relatives with tech meant setting VCR clocks.
  • Spent two weeks awakened every morning at exactly 3:05 AM. Maybe a building heater had a new routine for the cold weather or something, but the NYC area is noticeably louder at night than Chicago.
  • Attended several tech talks, most organized by RC.
  • Visited Chicago for a wedding, which was a great chance to see friends and family after so long away.
  • I’ve long dithered over the correct order for projects on my homepage. I cut the gordian knot by randomizing it with the rng seeded by year + week so it doesn’t change every single reload.
  • Spent Thanksgiving vounteering to serve meals to the elderly and indigent at a restaurant. After taking orders and running food for a bit, I spent the rest of my day behind the bar serving drinks. This was a very rewarding day and I see more volunteering in my future.
  • Restarted my use of spaced repetition study software (Anki + AnkiDroid) to shore up my American sign language and solidify the foundation of my Haskell knowledge as I shift into app dev. If the time I spend learning is an investment, SRS is a maintenance contract: I pay a little on a regular basis to ensure the investment doesn’t get lost.
  • Took a sharp detour in my last week of studying. Rather than continue to the end ot the Haskell book, I worked on art project called An Inaccurate Clock. Learned SVG for it, which is a nice tool for interactive graphing and vector drawing that I’m glad to put in my toolbox. (This will probably not be released publicly.)
  • Got to try an Oculus Rift VR headset, which I was nervous about as almost all 3D games give me motion sickness. I had a lot of fun with First Contact and Superhot and had only a mild reaction.
  • Toured New York City a bit. I have family in the area and have visited a number of times, so I didn’t do much of this. Highlights included walking Rockaway Beach, the High Line, a picnic in Central Park, and many long walks through Manhattan and Brooklyn. Took a side trip down to Philadelphia and Baltimore (east coast cities are so close together!) to visit some old friends.
  • Met a lot of very good people, saw their excellent, creative, strange, funny, personal, and impressive projects, and had a hundred great conversations about code, practices, careers, and life in general. (Veni, vidi, colloqui.)

If you’re considering attending Recurse, it is almost certainly worth your time. I’d be happy to answer any questions you have by email, on Twitter, or on Freenode.

If you’re considering hiring through Recurse (they keep the lights on with recruiting fees), it is an excellent source of high-quality developers. I don’t know what stronger signal you could get than someone choosing to spend three months learning and collaborating, really.

Posted in Life at 2017-12-15 15:49 | No comments | Tags: ,


Robots and elderly relatives have finally driven me to extreme measures. My voicemail greeting is now this “you have reached a number that has been disconnected” recording repeated for sixty seconds as a multi-pronged attack on voicemail:

  • The notes are the “intercept” special information tones indicating a line is disconnected and the robots should mark the number as dead.
  • The words should confuse or bore humans enough to hang up.
  • The length should prevent me from getting two-second empty voicemails from people hanging up too slowly.

(Before you suggest, my phone company doesn’t let me disable voicemail.)

A potential failure is that I want to continue doing business with a few companies that robocall me with notices (insurance, finance, utilities). If one of their robots flags my phone number as bad it might become a customer support hassle where they think they no longer have a valid phone number for me. I’ll edit in an update if this becomes a problem.

Posted in Life at 2017-12-03 13:50 | No comments | Tags: ,


I’m now the sysop of Lobsters, a social news site focused on technology.

Its creator jcs announced three weeks ago that he was ready pass the torch. I’ve been very active on the site, submitting tons of stories to help get the flywheel turning on a solid community. I want to see this good community continue and grow. With the support of the irc regulars, I stepped up to become the new administrator.

We planned the migration and executed it last weekend. There’s a handful of tidying-up tasks on the to-do list, but everything’s running smoothly on the new server.

The Lobsters codebase has been open source for years and I’m now maintaining it. There have been some great contributions from community members and I’ve tagged some issues to encourage new contributors. The new ansible playbook for configuring the site is also public, so hopefully it’ll now be very easy for more people to set up their own sites using the codebase.

I’ve been getting a lot of questions about managing communities in the last week, but I think I’ve already expressed most of my thoughts about it on Lobsters over the years with comments on what I think Lobsters is for, the environment I want to foster, difficulties with brief text on Twitter, and my approach to effective moderation.

If you’re reading this blog because we’ve met or spoken, please email me for an invitation. Otherwise, check the user list for someone you know or ask in chat (mention what you want to contribute or link a personal site/github so they know you’re not a random spammer). Hope to see you there!

Posted in Life at 2017-10-23 10:48 | No comments | Tags: , ,

Attending Recurse Center

I have been accepted to the Recurse Center to spend three months on collaborative, self-directed study of programming. I’m planning to continue studying Haskell and dependent types, proof assistants, and category theory. Maybe Coq, Idris, or TLA+ if I can find someone else interested.

Recurse encourages experienced devs to start or work on open source projects. For a couple years I’ve been taking notes on git’s command-line interface and joking about becoming the first CLI UX specialist, so I think I’m going to start that project as part of my Haskell practice. I don’t plan to re-implement git, I plan to wrap it with more cohesive mental models and useful features for day-to-day development work. If you have thoughts or resources in this area, I’d love to hear about them.

I’ll be attending the Fall 2 session in New York City from September 25 to December 15. If you’re in the NYC area those dates and would like to meet up, reach out, I’d love to meet up. And if you’re in Chicago, well, you won’t see me at Code and Coffee for a few months.

Posted in Life at 2017-08-29 15:22 | 5 comments | Tags: ,


I have some random episodes of podcasts laying around waiting to get listened to from podcasts I don’t (yet) care to subscribe to. Maybe they had an interesting guest or topic, or came recommended. These downloads will lay around on my computer for months because they’re not in my podcasting app, so they’re not really in my listening queue.

So I hacked up a PHP script to grab those mp3s and serve a valid (if spartan) podcast feed.

You can find the code on GitHub. It’s designed to be dropped into place rather than robustly deployed. Then I download mp3s to that folder and they’re delivered as my own personally-curated podcast feed.

Thanks to Shubham Jain for his PHP-ID3 library so the script can read some metadata into the feed.

Posted in Code at 2017-08-27 16:02 | 1 comment | Tags: , ,

Arithmetic Wrap in GMS2

I’m learning GameMaker Studio 2 because my 10-year old nephew wants to make video games (and the 10 year old inside of me wants to make video games, too). It’s a nice toolkit and IDE for games, very beginner-friendly, with a friendly community. It’s even been used in some highly polished and popular games. If you’re curious, there’s a ~90 minute tutorial playlist that’s easy to skim as a demo.

Pricing is reasonable, it’s $100 to export desktop games, couple hundred more to export to iOS + Android, HTML 5, even PS4 and Xbox. And this week version 1.4 (with a free trial and discounted upgrade to version 2) is on sale cheap.

The games are coded in “GameMaker Language”, which is approximately PHP 3. Little more OO, little less coercion, but it feels similarly very focused on its niche without much experience behind it. I’ve been mostly coding Haskell the last few weeks, so there’s a bit of whiplash moving between the two.

There’s some great video tutorials on YouTube showing how to make games like NES Zelda, Farming RPG, and Platformer. All three of those channels are worth clicking around on as they have other good playlists or one-off videos.

On that last channel I saw a video on Useful Scripts for GMS2 presenting five code snippets. In GML, a “script” is roughly a singleton static method object used to centralize game state or encapsulate snippets of functionality.

The third script presented at 5:18 in the video was wrap(value, min, max) which wraps values that exceed the min or max back around to the other side. So wrap(5, 0, 9) is 5 because it’s in the bounds, but wrap(11, 5, 9) is 6 because it wraps 2 past 9. There’s a visual in the video at 5:30 that makes it real clear. There’s also a screenshot of the code:

/// @description Wrap(value, min, max)
/// @function Wrap
/// @param value
/// @param min
/// @param max
// Returns the value wrapped, values over or under will be wrapped around

if (argument0 mod 1 == 0)
	while (argument0 > argument2 || argument0 < argument1)
		if (argument0 > argument2)
			argument0 += argument1 - argument2 - 1;
		else if (argument0 < argument1)
			argument0 += argument2 - argument1 + 1;
	var vOld = argument0 + 1;
	while (argument0 != vOld)
		vOld = argument0;
		if (argument0 < argument1)
			argument0 = argument2 - (argument1 - argument0);
		else if (argument0 > argument2)
			argument0 = argument1 + (argument0 - argument2);

There’s a lot going on there. This is probably hot-path code that runs every frame, but it has branches inside a loop for something that could almost certainly be an arithmetic one-liner. So for practice with GML and the IDE in general, I rewrote it.

I saved the above script as original_wrap and created my own wrap implementation:

/// @description wrap(value, min, max)
/// @function wrap
/// @param value The value to wrap into the bounds
/// @param min Minimum bound, inclusive
/// @param max Maximum bound, inclusive
// Returns the value wrapped to the range [min, max] (min and max can be swapped).
// Calls floor() on reals, but GML's modulo is doing something weird and original_wrap just hangs indefinitely on some values anyways so oh well.

var value = floor(argument0);
var _min = floor(min(argument1, argument2));
var _max = floor(max(argument1, argument2));
var range = _max - _min + 1; // + 1 is because max bound is inclusive

return (((value - _min) % range) + range) % range + _min;

Some oddities, like JavaDoc instead of a function signature, so arguments have automatic names (reminds me of perl 5). In dev I got a compiler error for referencing argument1 before argument0 – I’m not sure what that could be but look forward to reading the manual. I can’t unimport/shadow the global max and min, the convention seems to be to use a leading underscore for colliding names.

To test it, I created another script called test and invoked it from an object’s create event. Which felt a little roundabout for specifying that I wanted it to run at startup, but I’ve barely touched the manual so I’m probably missing something obvious. I know there’s 3rd-party test library but I wanted to hand-roll to see more moving pieces. I generated a golden master test suite to exercise a bunch of test data, though I didn’t go all the way into property-based testing:

// make this easy to spot in the build output
show_debug_message("HELLO &&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&");

for(i = -5; i < 25; i++) {
  var orig = original_wrap(i, -2, 5);
  var new = wrap(i, -2, 5)
  if (orig != new) {
    show_debug_message("int failed " + string(i) + " orig " + string(orig) + " new " + string(new));

//for(i = -5.0; i < 19.2; i = i + 1.1) {
//  show_debug_message(i);
//  var orig = original_wrap(i, -2.1, 5.3);
//  var new = wrap(i, -2.1, 5.3)
//  if (orig != new) {
//    show_debug_message("real failed " + string(i) + " orig " + string(orig) + " new " + string(new));
//  }

The commented-out testcase is, I think, about the broken behavior with regards to reals. I’m pretty sure the (argument0 mod 1 == 0) exists to type-check if argument0 is an integer or real. I’m not sure because GML has typeof for typechecks (is_real in 1.4, which feels very PHP 3), but this is probably well-copy-pasted newbie code. When I tried to test the behavior, I ran into a bug where original_wrap hung indefinitely on some inputs (the existing test triggers this, if you want to uncomment and run). I didn’t want to keep tinkering, so I dropped in some floor calls and moved on.

Anyways, this was some fun tinkering. I’m looking forward to working through the official tutorial with my nephew and maybe making some small games. (Oh, and I release this into the public domain, feel free to use it with or without credit.)

Posted in Code at 2017-08-06 21:50 | No comments | Tags: ,

Redshift With Cloudiness Adjustment

A Lobsters story on the bright blue light of displays reminded me I should post this. I use redshift to adjust the color temperature of my monitor at night so I sleep better, and I wrote a custom wrapper script to include an adjustment for how overcast it is.

set -e # exit on error
#set -x # debugging
if [ `pidof /usr/bin/redshift` ] ; then exit ; fi
# Chicago
# Tungsten: 2700K
# Halogen: 3400K
# Fluorescent: 4200K
# Daylight: 5500K
# figure out how overcast it is, and adjust temperature to match
TODAY=`date +%Y-%m-%d`
wget -q -O/tmp/clouds.xml "http://graphical.weather.gov/xml/sample_products/browser_interface/ndfdXMLclient.php?product=time-series&sky=sky&lat=$LAT&lon=$LONG&begin=${TODAY}T00:00:00&end=${TODAY}T23:59:59"
OVERCAST=`echo -e 's/[^0-9]*([0-9]+)<\/value>/1/m\nt xxx\nd\n:xxx' |sed -rf - /tmp/clouds.xml |tail -n 1`
TEMP=`echo "$MAX+${OVERCAST}0" |bc`
redshift-gtk -l $LAT:$LONG -t $TEMP:$DOWNTO -g $GAMMA -m $MODE
Posted in Code at 2017-01-25 12:32 | No comments | Tags: ,

Hard Lessons

Having worked on email-related code before, I have been morbidly fascinated by one of the founders of handmade.network writing an email client. Handmade Network is trying to reinvigorate programming by emphasizing small teams and from-scratch performant code. It’s a great way to write small, self-contained projects (games, libraries, utilities) that can be done, but fell out of favor two decades ago for complex user-facing software.

This update included a few sentences I’ve been waiting for:

The biggest lesson is that not everyone is RFC-compliant. It was a shock seeing some companies accept ill-formed e-mail addresses, developers showing their best-but-still-inaccurate regular expressions for compliance, and security agents from company’s mail servers trumping simple IMAP requests that should have yielded a proper response, but didn’t. Look, I always knew commercial software packages don’t fully adhere to a spec—not even language compilers achieve 100% accuracy—but seeing violations led to unfortunate wrinkles and hard-coding in specific recovery points when I try to talk to some servers.

From what he lists, he’s only seen the tip of the iceberg. For example, he hasn’t mentioned some of the fun problems of IMAP or talked about the woes of email encoding and attachment. Specifically, this strategy of “seeing violations led to unfortunate wrinkles and hard-coding in specific recovery points when I try to talk to some servers” is really, really not going to scale. C is a tough language for the tower of abstractions he’s going to build and rebuild in the face of unexpected inputs and dusty corners of the spec.

And email is a particularly hard domain because it’s old and *looks* simple, so there’s an incredible amount of errors you have to cope with from version 0.1. Users will never accept “Yeah, you just can’t read email from people using Outlook, it’s Microsoft’s bug.” And then on top of all that, many emails are shifting to HTML-only with increasing expectations of CSS support and you’re implementing or talking to a huge browser engine. Email was a big factor in ending my support for Postel’s maxim.

It might be another 5 months before I reach a working prototype for that [GUI], and probably another two months of polish before I consider the possibility of releasing some build publicly.

I wish him a lot of luck and there’s a tiny, windmill-tilting bit of me that hopes he’ll succeed, but I’m watching this race for the crash.

Posted in Code at 2016-09-28 10:39 | No comments | Tags: ,
  • Twitter: pushcx

  • More tweets below and @pushcx