Posts

Quick Ranked-Choice Elections with Google Forms

Image
Want to run a really quick ranked-choice election, like "which restaurant should we go to" or "where should we ask the city to build a crosswalk" ? See here for an example: Here's one way to do it: Create a new Google Form. In the form description, explain each of the choices. Add a "multiple choice grid" question. In the "rows" of the question, add one row for each choice: "Chocolate", "Vanilla", etc. In the "columns" of the question, add a "rank number" for each choice: "1st", "2nd", etc. In the "three dots" menu at the bottom-right of the question, turn on "limit to one response per column": Send out the form and wait for people to vote. Once the votes are in, go to the "Response" tab of the form and export the ballots to a CSV using the option under the "three dots" menu: Download ballots.py and pip install ...

Maslow's Hierarchy of Engineering Team Needs

Image
Management is the continuation of prioritization by other means. —Carl von Clausewitz Maslow's Hierarchy of Needs is the idea that people have an inherent and universal set of priorities. If you don't have enough air to breathe or water to drink, you'd better prioritize solving that problem, or you won't be around for very long to solve any other problems. Once you have that sorted out, you can focus on loftier goals, such as "feeling loved", "experiencing beauty", and "living a meaningful life". Software engineering teams have a similar natural hierarchy, and if you're leading one of them, thinking about the lowest point in the hierarchy where your team is struggling is a good way to decide how to invest your time. This post is also available as a Twitter thread . As the overriding goal of life is to maximize the spread of its genes and ideas, the overriding goal of an engineering team is to maximize the value it creates for ...

Act IV, Scene I

- what wizardry is this!? svn supports symlinks? A dark Filesystem. In the middle, a Repository boiling. Thunder.                  Enter the three  Programmers.        1 P ROGRAMMER.   Thrice the padded buf hath oe'r runn'd.        2  P ROGRAMMER .   Thrice and once, the platter spun.        3  P ROGRAMMER .   Hexate cries:—'tis time! 'tis time!        1  P ROGRAMMER .   Round about the repo go;     In spaghetti'd source code throw.—     Functors, that on blackest ARM,     Caused a user grievous harm;     Refactor'd business logic got,     Compile first i' the charmed pot!        A LL.   Double, double toil and trouble;     Cycles burn, and repo bubble.        2  P ROGRAMMER . ...

Multithreaded Python, extensions, and static data

The GIL The GIL and Context Switching I use Boost.Python to write some C++ extensions for Python. I work on an I/O-bound Python program; Python has a global interpreter lock ("the GIL") which means that in a multi-threaded program, only one thread can be executing code inside the Python interpreter at once. Now, a thread can drop the GIL, and the built-in Python read and write routines do this so that while one thread is doing I/O, another thread can run. However, due to a peculiarity in how the GIL is implemented, 1 even though the actual I/O takes place during system calls that drop the GIL, the need to re-acquire the GIL after every I/O operation was killing our performance. For instance, one of the things that the application does a lot of is logging. Doing the logging synchronously -- as the code is executing and it wants to write something to its log, it needs to wait for the write to the logfile to finish before it can continue going about its business -- turned...

Sloppy Graph, Sloppy Design

Image
I was spending time trying to fine-tune a graphviz file documenting the call graph of a piece of code and describing some of the critical functions. graphviz isn't really designed for the kind of long node labels I wanted to give it, so it would do things like put nodes in places which made it have to draw arrows reaching clear across the page. Finally I realized that rather than trying to talk graphviz into reordering its nodes, I could just refactor the thing I was graphing so that the flow wasn't so darned convoluted in the first place. Before (image links to full size version): After (image links to full size version): Corollary? If it's hard to get your call flow graph to look pretty, well, the graph isn't the only thing that's ugly...

An Avocado in the Snow

Image
An avocado, found in the snow near Portland St and Broadway, Cambridge, MA An avocado in the snow. Who left it there? I do not know. Not Father, Son, nor Ghost so holy, Rebirths you into guacamole. Did leaping from some wretched fate Allow you to feel special, great? Or did, cast down like ancient foe, You weep from terror, weep from woe? But lie here now, near Portland Street, And rest, green flesh and tasty meat.

Switching Finks

One of the open-source projects I contribute to is Fink , a package manager for OS X; if you've used apt-get or yum on Linux, it provides a similar facility, allowing you to install, say, GnuPG by running fink install gnupg . It installs things into its own directory tree, rooted at /sw by default, to avoid interfering with things shipped by Apple ( / , /usr ) or manually installed by the user ( /usr/local .) That is, if you have Fink installed, your system will have /sw/bin , /sw/lib , /sw/etc , /sw/share/man , &c. So that you can run things installed in these nonstandard locations, Fink provides some shell commands in /sw/bin/init.sh which edit environment variables like PATH and MANPATH to include the /sw/* directories. Most Fink users have . /sw/bin/init.sh in their ~/.profile , so these commands will be invoked when their shell starts. Having my shell automatically pull in Fink at startup doesn't work for me, though. It's important to me to have a clea...