Hardscrabble 🍫

By Maxwell Jacobson

See also: the archives and an RSS feed

git cleanup-branches

March 1, 2018

Do you clean up your git branches as you go or are you, like I am, a lazy hoarder?

$ git branch | wc -l
150

Look at all those things I did that I don’t care about anymore.

Yesterday I googled a little to try and find some magic incantation that would just clean up my branches for me. There are some, but I find that they’re either too conservative or too liberal for me. By “too conservative” I mean that they try to only delete branches that have been merged, except that they’re not actually very accurate, because they aren’t aware of GitHub’s “Squash and Merge” or “Rebase and Merge”, which I use pretty much exclusively. By “too liberal” I mean that some people recommend just literally deleting all of your branches.

I want to have control over the situation.

I can just run git branch -D branch-name-goes-here over and over, one-by-one, for all of my branches, but that would take several minutes, which I definitely technically have, but don’t want to spend that way, even while curled up with a podcast.

What I really kind of want is some kind of interactive process that gives me total control but doesn’t take that long to do. So I made a little shell script, which looks like this to use:

gif demonstrating git cleanup-branches which lets you interactively delete branches

As you may notice, it takes some loose inspiration from git’s interactive rebase.

It does something like this:

  1. get your list of branches
  2. open your default editor (whatever you have the $EDITOR global variable set to) (vim for me)
  3. wait for you to mark which branches should be deleted
  4. delete the ones you marked

git lets you plug in little scripts by just naming them git-whatever-you-want and putting that script on your $PATH and I think it’s fun to take advantage of that.

Here’s the latest version of the script as of this writing:

#!/usr/bin/env bash

set -euo pipefail

file="/tmp/git-cleanup-branches-$(uuidgen)"

function removeCurrentBranch {
  sed -E '/\*/d'
}

function leftTrim {
  sed -E 's/\*?[[:space:]]+//'
}


all_branches=$(git branch | removeCurrentBranch | leftTrim)

# write branches to file
for branch in $all_branches; do
  echo "keep $branch" >> $file
done

# write instructions to file
echo "

# All of your branches are listed above
# (except for the current branch, which you can't delete)
# change keep to d to delete the branch
# all other lines are ignored" >> $file

# prompt user to edit file
$EDITOR "$file"

# check each line of the file
cat $file | while read -r line; do

  # if the line starts with "d "
  if echo $line | grep --extended-regexp "^d " > /dev/null; then
    # delete the branch
    branch=$(echo $line | sed -E 's/^d //')

    git branch -D $branch
  fi
done

# clean up
rm $file

It follows the “chainable shell function” pattern I’ve written about before.

It uses set -o pipefail, my favorite recent discovery in shell scripting, which makes sure that each command succeeds, not just each expression. I should probably do a separate blog post about that with more detail.

Yeah, I guess that’s pretty much it. Have fun shell scripting out there.

2017 in television

January 3, 2018

Here’s my favorite shows that aired in 2017. Just sharing because I spent way too much time this year watching television, so maybe this will help you pick the good stuff, as long as your taste is also my taste, which it’s not. I’ll try to avoid spoilers.

10. Mr. Robot (s3)

This show remains a technical wonder. It has a very sharply drawn aesthetic – you know you’re watching this show by the mannered acting and the off-center camera compositions more than anything else. Nothing I saw on television was as cool as the 4th episode, which is presented as one long take, and aired without commercials. It feels like the rules don’t apply to this show. This season was mostly about pain and regret and what to do with them. Anything productive? Maybe it’s possible.

Rami Malek is and has been great, but this season was as much about the constellation of characters around him. This show knows it’s fun to watch smart people do hard things and so it drew up a bunch of them, made you love or fear them, and set them against each other. I particularly liked any scene with Dom, Grant, Darlene, or Angela.

Highlight: eps3.4_runtime-error.r00

9. Crazy Ex-Girlfriend (part of s2 / part of s3)

I’ve loved Rachel Bloom since I Steal Pets, a truly brilliant, stupid music video she made in 2011. Somehow she’s made a show that has several hysterical songs in each episode, a cast of lovable gentle Californian weirdos, and a very thoughtful depiction of what it’s like to struggle with mental health. It really feels like an auteur work in the sense that it’s hugely personal and no one else could’ve or would’ve made it. She writes and acts and sings. It’s nuts. I giggled like a child all through “I Go To The Zoo” and “The First Penis I Saw” and felt a swell of an uneasy hope during “My Diagnosis”.

Highlight: Josh Is A Liar

8. Catastrophe (s3)

This show is mostly special beacuse it’s very funny, and there are few pleasures comparable to Sharon and Rob making fun of each other so cruelly that you know they must really love each other or how else could they put up with that? It’s also one of the best, most real-feeling stories of alcoholism that I’ve seen. It reminded me, at times, of a crime drama like Dexter where the anti-hero has a secret and we’re for some reason invested in him not being found out as a serial killer, except here he’s sneaking drinks, and you feel it in the pit of your stomach that this is bad. It’s mostly very funny. But it’s also very dedicated to arguing that we’re better when we step up and be there for each other even when it sucks and I find that helpful to think about. The drama is very ordinary but the characters are so lovable that you care. And Carrie Fisher is great.

Highlight: Episode 6

7. The Marvelous Mrs. Maisel (s1)

Just watched this one over Christmas break, with my mom, so there may be some recency bias here, but I really loved it. This show entertains on so many levels. It’s hysterical, with great characters, acting, and dialogue. The scenes between the comedian characters in particular feel funny in a way that funny people are with each other, where they want to skip past the norms of what they’re supposed to say, and then also not laugh, and then also act like that was normal. All the scenes with Midge and Lenny Bruce were golden like that. And just watching a show about a person figuring out they want to do some kind of art and that they might be good at it and then realizing it’s going to be a lot of work and maybe not that fun all the time is hugely fun, because each step feels real and earned and satisfying. That that person is a Jewish woman with two kids in the fifties in Manhattan played by someone as charismatic as Rachel Brosnahan makes it feel very unique and alive. Also her parents are hysterical and Joel sucks in such a real and lived in way that it almost brings pleasure how reliably the dude sucks. And that the cinematography is frequently dazzling, with a camera that floats through clubs and apartments and over tables and around Hora dancers, and the soundtrack crackles with sometimes on-the-nose but very charming contemporary songs makes the whole thing just kinda whizz by.

Highlight: Because You Left

6. The Americans (s5)

Maybe I’m a sucker and a fool for things that are just the slightest bit unusual, but the premier’s exhuming sequence, which has no dialog for something like 15 minutes as we just watch these people do their job ultra competently and feel the weight of it on their backs and the amount they’re stuck with the decisions they’ve made and have been made for them growing and growing … is very good … and is enough to make me sit up straight and hold my breath.

This is the penultimate season and it kinda feels like one. This is the TV show version of a clenched jaw. It’s all heading to hell, for sure. I think of it as a show about marriage and parenting, which isn’t really an original way to think about it. But it really makes me feel the painful feeling that maybe for all our/their hard work, the next generation won’t really be better off. On that theme, the new characters of Tuan and Pasha were fascinating and painful to watch.

Highlight: Amber Waves

5. The Leftovers (s3)

The final season! This show was based on a book, but they pretty much covered it in the (pretty good) season one. Seasons two and three veered off and did their own thing and explored grief, mental health, love, religion, and family using some of the most bizarre scenarios with the most committed cast. It’s a really stunning show just to look at even if you don’t have any idea what’s going on, which you mostly don’t. Justin Theroux and Carrie Coon are incredible.

I don’t really need things to stick the landing perfectly; Lost’s ending wasn’t perfect but it was fine IMO. The Leftover’s is another Lindelof joint, and it does feel like Lost is hanging over it a little. He did a better job of managing expectations this time, because I don’t think anyone watching expected the show to start making sense right at the end. Nevertheless, the ending had me spellbound.

Highlight: It’s a Matt, Matt, Matt, Matt World

(for the submarine sequence if nothing else, but also the rest)

4. Better Call Saul (s4)

I did like Breaking Bad a lot and I didn’t really know what to make of this when it started. It’s a little hard to talk about. It’s really its own show, distinct from Breaking Bad. When I say that the whole show was building to this season, that doesn’t mean what you think it means if all you know is it’s the Breaking Bad prequel show. More than that it’s a family drama about a handful of lawyers, all proud, all brilliant, each kind of broken in their own way. Like Breaking Bad, it’s about how people’s consciences rot and fall away, or don’t, and the effects on other people. It’s pretty heavy, but in a way that feels real and awful. It’s also, frequently, hysterical.

Highlight: Lantern

3. The Carmichael Show (s3)

Really sharp writing and amazing chemistry from the cast. Nothing else made me laugh as often. I loved the sneaky emotional ones, too, which is almost all of them. Each character gets to take their turn being the asshole taking the overly harsh position on whatever the argument of the week is, and actually gets a chance to speak their mind, and then they keep digging until they find some understanding. It’s a very winning formula. I’m sad this one ended.

Highlight: Cynthia’s Birthday

2. Nathan For You (s3)

Nathan For You is audacious and radical and sweet and kind of cruel and depressing. I hope he does more. It’s so unpredictable, but in unpredictable ways. Most of the funniest moments come from Nathan violating some social norm, but the surprising thing is how polite he is as he does it. I often feel terrible for his subjects, except that it’s very hard to find fault in Nathan’s behavior. He’s never really ridiculing anyone. He’s more enabling people to succeed at whatever their dreams are, if only temporarily. That their results are uniformly terrible makes their dreams feel small and unimportant and them seem foolish for even having them. But maybe it’s better to live your dream than to not?

Highlight: Finding Frances

1. Halt and Catch Fire (s4)

This was the fourth and final season and it was just about perfect. The episode called “Goodwill” is one of the most beautiful things I’ve ever seen on television. What this show did better than any other is make you really love its characters and care about them and feel for them. That it was about the early days of the internet and felt real and lovely is only extra credit. That it told the story of Cam and Donna struggling and having success as women in tech, also extra credit, and I think not talked about enough, IMO.

Highlight: Goodwill

Honorable mentions (alphabetical ordered)

  • Black Mirror (s4)
  • Bold Type, The (s1)
  • Brooklyn Nine-Nine (s5)
  • Fargo (s3)
  • Fresh Off the Boat (s4)
  • Girls (s6)
  • Good Place, The (s2)
  • Master of None (s2)
  • Mindy Project, The (s6)
  • Scandal (s7)
  • Search Party (s2)
  • Sweet/Vicious (s1)

Also enjoyed (alphabetical ordered)

  • Broad City (s4)
  • Curb Your Enthusiasm (s9)
  • Game of Thrones (s7)
  • Glow (s1)
  • Handmaid’s Tale, The (s1)
  • Legion (s1)
  • New Girl (s6)
  • Rick and Morty (s3)
  • Stranger Things (s2)
  • Unbreakable Kimmy Schmidt (s3)
  • Veep (s6)
  • You’re the Worst (s4)

the hardware and software I use (2017)

December 21, 2017

I’m an inveterate reader of Uses This style articles and I’ve always wanted someone to ask me to participate in one and no one has, and I have a perfectly fine blog, so here goes nothing (actually something quite self-indulgent and in need of editing and unlikely to be an annual tradition now that I know how weird it feels to write this all out).

I’m borrowing the questions from that website (thanks).

Table of contents, because this got long, but I guess that’s because I really like using hardware and software, which is true, and that’s a good point when you think about it

Who are you, and what do you do?

Yes hello I am Max Jacobson, I’m a software engineer who makes web apps, currently at Code Climate. Occasionally, and not professionally, I write, speak in public, and podcast.

What hardware do you use?

I have too much and want to have fewer but I’m not sure what to not use. I try to make my hardware last as long as I can and avoid indulging the guilty thrill of buying new things, with mixed success. By frequency of use:

I use my iPhone 7 constantly. It’s great. I like the funny vibrating home button and don’t really miss the headphone jack. I got the AirPods for my birthday and they’re great, although they’ve turned me into someone who gets nervous stepping over grates in the sidewalk. I use it in a Smart Battery Case which is fine, although I feel very warped by it because I start feeling a little stressed out as soon as my phone’s battery dips below 100%.

At work, since March 2017, I use a Lenovo ThinkPad P50 which is enormous and heavy and has a numpad built in that I never use and that little red nub for mousing that I never use and a hinge that curiously opens to a full 180 degrees which I never do and a second set of mouse buttons above the track pad which I never use and a fingerprint scanner that I never use. I didn’t exactly pick it out: when someone left the company I took it over and turned in a MacBook Pro so I could try out switching to Linux (more on that later). I do like it: it’s super fast; the keyboard is good; the screen is sharp; it has all the ports you could want; the actual thing feels pretty good; and once your eyes adjust, its stark black and red aesthetic starts to look kind of slick. I’ll probably pick a smaller ThinkPad for my next laptop.

I use it with a WASD V2 87-Key Custom Mechanical Keyboard, which is awesome and a $5 AmazonBasics USB Mouse which is perfectly fine. I’m not in the camp of people who detest wires on a desk. If anything, I’m in the camp of people who detest having to charge things.

Next up is the 2016 9.7” iPad Pro. I mainly use it to do things like watch videos in bed or read Twitter on the couch. Occasionally I’ll take it out to a cafe with the Apple Magic Keyboard so I can do more productive stuff like write emails or research some project, where I appreciate being able to command+tab to switch between apps or command+space to quick-launch apps. I recently bought a Canopy keyboard case to kinda encourage me to do that more, and hopefully I’ll like that. (Edit: I did)

I like having it. It lets me give my phone a break. It’s so light. It has such a nice screen. Its speakers are surprisingly loud and nice-sounding. It’s fun to use and to look at (I have the pink one with the mint green smart cover).

For a personal, non-iPad computer, I used to have a 15-inch, Early 2011 MacBook Pro, but it died in early 2017. My grandma bought it for me after college when I was trying to become a filmmaker. It ended up being the computer where I learned to code instead. I put that machine through hell trying to keep it going, and I struggled for a while figuring out what to replace it with. I probably would’ve gotten a spec’d out MacBook pro except that all signs suggested they were going to release a big new update soon. They ended up doing so, but not until November, and it was kind of a controversial new design which I’m glad I didn’t wait for.

I ended up getting a 2015 Dell XPS 13 Developer Edition in November 2015, actually awhile before the MacBook Pro formally stopped booting. I was looking for a light laptop that I could travel with (by this point the MacBook Pro felt like a brick in my bag and had a few loose screws clattering around in it which left me preferring to keep it at home), and also to experiment with using Linux. It cost $1,370. I like this laptop fine. It’s light and fast and runs Linux and has a decent battery and a nice screen. I think it’s weird to have the webcam positioned below the display instead of above. The keyboard is only fine. It feels so sturdy and compact that it doesn’t feel fragile and I toss it in my bag without a case. This is the laptop I brought to India and studied Rust, and later brought to New Orleans to present at RubyConf. It’s reliable and straight-forward.

But when my MacBook Pro died, I did kind of feel like I needed a Mac. I had salvaged the harddrive from the laptop and bought a drive enclosure. I also had them backed up to another hard drive and to the cloud, via backblaze. All those backups cried out to be restored, somewhere.

I ended up getting a Late 2014 Mac Mini spec’d out with 16GB of RAM, an SSD, and whatever the fastest processor was. It cost $1,399. That’s a weird computer to choose in early 2017. Even in 2014, it was really poorly received because it didn’t offer all the options that the previous generation did and wasn’t as upgradable after purchase. I was kind of thinking it’d be a stop-gap until the new MacBook Pros came out, and then I’d sell it and get one of those, but then those came out and were not very appealing to me. But to be honest, I kind of love it. In my experience, it’s plenty fast and reliable. I almost bought a Mac Pro and it turned out the Mac Mini was enough for me. Lol. I don’t use it a ton: I’m on a computer enough at work and don’t thrill at the idea of spending much more time on one. But I still like to have a Mac somewhere in my life, to serve as a hub for things like my photo library, my music library, and all my old college essays and writing projects. And as much as I’ve come to like Linux, there remain a few things that I need a Mac for (more on this later).

I use it with another AmazonBasics mouse and a Spacesaver M White Buckling Spring keyboard from Unicomp. It’s hilarious and thunderous and retro and great. I love it.

For sound, I use Altec Lansing BXR1220 computer speakers I bought for $15 five and a half years ago which are perfectly fine and look pretty cool IMO.

For a display, I use a Dell U2713HM 27-Inch Screen LED-lit Monitor that The Wirecutter recommended when I bought it in 2014. It’s been really great.

For recording audio, I use a MXL Tempo USB Desktop Cardioid Condenser Microphone. I was going through a phase where I enjoyed red things. It wasn’t a huge investment, is simple to use, and sounds OK.

For Wi-Fi, I switched to Eero in 2016 to get better coverage of my apartment and it worked out great.

I watch TV and Movies using an Apple TV (which is fine) on a TV that my friend Russ handed down to me when his aunt handed hers down to him (which is fine).

When I write longhand, it’s usually on some cheap Gregg-ruled steno pad I picked up at a pharmacy (I like the spiral being at the top so it stays away from my wrists; I like for the margin to be right down the middle so I don’t feel weird writing right up to the edge of the page, and it also gives me a sense of how far across the line I’ve gotten at any given point? Maybe I don’t need the middle margin actually) using a Muji 0.5MM Gel-Ink black pen which my sister recommended to me once, years ago.

For reading books, I use the library.

I have way too much hardware, but at least I don’t have an Apple Watch.

And what software?

I try not to use too much software, because the more things I use the more keyboard shortcuts I have to remember, and the less room in my heart there is for poetry. I try to use built-in software when possible unless it’s really bad.

For programming a computer, I primarily use Ruby or, for simple things, shell scripts. I also like to use Rust.

For writing code, I prefer to use terminal-based tools, primarily: vim for editing text, tmux for terminal multiplexing (creating separate workspaces for separate projects, each consisting of a few related shells, controlling how they’re laid out and which to focus on), zsh for a shell, and git for tracking changes to source code. I like them because they’re free and open source, blazing fast, and have user interfaces that feel like they’re carved from stone. There’s a long tail of unix tools that assist in the process of writing and testing code, but I’m going to consider them out of the scope of this post. Thankfully, those all work pretty much the same on both macOS and Linux.

My dotfiles are available on GitHub. They use thoughtbot’s lovely rcm tool to ease installation and syncing across multiple machines.

On macOS, I use the built-in Terminal terminal emulator and on Linux I use rxvt-unicode.

For an operating system on my two laptops, I initially tried Arch Linux at the recommendation of a few co-workers and I’ve come to quite love it. It has a deserved reputation for being ultra minimalist, which means you have to do more legwork to get it up-and-running, but then you can customize it exactly to your taste. It’s way more bare bones than I could ever have imagined. If you want it to behave in any way at all, you have to tell it to – even for super basic things like locking the screen after a few minutes of inactivity – but it has all the seams in place for you to do just that. I initially set it up using this fabulous tutorial from LearnLinux.tv and have iterated on it via a lot of guidance from my patient co-workers and by copious browsing of the elaborate ArchWiki.

For managing windows on my laptops, I’m using xmonad, a tiling window manager. In the past I’ve tried macOS apps that add keyboard shortcuts for managing windows in a tiling fashion (Spectacle, I think, and others) and never found them to be particularly compelling. I thought things like: I’ve always arranged my windows using my mouse and it’s been fine; I don’t want to learn a bunch of new keyboard shortcuts; etc. But depite those earlier fears and protestations, xmonad is absolutely wonderful. I think I like it more because it’s not a layer on top of a dynamic window manager, it’s the whole system. I set it up so all of my windows get chunky, hot pink outlines. My screen is always 100% filled. Windows get automatically resized to fit as I open and close things. I can re-arrange and navigate the windows without ever using the mouse. It’s cool as hell. It’s also fast as hell.

For browsing the web, I’m a stubborn Firefox apologist and have been for a while. It feels like the internet to me. I even use it on iOS, so my history and bookmarks will sync there. Unfortunately, I end up in Safari for iOS all the time, since that’s the default browser for everyone.

For email, contacts, and calendar I use FastMail. It’s rock solid, has super fast and pleasant web interfaces, and has no ads. I pay $70 per two years for it. I love it.

For email, I use the built-in Mail app on iOS, which works great with FastMail. I’ve tried a handful of alternatives and didn’t really like any of them, and you can’t change the default app to handle email links anyway so I just go with the flow. On macOS and Linux, I just the FastMail web interface, which is great.

For interacting with my personal calendar on macOS and iOS, I use Fantastical which is very delightful.

For buying domains and managing DNS, I use NearlyFreeSpeech.NET. It’s one of my favorite websites. It’s extremely plain and extremely polite and extremely clear.

For lightweight checklists, both long-lived and short lived, I use the Apple Notes app. For example, I have a note called “movies out” which is a checklist of movies that are out or coming out soon that I think I might want to see. I refer to that occasionally when I think “hmm what’s out?” or when I pass a poster and think “Oh, that’s out?” I have another note called “pantry” which has a checklist of the staples I like to keep in my kitchen, and I check things off when I buy them, and uncheck them when they’re running low. I have another note called “Christmas gifts” which lists all the people I need to get gifts for, with checklists for each person of the things I’ve gotten them (checked) or am thinking about getting them (not checked). I’ll delete that one after Christmas. Sometimes I’ll make a note that just has a checklist of all the things I’d like to get to in the day, and I can look at it throughout the day, and then later on delete it.

For being upset and inspired and not-bored and informed about the world, I use Twitter. It’s a big part of my day. I can’t really imagine the world without it. I used to use it exclusively via a third-party app called Tweetbot, but I switched to the official iOS app and it’s honestly fine. I do see ads now, and I lose some neat features and design, but more importantly I get all of the modern twitter features, like polls and group DMs, which aren’t available to third-party apps. On Linux and macOS, I just use the web interface.

For subscribing to websites and newsletters, I use Feedbin. I still love RSS in 2017. It’s a big part of my day. Whenever I read anything I like on the web, I look for a feed so I can subscribe and get more. Also, whenever a newsletter seems interesting, I subscribe via feedbin rather than via my email, which helps me prevent my email inbox from getting cluttered. On iOS and macOS, I read via Reeder, which probably comes second only to Firefox as my favorite and most-used app of all time; I was browsing Google Reader via Reeder on an iPod Touch between classes in college. On Linux, I use the Feedbin web UI, which is actually really nice. On iOS, to detect RSS feeds on web pages and subscribe to them in Feedbin, I use Feed Hawk.

For hosting source code, I use GitHub. It’s great.

For making my blog, I use Jekyll to structure the source code and build the site, GitHub Pages to host the static site, Markdown to make it pleasant to write prose that will become HTML, and Clicky for some traffic analytics.

For creating slides for my one talk I gave in public, I used remark, an open source tool that let me use familiar web technologies like HTML, CSS, and JavaScript to customize the slides, and let me use my beloved Markdown for writing the actual content, and let me easily host the finished product on my blog.

For editing my podcast, I use … actually I do it so infrequently that each time I basically forget and try something new, and I currently don’t remember.

For listening to music, I use Spotify although I kind of wish I just paid for music again so I didn’t feel a mounting dread about how much money I’ve sunk into something I don’t get to keep. It has good native apps for all the platforms I use. Sometimes I use the Apple Music app for things that aren’t on Spotify, and other times I listen to musicforprogramming.net.

For listening to podcasts, I use the wonderful Overcast. I love to have a podcast app that does server-side polling and sends push notifications when new episodes are available. I generally use the iOS apps, but I’m glad it has a spartan web app I can use on Linux and macOS.

For tracking personal tasks, I use OmniFocus, which is available on all of the Apple platforms. I use it pretty passively. It’s more a thing I write to than read from. If someone recommends something, I’ll put it in OmniFocus. If I see a tweet with a link I want to check out later, I’ll put it in. If I have a random thought I want to explore further, I’ll put it in. If I feel guilty about something, I’ll put it in. Occasionally I’ll go back and look through it and check things off and delete things and organize them into little projects. It helps me remember what are all the things I want to or am supposed to do, which helps me not feel worried all the time, and when I do feel worried I know where to go to remind myself who I am. I used to use Instapaper for saving articles to read later, and this year I stopped, and it’s a relief. But I did make a single action project in OmniFocus called “articles to read later”, and I do occasionally put articles in it. It’s a little deranged. I dearly wish they had a web version so I could check it on Linux.

For tracking work-related personal tasks, I use Todoist, which is pretty similar to OmniFocus, except it feels less reliable to me, has subscription-based pricing, and has a web version so I can check it at work on my Linux computer. I actually kind of like keeping a divide between work stuff and personal stuff. I just wish its syncing engine felt more rock solid.

For keeping files in sync across my goofy amount of computers, and occasionally for sharing files with other people, I use Dropbox. I’m tempted to become more reliant on it. My photo library is currently in Apple’s Photos app, which I can’t access on Linux. That might be a project for next year.

For managing my personal passwords, I use 1Password. I’m very pleased because they recently introduced a web version, which should let me use it on Linux, although I haven’t tried yet. I think I may need to switch over to subscription pricing to use that, which would totally be worth it for that alone. Currently, whenever I need to look up a password on my personal laptop I just look it up on my phone and peck it in, which suuucks when your passwords are super involved. For my work passwords, I use Rooster, a CLI password manager.

For texting I use some combination of iMessage, WhatsApp, Facebook Messenger, Twitter DM, Instagram DM, and Slack depending on who I’m talking to. It’s a mess. And I’m just realizing three of those are owned by Facebook. In theory, I prefer Twitter and Slack most, because those are available on all of the operating systems I use. In practice, I use iMessage the most.

For making screencasts, I use QuickTime to record my screen and ScreenFlow if I need to do any editing. I have used recordmydesktop to record my screen on Linux and it works great, but I never really do it. And I have no idea how to edit video on Linux, although I’m sure it’s done.

For remembering where I’m at in which TV shows, I use iShows TV on my phone. I love it.

For figuring out where to go and planning trips, I use Foursquare.

For giving and receiving FOMO, and helping me remember later the names of the places I’ve been, I use Swarm on my phone.

For some twitter analytics, I use Birdbrain on my phone.

For reading comics, with cool panel-by-panel transition animations, I use Comixology, mostly on my iPad.

For tracking the shipping status of packages I use Deliveries on macOS and iOS.

What would be your dream setup?

Hmmmmm.

I wish that all iOS apps I liked had at least spartan web interfaces so I could interact with their data from my Linux computers.

I’m looking at you, iMessage and OmniFocus.

I wish Vimscript were replaced with Ruby.

I wish there were less lock-in.

I wish I could use iOS more like a general-purpose computer. I know some people can, but I don’t think I can until I can do things like:

  • change the default browser to Firefox so I can follow links in, for example, my email, and have them open the Firefox app
  • run a terminal emulator that gives me access to the actual file system and run arbitrary software and have access to a package manager such as Homebrew
  • not rely on a separate Mac to add arbitrary mp3s to the Music app
  • do things like invoke 1Password from Firefox without going into a share menu – using “sharing” as the way for apps to communicate feels like the wrong abstraction
  • probably other stuff

I should probably get better speakers.

I have a kind of allergy to using Google products that I should probably get over, because they do make a lot of good stuff.

I wish more people had blogs and fewer people had newsletters.

Normalizing surgical drain output

December 11, 2017

Let’s talk body fluids, and then math.

(Note: this isn’t medical advice. Listen to your doctor.)

During a surgery, it’s sometimes necessary to install a drain to prevent the build-up of fluids under your skin from whatever wound you’ve got. When the patient leaves the hospital, it becomes their responsibility to care for the drain. Here’s what that entails:

The drain is a tube connected to your body via some stitches. It runs along until it empties into a bulb, which you may keep clipped to your undershirt throughout the day. The bulb has most of the air squeezed out of it, to create suction.

Periodically, you must unplug the bulb and let in the air. Pour out whatever fluids have collected into a small measuring cup. Make a note of how much you’ve collected, and what time it is. Then dispose of the fluids, squeeze the air back out of the bulb, and plug it back up. Do this at least twice a day.

When you see your doctors, they’ll want to know the rate of drain output so they can get a sense for:

  1. how the wound is healing
  2. if it’s time to remove the drain

Let’s say you’ve taken these notes:

2017-12-07 00:00 0
2017-12-07 14:09 30
2017-12-07 22:10 10
2017-12-08 10:20 7.5
2017-12-08 10:55 23
2017-12-08 22:00 2.5
2017-12-09 11:45 5
2017-12-09 19:15 8
2017-12-10 11:50 18
2017-12-10 17:40 7
2017-12-11 8:55 10
2017-12-11 22:10 12.5

Some days you’ve taken two measurements, and other days three. Some of the measurements follow six hours after the previous one, and some much more.

Let’s say the doctor wants to know the answer to this question:

How many milliliters of serosanguineous fluids did you drain each day since your surgery?

We can do some eye-ball math and determine:

2017-12-07: 0 + 30 + 10 = 40
2017-12-08: 7.5 + 23 + 2.5 = 33
2017-12-09: 5 + 8 = 13
2017-12-10: 18 + 7 = 25
2017-12-11: 10 + 12.5 = 22.5

And that would probably be good enough. It gives you a sense for the trend:

40
33
13
25
22.5

Slowly going down, except for one weirdly quiet day.

But IMO this feels dissatisfying and wrong.

Let’s look at these two measurements again:

2017-12-09 19:15 8
2017-12-10 11:50 18

Is it really fair to bucket those 18 milliliters of serosanguineous fluids solely on 2017-12-10? You emptied the drain at 19:15 the day prior, so those 18 milliliters were trickling out for about five hours on one day, and about twelve hours the next. If we can assume that it trickled out evenly, we should be able to smear that data across both days and get a more accurate picture of the daily trend.

This bugged me enough that I wrote a quick ruby script to do this for me:

require "time"

Measure = Struct.new(:time, :value)

data = File.read("./data").lines.map { |line|
  date, time, amount = line.split(" ")

  Measure.new(
    DateTime.parse(date + " " + time).to_time,
    amount.to_f,
  )
}

all = [data.shift]

raise "no data!!!!" if all.empty?
raise "must start with zero value!!!" if all.first.value.nonzero?

data.each do |next_data_point|
  last_data_point = all.last

  amount = next_data_point.value
  diff = (next_data_point.time - last_data_point.time).to_i

  amount_per_diff = amount / diff.to_i

  diff.times do |n|
    all.push(Measure.new(
      (last_data_point.time + n),
      amount_per_diff,
    ))
  end
end

result = all.each_with_object({}) do |measure, obj|
  obj[measure.time.to_date] ||= 0
  obj[measure.time.to_date] += measure.value
end

result.sort_by(&:first).each do |(date, total)|
  puts "#{date} - #{total.round(2)}"
end

I hacked this together pretty quickly and I’m a little pleased with it. Here’s the idea:

Instead of having just a few measurements taken at odd intervals, let’s pretend we have many thousands of measurements taken at regular intervals. One per second, in this implementation. And then use code instead of dumb eyeballs to add up all the measurements in each day. I’m calling this smearing the data for want of a proper term.

After smearing the data (assuming an even trickle between measurements), the trend looks like this:

41.13
32.6
17.43
24.0
18.35

In this case, it’s so close to the eyeball math that it may not have been worth doing, but I will rest easier nevertheless.

I just have one urgent question for you my dear reader: is there a name for what I did here? I want to learn more about data. As I learn things, I am often pleased to find out that all of the ideas already exist and have good names. What’s this one’s?

mewithoutYou and me

September 29, 2017

mewithoutYou is a fairly prolific rock and roll band from Philadelphia who I love very much. In this post, I’m going to talk a little bit about why and share some of my favorite songs.

Catch For Us The Foxes (2004)

I first heard mewithoutYou in probably 2004. I was going to see my then (and current) favorite band Bear Vs. Shark play a club in Poughkeepsie called The Loft. There were two openers, Codeseven and mewithoutYou, neither of which I had heard of. I’m sure I probably pirated both of their albums, so I could be prepared. I’m not sure if I ever got around to listening to Codeseven…

I remember sitting on the couch in my parents house with headphones on (did I have an iPod? did I burn a CD for an album I wasn’t even sure I liked?) and being fully knocked on my ass.

The album, Catch For Us The Foxes, is their second. It starts with a song called Torches Together. Immediately… who the hell is this guy? What is he talking about? Why isn’t he singing? This dude is out of control spazzing out while very comfortably weaving a metaphor about, I think, the power that comes from letting go of personal ego and joining a community? Individual lines jump out: “Anyway, aren’t you unbearably sad?” Just like that, as an aside. Later: “And I’m afraid and everyone’s afraid and everyone knows it / But we don’t have to be afraid anymore.”

I recently read a brief profile of chef and cookbook author Meera Sodha. She has this great line:

You know when you realize what you’re eating is just so magnificent, and there’s a sort of rip in the atmosphere?

Torches Together ripped into my 16-year-old atmosphere.

Anyway, Catch For Us The Foxes isn’t my favorite album of theirs. Maybe my least favorite. It has a lot of nice moments, but it’s not very focused. Stylistically, I think it reaches the limits of the spoken (and shouted) word style. It gets a lot of mileage from the contrast between the band (who play very precisely) and Weiss’s unhinged vocals. He sounds, often, distressed, and the music behind him almost feels like it’s trying to keep up with him and support the performance like a movie or broadway score. Imagine, if you were distressed, and you broke down, and as you expressed your feelings, some chunky riffs and a tight rhythtm section buoyed you, and encouraged you to keep going. That might be kind of powerful and you might feel kind of validated.

The style is definitely not for everyone, but I love it, and that’s sort of the lens I see it through. Maybe that’s how all bands work, I don’t know.

[A->B] Life (2002)

After the concert (which was amazing, I can’t believe I got to see Bear Vs. Shark and mewithoutYou in the same night) I went back and listened to their debut album, [A->B] Life.

Honestly, I think this is is a really good album. It’s not really trying to be that profound. It’s mostly trying to rock out. It’s short. It moves fast. Weiss pretty consistently screams all his lyrics. There are a few spacey interludes, but overall it’s very crunchy. Track eight, “We Know Who Our Enemies Are”, has a kind of hilarious moment where it fades out and then back in for some reason. It ends with a secret acoustic track, so you know they have a sensitive side.

There are a few songs that are more on the snotty and abrasive side IMO (“I Never Said That I Was Brave”). But a lot of them are (relative) bangers, like “The Ghost”:

Can you even imagine how fun it is sing lines like “Put music! Put music! Put music to our troubles!” along at a concert?

Look, things aren’t going well, and there are simple pleasures to be had. Consider air-guitarring to the little guitar solo at the end there.

This year, in 2017, they’re doing a 15 year anniversary tour where they’re playing the album in full. I’m obviously going.

Brother, Sister (2006)

So album three comes out and I’m officially a fan. I’m also in college now, and sophisticated. I order it on vinyl and put it on my wall (I do not have a record player).

I think this is their first great album. The corner they turned is that Weiss has started to transition from performing anguish to telling stories. He’s still kind of freaked out by everything, but he doesn’t quite as angry anymore. He’s coming around to being gently amused.

Here’s “The Dryness and the Rain”:

My favorite moment comes near the end:

A fish swims in the sea
While the sea is in a certain sense
Contained within the fish!
Oh, what am I to think
What the writing
Of a thousand lifetimes
Could not explain
If all the forest trees were pens
And all the oceans ink?

What am I to think?

Not for the first time, many of their best lines are cribbed from or inspired by The Qoran and the Sufi Islam teacher(s?) Weiss is obsessed with.

The next song, “Wolf Am I! (and Shadow)” is maybe my favorite of their hard rock songs:

I just think the band sounds so tight and good. But also, Weiss finds room for some spontaneity in a way that I find pleasingly self-deprecating:

Oh there, I go showing off again
Self-impressed by how well I can put myself down!

Later, he corrects himself in a way that almost feels like he’s making all this up as he goes:

Shadow am I!
Like suspicion that’s never confirmed
But it’s never denied
Wolf am I

No, “shadow”, I think is better
As I’m not so much something
More like the absence of something

So shadow am I!

Of course, I hope, he’s not just making it up as he goes. But it does play like an effective performance of confusion and self-loathing and fear.

This might feel a little like more of the last album, but it’s redeemed by two things:

  1. it just sounds so good
  2. it’s in the context of an album that isn’t just that, but seeks and finds some level of grace by the end of it

So let’s jump to that…

The album ends with a song called “In a Sweater Poorly Knit” (the title winks at an earlier song’s title, “In a Market Dimly Lit”). It’s the story of Moses in Egypt, sort of. It features some lovely harp and acoustic guitar. All of the genius annotations for this song insist it’s a big metaphor for a breakup, which I’d never once considered before. Eh. Idk. It’s so pretty. Like most of their songs, I think it’s about his relationship with God and with his own ego. It ends the same way the album opens, with the line “I do not exist”. Mostly it’s just so pretty.

At some point you realize he started actually singing and not speaking or shouting and it kind of suits him. He’ll do more of that soon.

It’s All Crazy! It’s All False! It’s All a Dream! It’s Alright (2009)

OK. Here’s my big opinion: this album is a masterpiece.

Pretty much all traces of personal anguish are gone. Almost every song is a story. Almost all of the characters are animals. When they’re not animals, they’re fruits and vegetables. When they’re not produce, they’re the baby Jesus. It sounds gorgeous.

The opening track, “Every Thought A Thought of You”, is a blissed out, bouncy, slightly strained devotional to God. The closing track, “Allah, Allah, Allah”, is also basically the same, except it has a kind of fun campfire singalong vibe.

I’m not a religious person in any way except that I love this band and find them very persuasive, particularly the way they seem almost absurdly non-denominational. There’s even room in these songs for doubt. One of my favorites is the longest song on the album, “The King Beetle On a Coconut Estate”:

What is this song getting at? Is the King a fool? It seems he’s just a dumb bug who flew into a light and died. That’s not so great. The “great mystery” turned out to be dumb. Hmm.

The details in this song are so lovingly rendered (“The beetle king summoned his men / From the top of the rhododendron stem”; “The lieutenant stepped out from the line; As he lassoed his thorax with twine”) that I can’t help but feel that Weiss empathizes with the plight of the Beetle King.

Why not be utterly changed into fire?

Wuff..

Most of all this album sounds peaceful and gentle and assured and pretty. Here’s “A Stick, A Carrot, A String”, which positively shimmers:

Look, this one is straight up about the baby Jesus, from the perspective of the animals who were around when he was born. Weiss finds time to make you empathize with each one:

At a distance stood a mangy goat
With the crooked teeth and a matted coat
Weary eyes and worn
Chipped and twisted horns

Thinking “maybe I’ll make friends someday
With the cows and the hens and the rambouillet
But for now, I’ll keep away
I’ve got nothing smart to say”

God damn - I love that goat.

There are so many songs I love on this album (all of them). Other highlights:

  • “Goodbye, I!” – the bit where he sings “Let’s stand completely still” and then the drummer pitter patters out a little drum solo makes me catch my breath each time I hear it
  • “The Fox, The Crow and the Cookie” – this is a perfect little story delightfully rendered
  • “Fig With A Bellyache” – First of all, that title, come on. But it’s the most stylistically weird song on the album and features some wonderfully awkward lyrics (“The dog below our waists aroused as arms embraced the pretty gals / It came much more as a surprise / It happening while I hugged the guys”)
  • “Cattail Down” – for the conclusion “You think you’re you? You’re not you. You’re everyone else.” and some sweet trumpet action

One thing I loved about this album when it came out is that it felt like the culmination of everything that came before it. Over time their albums became less angry and more concerned with humility. The arrival of wind and string instruments felt like an answer. The urgent searching of youth seemed resolved. The answers had been found.

So where do they go from there?

Ten Stories (2012)

For one thing, they decided to play their electric guitars on all the songs again. I think I recall reading that the non-Weiss members of the band wanted to play more rock songs again, and Weiss was like, sure. When it came out, I was disappointed that it didn’t feel like a continuation of the aesthetic of the previous album. In some ways, it is, though. It’s also concerned with fables, this time it loosely tracks the story of a collection of circus animals who cause a train wreck and make their escape. I don’t really connect to this story. I dunno. For me, this album is just fine.

There’s one song which sounds like it could’ve been on the previous album, “Cardiff Giant”, and it is my favorite song on the album:

Pale Horses (2015)

When this one was coming out, I felt trepidation. Were mewithoutYou drifting in a direction I didn’t like? Was Weiss being held hostage by the rock and roll instincts of his band mates?

I don’t know, but this album is super good, so who cares.

Here’s something from an interview with Weiss:

Interviewer: What does Pale Horses mean to you?

Weiss: That’s a hard one. That question could take up the whole interview. I wouldn’t know where to begin, but it probably doesn’t differ too much from our other albums in that it’s just an expression of where I’m at and what I’ve been experiencing in the past few years, what my convictions are and what my hopes are. It’s pretty personal. Probably more so than some of our more recent albums, which were a little bit more distant and third person and fabulous – you know, fable-based and character-based. For this one I’ve come back more to the first person to try to share what’s in my heart and what’s on my mind, and hopefully be somewhat uplifting in the process. But covers a wide range of things, so it’d be too hard to pinpoint any one of those.

So here’s my theory: the hard rock vibe doesn’t work well with the fables (see Ten Stories) but it works great for the not stories.

The interview continues:

Interviewer: What do you think brought mewithoutYou back to you, as opposed to those third-person fables? Why did you decide to do that?

Weiss: For a couple of reasons, I guess, but the easiest one to give you is that the guys in my band asked me to, and I was happy to oblige. A little bit more of a personal reason has to do with wanting to keep things fresh. When we put out It’s All Crazy! and Ten Stories, that was me trying to move away from the first person and get the ego out of the way, trying to write in a way that others could relate to just as well, or address content that might have some universal – or quasi-universal – significance, and trying to avoid letting my subjectivity muddy the waters. But more recently, I’ve started to doubt whether I can ever do that, and it felt like maybe those attempts were too ambitious and I was maybe biting off more than I could chew. So I thought if there’s one thing I can write about with some insight, it’s myself. That’s not to say I even have any expertise on myself…

Aha. Here is the real, correct answer to “where do you go” from the 2009 album. You walk it back a little. You didn’t find the answers. Obviously. C’mon. Who are you? All that peace you cultivated? Maybe try living life for a little while and see how that goes.

So: he’s screaming again.

Here’s a lovely music video for “Red Cow” and “Dorothy” which hard-lefts from a screamy rock jam into a graceful, melancholy wind-down:

This feels like rich new ground to root around in.

Here’s another song, Blue Hen, that just sounds great, and contains an all-time great Weiss freak out

And I’ll wrap up your absence
In blankets of reverence
A mastodon shadow
Divided by zero

I have no idea what that means but I totally know what it means and I love it.

My favorite song has got to be the last one, “Rainbow Signs”:

It’s long and builds slowly and contains the apocalypse and I guess is about his father dying. I find it very powerful and kind of awe inspiring.

(????) (2018??)

mewithoutYou seems to be in the studio, per their twitter, and a new album should come out soon enough, and I can’t wait.

Sad Blocks

July 6, 2017

I wish Ruby knew when you wrote a sad block.

What is a sad block?

It’s something I just made up.

Consider this code:

Candle.all.each do |candle|
  puts candle.inspect
end

Let’s say you run it, and you see no output. What do you conclude? Probably that there aren’t any candles.

Well, maybe. Or maybe Candle is implemented like this:

# candle.rb
class DatabaseResult
  def each; end
end

class Candle
  def self.all
    DatabaseResult.new
  end
end

Look, that would be weird, but it’s possible, and Ruby doesn’t do anything to help you out here, and I feel like it should.

What’s happening? You’re calling the instance method #each of the DatabaseResult class. And it’s just not doing anything at all and doesn’t even know you gave it a block. Cool.

Brief digression time.

That method has an “arity” of zero. How do I know that?

$ irb
>> require "./candle"
=> true
>> DatabaseResult.instance_method(:each).arity
=> 0

Also by looking at it.

What does it mean? It means that the method takes zero arguments.

But when we count the arity, we’re not considering blocks, because blocks are a special, weird kind of argument, where you can provide it or not and it’s kind of outside of the method signature. You can have methods that takes a block and uses it, and its arity will still be zero:

# candle2.rb
class DatabaseResult
  def initialize(values)
    @values = values
  end

  def each
    @values.each do |value|
      yield(value)
    end
  end
end

class Candle
  def self.all
    DatabaseResult.new([
      new("Geranium"),
      new("Lavender"),
    ])
  end

  def initialize(scent)
    @scent = scent
  end
end

Candle.all.each do |candle|
  puts candle.inspect
end
$ irb
>> require "./candle2"
=> true
>> DatabaseResult.instance_method(:each).arity
=> 0

Even though we use the block we’re given, the arity is still zero.

What about that other syntax where you explicitly put the block in the method signature, does that make it count toward the arity?

def each(&block)
  @values.each do |value|
    block.call(value)
  end
end

I’ll tell you: it doesn’t. Even though it sort of feels like it should.

These versions of the method really require you to pass them a block, which you just have to know. If you forget to pass a block, you get a nasty error:

# candle4.rb
# ...
def each(&block)
  @values.each do |value|
    block.call(value)
  end
end
# ...

Candle.all.each
candle4.rb:9:in `block in each': undefined method `call' for nil:NilClass (NoMethodError)
        from candle4.rb:8:in `each'
        from candle4.rb:8:in `each'
        from candle4.rb:27:in `<main>'

Or in this version, an even better error:

# candle5.rb
# ...
def each
  @values.each do |value|
    yield value
  end
end
# ...

Candle.all.each
candle5.rb:9:in `block in each': no block given (yield) (LocalJumpError)
        from candle5.rb:8:in `each'
        from candle5.rb:8:in `each'
        from candle5.rb:27:in `<main>'

No block given. Local jump error. Sure. That’s Ruby trying to be helpful and I appreciate that.

Ruby helps you (by raising a helpful error) when you don’t provide a block, but you were supposed to. But it doesn’t help you when you do provide a block, and you weren’t supposed to.

Ruby’s like, yeah, sure, just provide a block wherever you want, this is a free country.

If you wanted to change this behavior in your code, and get helpful errors when your blocks are unexpectedly not invoked, you could do something like this:

class SadBlock
  def initialize(&block)
    @block = block
    @called = false
  end

  def verify
    raise 'hell' unless @called
  end

  def to_proc
    ->(*args) {
      @called = true
      @block.call(*args)
    }
  end
end

sad_block = SadBlock.new do |candle|
  puts candle.inspect
end

Candle.all.each(&sad_block)
sad_block.verify

I don’t think you should do this, but you could, and I kind of wish Ruby just did it automatically.

I know it’s an impractical request, because there are valid use-cases where you might pass a block to a method, and the method just assigns it to an instance variable without calling it, but it promises to call it later. But maybe Ruby could detect that somehow. I’m just thinking out loud here.

I’ve seen tests where assertions lived in blocks, and the blocks were never being called, so they weren’t actually asserting anything.

I’ve seen configuration being done via a DSL in a block, except the block wasn’t being called, so the defaults were being used.

I guess what I’m saying is it’s a little weird to me that blocks aren’t treated like ordinary arguments. If they were, you’d get an ArgumentError if you forgot to provide it or if you provided it and it wasn’t expected.

That’s what I want.

there are no rules in ruby

July 2, 2017

Note: I’ve expanded on these ideas in a conference talk, which you can see here.


I recently learned about a feature of the Ruby programming language that has shaken me to my very core.

Consider this code:

# dog.rb
class Dog
  attr_reader :name

  def initialize(name)
    @name = name or raise ArgumentError
  end
end

def get_dog
  Dog.new("Milo")
end

thing = get_dog
if Dog === thing
  puts thing.name + " is a dog"
end

What happens when you run this code? Feel free to try.

But I’ll tell you.

$ ruby dog.rb
Milo is a dog

This code seems pretty resilient to unexpected runtime errors.

Looking at the code, it seems pretty reasonable to believe:

when we have an instance of Dog, we will be able to send it the message name and get back a String

Up is up. The sky is blue. We’re living in a society.

Well, ok, but we can’t actually assume that the value will be a String, because it doesn’t check that. If we change our definition of get_dog, things blow up:

def get_dog
  Dog.new(["Milo"])
end
$ ruby dog.rb
dog.rb:15:in `<main>': no implicit conversion of String into Array (TypeError)

But, OK, at least that error message is pretty good. This is user error. When we write thing.name + " is a dog", we’re expressing some amount of faith in ourselves that we expect a String, because values of other types don’t necessarily respond to a + method. This is a leap of faith that we’re all willing to make when we use Ruby. Other languages eliminate the need to make that leap of faith by checking types when you compile your code, but Ruby doesn’t do that.

And that’s fine.

So maybe our expectation should be:

when we have an instance of Dog, we will be able to send it the message name and get back a truthy value

And we’ll just remember to provide Strings. Maybe we’ll write a comment indicating the expected type of the parameter.

Well, what if get_dog looked like this:

def get_dog
  dog = Dog.new("Milo")
  def dog.name
    nil
  end
  dog
end

Maybe it just casually redefined the name method for that instance. Then your program crashes like this:

$ ruby dog.rb
dog.rb:19:in `<main>': undefined method `+' for nil:NilClass (NoMethodError)

Which… OK, who’s going to write code like that? Not me and no one I work with, for sure!

But where does that leave our statement of beliefs?

when we have an instance of Dog, we will be able to send it the message name

We can’t even say “and get back a value” because what if the override raises an error?

Perhaps you see where this is going…

Well, what if get_dog looked like this?

def get_dog
  dog = Dog.new("Milo")
  dog.instance_eval('undef :name')
  dog
end
$ ruby dog.rb
dog.rb:17:in `<main>': undefined method `name' for #<Dog:0x007fecc104a870 @name="Milo"> (NoMethodError)

Which, again, lol. You can just remove methods if you want to? Sure. No one is going to write this. I know.

(By the way, hat tip to Agis on Stack Overflow for sharing this trick. I figured it was possible but didn’t know how.)

OK so what can we say for sure?

How about this:

when we have an instance of Dog, it will have an instance variable @name defined

Wow that’s sad! How do we even check that? Maybe like this:

thing = get_dog
if Dog === thing
  puts thing.instance_variable_defined?("@name").inspect
  puts thing.instance_variable_get("@name").inspect
end
$ ruby dog.rb
true
"Milo"

OK great, have we reached the bottom?

No, because there are no rules in Ruby.

We can probably break this in many ways. Here’s one:

def get_dog
  dog = Dog.new("Milo")
  dog.remove_instance_variable("@name")
  dog
end

IMO this one is a bit pedestrian. Yeah, fine, you can just remove instance variables on random objects if you want to. Of course. My spirit is already broken, this isn’t meaningfully worse.

So let’s just try to say something that we don’t have to take back right away:

when we have an instance of Dog, the code in the initialize method must have run

Right? That has to be true. We’re living in a society, remember?

Nope:

def get_dog
  Dog.allocate
end

That results in this output:

$ ruby dog.rb
false
nil

What the hell is this?

This is the thing I mentioned at the beginning that I learned recently. When we create new objects in Ruby, we usually use the new class method. Notably, we don’t call the initialize instance method ourselves, although that’s what we are responsible for defining. Ruby handles calling that method for us. But before Ruby can call an instance method, it needs an instance, and that’s where allocate comes in. It just makes an instance of the class.

And you’re allowed to use it in your Ruby code, if you want to.

(Hat tip to John Crepezzi whose blog post explains this really well)

If you do, you get back a normal instance of your class in every way, except that the initialize method hasn’t run.

You can even call your own initialize method if you want to:

def get_dog
  dog = Dog.allocate
  dog.send(:initialize, "Milo")
  dog
end

We have to use send because initialize is private. Well, unless we change that:

class Dog
  attr_reader :name

  public def initialize(name)
    @name = name or raise ArgumentError
  end
end

def get_dog
  dog = Dog.allocate
  dog.initialize("Milo")
  dog
end

Sooooo where does that leave us?

when we have an instance of Dog, it’s a good dog

Basically: 🤷‍♂️.

That’s the bottom. That’s as far as I know how to go. Maybe there’s more. Please don’t tell me.


I want to emphasize: this is not a criticism of Ruby. I’m only faux-alarmed. Ruby is a springy ball of dough. It’s whatever you want it to be. All of these features are sharp knives you can use or abuse.

As I’ve been learning another language which feels much less pliant, I’ve started to notice things about Ruby that never occurred to me before. When I write Rust, I take some pleasure and comfort from the rigid rules. It’s more possible to use words like “guarantee” and “safety” in Rust-land.

But Ruby keeps you on your toes.

chainable shell functions

February 6, 2017

I learned a neat shell script refactoring strategy yesterday that I’d like to share. First some background:

I used to use a rubygem to help me write this blog. When I wanted to create a new post called “chainable shell functions” I would have run:

bin/poole draft "chainable shell functions"

And it would create a file called _drafts/chainable-shell-functions.md with some metadata in the first few lines.

Yesterday I got the urge to try replacing that rubygem with a custom shell script which does exactly the same thing.

I am an enthusiastic novice shell scripter.

I’m vaguely aware there are different dialects of shell scripting and that I’m probably using the wrong one.

Really I’m not expert in this stuff.

But while writing this one I learned something interesting that I’m going to share with you now.

Here is the first draft (annotated with comments for your convenience):

#!/usr/bin/env bash

# fail fast if any expression fails
set -e

# read all of the arguments into a string
title="$*"

# OK don't worry about this gnarly line, I'm going to break it down
slug=$(
  echo "$title" | sed "s/ /-/g" | tr -dc '[:alnum:]-' | tr '[:upper:]' '[:lower:]'
)

# the file we're going to create
filename="./_drafts/$slug.md"

# create the folder if it doesn't already exist
mkdir -p _drafts

# stop if the file already exists -- I don't want to overwrite an in-progress draft
if [[ -e "$filename" ]]; then
  echo "$filename already exists"
  exit 1
fi

# create the draft by piping a string into a file
echo "---
title: $title
date: $(date '+%Y-%m-%d')
---

Alright, this is where your post goes." > $filename

# Print a successful message
echo "Created $filename"

OK did you read that? Great.

So you saw that line I promised I would break down? The idea with that line is that I want to take the input, which is the title of the post, and figure out what is an appropriate filename for the post. I’m figuring that out by applying a series of transformations to the title:

  • echo "$title"
    • just repeats the title, directing the output into a “pipe”, which the next command will read
  • sed "s/ /-/g"
    • sed is a “stream editor”; it reads in a stream of data and prints out a stream of data
    • here we’re using regular expressions to “s” or substitute all occurences of a space with - (hyphen)
    • we want hyphens because they make for nicer looking URLs than spaces, which get escaped to %20.
    • the g at the end means “global”; without it, we would only subsitute the first space
  • tr -dc '[:alnum:]-'
    • tr is short for “translate”
    • -d means “delete”
    • -c means “complementary”
    • this command means “delete all the characters that complement this set of characters”
    • in other words, “delete all the characters that aren’t alphanumeric or a hyphen”
  • tr '[:upper:]' '[:lower:]'
    • “translate” again!
    • this time we’re translating all of the upper-case letters to lower-case letters
  • Finally, we stop piping the output to the next command, and we’re done, so the result is saved in that local variable.

OK so that’s a lot going on in one line, and because of the compact nature of these commands, it’s not super readable.

In other languages, when I have a lot going on in one function, I want to split out smaller, well-named functions. Can I do the same thing here?

At first I wasn’t sure. I knew it was possible to write functions that received arguments by checking $1, $2, etc in the function, but I wasn’t sure how to make them “return” values…

After a little googling I learned: you can just write a shell function that calls commands that read from a pipe, and pipe things to that function.

Let me show you what I mean.

Here’s the second (and, frankly, final) draft:

#!/usr/bin/env bash

set -e

function dashify() {
  sed "s/ /-/g"
}

function removeSpecialChars() {
  tr -dc '[:alnum:]-'
}

function downcase() {
  tr '[:upper:]' '[:lower:]'
}

title="$*"
slug=$(
  echo "$title" | dashify | removeSpecialChars | downcase
)
filename="./_drafts/$slug.md"
mkdir -p _drafts

if [[ -e "$filename" ]]; then
  echo "$filename already exists"
  exit 1
fi

echo "---
title: $title
date: $(date '+%Y-%m-%d')
---

Alright, this is where your post goes." > $filename

echo "Created $filename"

Look at that!

When to use defined? to memoize in Ruby

February 5, 2017

Here’s a quick Ruby thing.

traditional memoization in Ruby

Let’s say you have an object whose responsibility is to give a haircut to a dog.

(I may have recently been reading about this)

class DogStylist
  def initialize(dog_id)
    @dog_id = dog_id
  end

  def perform
    if dog
      dog.sedate
      dog.groom
      dog.instagram
    end
  end

  private

  def dog
    Dog.find(@dog_id)
  end
end

This is kind of fine, but it has one problem: each time you reference dog, you’re calling the dog method, which queries the database each time it’s called, so you’re querying the database over and over, when you really only need to do so once.

Better to write it like this:

def dog
  @dog ||= Dog.find(@dog_id)
end

Here you’re still calling the dog method over and over, but now it’s “memoizing” the result of the database query.

But what does that mean?

Here’s a more verbose version of the dog method that does the same thing:

def dog
  @dog = @dog || Dog.find(@dog_id)
end

You can see that ||= is a syntactical shorthand similar to +=.

In case you’re unfamiliar with +=, here’s an example. These two statements are equivalent:

count = count + 1
count += 1

Here’s an even more verbose version of the dog method that does the same thing:

def dog
  if @dog
    @dog
  else
    @dog = Dog.find(@dog_id)
  end
end

The goal here is to avoid evaluating the database query more than once. The first time the method is called, the @dog instance variable is not defined. In Ruby, it’s safe to reference an instance variable that isn’t defined. It will return nil. And nil is falsey, so the database query will be evaluated, and its result assigned to the instance variable.

This is where things get interesting.

Ponder this question: does this memoization strategy guarantee that the database query will only be executed once, no matter how many times the dog method is called?

It doesn’t.

Why????

I’ll tell you.

What if there is no dog with that ID? Dog.find(4000) returns either a dog, or nil. And, like we said earlier, nil is falsey. So hypothetically, if our perform method looked like this:

def perform
  dog
  dog
  dog
  dog
  dog
end

… then we would execute the database query five times, even though we made an effort to prevent that.

This is actually totally fine, because our perform method isn’t written like that (again, that was just a hypothetical). Our perform method only calls the dog method more than once if it’s truthy, so there’s no problem here.

memoization using defined?

Let’s consider another example, where things aren’t as hunky-dory. Hold please while I contrive one.

OK, I’ve got it.

Let’s say we only want to groom a dog when he or she is unkempt. When she logs into our web site, we want to pepper some subtle calls to action throughout the page encouraging her to book an appointment. We’ll need a method to check if she is unkempt, and we’re going to call it a few times. It looks like this:

class Dog
  HAIRS_THRESHOLD = 3_000_000

  def unkempt?
    Hair.count_for(self) > HAIRS_THRESHOLD
  end
end

That’s right: we’ve got a table in our database for all of the hairs on all of our dogs.

You can imagine this unkempt? method might be kind of “expensive”, which is to say “slow”.

Let’s try adding some memoization to this method:

def unkempt?
  @unkempt ||= Hair.count_for(self) > HAIRS_THRESHOLD
end

Here our goal is to prevent doing the expensive database query (Hair.count_for(self)) more than once.

Ponder this question: does our memoization strategy accomplish this goal?

Answer: it does not.

What?????

I know. Let me show you.

You can try running this Ruby script yourself:

$count = 0
class Hair
  def self.count_for(dog)
    $count += 1
    puts "called #{$count} times"
    2_000_000
  end
end

class Dog
  HAIRS_THRESHOLD = 3_000_000

  def unkempt?
    @unkempt ||= Hair.count_for(self) > HAIRS_THRESHOLD
  end
end

dog = Dog.new
puts "Is the dog unkempt? #{dog.unkempt?}"
puts "Is the dog unkempt? #{dog.unkempt?}"

It outputs the following:

called 1 times
Is the dog unkempt? false
called 2 times
Is the dog unkempt? false

In this script, I have a fake implementation of the Hair class. It’s meant to demonstrate that the count_for method is being called more than once, even though we specifically tried for it not to.

So what’s going on here?

Well, in a way, everything is working as it’s supposed to. The first time we call the unkempt? method, the @unkempt instance variable is not defined, which means it returns nil, which is falsey. When the instance variable is falsey, we evaluate the expression and assign its result, false, to the instance variable. The second time we call the unkempt? method, the @unkempt instance variable is defined, but its value is now false, which is also falsey (which you have to admit is only fair). So, again, because the instance variable is falsey, we evaluate the expression and assign its result, false, to the instance variable.

Shoot – that kind of makes sense.

So what to do? Here’s another way to write this:

def unkempt?
  if defined?(@unkempt)
    @unkempt
  else
    @unkempt = Hair.count_for(self) > HAIRS_THRESHOLD
  end
end

This approach uses Ruby’s built-in defined? keyword to check whether the instance variable is defined at all, rather than if its value is truthy. This is more resilient to the possibility that your value may be falsey.

I wish there were a more succinct way to write this, because I think it’s generally how you actually want your code to behave when you use ||=.

To be fair, you can avoid defined? and instead write this method like this:

def unkempt?
  @hair_count ||= Hair.count_for(self)
  @hair_count > HAIRS_THRESHOLD
end

It’s really just a matter of taste if you prefer one over the other.

Alright, take care.

Using git to track git

August 21, 2016

I made a screencast to share a fun idea I had while exploring a bit how git works.

You may know that when you use git to track a project, it creates a hidden .git directory with some files in it. But what actually goes on in there? And when do the contents of those files change?

Here’s the idea: I know a tool for tracking the changes to a directory over time, and that tool is git itself!

So in this screencast you can see me try and do that – I initialized a git repository, which created a .git folder, and then I initialized another git repository within that .git directory.

I still don’t have a really great understanding of how git represents the data, although I’ve read Mary Rose Cook’s very good essay about this topic Git From The Inside Out, which does contain those answers (I read it a while ago and forgot the details).

But I feel like I learned a few things thru this little experiment, specifically about when they change.