<?xml version="1.0" encoding="UTF-8"?>
<feed xmlns="http://www.w3.org/2005/Atom">
  <title>Robey</title>
  <link href="http://robey.lag.net/atom.xml" rel="self"/>
  <link href="http://robey.lag.net/"/>
  <updated>2025-12-01T11:34:44-08:00</updated>
  <id>http://robey.lag.net/</id>
  <author>
    <name>Robey Pointer</name>
    <email>robeypointer@gmail.com</email>
  </author>
  
    <entry>
      <title>My Watchy OS</title>
      <link href="http://robey.lag.net/2025/09/14/my-watchy.html"/>
      <updated>2025-09-14T00:00:00-07:00</updated>
      <id>http://robey.lag.net/2025/09/14/my-watchy</id>
      <content type="html">
        &lt;p&gt;In the summer of 2021, I bought a &lt;a href=&quot;https://www.crowdsupply.com/sqfmi/watchy&quot;&gt;Watchy&lt;/a&gt;: a hobbyist watch with a tiny (200x200 pixel, 4cm) e-ink screen, an ESP32 processor (plus separate real-time clock chip), 4 buttons, a step-counting accelerometer, and 200mAh battery. I was doing a lot of ESP32 coding at work, so the idea of writing my own watch software sounded like fun, and the ESP32 is pretty powerful: &lt;em&gt;tons&lt;/em&gt; of memory, bluetooth/wifi support, and good low-power modes.&lt;/p&gt;

&lt;p&gt;Over the course of the next year, I iterated on a unique watch design that I really liked, and had fun showing off to other nerds.&lt;/p&gt;

&lt;div class=&quot;blog-images blog-images-2&quot;&gt;
    &lt;a href=/assets/images/2025/watchy-blog-2.jpg target=&quot;_blank&quot;&gt;
        &lt;img src=/assets/images/2025/watchy-blog-2.jpg title=&quot;Watchy box&quot;&gt;
    &lt;/a&gt;
    &lt;a href=/assets/images/2025/watchy-back.jpg target=&quot;_blank&quot;&gt;
        &lt;img src=/assets/images/2025/watchy-back.jpg title=&quot;Watchy box&quot;&gt;
    &lt;/a&gt;
&lt;/div&gt;


&lt;h2&gt;How does it work?&lt;/h2&gt;

&lt;p&gt;In normal operation, Watchy&amp;rsquo;s ESP32 is powered down. That&amp;rsquo;s right, the cores and all but 8KB of RAM are turned off in what they call &amp;ldquo;deep sleep&amp;rdquo; mode. The e-ink screen is also off, conveniently still showing the most recently-drawn clock face. Only the RTC (real-time clock) chip is powered, to track the current time. When that time rolls over to the next minute, the RTC triggers an interrupt that wakes up (actually: boots up) the ESP32. The four buttons are also connected to a different interrupt/wake pin so they can have a sub-minute reaction time. As it &amp;ldquo;boots up&amp;rdquo; once a minute, the sample Watchy code initializes the e-ink display, updates it for the current time, and then powers everything off again.&lt;/p&gt;

&lt;p&gt;But the fun of owning a hobbyist watch like this is replacing the sample code with something personalized, so of course that&amp;rsquo;s what I did.&lt;/p&gt;

&lt;p&gt;First, I drew a round clock face to show the current (12-hour) time, with no number markings, because it looked cooler that way. Then I put the digital (24-hour) time and current day in the bottom corners, and an icon of the battery level in the top corner. I&amp;rsquo;m a &lt;a href=&quot;https://en.wikipedia.org/wiki/Visual_learning&quot;&gt;visual learner&lt;/a&gt;, so the large clock face gave me an instant impression of &lt;em&gt;roughly&lt;/em&gt; what time it is, while the digital time in the corner let me know the exact minute if I was about to be late for a meeting.&lt;/p&gt;

&lt;div class=&quot;blog-images&quot;&gt;
    &lt;a href=/assets/images/2025/watchy-face-1.jpg target=&quot;_blank&quot;&gt;
        &lt;img src=/assets/images/2025/watchy-face-1.jpg title=&quot;Watchy face&quot;&gt;
    &lt;/a&gt;
&lt;/div&gt;


&lt;p&gt;I&amp;rsquo;d written code for an e-ink display before (the &lt;a href=&quot;https://soldered.com/categories/inkplate/&quot;&gt;Inkplate&lt;/a&gt;), and that one could take about a dozen quick-refresh partial updates before the screen started to show the faded remnants of old content, like a half-erased etch-a-sketch. To avoid that, you needed to do a &lt;em&gt;full&lt;/em&gt; refresh, which causes the screen to distractingly flash black and white a few times. Whatever e-ink display they used in the Watchy does &lt;em&gt;not&lt;/em&gt; have that problem. It looked like I could update the clock face every minute for hours (maybe even days?) at a time without the full refresh. I ended up doing a full refresh for any user interaction via button press that was going to change the whole screen anyway, but I&amp;rsquo;m not sure it needed even that. Amazing!&lt;/p&gt;

&lt;p&gt;The most obvious use for the built-in wifi is NTP, and I believe some of the example code from Watchy already demonstrated this. It&amp;rsquo;s easy because an NTP client is built into the ESP&amp;rsquo;s standard library. Wifi, however, is &lt;em&gt;extremely power hungry&lt;/em&gt; for a tiny embedded device, so I set it to connect only at the top of each hour. The RTC chip is not very accurate, losing about 5 seconds a day, but an hourly wifi check was enough to keep it pretty accurate without draining the battery. Given how much time I spent away from my home wifi without reconfiguring the watch&amp;rsquo;s connection, it was probably good enough to be unnoticeable even if it only updated every day or two.&lt;/p&gt;

&lt;p&gt;One improvement I made was to set the RTC&amp;rsquo;s time in UTC (as it comes from the NTP server), then use the ESP&amp;rsquo;s standard library to convert to the current time zone. It already has support for one of the standard time zone description formats, including daylight savings, so it was both easier and better than trying to do it by hand, and left open the possibility of switching between a set of predefined time zones (foreshadowing).&lt;/p&gt;

&lt;p&gt;At that point, I thought: But this watch has &lt;em&gt;wifi&lt;/em&gt;. Much more is possible!&lt;/p&gt;

&lt;h2&gt;Weather conditions&lt;/h2&gt;

&lt;p&gt;I used to track our house&amp;rsquo;s thermostat usage against the outside temperature, so I got skilled at bringing up a new API client as each weather service either died (Weather Underground), enshittified (Dark Sky), or both. I&amp;rsquo;m currently using &lt;a href=&quot;https://openweathermap.org/&quot;&gt;OpenWeather&lt;/a&gt; and like it just fine. I drew some tiny icons to represent the current conditions, and displayed the &amp;ldquo;current&amp;rdquo; temperature and humidity from the last time it connected to wifi.&lt;/p&gt;

&lt;p&gt;Wildfires and &lt;a href=&quot;https://www.sfchronicle.com/california-wildfires/article/The-day-the-sun-didn-t-come-up-People-in-15554470.php&quot;&gt;the day the sun didn&amp;rsquo;t rise&lt;/a&gt; were also top-of mind, so I connected to the &lt;a href=&quot;https://www.airnow.gov/&quot;&gt;AirNow&lt;/a&gt; API too, and drew some tiny icons representing 5 different levels of air quality, from &amp;ldquo;great&amp;rdquo; to &amp;ldquo;gas mask time&amp;rdquo;.&lt;/p&gt;

&lt;p&gt;Here are the icons for your amusement, and feel free to use them for your own projects if you like. If it&amp;rsquo;s possible to license a 24-pixel icon, I hereby release them under &lt;a href=&quot;https://creativecommons.org/public-domain/cc0/&quot;&gt;CC0&lt;/a&gt;:&lt;/p&gt;

&lt;div class=&quot;blog-images blog-images-small blog-images-2&quot; style=&quot;height: 20em;&quot;&gt;
    &lt;a href=/assets/images/2025/weather-icons-2.png target=&quot;_blank&quot;&gt;
        &lt;img src=/assets/images/2025/weather-icons-2.png title=&quot;Hand-drawn weather icons&quot; style=&quot;height: 20em;&quot;&gt;
    &lt;/a&gt;
    &lt;a href=/assets/images/2025/aqi-levels.png target=&quot;_blank&quot;&gt;
        &lt;img src=/assets/images/2025/aqi-levels.png title=&quot;Hand-drawn AQI faces&quot; style=&quot;height: 20em;&quot;&gt;
    &lt;/a&gt;
&lt;/div&gt;


&lt;p&gt;What next? Why not sunrise and sunset? Why not the current moon phase, and moonrise and moonset? I often go for night walks, so this is not useless info! Turns out you can get a great estimate of all of these if you put the current time and your latitude/longitude into a set of cubic equations that first appeared as a Pascal program on a floppy disk included with a &lt;a href=&quot;https://archive.org/details/astronomyonperso0000mont/page/n5/mode/2up&quot;&gt;paper book about astronomy&lt;/a&gt; in 1994. I only mention that because almost every code sample you can find online is a direct descendant of that code &amp;ndash; including mine. You can find this same code translated into QBasic, Javascript, and Python. It deserves its own &amp;ldquo;secretly influential code&amp;rdquo; blog post. (The equations are complicated because not only are all three orbits elliptical, but everything wobbles.)&lt;/p&gt;

&lt;p&gt;I&amp;rsquo;m not a great artist (please act shocked), so I bought &lt;a href=&quot;https://thenounproject.com/browse/collection-icon/moon-phases-4033/&quot;&gt;high-quality icons of the moon phases&lt;/a&gt; from the Noun Project and down-res&amp;rsquo;d the images to 48 pixels, which did them a lot of injustice, but still looked great.&lt;/p&gt;

&lt;div class=&quot;blog-images&quot;&gt;
    &lt;a href=/assets/images/2025/watchy-weather.jpg target=&quot;_blank&quot;&gt;
        &lt;img src=/assets/images/2025/watchy-weather.jpg title=&quot;Weather conditions, AQI, moon &amp; sun motion, and weather in a few favorite places too&quot;&gt;
    &lt;/a&gt;
&lt;/div&gt;


&lt;p&gt;While working on this feature, I took a vacation to Hawai&apos;i, which bumped up the priority of supporting multiple time zones. Naturally I had to stay up all night on the lanai, hacking on my watch as the moon rose. I ended up making a table of locations popular with my friends and family, and letting you switch between these locations by name. Each location has a time zone descriptor and latitude/longitude, which is enough to localize the time, weather, and astronomical conditions. It&amp;rsquo;s easy to add new ones by looking up a city&amp;rsquo;s entry on wikipedia, which has all the relevant data in a handy table in a sidebar.&lt;/p&gt;

&lt;h2&gt;Now it gets excessive&lt;/h2&gt;

&lt;p&gt;All this weather and moon information really needed to be on a second screen to keep the main clock face from getting cluttered. There also needed to be a way to change the current location (and possibly other future settings) without recompiling and re-installing the watch each time. So, of course, I decided to write a custom UI toolkit, and assigned a purpose to each button: menu/select, back, up, and down.&lt;/p&gt;

&lt;p&gt;Several KB of RAM are preserved when the ESP32 is in deep sleep, and that&amp;rsquo;s more than enough to store all the state you need to track user interactions: which &amp;ldquo;view&amp;rdquo; is currently displayed, a small stack of previous views for navigating &amp;ldquo;back&amp;rdquo;, and the state of each view (like which menu item is highlighted). It&amp;rsquo;s a small screen that can only display 8 lines of 3mm-height text, so any long text or menu also needs to support scrolling and remembering its scroll position. Aside from memory reserved for the system log and a dynamic demo, it all uses less than 1KB of state&amp;hellip; and most of that is for caching the current weather &amp;amp; air quality across 10 locations.&lt;/p&gt;

&lt;p&gt;I was so pleased when I got word-wrap and scroll working &amp;ndash; with a scroll bar and long-press to scroll by a page! &amp;ndash; that I recorded a small video demonstrating it on a famous PKD quote. Then I built a small menu widget for changing settings on the fly (like location). Preferences are stored in NVS, a tiny &lt;a href=&quot;https://en.wikipedia.org/wiki/Wear_leveling&quot;&gt;wear-leveled&lt;/a&gt; key-value flash store that&amp;rsquo;s part of the ESP standard library. EZPZ.&lt;/p&gt;

&lt;div class=&quot;blog-images blog-images-2&quot;&gt;
    &lt;video controls src=/assets/images/2025/watchy-pkd.mp4 title=&quot;Scrolling demonstration&quot;&gt;
    &lt;/video&gt;
    &lt;video controls src=/assets/images/2025/watchy-menu.mp4 title=&quot;Menu demonstration&quot;&gt;
    &lt;/video&gt;
&lt;/div&gt;


&lt;p&gt;You may have looked at the images so far and thought, &amp;ldquo;What bitmap font is that? I haven&amp;rsquo;t seen one that odd before.&amp;rdquo; That&amp;rsquo;s because I took my &lt;a href=&quot;https://robey.lag.net/2020/02/09/bizcat-bitmap-font.html&quot;&gt;Bizcat font&lt;/a&gt; and adapted it to a larger size (24-pixel) proportional style to fit the watch.&lt;/p&gt;

&lt;h2&gt;Nothing lasts forever&lt;/h2&gt;

&lt;p&gt;For a while, I had a lot of fun writing the code and adding features. Then it felt sort of &amp;ldquo;done&amp;rdquo; and it was my working watch for two years, which may be the highest praise to give a thing like a wristwatch: after a while, I took it for granted. Every once in a while, someone would notice it and I could show it off, but most of the time, I just &amp;hellip; used it.&lt;/p&gt;

&lt;p&gt;I tried to connect with other Watchy fans to share code &amp;amp; ideas and get inspired, but the only active forum seemed to be a Discord guild. As with all discords, information tended to scroll gently away into oblivion, with no way to pull out or organize the good stuff. A message board and/or a group wiki for tracking projects and toolkits would have been invaluable, but the community never got enough traction to make the leap, and the creator wasn&amp;rsquo;t really engaged with it by then.&lt;/p&gt;

&lt;p&gt;If you feel like iterating on the Watchy design, &lt;a href=&quot;https://watchy.sqfmi.com/docs/hardware&quot;&gt;the schematics are online&lt;/a&gt;. There were two common suggestions from users for a 2nd rev:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Add some minimal amount of water resistance to the case. Some people reported that a single drop of water could kill the device. This makes it hard to wear if you live in a place where it rains.&lt;/li&gt;
&lt;li&gt;Add a little LED light like old Casios had. I don&amp;rsquo;t think it would have hurt the battery life much since you usually don&amp;rsquo;t hold the light on for very long. Without this, the watch was unreadable outside at night.&lt;/li&gt;
&lt;/ul&gt;


&lt;p&gt;I found network connections over wifi to be extremely flaky, though it seemed to be a software problem, not hardware. At the top of each hour, if I was home, my Watchy would connect to the house wifi and update NTP and weather data. Weather involved making a separate HTTP request to OpenWeather and AirNow for each of the 4 or 5 cities I was tracking, but I rarely saw it complete all of the cities before it would start getting network errors as if the wifi had dropped out. (The wifi was fine.) Sometimes it would only get one city, sometimes almost all of them. I tried adding delays and fussing around to triple-ensure that all resources were closed after each HTTP request, but nothing worked. It might have been a bug in the ESP network stack&amp;hellip; or maybe there was &lt;em&gt;one last elusive resource&lt;/em&gt; I didn&amp;rsquo;t close correctly. I never figured it out.&lt;/p&gt;

&lt;p&gt;As you can see, mine got a lot of use despite those shortcomings.&lt;/p&gt;

&lt;div class=&quot;blog-images&quot;&gt;
    &lt;a href=/assets/images/2025/watchy-dead.jpg target=&quot;_blank&quot;&gt;
        &lt;img src=/assets/images/2025/watchy-dead.jpg title=&quot;It got a lot of use&quot;&gt;
    &lt;/a&gt;
&lt;/div&gt;


&lt;p&gt;My first watch died after about a year for mysterious reasons. I bought a replacement and felt newly inspired to hook up the step counter and track a small history of daily steps in flash. I factored out common code into a &amp;ldquo;Watchy OS&amp;rdquo; library that others could reuse, but never felt motivated to actually post it as a separate repo. Later I found out this &amp;ldquo;shared base OS&amp;rdquo; idea had percolated through the community a few times before without much success.&lt;/p&gt;

&lt;p&gt;My second watch died within about a year for similarly mysterious reasons. This time, it was still working, but could no longer be charged. Once it drained its battery completely, it was an ex-watch, permanently showing the last time it had enough juice to update the screen.&lt;/p&gt;

&lt;p&gt;I decided not to buy a third, because it was kind of expensive for a watch that lasts one year, and it was clear the product had quietly reached end-of-life. I still miss it.&lt;/p&gt;

&lt;p&gt;The code is here, with an Apache-2 license, if you want to check it out or borrow any of it: &lt;a href=&quot;https://code.lag.net/robey/nuwatchy&quot;&gt;code.lag.net/robey/nuwatchy&lt;/a&gt;&lt;/p&gt;
 
        <a href="http://flattr.com/thing/40430/Robey" target="_blank">
        <img src="http://api.flattr.com/button/button-compact-static-100x17.png" alt="Flattr this" title="Flattr this" border="0" />
        </a>
      </content>
    </entry>
  
    <entry>
      <title>Setting up a CI server for Forgejo</title>
      <link href="http://robey.lag.net/2025/08/10/forgejo-ci.html"/>
      <updated>2025-08-10T00:00:00-07:00</updated>
      <id>http://robey.lag.net/2025/08/10/forgejo-ci</id>
      <content type="html">
        &lt;p&gt;I recently got CI working with my personal forgejo instance, and thought I would share how I did it. It&amp;rsquo;s not that hard, but has a few confusing quirks, and all the tutorials I found online were wrong, outdated, or both. They also tend to include a few pages of steps you don&amp;rsquo;t really need for a small instance.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Background&lt;/strong&gt;: &lt;a href=&quot;https://forgejo.org/&quot;&gt;Forgejo&lt;/a&gt; is a &amp;ldquo;software forge&amp;rdquo; &amp;ndash; a way to host git &amp;amp; jujutsu code repos for you, your friends, or your team. It&amp;rsquo;s part of the &amp;ldquo;small communities&amp;rdquo; decentralization movement, and is a good replacement for things like Github or Launchpad. CI means &amp;ldquo;continual integration&amp;rdquo; which just means &amp;ldquo;build server&amp;rdquo; like Jenkins, TeamCity, or Tinderbox. It&amp;rsquo;s totally possible to host your own code and CI on 1 or 2 servers, virtual or home lab.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;How it works&lt;/strong&gt;: The build server runs some kind of Linux container manager. I chose &lt;a href=&quot;https://podman.io/&quot;&gt;podman&lt;/a&gt;, a command-line tool that&amp;rsquo;s compatible with Docker, but much smaller &amp;amp; simpler, and doesn&amp;rsquo;t have to run as root. A separate service called &lt;code&gt;forgejo-runner&lt;/code&gt; authenticates with your forgejo server, receives build requests, runs them on the container, and sends back logs and artifacts.&lt;/p&gt;

&lt;p&gt;Forgejo recommends putting the build server on a different machine than the forge, because both pieces of software can run hot, and the build server will be literally running new Linux VMs to do builds. For security, you probably want to treat the build machine as disposable: don&amp;rsquo;t give it access to anything besides your forge, and rebuild it from scratch if it behaves suspiciously. (I haven&amp;rsquo;t had any trouble here. This is just general good advice.)&lt;/p&gt;

&lt;p&gt;I chose Alpine as the Linux install for the build machine. It&amp;rsquo;s a good thin distribution for servers, where you don&amp;rsquo;t need any bells and whistles or a full desktop. The first time I tried it, I was pleasantly surprised that the display of &lt;code&gt;top&lt;/code&gt; only showed my servers, not pages and pages of systemd and random &amp;ldquo;support&amp;rdquo; daemons. It also has packages for podman and forgejo-runner, which greatly simplifies the CI install.&lt;/p&gt;

&lt;h2&gt;Install Alpine&lt;/h2&gt;

&lt;p&gt;If you already have an Alpine 3.22 VM ready, you can skip this part. Otherwise, install a fresh Alpine image, and do the bare minimum:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;# setup-alpine
&lt;/code&gt;&lt;/pre&gt;

&lt;ul&gt;
&lt;li&gt;Make sure to create a user account for yourself and add your SSH key.&lt;/li&gt;
&lt;li&gt;Add your user account to &lt;code&gt;/etc/sudoers&lt;/code&gt; under &lt;code&gt;root&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Make sure you can login as your new user, from a new ssh connection, and &lt;code&gt;sudo echo hi&lt;/code&gt; to make sure you can sudo.&lt;/li&gt;
&lt;li&gt;Turn off ssh password auth. I don&amp;rsquo;t understand why this defaults on for virtual machine images.

&lt;ul&gt;
&lt;li&gt;Edit &lt;code&gt;/etc/ssh/sshd_config&lt;/code&gt;, find the &lt;code&gt;PasswordAuthentication&lt;/code&gt; line, and change the value to &lt;code&gt;No&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;


&lt;p&gt;If you&amp;rsquo;re picky like me, now is also your chance to install some of your favorite tools:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;# apk add less lsof
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Now upgrade it to at least 3.22, if it&amp;rsquo;s not already. That&amp;rsquo;s the minimum version to get forgejo-runner.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Edit &lt;code&gt;/etc/apk/repositories&lt;/code&gt;

&lt;ul&gt;
&lt;li&gt;Change the version number to &lt;code&gt;3.22&lt;/code&gt; on every line.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;


&lt;pre&gt;&lt;code&gt;# apk update
# apk add --upgrade apk-tools
# apk upgrade --available
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;This should be pretty fast. Then reboot into the new, fresh-smelling 3.22:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;# reboot
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;From now on, you&amp;rsquo;ll be logging into this machine as yourself (the username you added above), not root, and using &amp;ldquo;sudo&amp;rdquo; to do things that require root permission.&lt;/p&gt;

&lt;h2&gt;Install podman &amp;amp; runner&lt;/h2&gt;

&lt;p&gt;Podman and forgejo-runner can be installed at the same time, but they need extra dependencies. Some are obvious (git), others are needed to create virtual file systems and network interfaces.&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;# apk add nodejs npm rsync git iptables podman forgejo-runner slirp4netns fuse
# rc-update add cgroups
# rc-service cgroups start
# modprobe tun
# echo tun &amp;gt;&amp;gt;/etc/modules
# echo forgejo-runner:100000:9999 &amp;gt;&amp;gt;/etc/subuid
# echo forgejo-runner:100000:9999 &amp;gt;&amp;gt;/etc/subgid
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;If you aren&amp;rsquo;t already using tmpfs, you need to set that up too. Podman has a panic attack if it sees old files in &lt;code&gt;/tmp&lt;/code&gt; after a reboot:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;# echo &quot;tmpfs /tmp tmpfs nodev,nosuid,size=1G 0 0&quot; &amp;gt;&amp;gt; /etc/fstab
# mount /tmp
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;At this point, you should be able to run a test image with podman &amp;ndash; as your normal user account! &amp;ndash; to prove it&amp;rsquo;s installed correctly.&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;$ podman run --rm hello-world
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;We need to do a little bootstrapping to make sure the environment is set up correctly before starting the daemons. Runner creates its own user (&lt;code&gt;forgejo-runner&lt;/code&gt;) and we want podman to run as the same user. Runner will create this user&amp;rsquo;s home folder the first time it starts, but it expects podman to be running already, and podman will crash if it can&amp;rsquo;t reach the same home folder. Easy to untangle, though.&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;# forgejo-runner generate-config &amp;gt; /etc/forgejo-runner/config.yaml
# mkdir /var/lib/forgejo-runner
# chown forgejo-runner:forgejo-runner /var/lib/forgejo-runner
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Runner and podman communicate through a unix socket. Podman&amp;rsquo;s default location for this socket is undiscoverable, so tell them to look in &lt;code&gt;/tmp&lt;/code&gt;.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Edit &lt;code&gt;/etc/conf.d/podman&lt;/code&gt; and change these lines:

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;podman_uri=&quot;unix:///tmp/podman.sock&quot;&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;podman_user=&quot;forgejo-runner&quot;&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Edit &lt;code&gt;/etc/forgejo-runner/config.yaml&lt;/code&gt; and change this line inside the &lt;code&gt;container&lt;/code&gt; section at the end:

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;docker_host: &quot;unix:///tmp/podman.sock&quot;&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;


&lt;p&gt;&lt;em&gt;Also&lt;/em&gt;, the startup script for forgejo-runner has a bug. It can&amp;rsquo;t start at boot time until podman is running, but they forget to add a dependency.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Edit &lt;code&gt;/etc/init.d/forgejo-runner&lt;/code&gt; and add this line inside &lt;code&gt;depend()&lt;/code&gt;:

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;need podman&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;


&lt;p&gt;That makes the &lt;code&gt;depend()&lt;/code&gt; function look like:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;depend() {
    need net
    need podman
    use dns logger
}
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Now &lt;code&gt;reboot&lt;/code&gt; to make sure all the new config is loaded (especially the changes to &lt;code&gt;/etc/subuid&lt;/code&gt; and &lt;code&gt;/etc/subgid&lt;/code&gt;).&lt;/p&gt;

&lt;h2&gt;Start the podman &amp;amp; runner services&lt;/h2&gt;

&lt;pre&gt;&lt;code&gt;# rc-update add podman
# rc-service podman start
# rc-service podman status
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;As your normal user, double-check that the runner can talk to podman, and register it with your forgejo server:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;$ doas -u forgejo-runner podman run --rm alpine echo &quot;It works!&quot;
$ cd /var/lib/forgejo-runner &amp;amp;&amp;amp; doas -u forgejo-runner forgejo-runner register
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;It will ask for your forgejo server&amp;rsquo;s url, and then a token. There are a few kinds of tokens, but the simplest kind is the &amp;ldquo;site&amp;rdquo; token which gives access to every project on your server. That&amp;rsquo;s in the upper right corner under &amp;ldquo;Site administration&amp;rdquo; -&gt; &amp;ldquo;Actions&amp;rdquo; -&gt; &amp;ldquo;Runners&amp;rdquo; -&gt; &amp;ldquo;Create new runner&amp;rdquo;.&lt;/p&gt;

&lt;p&gt;After that, you should see the config in &lt;code&gt;/var/lib/forgejo-runner/.runner&lt;/code&gt; as JSON. You can change the label here if you like, but I figured &amp;ldquo;docker&amp;rdquo; is already a pretty good description of what&amp;rsquo;s going on.&lt;/p&gt;

&lt;p&gt;Now you can start up the runner:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;# rc-update add forgejo-runner
# rc-service forgejo-runner start
# rc-service forgejo-runner status
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Back on your forgejo server, reloading the &amp;ldquo;Runners&amp;rdquo; admin page should show your new runner as idle. You did it!&lt;/p&gt;

&lt;p&gt;As a last step, you may need to &amp;ldquo;activate&amp;rdquo; actions for your project(s). That&amp;rsquo;s a separate checkbox in the project&amp;rsquo;s &amp;ldquo;Settings&amp;rdquo; page, under &amp;ldquo;Units&amp;rdquo; -&gt; &amp;ldquo;Overview&amp;rdquo;.&lt;/p&gt;

&lt;h2&gt;How do I use this?&lt;/h2&gt;

&lt;p&gt;Forgejo runners seem to be based on a Github feature called &amp;ldquo;Github Actions&amp;rdquo;. They&amp;rsquo;re so heavily based on it that they use the same build file structure, use Github&amp;rsquo;s name in many of the field names and environment variables, and require a lot of ceremony that&amp;rsquo;s overkill for a team build server.&lt;/p&gt;

&lt;p&gt;Describe a build by committing a special file into your repo in a &lt;code&gt;.forgejo/workflows/&lt;/code&gt; folder. This file must be YAML. Inside, you declare which runner to use (usually &amp;ldquo;docker&amp;rdquo; unless you changed it), which docker base image to start from, and a set of steps/commands. Optionally, you can set which branches trigger the build when pushed. Here&amp;rsquo;s a simple example:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;# .forgejo/workflows/build.yaml

---
name: build
&quot;on&quot;:
  push: &quot;*&quot;
jobs:
  build:
    runs-on: docker
    container:
      image: &quot;rust:alpine&quot;
    steps:
      - run: apk add nodejs npm git
      - uses: actions/checkout@v4
      - run: &quot;./ci.sh&quot;
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;This calls the build &amp;ldquo;build&amp;rdquo;, starts it on a push to any branch, starts with the &lt;code&gt;rust:alpine&lt;/code&gt; base docker image, and runs the shell script &lt;code&gt;ci.sh&lt;/code&gt; to do the actual build.&lt;/p&gt;

&lt;p&gt;Two tricky bits to catch here: You have to add the &lt;code&gt;uses:&lt;/code&gt; line to ask explicitly for your code to be cloned into the image &amp;ndash; without that, you get an empty folder. And before that, you need to install nodejs &amp;amp; git in the image, because the &amp;ldquo;plugin&amp;rdquo; that handles that is written in typescript, and will fallback to downloading your code over an API if it can&amp;rsquo;t find git installed. This looks like a bunch of cruft &amp;ldquo;borrowed&amp;rdquo; from Github, which hasn&amp;rsquo;t bothered anyone enough to get fixed yet.&lt;/p&gt;

&lt;p&gt;As soon as you push this file to your forgejo repo, you can go watch your build in the &amp;ldquo;Actions&amp;rdquo; tab. Congrats!&lt;/p&gt;
 
        <a href="http://flattr.com/thing/40430/Robey" target="_blank">
        <img src="http://api.flattr.com/button/button-compact-static-100x17.png" alt="Flattr this" title="Flattr this" border="0" />
        </a>
      </content>
    </entry>
  
    <entry>
      <title>Bizcat - an 8x16 bitmap font</title>
      <link href="http://robey.lag.net/2020/02/09/bizcat-bitmap-font.html"/>
      <updated>2020-02-09T00:00:00-08:00</updated>
      <id>http://robey.lag.net/2020/02/09/bizcat-bitmap-font</id>
      <content type="html">
        &lt;p&gt;Bizcat is a retro 8x16 bitmap font, intended for hobby computers or terminals that use a 640x480 graphics mode, like the Linux VGA console. It supports most of Latin-9 and box-drawing glyphs. It&amp;rsquo;s available to use under the Creative Commons &lt;a href=&quot;http://creativecommons.org/licenses/by/4.0/&quot;&gt;&amp;ldquo;share and adapt&amp;rdquo;&lt;/a&gt; license, so feel free to tweak it or use it in your own projects.&lt;/p&gt;

&lt;p&gt;An image file in &lt;a href=&quot;https://code.lag.net/robey/font-problems/raw/branch/main/fonts/bizcat.bmp&quot;&gt;BMP&lt;/a&gt; format and a Linux console &lt;a href=&quot;https://code.lag.net/robey/font-problems/raw/branch/main/fonts/bizcat.psf&quot;&gt;PSF&lt;/a&gt; file are available in the &lt;code&gt;fonts/&lt;/code&gt; folder of my &lt;a href=&quot;https://code.lag.net/robey/font-problems&quot;&gt;font-problems&lt;/a&gt; toolset.&lt;/p&gt;

&lt;div style=&quot;width: 100%; margin: 2em 0; display: grid; grid-template-columns: 1fr 1fr; grid-row-gap: 1em; grid-column-gap: 1.5em;&quot;&gt;
  &lt;figure style=&quot;margin: 0; display: table&quot;&gt;
    &lt;a href=/assets/images/2020/bizcat-js.png target=&quot;_blank&quot;&gt;
      &lt;img src=/assets/images/2020/bizcat-js.png title=&quot;Hello&quot;&gt;
    &lt;/a&gt;
  &lt;/figure&gt;

  &lt;figure style=&quot;margin: 0; display: table&quot;&gt;
    &lt;a href=/assets/images/2020/bizcat-welcome.png target=&quot;_blank&quot;&gt;
      &lt;img src=/assets/images/2020/bizcat-welcome.png title=&quot;Hello&quot;&gt;
    &lt;/a&gt;
  &lt;/figure&gt;
&lt;/div&gt;


&lt;h2&gt;Why?&lt;/h2&gt;

&lt;p&gt;Retro-computing has received a new wave of interest over the past few years. It may be a reaction to the boggling complexity and fragility of modern systems: x86 boxes apparently require &lt;a href=&quot;https://en.wikipedia.org/wiki/Intel_Management_Engine&quot;&gt;a separate CPU and OS&lt;/a&gt; just to bootstrap the real CPU, and once it&amp;rsquo;s running, it uses tricks so baroque that it took over a decade to figure out they were &lt;a href=&quot;https://en.wikipedia.org/wiki/Spectre_%28security_vulnerability%29&quot;&gt;subtly flawed&lt;/a&gt;. It may also be due to the explosion of the &amp;ldquo;maker&amp;rdquo; community and the recent availability of simple hardware and components: you can &lt;a href=&quot;https://www.youtube.com/playlist?list=PLowKtXNTBypGqImE405J2565dvjafglHU&quot;&gt;build your own custom CPU from logic chips&lt;/a&gt; or &lt;a href=&quot;https://gigatron.io/&quot;&gt;assemble a motherboard for a new 8-bit platform&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Over the winter, I played around with the &lt;a href=&quot;https://github.com/x16community/x16-emulator&quot;&gt;Commander X16 emulator&lt;/a&gt;, part of a project by David Murray (&lt;a href=&quot;https://www.youtube.com/channel/UC8uT9cgJorJPWu7ITLGo9Ww&quot;&gt;The 8-bit Guy&lt;/a&gt;) and his friends to create a new hackable 8-bit home computer in the style of the Commodore 64. The video output is 640x480 VGA, and by default it uses a blocky 8x8 font, maintaining the spirit of Commodore graphics while scaling up to allow a console of 80x60 characters. Unfortunately, while square letters are authentic, they clearly represent a limitation of the old graphics mode (which was only 320x200 or 40x25), not an aesthetic choice.&lt;/p&gt;

&lt;div style=&quot;width: 100%; margin: 2em 0&quot;&gt;
  &lt;figure style=&quot;margin: 0; display: table&quot;&gt;
    &lt;a href=/assets/images/2020/8bit-basic.png target=&quot;_blank&quot;&gt;
      &lt;img src=/assets/images/2020/8bit-basic.png title=&quot;Hello&quot;&gt;
    &lt;/a&gt;
    &lt;figcaption&gt; It&apos;s hip to be square. &lt;/figcaption&gt;
  &lt;/figure&gt;
&lt;/div&gt;


&lt;p&gt;This made me think about how the old VGA PCs drew characters. With a wide-open 640x480 space, you can fit a &lt;a href=&quot;http://www.righto.com/2019/11/ibm-sonic-delay-lines-and-history-of.html&quot;&gt;standard 80x25 terminal&lt;/a&gt; by using a character cell size of 8x16, so that&amp;rsquo;s what they did. A 2:1 ratio sounds really tall for that era, but they used the extra vertical space to give more breathing room to accents and to pad out the line spacing. The result (check out &lt;a href=&quot;https://int10h.org/oldschool-pc-fonts/&quot;&gt;this awesome collection of IBM fonts&lt;/a&gt;) looks really pretentious to me because of all the serifs. I think IBM chose a typewriter style to differentiate their &amp;ldquo;strictly business&amp;rdquo; PCs from the &amp;ldquo;fun time&amp;rdquo; look of their competitors. But now it&amp;rsquo;s fun time again.&lt;/p&gt;

&lt;p&gt;I was immediately bitten by the bug. Time to draw a new bitmap font!&lt;/p&gt;

&lt;p&gt;Since I was committed to spending my free time on this, I decided to make a few other philosophical changes. In the 1980s, you needed a 100-kilo CRT to view text. These days, you&amp;rsquo;re more likely to be looking at VGA graphics on a 7&quot; flatscreen made from old tablet parts. So I decided to use thick lines that can be seen at high DPI. If all lines are two pixels wide, then 1-pixel offsets act as a kind of anti-aliasing to smooth out curves. And if curves look nice, let&amp;rsquo;s lean into them and make circles look as round as possible. Some fonts push circles in the direction of rounded rectangles, which gives a nice rectangular look overall, but to me, geometric looks more &amp;ldquo;fun&amp;rdquo;, and circles are very retro-80s.&lt;/p&gt;

&lt;div style=&quot;width: 100%; margin: 2em 0&quot;&gt;
  &lt;figure style=&quot;margin: 0; display: table&quot;&gt;
    &lt;a href=/assets/images/2020/yess-yess.png target=&quot;_blank&quot;&gt;
      &lt;img src=/assets/images/2020/yess-yess.png title=&quot;Hello&quot;&gt;
    &lt;/a&gt;
    &lt;figcaption&gt; Left: International Business Machines. Right: Business cat. &lt;/figcaption&gt;
  &lt;/figure&gt;
&lt;/div&gt;




&lt;div style=&quot;width: 100%; margin: 2em 0&quot;&gt;
  &lt;figure style=&quot;margin: 0; display: table&quot;&gt;
    &lt;a href=/assets/images/2020/bizcat-asm.png target=&quot;_blank&quot;&gt;
      &lt;img src=/assets/images/2020/bizcat-asm.png title=&quot;Hello&quot;&gt;
    &lt;/a&gt;
    &lt;figcaption&gt; 6502 assembly on the X16 &lt;/figcaption&gt;
  &lt;/figure&gt;
&lt;/div&gt;


&lt;p&gt;I tested and iterated on the font by trying it out on the Commander X-16 emulator. The VERA video &amp;ldquo;chip&amp;rdquo; has two layers, and each can be assigned a different bitmap font, so I sliced the 8x16 font into two half-fonts, with each character&amp;rsquo;s top half on one layer and the bottom half on the other. Once I was satisfied, I realized I could also use this font on my physical Linux server console, after cleaning the spider webs off of it.&lt;/p&gt;

&lt;div style=&quot;width: 100%; margin: 2em 0; display: grid; grid-template-columns: 1fr 1fr; justify-items: center; grid-row-gap: 1em; grid-column-gap: 1.5em;&quot;&gt;
  &lt;figure style=&quot;margin: 0px&quot;&gt;
    &lt;a href=/assets/images/2020/bizcat-epoll.jpg target=&quot;_blank&quot;&gt;
      &lt;img src=/assets/images/2020/bizcat-epoll.jpg&gt;
    &lt;/a&gt;
    &lt;figcaption&gt; man epoll &lt;/figcaption&gt;
  &lt;/figure&gt;
  &lt;figure style=&quot;margin: 0px&quot;&gt;
    &lt;a href=/assets/images/2020/bizcat-mc.jpg target=&quot;_blank&quot;&gt;
      &lt;img src=/assets/images/2020/bizcat-mc.jpg&gt;
    &lt;/a&gt;
    &lt;figcaption&gt; midnight commander &lt;/figcaption&gt;
  &lt;/figure&gt;
&lt;/div&gt;


&lt;p&gt;So jaunty! I think I&amp;rsquo;ll keep it.&lt;/p&gt;

&lt;p&gt;If you make any significant changes, or if you use this font in any interesting places, I&amp;rsquo;d love to see them!&lt;/p&gt;

&lt;div style=&quot;width: 100%; margin: 2em 0&quot;&gt;
  &lt;figure style=&quot;margin: 0; display: table&quot;&gt;
    &lt;a href=/assets/images/2020/bizcat.png target=&quot;_blank&quot;&gt;
      &lt;img src=/assets/images/2020/bizcat.png title=&quot;Hello&quot;&gt;
    &lt;/a&gt;
    &lt;figcaption&gt; glyphs so far &lt;/figcaption&gt;
  &lt;/figure&gt;
&lt;/div&gt;

 
        <a href="http://flattr.com/thing/40430/Robey" target="_blank">
        <img src="http://api.flattr.com/button/button-compact-static-100x17.png" alt="Flattr this" title="Flattr this" border="0" />
        </a>
      </content>
    </entry>
  
    <entry>
      <title>The Year of the Linux Laptop - Darter Pro Review</title>
      <link href="http://robey.lag.net/2019/04/21/darter-pro-review.html"/>
      <updated>2019-04-21T00:00:00-07:00</updated>
      <id>http://robey.lag.net/2019/04/21/darter-pro-review</id>
      <content type="html">
        &lt;h2&gt;Background&lt;/h2&gt;

&lt;p&gt;I started using Linux in the early 1990s, first as a toy, and gradually as my primary/only OS. Aside from the cute Solitaire game, Windows 3 didn&amp;rsquo;t really appeal to me, while Linux had native support for the internet and a development environment that would let you write networked programs that could do several things at once through multitasking &amp;ndash; a world of possibilities, which I promptly &lt;a href=&quot;https://en.wikipedia.org/wiki/Eggdrop&quot;&gt;exploited&lt;/a&gt;.&lt;/p&gt;

&lt;div style=&quot;width: 100%; margin: 2em 0&quot;&gt;
  &lt;figure style=&quot;margin: 0; display: table&quot;&gt;
    &lt;a href=/assets/images/2019/desktop-2000.jpg target=&quot;_blank&quot;&gt;
      &lt;img src=/assets/images/2019/desktop-2000.jpg title=&quot;Yes, that is Charizard. I don&apos;t want to talk about it.&quot;&gt;
    &lt;/a&gt;
    &lt;figcaption&gt; 2000: Year of the 640x480 laptop &lt;/figcaption&gt;
  &lt;/figure&gt;
&lt;/div&gt;


&lt;p&gt;In 2000, my employer loaned me a Linux Dell laptop. I think it was called &amp;ldquo;Geographer&amp;rdquo; or &amp;ldquo;Latitude&amp;rdquo;. It was a mess. Despite the internet bursting into popularity five years prior, you needed a separate dongle with a modem or ethernet adapter that connected directly to the main bus through a slot on the side. Once plugged in, you had to &lt;code&gt;modprobe&lt;/code&gt; the right driver to bring the network up. If the laptop ever went to sleep, the driver would die and you had to reboot.&lt;/p&gt;

&lt;p&gt;I say &amp;ldquo;sleep&amp;rdquo; but it actually had three different ways to pause, with silly names like &amp;ldquo;cat-nap&amp;rdquo; and &amp;ldquo;hibernate&amp;rdquo;, each triggered by a different F-key. If you used any of them, the laptop had a 50% chance of hard-crashing, either right away, or when you tried to wake it up later. The battery drained so quickly that you couldn&amp;rsquo;t count on it lasting through a meeting.&lt;/p&gt;

&lt;p&gt;That same year, I bought an iBook. It was my first Mac. It was very bad for coding, but it was pretty. It could play music without glitching, because there was no preemptive multi-tasking. It could connect to the network through a built-in ethernet port or wifi, without dongles. If you closed it, it paused, and when you opened it, it resumed and reconnected to the network without crashing or rebooting. It was a computer re-imagined as a tool. I fell in love.&lt;/p&gt;

&lt;p&gt;Over the next few years, I started using Mac laptops for all development work, personal or paid, and used Linux exclusively as a server platform. By the late zeros, I wasn&amp;rsquo;t considered &amp;ldquo;quirky&amp;rdquo; for this anymore: almost all developers had moved their daily work to Mac laptops. Windows and Linux had quietly given up the (admittedly very small) tech-worker share of the market.&lt;/p&gt;

&lt;p&gt;But for the past decade, there&amp;rsquo;s been a rising anxiety about this situation in the tech world. Apple probably didn&amp;rsquo;t intend to become the premier (or only) manufacturer of development machines, and they&amp;rsquo;ve become increasingly unsubtle about their intention to focus entirely on the highly lucrative fashion-accessory market instead. The rapid &lt;a href=&quot;https://theoutline.com/post/2402/the-new-macbook-keyboard-is-ruining-my-life&quot;&gt;decline&lt;/a&gt; in laptop &lt;a href=&quot;https://lobste.rs/s/i3yo2s/developer_laptop_s_not_macbook&quot;&gt;quality&lt;/a&gt; has &lt;a href=&quot;https://marco.org/2017/11/24/fixing-the-macbook-pro&quot;&gt;made&lt;/a&gt; this &lt;a href=&quot;https://twitter.com/JoannaStern/status/1110922607946334208&quot;&gt;palpable&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Surely in the past 20 years, the PC world has caught up enough to become a viable alternative, right? I decided it was time to give it another try.&lt;/p&gt;

&lt;h2&gt;Investigation&lt;/h2&gt;

&lt;p&gt;I&amp;rsquo;m not an Apple fanboy, so I haven&amp;rsquo;t been oblivious to the outside world. Several friends are die-hard fans of Linux and/or freedom, and for years they&amp;rsquo;ve been swearing that the water is fine, and I should dive in.&lt;/p&gt;

&lt;p&gt;My table stakes, though, are that a candidate laptop has to pass two tests:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;It can be paused by closing the lid. When the lid is opened and the screen is unlocked, it resumes without crashing.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;It can remain wifi-capable for at least a week without requiring a reboot.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;


&lt;p&gt;Apparently these requirements are still enough to disqualify most laptops, but one that gets a lot of love is the Lenovo (previously IBM) Thinkpad. More than one person has proclaimed to me over a beer that the Thinkpad is the best Linux laptop, full stop. So over the winter holidays, I read several reviews of the current model, the &amp;ldquo;Thinkpad X1&amp;rdquo;.&lt;/p&gt;

&lt;p&gt;These reviews are
&lt;a href=&quot;https://medium.com/@hkdb/ubuntu-18-04-on-lenovo-x1-carbon-6g-d99d5667d4d5&quot;&gt;nearly&lt;/a&gt;
&lt;a href=&quot;https://mensfeld.pl/2018/07/lenovo-thinkpad-x1-carbon-6th-gen-2018-review-sad-story-of-a-potentially-great-ultrabook/&quot;&gt;universally&lt;/a&gt;
&lt;a href=&quot;https://www.notebookcheck.net/The-6th-gen-Lenovo-ThinkPad-X1-Carbon-on-Linux-is-facing-sleep-mode-issues-unofficial-patch-available-for-a-while.316584.0.html&quot;&gt;terrible&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;As far as I can tell, Lenovo doesn&amp;rsquo;t actually consider this to be a Linux laptop. It&amp;rsquo;s not mentioned in their marketing materials, and they don&amp;rsquo;t offer a version with Linux installed. Instead, you&amp;rsquo;re responsible for installing a Linux distro from scratch, then hunting down and installing various custom drivers if you would like to use features like the trackpad.&lt;/p&gt;

&lt;p&gt;I don&amp;rsquo;t think this model can work. I know Linux fans really want to believe it can, but I think laptops just contain too much custom hardware. To be a &amp;ldquo;Linux laptop&amp;rdquo;, I think the &lt;em&gt;manufacturer&lt;/em&gt; must provide and install the right drivers &lt;em&gt;at the factory&lt;/em&gt;. It can&amp;rsquo;t be the customer&amp;rsquo;s job to go scavenging on sketchy websites for drivers.&lt;/p&gt;

&lt;p&gt;If you want a good experience, the laptop needs to be sold to you as a &amp;ldquo;Linux laptop&amp;rdquo;, with the explicit promise that it has an OS with drivers that have been tested and pre-installed. Surprisingly few laptop makers are doing this (yet?).&lt;/p&gt;

&lt;h2&gt;Darter Pro Hardware&lt;/h2&gt;

&lt;p&gt;I heard about System76 from an enthusiastic co-worker, and had been eyeing one of their laptops as a contender, but I was indecisive, and a few months later it had been discontinued. Then the &lt;a href=&quot;https://system76.com/laptops/darter&quot;&gt;Darter Pro&lt;/a&gt; was posted in February, the specs looked reasonable, and the initial reviews were positive, so I went for it.&lt;/p&gt;

&lt;div style=&quot;width: 100%; margin: 2em 0; display: grid; grid-template-columns: 1fr 1fr; justify-items: center; grid-row-gap: 1em; grid-column-gap: 1.5em;&quot;&gt;
  &lt;figure style=&quot;margin: 0px&quot;&gt;
    &lt;a href=/assets/images/2019/unboxing1.jpg target=&quot;_blank&quot;&gt;
      &lt;img src=/assets/images/2019/unboxing1.jpg&gt;
    &lt;/a&gt;
  &lt;/figure&gt;
  &lt;figure style=&quot;margin: 0px&quot;&gt;
    &lt;a href=/assets/images/2019/unboxing3.jpg target=&quot;_blank&quot;&gt;
      &lt;img src=/assets/images/2019/unboxing3.jpg&gt;
    &lt;/a&gt;
  &lt;/figure&gt;

  &lt;figure style=&quot;margin: 0px; grid-column: 1 / 3;&quot;&gt;
    &lt;a href=/assets/images/2019/unboxing2.jpg target=&quot;_blank&quot;&gt;
      &lt;img src=/assets/images/2019/unboxing2.jpg title=&quot;Altoids tin for scale&quot;&gt;
    &lt;/a&gt;
    &lt;figcaption&gt; The requisite unboxing photos &lt;/figcaption&gt;
  &lt;/figure&gt;
&lt;/div&gt;


&lt;p&gt;As you can see, it&amp;rsquo;s a cool unboxing experience. There are a bunch of stickers and a welcome card inside; it looks like the expected audience is a hardware &amp;ldquo;maker&amp;rdquo; who is trying out Linux for the first time. It&amp;rsquo;s lighter than a macbook, which made it feel a flimsy at first, but it&amp;rsquo;s really sturdy and I&amp;rsquo;ve grown to like the feel of it.&lt;/p&gt;

&lt;p&gt;The laptop is ready to use when you open it, and does some Apple-style setup screens before dumping you into a cute-looking variant of Gnome. It configured my wifi during setup, and also connected my Google and Nextcloud accounts so that my calendar and file-sharing started syncing immediately. It gives a great first impression.&lt;/p&gt;

&lt;p&gt;The keyboard&amp;hellip; is weird. It looks like it was designed by committee, or a machine learning system gone haywire. There&amp;rsquo;s a number keypad on the right side, which pushes the main keyboard to the left edge. There are full-sized arrow keys (yay) that are hard to find by touch (boo). Keys with no purpose, like &amp;ldquo;Scroll Lock&amp;rdquo;, &amp;ldquo;System Request&amp;rdquo;, and &amp;ldquo;Number Lock&amp;rdquo;, are resurrected from the distant past, seemingly just to fill in empty space. There are &lt;em&gt;four separate function keys&lt;/em&gt; for controlling the brightness and hue of the keyboard backlight. 😂 That said, once you get used to holding your hands on the left side of the laptop, the keys are pleasantly tactile and feel nice to type on. I&amp;rsquo;ve had to unlearn some Mac shortcuts for delete, page up, and page down, but those keys are relatively easy to find by touch after some practice.&lt;/p&gt;

&lt;div style=&quot;width: 100%; margin: 2em 0&quot;&gt;
  &lt;figure style=&quot;margin: 0; display: table&quot;&gt;
    &lt;a href=/assets/images/2019/keyboard2.jpg target=&quot;_blank&quot;&gt;
      &lt;img src=/assets/images/2019/keyboard2.jpg title=&quot;Even the typeface on the keys is bizarre&quot;&gt;
    &lt;/a&gt;
    &lt;figcaption&gt; Weird but functional keyboard layout &lt;/figcaption&gt;
  &lt;/figure&gt;
&lt;/div&gt;


&lt;p&gt;The screen, sadly, is not retina (also known as 4K or Hi-DPI), and it &lt;em&gt;is&lt;/em&gt; noticeable. I don&amp;rsquo;t mind most of the time, and my friends tell me I wouldn&amp;rsquo;t want a retina display yet anyway, because X11/Gnome doesn&amp;rsquo;t support it well yet. But it means that small text in Firefox looks pretty retro and frankly bad.&lt;/p&gt;

&lt;p&gt;I was really nervous about the trackpad, given that every PC laptop review complains about how bad they are. But it works great! Moving the pointer, two-finger scrolling, and even double-tap-drag work without editing a single config file. It works so simply and effortlessly that I&amp;rsquo;m sure it was a huge project, so: hats off to whoever hacked on trackpad support! It&amp;rsquo;s amazing!&lt;/p&gt;

&lt;p&gt;There are two wobbly physical mouse buttons under the trackpad. They&amp;rsquo;re hard to find by touch so I rarely use them.&lt;/p&gt;

&lt;p&gt;This laptop would like you to know it has a fan. At random times, even if nothing is happening, the fan will come on full blast for about 5 seconds and then shut off. It&amp;rsquo;s alarming but hopefully harmless? The fan seems to have no intermediate setting: it&amp;rsquo;s either off, or it&amp;rsquo;s a jet engine. Once, the fan stayed on for 8 hours and I worried that it was broken, but it turned out that I had accidentally hit Fn-1, which is a secret command to turn the fan on max power. I&amp;rsquo;m not sure why that seemed like an important feature to have, and an important feature to hide.&lt;/p&gt;

&lt;p&gt;Relatedly, sometimes the laptop will turn off unexpectedly. It&amp;rsquo;s happened 3 or 4 times in the past two months, and doesn&amp;rsquo;t seem to be related to load, so it&amp;rsquo;s probably a firmware bug. Save early and often. On the other hand, this laptop cold-boots faster than anything, so I&amp;rsquo;m not offline for long.&lt;/p&gt;

&lt;p&gt;The battery lasts forever. Several hours, sometimes most of a day. It has so much capacity that it takes the power brick a few hours to fully recharge it.&lt;/p&gt;

&lt;p&gt;This is a very powerful machine. I haven&amp;rsquo;t been able to fill up its 32GB of RAM, even running &lt;em&gt;several&lt;/em&gt; electron apps and &lt;em&gt;two&lt;/em&gt; browsers. The fan may come on intermittently, but Minecraft is the only app that&amp;rsquo;s been able to keep it on continuously (a feat it accomplishes with equal ease on my macbook). It never approaches the macbook&amp;rsquo;s heat level either.&lt;/p&gt;

&lt;h2&gt;Software&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Table stakes&lt;/strong&gt;: It does indeed pause when you close the lid, and resume with an unlock screen when you open it again. Wifi comes back online and it doesn&amp;rsquo;t crash! (I wish this surprised me less than it does.) Usually it wakes up immediately, but occasionally it takes about 30 seconds. The syslogs make it look like sometimes the kernel doesn&amp;rsquo;t finish putting everything away before the CPU turns off, so when it wakes up again, it spends a few seconds continuing to pause before realizing that it&amp;rsquo;s supposed to be waking up now.&lt;/p&gt;

&lt;p&gt;The OS is labeled as &amp;ldquo;Pop! OS&amp;rdquo;, which seems to be Ubuntu with a new desktop GUI, probably in reaction to Ubuntu&amp;rsquo;s floundering around Unity. My recent Linux desktop experience has been limited to xfce in virtualbox, and this is at least as good. Hitting the command key (also known as the &amp;ldquo;super&amp;rdquo; key) brings up a view of every open desktop and app, a launcher, a package installer, and a file manager which seems to be a distant descendant of &lt;a href=&quot;https://en.wikipedia.org/wiki/GNOME_Files&quot;&gt;Nautilus&lt;/a&gt;, to my embarrassment. Nothing is ugly and everything is snappy.&lt;/p&gt;

&lt;p&gt;Apparently, while I&amp;rsquo;ve been away, Linux has migrated its command key from  &amp;ldquo;Alt&amp;rdquo; to &amp;ldquo;Control&amp;rdquo;. This is a terrible idea, since many control-keys already have a defined meaning, but I can&amp;rsquo;t find any global setting to fix it back. So, for example, many text fields will interpret &lt;code&gt;^A&lt;/code&gt; as &amp;ldquo;select all&amp;rdquo; instead of &amp;ldquo;start of line&amp;rdquo;, and erase everything you typed. It&amp;rsquo;s funny the first few dozen times.&lt;/p&gt;

&lt;p&gt;This includes all terminal apps, which need to send control keys to the terminal so they can be used for their normal purposes. Most try to rebind the command keys to new places, so &amp;ldquo;copy&amp;rdquo; becomes control-shift-C or alt-C, but all this does is add to the confusion. The punch line is that few apps have any use for the &amp;ldquo;Alt&amp;rdquo; or &amp;ldquo;Command&amp;rdquo; (&amp;ldquo;Super&amp;rdquo;) keys, so &amp;ldquo;Control&amp;rdquo; does the duty of every possible meta-command, and the rest are wasted. I ended up binding &amp;ldquo;Command&amp;rdquo; to various window manager tasks, and used a tool called &lt;a href=&quot;https://github.com/autokey/autokey&quot;&gt;AutoKey&lt;/a&gt; to bind command-C and command-V to send either control-C or control-shift-C depending on which app is active. It&amp;rsquo;s a total hack, it feels dirty, and it makes Linux look bad.&lt;/p&gt;

&lt;div style=&quot;width: 100%; margin: 2em 0&quot;&gt;
  &lt;figure style=&quot;margin: 0; display: table&quot;&gt;
    &lt;a href=/assets/images/2019/shortcuts.jpg target=&quot;_blank&quot;&gt;
      &lt;img src=/assets/images/2019/shortcuts.jpg&gt;
    &lt;/a&gt;
    &lt;figcaption&gt; Why is this necessary? &lt;/figcaption&gt;
  &lt;/figure&gt;
&lt;/div&gt;


&lt;p&gt;I&amp;rsquo;m impressed with how many apps have a Linux port that works great without effort. Success stories include:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Firefox (and Chrome)&lt;/li&gt;
&lt;li&gt;Slack, Discord, Telegram, Skype&lt;/li&gt;
&lt;li&gt;Spotify&lt;/li&gt;
&lt;li&gt;VS Code (and Atom)&lt;/li&gt;
&lt;li&gt;VLC&lt;/li&gt;
&lt;li&gt;Minecraft&lt;/li&gt;
&lt;/ul&gt;


&lt;p&gt;A few that are missing:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Sonos&lt;/li&gt;
&lt;li&gt;an image editor similar to Acorn (though Krita appears to be a cool paint app)&lt;/li&gt;
&lt;li&gt;a git visualizer similar to Tower or Fork&lt;/li&gt;
&lt;li&gt;a tiling terminal app similar to iTerm&lt;/li&gt;
&lt;/ul&gt;


&lt;p&gt;The last one was &lt;em&gt;very&lt;/em&gt; surprising. I assumed desktop Linux was primarily used by people who spend their day in terminals. Not so. Gnome-terminal has never progressed beyond the level of &amp;ldquo;demo app&amp;rdquo;, and most of the others I tried (Alacritty, Guake, Terminology) exist to show off a whiz-bang graphics trick, not to be a power tool. I settled on &lt;a href=&quot;https://github.com/Eugeny/terminus&quot;&gt;Terminus&lt;/a&gt;, which is very configurable and supports multi-pane windows.&lt;/p&gt;

&lt;p&gt;There are also the usual glitches: once, across a reboot, the entire settings panel (which is an app) just&amp;hellip; vanished. I had to research what it&amp;rsquo;s called and reinstall it from &lt;code&gt;apt&lt;/code&gt;. It was more funny than annoying.&lt;/p&gt;

&lt;p&gt;So far, Pop! OS has never displayed a popup nagging me to change my web browser, or insisted that it needs to reboot to install an update to a video codec, so it&amp;rsquo;s an improvement over OSX from the start. It&amp;rsquo;s also, bewilderingly, able to switch apps much faster than OSX. I have my main apps each bound to a different &amp;ldquo;super&amp;rdquo; keystroke (using &lt;code&gt;wmctrl&lt;/code&gt; to change the active window), and when I hit one of these key combos, there&amp;rsquo;s a very short animation, and then the new app is immediately responsive. On the macbook, apps often respond sluggishly for a second or so after activation.&lt;/p&gt;

&lt;h2&gt;Summary&lt;/h2&gt;

&lt;p&gt;This review probably sounds overly critical, but I wanted to be honest about the warts and splinters, and prepare anyone else who&amp;rsquo;s thinking of taking the plunge back into the Linux world. For every flaw, there were two or three things that worked better than expected, or wowed me.&lt;/p&gt;

&lt;p&gt;I&amp;rsquo;ve had the laptop for about two months now. During the first two weeks, I switched often between the Darter and my macbook, depending on what I was doing. Then, one morning, I noticed that the macbook was sitting on a desk collecting dust, and hadn&amp;rsquo;t been opened in days. I now use this Linux laptop almost exclusively &amp;ndash; for everything but image editing, and I&amp;rsquo;m still holding out hope on that one.&lt;/p&gt;

&lt;p&gt;It&amp;rsquo;s a weird little laptop, and I love it.&lt;/p&gt;
 
        <a href="http://flattr.com/thing/40430/Robey" target="_blank">
        <img src="http://api.flattr.com/button/button-compact-static-100x17.png" alt="Flattr this" title="Flattr this" border="0" />
        </a>
      </content>
    </entry>
  
    <entry>
      <title>Interaction</title>
      <link href="http://robey.lag.net/2012/12/13/interaction.html"/>
      <updated>2012-12-13T00:00:00-08:00</updated>
      <id>http://robey.lag.net/2012/12/13/interaction</id>
      <content type="html">
        &lt;p&gt;I&amp;rsquo;ve been reading more and more blog posts of the &amp;ldquo;please don&amp;rsquo;t interrupt me&amp;rdquo;
variety, from yesterday&amp;rsquo;s post by Zach of Github
&lt;a href=&quot;http://zachholman.com/posts/chat/&quot;&gt;about communicating over text&lt;/a&gt;
back to
&lt;a href=&quot;http://www.paulgraham.com/makersschedule.html&quot;&gt;Paul Graham&amp;rsquo;s essay on meetings&lt;/a&gt;
to the under-appreciatied
&lt;a href=&quot;http://www.amazon.com/Peopleware-Productive-Projects-Teams-Second/dp/0932633439&quot;&gt;Peopleware&lt;/a&gt;
(from 1987!).&lt;/p&gt;

&lt;p&gt;Just so you don&amp;rsquo;t get the wrong idea, I agree with all of these sentiments. In
fact, usually I think they&amp;rsquo;re too narrow-focused &amp;ndash; it may surprise you to
learn that coders are not the only people who have to think on the job, and
need uninterrupted time.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;../../../images/commie-pensive.jpg&quot; style=&quot;float: right; margin-left: 1em;&quot;&gt;&lt;/p&gt;

&lt;h2&gt;Interruptions bad&lt;/h2&gt;

&lt;p&gt;Every place I&amp;rsquo;ve worked, interruptions have been an issue.&lt;/p&gt;

&lt;p&gt;Sometimes, it&amp;rsquo;s just a difference in perceived priority. When a co-worker taps
your shoulder, breaking your concentration, it may not be because they have a
different way of scheduling time. I usually find that it&amp;rsquo;s because when you
have a problem that you need help with, it becomes the highest priority &amp;ldquo;work
item&amp;rdquo; you have. You can&amp;rsquo;t do anything but twiddle your thumbs and be unhappy
until you get help. The person you&amp;rsquo;re interrupting is busy working, though, so
answering questions is a much lower priority, and your interruption seems
rude. The best solution I&amp;rsquo;ve seen for this is to have a group chat or IRC
channel where anyone can ask a question, and the audience is large enough that
someone will be around who can help.&lt;/p&gt;

&lt;p&gt;Sometimes, the work environment is bankrupt. As offices with doors gave way to
cheaper &amp;ldquo;Dilbert cubes&amp;rdquo;, which gave way to even cheaper sweatshop tables,
background noise levels have crept up. Some workspaces now have the feel of
never-ending house parties. You can tell this is becoming a problem when a
large percentage of people are wearing headphones at any given moment, and
conference rooms are confiscated for coding.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Peopleware&lt;/em&gt; categorizes work communication as either interrupt-driven or not.
Interrupt-driven communication includes face-to-face meetings and telephone
calls, which break your concentration. (This book is from the 1980s when it
was common for each desk to have an office phone.) In fact, they provide
evidence that each interruption of this type takes at least 15 minutes to
recover from, afterwards, before you can get back &amp;ldquo;in the zone&amp;rdquo;. Email and
chat are not interrupt-driven, and you can check them between tasks, without
losing efficiency.&lt;/p&gt;

&lt;p&gt;There is no question that whenever possible, you should favor non-interrupt-
driven communication channels. But all the other blogs have been saying the
same thing, using more flowery words. I want to talk about the other side of
this coin:&lt;/p&gt;

&lt;p&gt;You cannot have a job where you don&amp;rsquo;t interact, often, face to face (or its
video equivalent) with your co-workers.&lt;/p&gt;

&lt;h2&gt;Socializing good&lt;/h2&gt;

&lt;p&gt;Humans are social creatures. Even engineers! Even (heaven forfend) neckbearded
hackers from the C++ caverns! Think of the grumpiest, more hermit-like person
you know. I bet they still do something social, just not in a format you&amp;rsquo;re
used to. They may play MMORPG tournaments all night long, or meet up for chess
clubs or Yu-Gi-Oh tournaments.&lt;/p&gt;

&lt;p&gt;Some anthropologists argue that our social behaviors spawned the creation of
language. Language gave us the ability to pass things we&amp;rsquo;ve learned firsthand
on to other people, creating our entire culture. Big stuff.&lt;/p&gt;

&lt;p&gt;Because we are social creatures, we need to interact with the people we&amp;rsquo;re
working with. We need to create bonds. We need to create a shared sense that
we&amp;rsquo;re in the same &amp;ldquo;tribe&amp;rdquo; together, working toward the same goals. We need to
build a rapport and trust, so that if I do something wrong, or something that
you aren&amp;rsquo;t fully informed about, you&amp;rsquo;ll give me the benefit of doubt, and stay
focused on your part of the overall project. This is part of the magic sauce
that makes a successful team.&lt;/p&gt;

&lt;p&gt;Why does this matter? As an example, I might notice an odd-looking bit of code
one night while I&amp;rsquo;m working on an unrelated feature. In fact, I might think,
&amp;ldquo;This is a bug.&amp;rdquo; If I don&amp;rsquo;t know the author very well, my reaction might be
anything from &amp;ldquo;I should file a bug&amp;rdquo; to &amp;ldquo;Ugh, another piece of buggy crap,
whatever&amp;rdquo;. If I&amp;rsquo;m comfortable with the author, though, I might shoot off an
email instantly: &amp;ldquo;What on earth is this?&amp;rdquo; We might avoid downtime because I&amp;rsquo;m
not worried about offending my team-mate. Or my confidence level might be
raised because they&amp;rsquo;re not worried about shooting me down. (&amp;ldquo;That is seriously
how the library works, Robey. Check out my snarky comment 3 lines up.&amp;rdquo;)&lt;/p&gt;

&lt;p&gt;These social bonds are really hard to form over email.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;../../../images/buttons-pensive.jpg&quot; style=&quot;float: right; margin-left: 1em;&quot;&gt;&lt;/p&gt;

&lt;h2&gt;How to socialize&lt;/h2&gt;

&lt;p&gt;My gut tells me that this socialization is why some bad teams have weekly
&amp;ldquo;staff meetings&amp;rdquo; (now, thankfully, out of fashion). The manager understands,
at some level, that everyone needs to be in the same room periodically, but
doesn&amp;rsquo;t know how to do that without scheduling a meeting where everyone reads
a spreadsheet out loud from a projector. Standups are not good for this,
either, since the purpose is to share information quickly, not to chit-chat.&lt;/p&gt;

&lt;p&gt;If you understand that the socializing is important, there are better ways to
work it in.&lt;/p&gt;

&lt;p&gt;I had a co-worker once who went around to our whole team at lunchtime every
day and demanded that we go out to eat, outside the office. He did not want to
hear that you would maybe get something from the cafeteria, or that you might
just bring something back to your desk. We were going to go out, as a team,
and eat together. And even though we tried to avoid talking about work, at
least one day out of five, I would find out something interesting and relevant
about what someone else was working on.&lt;/p&gt;

&lt;p&gt;The &amp;ldquo;coffee train&amp;rdquo; phenomenon works well, too. In the doldrums of the
afternoon, everyone that&amp;rsquo;s not in crunch time gathers and goes out to get
coffee. This is sometimes mystifying to managers, because there&amp;rsquo;s coffee
available in the office &amp;ndash; even a fancy espresso machine! But the purpose is
(1) to leave the office, and (2) to talk to each other for a while.&lt;/p&gt;

&lt;p&gt;At one company, we used our &amp;ldquo;team building&amp;rdquo; budget to buy a kegerator (a mini-
fridge that&amp;rsquo;s been retrofitted to serve beer from a keg). Once a week, late in
the evening, we rolled it out next to a bunch of couches and had a social. It
got so popular that it was hard to get near the keg, but you could meet people
from all over, and learn a lot. Several times, an utter stranger would walk up
to me, beer in hand, and say something like, &amp;ldquo;I&amp;rsquo;m from team X, and I didn&amp;rsquo;t
want to bother you about this, but I was wondering&amp;hellip;&amp;rdquo; and suddenly I&amp;rsquo;d find
out something really important to the success of my project.&lt;/p&gt;

&lt;p&gt;On the other end of the scale, some of my saddest experiences have been with
teams that don&amp;rsquo;t communicate with each other. They silo themselves off,
sometimes because they don&amp;rsquo;t think anyone else has anything valuable to offer,
or sometimes because they just need to be &amp;ldquo;heads down&amp;rdquo; to meet an impossible
ship date. Months later, they can&amp;rsquo;t ship anyway, because they missed an
important prerequisite or spent too much time duplicating a bunch of existing
work. They were too busy to talk to anyone, and instead wasted a chunk of
their life that they&amp;rsquo;ll never get back.&lt;/p&gt;

&lt;p&gt;So, while I love the new awareness about interruptions and alternate means of
communication, I strongly encourage you: Find some way to interact with your
coworkers, socially, between code sprints. It may seem like you&amp;rsquo;re just
&amp;ldquo;wasting time&amp;rdquo; chatting at the water cooler, but you&amp;rsquo;re really making an
investment that can make you more productive, and your team more successful.&lt;/p&gt;
 
        <a href="http://flattr.com/thing/40430/Robey" target="_blank">
        <img src="http://api.flattr.com/button/button-compact-static-100x17.png" alt="Flattr this" title="Flattr this" border="0" />
        </a>
      </content>
    </entry>
  
    <entry>
      <title>How to add numbers (part 2)</title>
      <link href="http://robey.lag.net/2012/11/14/how-to-add-numbers-2.html"/>
      <updated>2012-11-14T00:00:00-08:00</updated>
      <id>http://robey.lag.net/2012/11/14/how-to-add-numbers-2</id>
      <content type="html">
        &lt;p&gt;&lt;a href=&quot;../../../2012/11/07/how-to-add-numbers-1.html&quot;&gt;Last time&lt;/a&gt;,
I explained how adders work in CPUs, and one nice trick for speeding them up.
Be sure to read part 1 before diving into this!&lt;/p&gt;

&lt;h2&gt;Generation and propagation&lt;/h2&gt;

&lt;p&gt;In 1958,
&lt;a href=&quot;http://www.acsel-lab.com/Projects/fast_adder/references/papers/Weinberger-CLA-1858.pdf&quot;&gt;some sharp fellows named Weinberger &amp;amp; Smith&lt;/a&gt;
hit the carry ripple problem from a different angle. Even if you don&amp;rsquo;t know
what a column&amp;rsquo;s carry-in will be yet, you can make some assumptions about what
will happen:&lt;/p&gt;

&lt;table style=&quot;text-align: center;&quot;&gt;
  &lt;tr&gt;
    &lt;th&gt;A&lt;/th&gt;
    &lt;th&gt;B&lt;/th&gt;
    &lt;th class=&quot;wide&quot;&gt;C&lt;sub&gt;out&lt;/sub&gt;&lt;/th&gt;
  &lt;/tr&gt;
  &lt;tr&gt;
    &lt;td&gt;0&lt;/td&gt;&lt;td&gt;0&lt;/td&gt;&lt;td class=&quot;section&quot;&gt;0&lt;/td&gt;
  &lt;/tr&gt;
  &lt;tr&gt;
    &lt;td&gt;0&lt;/td&gt;&lt;td&gt;1&lt;/td&gt;&lt;td class=&quot;section&quot;&gt;C&lt;sub&gt;in&lt;/sub&gt;&lt;/td&gt;
  &lt;/tr&gt;
  &lt;tr&gt;
    &lt;td&gt;1&lt;/td&gt;&lt;td&gt;0&lt;/td&gt;&lt;td class=&quot;section&quot;&gt;C&lt;sub&gt;in&lt;/sub&gt;&lt;/td&gt;
  &lt;/tr&gt;
  &lt;tr&gt;
    &lt;td&gt;1&lt;/td&gt;&lt;td&gt;1&lt;/td&gt;&lt;td class=&quot;section&quot;&gt;1&lt;/td&gt;
  &lt;/tr&gt;
&lt;/table&gt;


&lt;p&gt;If both inputs are 0, the carry will definitely be 0, so the carry is
&amp;ldquo;killed&amp;rdquo;. If both are 1, the carry will definitely be 1, so a carry is
&amp;ldquo;generated&amp;rdquo;. Both of these cases are the same whether the carry-in is 0 on 1.
But if only one of the inputs is 1, then we&amp;rsquo;ll only have a carry-out if we had
a carry-in, so a carry is &amp;ldquo;propagated&amp;rdquo;.&lt;/p&gt;

&lt;p&gt;We can use &amp;ldquo;G&amp;rdquo; to mean a 1-bit adder would generate a carry by itself, and &amp;ldquo;P&amp;rdquo;
to mean it will propagate its incoming carry.&lt;/p&gt;

&lt;div class=&quot;math&quot;&gt;
G = A&amp;sdot;B&lt;br/&gt;
P = A&amp;oplus;B
&lt;/div&gt;


&lt;p&gt;So, for any column, the carry-out will be 1 if either &amp;ldquo;G&amp;rdquo; is 1 (it generates
a carry), or &amp;ldquo;P&amp;rdquo; is 1 (it propagates a carry) and the carry-in is 1.&lt;/p&gt;

&lt;div class=&quot;math&quot;&gt;
C&lt;sub&gt;out&lt;/sub&gt; = G + P&amp;sdot;C&lt;sub&gt;in&lt;/sub&gt;
&lt;/div&gt;


&lt;p&gt;For the lowest bit, if we substitute G and P into the above equation, we get:&lt;/p&gt;

&lt;div class=&quot;math&quot;&gt;
C&lt;sub&gt;out&lt;/sub&gt; = A&amp;sdot;B + (A&amp;oplus;B)&amp;sdot;C&lt;sub&gt;in&lt;/sub&gt;
&lt;/div&gt;


&lt;p&gt;which is equivalent to our original carry-out equation:&lt;/p&gt;

&lt;div class=&quot;math&quot;&gt;
C&lt;sub&gt;out&lt;/sub&gt; = A&amp;sdot;B + A&amp;sdot;C&lt;sub&gt;in&lt;/sub&gt; + B&amp;sdot;C&lt;sub&gt;in&lt;/sub&gt;
&lt;/div&gt;


&lt;p&gt;The fun comes when you consider the second bit. It will have a carry-out if
it generates one, or it propagates one and the lowest bit generated one, &lt;em&gt;or&lt;/em&gt;
it propagates one and the lowest bit propagates one and the carry-in was 1.&lt;/p&gt;

&lt;div class=&quot;math&quot;&gt;
C&lt;sub&gt;0&lt;/sub&gt; = G&lt;sub&gt;0&lt;/sub&gt; + P&lt;sub&gt;0&lt;/sub&gt;&amp;sdot;C&lt;sub&gt;in&lt;/sub&gt;&lt;br/&gt;
C&lt;sub&gt;1&lt;/sub&gt; = G&lt;sub&gt;1&lt;/sub&gt; + P&lt;sub&gt;1&lt;/sub&gt;&amp;sdot;G&lt;sub&gt;0&lt;/sub&gt; + P&lt;sub&gt;1&lt;/sub&gt;&amp;sdot;P&lt;sub&gt;0&lt;/sub&gt;&amp;sdot;C&lt;sub&gt;in&lt;/sub&gt;&lt;br/&gt;
C&lt;sub&gt;2&lt;/sub&gt; = G&lt;sub&gt;2&lt;/sub&gt; + P&lt;sub&gt;2&lt;/sub&gt;&amp;sdot;G&lt;sub&gt;1&lt;/sub&gt; + P&lt;sub&gt;2&lt;/sub&gt;&amp;sdot;P&lt;sub&gt;1&lt;/sub&gt;&amp;sdot;G&lt;sub&gt;0&lt;/sub&gt; +
P&lt;sub&gt;2&lt;/sub&gt;&amp;sdot;P&lt;sub&gt;1&lt;/sub&gt;&amp;sdot;P&lt;sub&gt;0&lt;/sub&gt;&amp;sdot;C&lt;sub&gt;in&lt;/sub&gt;&lt;br/&gt;
...
&lt;/div&gt;


&lt;h2&gt;Parallel (in small doses)&lt;/h2&gt;

&lt;p&gt;This series can go on indefinitely. If we compute a G and P for each column,
then we can compute the carry bit for a column N by making an &lt;code&gt;OR&lt;/code&gt; gate with N
+ 2 inputs, each of which is a G and a string of Ps, with the last &lt;code&gt;AND&lt;/code&gt; gate
having N + 1 inputs. We could compute each carry bit in 3 gate delays, but
to add 64 bits, it would require a pile of mythical 65-input &lt;code&gt;AND&lt;/code&gt; and &lt;code&gt;OR&lt;/code&gt;
gates, and a lot of silicon.&lt;/p&gt;

&lt;p&gt;It&amp;rsquo;s more feasible for small adders, like 4 or 8 bits at a time. Here&amp;rsquo;s a
sample two-bit adder that computes the two carry-out bits in parallel, by
computing P and G first:&lt;/p&gt;

&lt;div class=&quot;inset&quot;&gt;
&lt;img src=&quot;../../../images/two-bit-adder.png&quot; /&gt;
&lt;/div&gt;


&lt;p&gt;That circuit is already a bit intimidating to look at, so I didn&amp;rsquo;t show the
sum bits, but remember that the sum bit is&lt;/p&gt;

&lt;div class=&quot;math&quot;&gt;
S = A&amp;oplus;B&amp;oplus;C&lt;sub&gt;in&lt;/sub&gt;
&lt;/div&gt;


&lt;p&gt;or, using P:&lt;/p&gt;

&lt;div class=&quot;math&quot;&gt;
S = P&amp;oplus;C&lt;sub&gt;in&lt;/sub&gt;
&lt;/div&gt;


&lt;p&gt;So the sum for any column is just an &lt;code&gt;XOR&lt;/code&gt; of the carry-in bit and the P bit
that we already computed for our carry-out. That adds one more gate, for a
total of 4 gate delays to compute the whole 2-bit sum.&lt;/p&gt;

&lt;p&gt;If we built a set of 4-bit adders this way &amp;ndash; assuming a 6-way &lt;code&gt;OR&lt;/code&gt; gate is
fine &amp;ndash; our carry-select adder could add two 64-bit numbers in 19 gate
delays: 3 for all of the carries to be generated, and 16 for the muxes to
ripple down. These ripples now account for almost all of the delay.&lt;/p&gt;

&lt;h2&gt;Kogge-Stone&lt;/h2&gt;

&lt;p&gt;In 1973, probably while listening to a Yes or King Crimson album, Kogge and
Stone came up with
&lt;a href=&quot;http://www.acsel-lab.com/Projects/fast_adder/references/papers/Kogge-Stone-73.pdf&quot;&gt;the idea of parallel-prefix computation&lt;/a&gt;.
Their paper
was a description of how to generalize recursive linear functions into forms
that can be quickly combined in an arbitrary order, but um, they were being
coy in a way that math people do. What they were really getting at is that
these G and P values can be combined before being used.&lt;/p&gt;

&lt;p&gt;If you combine two columns together, you can say that as a whole, they may
generate or propagate a carry. If the left one generates, or the left one
propagates and the right one generates, then the combined two-column unit will
generate a carry. The unit will only propagate a carry bit across if both
columns are propagating. It looks like this:&lt;/p&gt;

&lt;div class=&quot;math&quot;&gt;
G&lt;sub&gt;unit&lt;/sub&gt; = G&lt;sub&gt;1&lt;/sub&gt; + P&lt;sub&gt;1&lt;/sub&gt;&amp;sdot;G&lt;sub&gt;0&lt;/sub&gt;&lt;br/&gt;
P&lt;sub&gt;unit&lt;/sub&gt; = P&lt;sub&gt;1&lt;/sub&gt;&amp;sdot;P&lt;sub&gt;0&lt;/sub&gt;
&lt;/div&gt;


&lt;p&gt;In a circuit, it adds 2 gate delays, but can be used to combine any set of P
and G signals that are next to each other, and even to combine some P and G
signals that are already combined. On the right, below, is the symbol we&amp;rsquo;ll
use to represent this combining operation from now on:&lt;/p&gt;

&lt;div class=&quot;inset&quot;&gt;
&lt;img src=&quot;../../../images/combine-g-p.png&quot; /&gt;
&lt;/div&gt;


&lt;p&gt;Any time we can do a recursive combination like this, we&amp;rsquo;re in
&lt;a href=&quot;http://en.wikipedia.org/wiki/Logarithmic_scale&quot;&gt;log-scale&lt;/a&gt;
country. This is the country where cowboys ride horses that go twice as far
with each hoofstep. But seriously, it means we can compute the final carry in
an 8-bit adder in 3 steps.&lt;/p&gt;

&lt;div class=&quot;inset&quot;&gt;
&lt;img src=&quot;../../../images/kogge-stone-8-bit.png&quot; /&gt;
&lt;/div&gt;


&lt;p&gt;Wait, what? Well, the numbers at the top represent the computed P and G bit
for each of the 8 columns of our 8-bit adder. The diamonds combine two
adjacent sets of columns and produce a new combined P and G for the set. If
this works, at the bottom, each arrow should represent the combined P and G
for that column and every column to its right.&lt;/p&gt;

&lt;p&gt;Look at the line on the far left, and trace it back up. It combines the lines
from 7 and 3, and as we trace that up again, each of those combines two more
units, and then again to cover all 8 columns. The same path up should work
for each column.&lt;/p&gt;

&lt;p&gt;There are lots of wires/connections because we need to compute the combined P
and G for each column, not just the final one. These combined P and G values
represent the combined value for each set of columns all the way to the right
edge, so they can be used to compute the carry-out for each column from the
original carry-in bit, instead of rippling:&lt;/p&gt;

&lt;div class=&quot;math&quot;&gt;
C&lt;sub&gt;n&lt;/sub&gt; = G&lt;sub&gt;n-combined&lt;/sub&gt; + P&lt;sub&gt;n-combined&lt;/sub&gt;&amp;sdot;C&lt;sub&gt;in&lt;/sub&gt;&lt;br/&gt;
&lt;/div&gt;


&lt;p&gt;The sum bit can still be computed with a final &lt;code&gt;XOR&lt;/code&gt;, using the original (not
combined) P and the carry bit to its immediate right:&lt;/p&gt;

&lt;div class=&quot;math&quot;&gt;
S&lt;sub&gt;n&lt;/sub&gt; = P&lt;sub&gt;n&lt;/sub&gt;&amp;oplus;C&lt;sub&gt;n-1&lt;/sub&gt;&lt;br/&gt;
&lt;/div&gt;


&lt;p&gt;This final step adds three gates to the end of each column. As we saw above,
each combining operation is two gates, and computing the original P and G is
one more. For this 8-bit adder, which uses three combining steps, we wait
&lt;span class=&quot;mathspan&quot;&gt;1 + 3&amp;sdot;2 + 3 = 10&lt;/span&gt; gate delays for the
result. For a 64-bit adder, we need 6 combining steps, and get our result in
16 gate delays!&lt;/p&gt;

&lt;p&gt;The Kogge-Stone adder is the fastest possible layout, because it scales
logarithmically. Every time we add a combining step, it doubles the number of
bits that can be added. It&amp;rsquo;s so efficient that 25% of the delay in our 64-bit
adder will be the setup and final computation before and after the combining
phase. The only real flaw is that the number of wires gets a little crazy &amp;ndash;
the 8-bit adder is already filled with cross-connections, and that gets so
much worse in the 64-bit version that I&amp;rsquo;m not going to try to draw it. It
might even monopolize a lot of the chip space if we tried to build it.&lt;/p&gt;

&lt;p&gt;Luckly, there&amp;rsquo;s a compromise that adds a few steps but removes a lot of the
wires.&lt;/p&gt;

&lt;h2&gt;Brent-Kung&lt;/h2&gt;

&lt;p&gt;In 1982, Brent &amp;amp; Kung described this clever modification, which just computes
the left-most column in a binary tree, and then fills in the intermediate
columns in a reverse tree:&lt;/p&gt;

&lt;div class=&quot;inset&quot;&gt;
&lt;img src=&quot;../../../images/brent-kung-8-bit.png&quot; /&gt;
&lt;/div&gt;


&lt;p&gt;If you walk up the tree from bottom to top on any column, it should still end
up combining every other column to its right, but this time it uses far fewer
connections to do so. A
&lt;a href=&quot;http://citeseerx.ist.psu.edu/viewdoc/summary?doi=10.1.1.102.6716&quot;&gt;nice paper from 2007&lt;/a&gt;
compares several adder strategies and decides that this one is the most
energy-efficient because of the trade-off of speed for simplicity. That is,
it can be built easier than the Kogge-Stone adder, even though it has nearly
twice as many combination steps in it. For our 64-bit adder, we&amp;rsquo;d have 11
steps, for &lt;span class=&quot;mathspan&quot;&gt;1 + 11 &amp;sdot; 2 + 3 = 26&lt;/span&gt; gate delays.
(This is more than our best-case of 16 for the Kogge-Stone adder, and a bit
more than our naive-case of 24 with the carry-select adder.)&lt;/p&gt;

&lt;p&gt;One potential problem is &amp;ldquo;fan-out&amp;rdquo;, which means one outgoing signal is being
sent to several other gates as inputs. Electronics people would say one gate
is &amp;ldquo;driving&amp;rdquo; a bunch of other gates, and this is bad, because the current gets
split several different ways and diluted and weakened, just like water through
a fork in a pipe. You can see this especially in column 3. A Brent-Kung adder
will actually turn the joints (that I&amp;rsquo;ve marked with black circles) into
buffers, or gates that don&amp;rsquo;t do anything. That reduces the fan-out back to 2
without slowing anything down.&lt;/p&gt;

&lt;h2&gt;Hybrid&lt;/h2&gt;

&lt;p&gt;One thing you might have spotted with your eagle eye is that the Brent-Kung
adder doesn&amp;rsquo;t slow down the left-most column, which generates the final carry-
out bit. So if we were to combine this strategy with the carry-select strategy
from last time, our carry bits could start rippling across the adder units
before each unit finishes computing the intermediate bits. &lt;em&gt;Hmm.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;An &lt;code&gt;n&lt;/code&gt;-bit Brent-Kung adder will be able to generate the carry-out bit in
&lt;span class=&quot;mathspan&quot;&gt;log&lt;sub&gt;2&lt;/sub&gt;(n)&lt;/span&gt; steps, using 2 gates per
step, with an additional gate delay for computing P and G for each bit, and
two extra gate delays to compute the carry-out from the combined P/G.&lt;/p&gt;

&lt;div class=&quot;inset&quot;&gt;
&lt;img src=&quot;../../../images/brent-kung-delays.png&quot; /&gt;
&lt;/div&gt;


&lt;p&gt;The full sum will take an extra
&lt;span class=&quot;mathspan&quot;&gt;log&lt;sub&gt;2&lt;/sub&gt;(n) - 1&lt;/span&gt;
steps, and an extra gate to do the
&lt;span class=&quot;mathspan&quot;&gt;P&amp;oplus;C&lt;sub&gt;in&lt;/sub&gt;&lt;/span&gt; operation.&lt;/p&gt;

&lt;p&gt;When a carry-select adder is used with &lt;code&gt;k&lt;/code&gt; units, the ripple delay is &lt;code&gt;k&lt;/code&gt;
plus the time it takes to get a carry-out from the first unit.&lt;/p&gt;

&lt;p&gt;So if we split our 64-bit adder into 8 8-bit Brent-Kung adders, and combine
those into a carry-select adder, the 8-bit adders will compute their carry-out
bits in 9 gate delays, after which the carry bits ripple through the muxes for
7 gate delays, for a total of 16. The sum bits are available after 14 gate
delays, in plenty of time. So we got it down to 16 total, and this time in a
pretty efficient way!&lt;/p&gt;

&lt;div class=&quot;inset&quot;&gt;
&lt;img src=&quot;../../../images/carry-select-brent-kung.png&quot; /&gt;
&lt;/div&gt;


&lt;p&gt;Adding numbers: Proof that humans can make &lt;em&gt;anything&lt;/em&gt; complicated, if they try
hard enough.&lt;/p&gt;

&lt;p&gt;There are a bunch of other historical strategies, but I thought these were the
most interesting and effective. If you stuck it out through both articles, I&amp;rsquo;d
love to hear your thoughts, ideas, and/or corrections.&lt;/p&gt;
 
        <a href="http://flattr.com/thing/40430/Robey" target="_blank">
        <img src="http://api.flattr.com/button/button-compact-static-100x17.png" alt="Flattr this" title="Flattr this" border="0" />
        </a>
      </content>
    </entry>
  
    <entry>
      <title>How to add numbers (part 1)</title>
      <link href="http://robey.lag.net/2012/11/07/how-to-add-numbers-1.html"/>
      <updated>2012-11-07T00:00:00-08:00</updated>
      <id>http://robey.lag.net/2012/11/07/how-to-add-numbers-1</id>
      <content type="html">
        &lt;p&gt;A few weeks ago, probably due to my recent
&lt;a href=&quot;http://en.wikipedia.org/wiki/Arduino&quot;&gt;Arduino&lt;/a&gt; and
&lt;a href=&quot;en.wikipedia.org/wiki/0x10c&quot;&gt;D-CPU&lt;/a&gt; obsessions, I started thinking about with
this topic: How do modern computer CPUs add numbers? I took classes on this in
school, so I had a basic understanding, but the more I thought about it, the
more I realized that my ideas about how this would scale up to 64-bit
computers would be too slow to actually work.&lt;/p&gt;

&lt;p&gt;I started digging around, and even though wikipedia is usually exhaustive
(and often inscrutable) about obscure topics, I had reached the edge of the
internet. Only context-less names like &amp;ldquo;Kogge-Stone&amp;rdquo; and unexplained box
diagrams greeted me. I had to do actual &lt;em&gt;research&lt;/em&gt; of the 20th-century kind.&lt;/p&gt;

&lt;p&gt;So come with me over the precipice and learn &amp;ndash; in great detail &amp;ndash; how to add
numbers!&lt;/p&gt;

&lt;p&gt;I&amp;rsquo;m going to start out as if you&amp;rsquo;ve never taken a class in computer
engineering. If you&amp;rsquo;re familiar with the basics of binary addition, skip below
to get to the good stuff.&lt;/p&gt;

&lt;h2&gt;Adding in binary&lt;/h2&gt;

&lt;p&gt;For big numbers, addition by hand means starting on the rightmost digit,
adding all the digits in the column, and then writing down the units digit and
carrying the tens over. In the example below, 8 plus 4 is 12, so we carry the
1, which I&amp;rsquo;ve indicated with a precious tiny blue 1 over the left column:&lt;/p&gt;

&lt;div class=&quot;math&quot;&gt;
&amp;nbsp;&lt;span class=&quot;blue small&quot;&gt;1&lt;/span&gt;&lt;br/&gt;
&amp;nbsp;482&lt;br/&gt;
+345&lt;br/&gt;
----&lt;br/&gt;
&amp;nbsp;&lt;span class=&quot;blue&quot;&gt;827&lt;/span&gt;&lt;br/&gt;
&lt;/div&gt;


&lt;p&gt;We memorize this in school, but the reason it works is that each column is the
same power of ten: 8 tens plus 4 tens is 12 tens. And 12 tens is really 1
hundred and 2 tens, so the 1 hundred is shifted/carried over to the hundreds
column.&lt;/p&gt;

&lt;p&gt;This works the same in binary, but the digits can only ever be 0 or 1, so the
biggest number we can add is 1 plus 1. This would be 2, or &amp;ldquo;10&amp;rdquo; in binary (1
two and 0 ones), so there&amp;rsquo;s a carry of 1. In fact, if we have a carry, 1 plus
1 with a carried 1 is 3: &amp;ldquo;11&amp;rdquo; (1 two and 1 one). That still only carries a 1,
which is convenient, because it means the carry can be represented in binary
just like every other digit.&lt;/p&gt;

&lt;div class=&quot;math&quot;&gt;
&amp;nbsp;&lt;span class=&quot;blue small&quot;&gt;1 1&lt;/span&gt;&lt;br/&gt;
&amp;nbsp;0110 &lt;span class=&quot;green small&quot;&gt;(6)&lt;/span&gt;&lt;br/&gt;
+0111 &lt;span class=&quot;green small&quot;&gt;(7)&lt;/span&gt;&lt;br/&gt;
-----&lt;br/&gt;
&amp;nbsp;&lt;span class=&quot;blue&quot;&gt;1101&lt;/span&gt; &lt;span class=&quot;green small&quot;&gt;(13)&lt;/span&gt;&lt;br/&gt;
&lt;/div&gt;


&lt;p&gt;So, to add two binary numbers, we just need to add 3 binary digits (one digit
from each of the numbers, plus a possible incoming carry), and produce a sum
bit and an outgoing carry bit. We can make a logic table for this:&lt;/p&gt;

&lt;table style=&quot;text-align: center;&quot;&gt;
  &lt;tr&gt;
    &lt;th&gt;A&lt;/th&gt;
    &lt;th&gt;B&lt;/th&gt;
    &lt;th&gt;C&lt;/th&gt;
    &lt;th class=&quot;wide&quot;&gt;Carry&lt;/th&gt;
    &lt;th class=&quot;wide&quot;&gt;Sum&lt;/th&gt;
  &lt;/tr&gt;
  &lt;tr&gt;
    &lt;td&gt;0&lt;/td&gt;&lt;td&gt;0&lt;/td&gt;&lt;td&gt;0&lt;/td&gt;&lt;td class=&quot;section&quot;&gt;0&lt;/td&gt;&lt;td&gt;0&lt;/td&gt;
  &lt;/tr&gt;
  &lt;tr&gt;
    &lt;td&gt;0&lt;/td&gt;&lt;td&gt;0&lt;/td&gt;&lt;td&gt;1&lt;/td&gt;&lt;td class=&quot;section&quot;&gt;0&lt;/td&gt;&lt;td&gt;1&lt;/td&gt;
  &lt;/tr&gt;
  &lt;tr&gt;
    &lt;td&gt;0&lt;/td&gt;&lt;td&gt;1&lt;/td&gt;&lt;td&gt;0&lt;/td&gt;&lt;td class=&quot;section&quot;&gt;0&lt;/td&gt;&lt;td&gt;1&lt;/td&gt;
  &lt;/tr&gt;
  &lt;tr&gt;
    &lt;td&gt;0&lt;/td&gt;&lt;td&gt;1&lt;/td&gt;&lt;td&gt;1&lt;/td&gt;&lt;td class=&quot;section&quot;&gt;1&lt;/td&gt;&lt;td&gt;0&lt;/td&gt;
  &lt;/tr&gt;
  &lt;tr&gt;
    &lt;td&gt;1&lt;/td&gt;&lt;td&gt;0&lt;/td&gt;&lt;td&gt;0&lt;/td&gt;&lt;td class=&quot;section&quot;&gt;0&lt;/td&gt;&lt;td&gt;1&lt;/td&gt;
  &lt;/tr&gt;
  &lt;tr&gt;
    &lt;td&gt;1&lt;/td&gt;&lt;td&gt;0&lt;/td&gt;&lt;td&gt;1&lt;/td&gt;&lt;td class=&quot;section&quot;&gt;1&lt;/td&gt;&lt;td&gt;0&lt;/td&gt;
  &lt;/tr&gt;
  &lt;tr&gt;
    &lt;td&gt;1&lt;/td&gt;&lt;td&gt;1&lt;/td&gt;&lt;td&gt;0&lt;/td&gt;&lt;td class=&quot;section&quot;&gt;1&lt;/td&gt;&lt;td&gt;0&lt;/td&gt;
  &lt;/tr&gt;
  &lt;tr&gt;
    &lt;td&gt;1&lt;/td&gt;&lt;td&gt;1&lt;/td&gt;&lt;td&gt;1&lt;/td&gt;&lt;td class=&quot;section&quot;&gt;1&lt;/td&gt;&lt;td&gt;1&lt;/td&gt;
  &lt;/tr&gt;
&lt;/table&gt;


&lt;p&gt;&amp;hellip;and then design a logic circuit to generate the Sum and Carry bits. In
logic circuit equations,
&amp;ldquo;&lt;code&gt;+&lt;/code&gt;&amp;rdquo; means &lt;a href=&quot;http://en.wikipedia.org/wiki/OR_gate&quot;&gt;&lt;code&gt;OR&lt;/code&gt;&lt;/a&gt;,
&amp;ldquo;&amp;sdot;&amp;rdquo; means &lt;a href=&quot;http://en.wikipedia.org/wiki/AND_gate&quot;&gt;&lt;code&gt;AND&lt;/code&gt;&lt;/a&gt;,
and &amp;ldquo;&amp;oplus;&amp;rdquo; means &lt;a href=&quot;http://en.wikipedia.org/wiki/XOR_gate&quot;&gt;&lt;code&gt;XOR&lt;/code&gt;&lt;/a&gt;.
(Programmers usually use &amp;ldquo;&lt;code&gt;&amp;amp;&lt;/code&gt;&amp;rdquo; to mean &lt;code&gt;AND&lt;/code&gt;, and &amp;ldquo;&lt;code&gt;|&lt;/code&gt;&amp;rdquo; to mean &lt;code&gt;OR&lt;/code&gt;, but I
think in this case it&amp;rsquo;s important to use the symbols that professional circuit
designers use. It gives you a bit more intuition when dealing with logical
equations, which will come up later.)&lt;/p&gt;

&lt;p&gt;One way to think of it is: According to the logic table we just made, the sum
should be 1 if there are an odd number of incoming 1s. &lt;code&gt;XOR&lt;/code&gt; is the operation
that matches odd inputs. And the carry should be 1 if at least two of the
incoming digits are 1.&lt;/p&gt;

&lt;h2&gt;Adding in circuitry&lt;/h2&gt;

&lt;p&gt;The most straightforward logic circuit for this is&lt;/p&gt;

&lt;div class=&quot;inset&quot;&gt;
&lt;img src=&quot;../../../images/full-adder-simple.png&quot; /&gt;
&lt;/div&gt;


&lt;p&gt;assuming you have a 3-input &lt;code&gt;XOR&lt;/code&gt; gate. If you don&amp;rsquo;t, you can just hook two
2-input &lt;code&gt;XOR&lt;/code&gt; gates together.&lt;/p&gt;

&lt;p&gt;Now rename C to C&lt;sub&gt;in&lt;/sub&gt;, and Carry to C&lt;sub&gt;out&lt;/sub&gt;, and we have a
&amp;ldquo;full adder&amp;rdquo; block that can add two binary digits, including an incoming
carry, and generate a sum and an outgoing carry.&lt;/p&gt;

&lt;div class=&quot;inset&quot;&gt;
&lt;img src=&quot;../../../images/full-adder-block.png&quot; /&gt;
&lt;/div&gt;


&lt;p&gt;And if we put a bunch of them in a row, we can add any N-bit numbers together!&lt;/p&gt;

&lt;div class=&quot;inset&quot;&gt;
&lt;img src=&quot;../../../images/full-adder-block-four.png&quot; /&gt;
&lt;/div&gt;


&lt;p&gt;Starting along the top, there are four inputs each of A and B, which allows us
to add two 4-bit numbers. The right-most bit, A&lt;sub&gt;0&lt;/sub&gt;, is the &amp;ldquo;ones&amp;rdquo;,
A&lt;sub&gt;1&lt;/sub&gt; is the &amp;ldquo;twos&amp;rdquo;, and so on through the &amp;ldquo;fours&amp;rdquo; and &amp;ldquo;eights&amp;rdquo;
(powers of two instead of ten). On the far right, we have a dangling carry-in
which we&amp;rsquo;ll just set to zero so that it doesn&amp;rsquo;t matter.&lt;/p&gt;

&lt;p&gt;The carry-out from the right-most adder is passed along to the second adder, just like in long
addition: any carry from the &amp;ldquo;ones&amp;rdquo; is added to the &amp;ldquo;twos&amp;rdquo; column. Finally, on the far
left, we get an &amp;ldquo;extra&amp;rdquo; carry out, because the addition of two 4-bit numbers may require 5 bits.
Normally this is considered an &amp;ldquo;overflow&amp;rdquo;, but the carry-out bit is stored in some
kind of status register by every CPU that I know of. It just usually can&amp;rsquo;t be
accessed from C or any other language directly, so it gets lost.&lt;/p&gt;

&lt;h2&gt;Adding in slow-motion&lt;/h2&gt;

&lt;p&gt;But here&amp;rsquo;s where the problems come in. Imagine setting up 64 of those adders
in a chain, so you could add two 64-bit numbers together. How long would it
take? The circuit diagram above shows that each sum goes through one or two
gates, and each carry-out goes through two. And the carry-out of one adder
becomes the carry-in for the next one. So to generate the entire sum and the
final carry-out bit, we need to go through
&lt;span class=&quot;mathspan&quot;&gt;64 &amp;sdot; 2 = 128&lt;/span&gt; gates.&lt;/p&gt;

&lt;p&gt;Uh oh.&lt;/p&gt;

&lt;p&gt;Spoiler alert: No CPU has time to wait for 128 gates to flip in sequence, so
no CPU actually adds this way. The problem is that the carry bit needs to
&amp;ldquo;ripple&amp;rdquo; across each bit, and will only scale linearly with the number of bits
being added. We&amp;rsquo;ll need some way to break out of linearity.&lt;/p&gt;

&lt;h2&gt;Carry-select adder&lt;/h2&gt;

&lt;p&gt;The trick that seems most obvious to me &amp;ndash; and the only one I thought of
before doing research &amp;ndash; was
&lt;a href=&quot;http://www.acsel-lab.com/Projects/fast_adder/references/papers/Sklansky-Cond_Sum-IRE.pdf&quot;&gt;apparently invented in 1960 by Sklansky&lt;/a&gt;.
If you&amp;rsquo;re
willing to add more circuitry in exchange for speed, you can put two adders in
parallel. One computes the sum with a carry-in of 0, and the other computes
with a carry-in of 1. When the real carry-in signal arrives, it selects which
addition to use. Here&amp;rsquo;s an example of a 4-bit carry-select adder:&lt;/p&gt;

&lt;div class=&quot;inset&quot;&gt;
&lt;img src=&quot;../../../images/carry-select-adder.png&quot; /&gt;
&lt;/div&gt;


&lt;p&gt;The weird rhombus-shapes are multiplexers, or &amp;ldquo;mux&amp;rdquo; for short. A mux takes two
inputs and selects one or the other, based on a control signal. In this case,
each mux uses the carry-in signal to determine which adder output to use, for
each of the four sum bits (along the bottom), and the carry-out bit (on the
left).&lt;/p&gt;

&lt;p&gt;The diagram gets simpler if we make a shortcut box for a series of connected
adder units, and draw each group of 4 input or output bits as a thick gray
bus:&lt;/p&gt;

&lt;div class=&quot;inset&quot;&gt;
&lt;img src=&quot;../../../images/carry-select-adder-units.png&quot; /&gt;
&lt;/div&gt;


&lt;p&gt;Now, for example, to compute the sum of two 16-bit numbers, we can split each
number into four chunks of four bits each, and let each of these 4-bit chunks
add in parallel. When the adders are finished, the carry-out bit from the
lowest (rightmost) adder is used to select which adder&amp;rsquo;s result to use for the
next four bits, and then that selected carry-out is used to select the next
adder&amp;rsquo;s result, and so on. Simplifying the diagram a bit more, it looks like:&lt;/p&gt;

&lt;div class=&quot;inset&quot;&gt;
&lt;img src=&quot;../../../images/carry-select-adder-16bits.png&quot; /&gt;
&lt;/div&gt;


&lt;p&gt;If we assume a mux takes as long as a logic gate, then this circuit can
compute a 16-bit addition in &lt;span class=&quot;mathspan&quot;&gt;2 &amp;sdot; 4 + 4 = 12&lt;/span&gt;
gate delays: 8 for all the adders to finish, and 4 for the muxs to ripple the
carry bits across. For a 64-bit adder, it would take 24 delays, because it
would have 16 muxes instead of 4. Going from 128 to 24 is a great start, and
it only cost us a little less than twice as many gates!&lt;/p&gt;

&lt;p&gt;We can fuss with this and make it a little faster. The leftmost adder unit
waits a long time to get its incoming carry bit, and the first 75% of the
time is spent waiting for the first adder to finish. If we compute only one
bit at a time on the right, then two, then three, and so on as it goes left,
we can shave off a few more.&lt;/p&gt;

&lt;p&gt;But&amp;hellip; we can do better.&lt;/p&gt;

&lt;p&gt;Next time, some tricker adding methods that end up being quicker.&lt;/p&gt;
 
        <a href="http://flattr.com/thing/40430/Robey" target="_blank">
        <img src="http://api.flattr.com/button/button-compact-static-100x17.png" alt="Flattr this" title="Flattr this" border="0" />
        </a>
      </content>
    </entry>
  
    <entry>
      <title>C++ quirks, remembered</title>
      <link href="http://robey.lag.net/2012/10/09/cpp-quirks-remembered.html"/>
      <updated>2012-10-09T00:00:00-07:00</updated>
      <id>http://robey.lag.net/2012/10/09/cpp-quirks-remembered</id>
      <content type="html">
        &lt;p&gt;&lt;img src=&quot;../../../images/dads-painting.jpg&quot; style=&quot;float: right; margin-left: 1em;&quot;&gt;&lt;/p&gt;

&lt;p&gt;Remember how annoying it was to try to get anything done in C++? Typing reams
of boilerplate and fighting mysterious compiler errors that need to be fed
through &lt;code&gt;c++filt&lt;/code&gt; to make any sense of them? Or maybe those days have faded
into the rose-tinged past, when we were &amp;ldquo;real&amp;rdquo; programmers, who ran through
the gauntlet just to prove we could.&lt;/p&gt;

&lt;p&gt;It&amp;rsquo;s been over five years since I did any serious C++ coding, but I dusted it
off for a pet project recently, and had forgotten a lot more than I thought.
It was also a lot worse than I remembered.&lt;/p&gt;

&lt;p&gt;The main thing I remembered is that C++ is more verbose (by line count) than
modern languages. At a previous job, we translated a few servers from C++ to
Java, and calculated that Java required about half as many lines of code, not
counting custom libraries for things like network I/O (which you get for free
in Java). I strongly believe that verbosity and boilerplate are bad features
in a programming language, but I&amp;rsquo;ll save that argument for a future blog post.&lt;/p&gt;

&lt;p&gt;But the quirkiness of C++ goes a lot deeper than its wordiness. Check out
these things I&amp;rsquo;ve been uncovering as I work on my project.&lt;/p&gt;

&lt;h2&gt;Private inheritance&lt;/h2&gt;

&lt;p&gt;Woe be unto you if you think of the java line&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;class Complex extends Number
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;and you write it in C++ as&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;class Complex : Number
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;because gotcha! C++ predates consensus ideas about public/private exposure,
and the default inheritance actually changes the exposure of all inherited
members to be private (hidden). Like most of the 137,000 features of C++, this
is probably useful to someone somewhere, and everyone else just has to
remember the rule that you need to type&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;class Complex : public Number
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;to get standard inheritance.&lt;/p&gt;

&lt;h2&gt;Implicit constructors&lt;/h2&gt;

&lt;p&gt;This is a feature where, if you have a constructor taking a single parameter,
like&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;CatList(int maxSize);
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;and a function that takes an object of that type, like&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;void feed(CatList&amp;amp; cats);
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;then you can make a seemingly nonsensical or broken call like&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;feed(3);
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;and it will compile. Why? Because the C++ compiler sees that you didn&amp;rsquo;t pass
a &lt;code&gt;CatList&lt;/code&gt;, and it starts rooting through your garbage to find something
that will work. (Like perl, C++ would rather do the wrong thing than fail to
compile.) So it finds the &lt;code&gt;CatList&lt;/code&gt; constructor that takes an int, and turns
your call into&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;feed(CatList(3));
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;so that it creates an empty list of cats and feeds them. I&amp;rsquo;m sure that&amp;rsquo;s what
the author meant!&lt;/p&gt;

&lt;p&gt;This became such a huge problem that C++ eventually added the &lt;code&gt;explicit&lt;/code&gt;
keyword, so you can mark which constructors should be safe &amp;ndash; more
boilerplate to memorize.&lt;/p&gt;

&lt;p&gt;Scala added a similar feature, but reversed the sense, so you have to mark a
method as &lt;code&gt;implicit&lt;/code&gt; before it will be considered. You also have to import any
implicit conversions you want to use in a file, so they become a bit more
explicit. But scala coders will tell you that even with all these
restrictions, they can bite you from time to time. C++ making them default
behavior is just punitive.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;../../../images/dust-storm-small.jpg&quot; style=&quot;float: right; margin-left: 1em;&quot;&gt;&lt;/p&gt;

&lt;h2&gt;Generic classes must live in headers&lt;/h2&gt;

&lt;p&gt;This is pretty obscure, but if you make a generic class, which are called
&amp;ldquo;template classes&amp;rdquo; in C++, it must live entirely in a header file, or else be
used only in the file it&amp;rsquo;s defined in.&lt;/p&gt;

&lt;p&gt;Normal C++ classes have a header file with the class&amp;rsquo;s interface, and a code
file for the implementation. This can&amp;rsquo;t be done for generic classes because
the compiler still treats templates as macros: each possible variant of a
generic class is effectively compiled into a separate class. If you put part
of the implementation into a C++ file, &lt;em&gt;the compiler can&amp;rsquo;t find it&lt;/em&gt;. You&amp;rsquo;ll
just get context-free link errors.&lt;/p&gt;

&lt;p&gt;There&amp;rsquo;s a great description of what&amp;rsquo;s going on
&lt;a href=&quot;http://www.parashift.com/c++-faq-lite/templates-defn-vs-decl.html&quot;&gt;here&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;My favorite part is that the C++ standards body tried out a fix for this, but
the fix turned out to be broken in a different way, so they deprecated the
fix. (Details
&lt;a href=&quot;http://www.parashift.com/c++-faq/separate-template-fn-defn-from-decl-export-keyword.html&quot;&gt;here&lt;/a&gt;.)
It&amp;rsquo;s as if they&amp;rsquo;ve thrown up their hands and said &amp;ldquo;Well this is
hopeless. Just remember to treat these classes specially.&amp;rdquo;&lt;/p&gt;

&lt;h2&gt;Method pointers&lt;/h2&gt;

&lt;p&gt;It&amp;rsquo;s possible to grab a pointer to a method in C++. Most people I&amp;rsquo;ve mentioned
this to looked surprised, but really, it&amp;rsquo;s an old, supported language feature.
If you have a class like&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;class CatList {
  void add(Cat&amp;amp; cat);
}
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;then you can define a type for the &lt;code&gt;add&lt;/code&gt; method (which you should absolutely
do, because good grief look at this mess) &amp;ndash; let&amp;rsquo;s call it &lt;code&gt;Method&lt;/code&gt;:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;typedef void (CatList::*Method)(Cat&amp;amp; cat);
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;and you can pick out the method pointer and save it!&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;Method method = &amp;amp;CatList::add;
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;And you can call it later!&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;CatList *c = ...;
(c-&amp;gt;*method)(cat);
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;If you&amp;rsquo;ve never seen &lt;code&gt;::*&lt;/code&gt; or &lt;code&gt;-&amp;gt;*&lt;/code&gt; in C++ code before, that&amp;rsquo;s because they
are special operators added just to make this feature work. The parenthesis
around &lt;code&gt;c-&amp;gt;*method&lt;/code&gt; are because they thought it would be funny to give these
new operators incredibly low precedence, for maximum surprise-factor.&lt;/p&gt;

&lt;p&gt;I wanted to use this feature to translate method calls on a javascript (v8)
object into method calls on a C++ object. v8 will pass a &lt;code&gt;(void *)&lt;/code&gt; to the C++
handler, so all I need to do is stuff the method pointer in there and cast it
back on the way out&amp;hellip; right? Wrong!&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;error: cannot cast from type &apos;Method&apos; (aka &apos;void (CatList::*)(Cat &amp;amp;)&apos;) to pointer type &apos;void *&apos;
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;The
&lt;a href=&quot;http://www.parashift.com/c++-faq/cant-cvt-memfnptr-to-voidptr.html&quot;&gt;pages about this&lt;/a&gt;
in the C++ faq read like &amp;ldquo;Get off my lawn!&amp;rdquo; and don&amp;rsquo;t
explain &lt;em&gt;why&lt;/em&gt; this won&amp;rsquo;t work, so I&amp;rsquo;ll try. In C++, a method pointer isn&amp;rsquo;t
just an address; it&amp;rsquo;s potentially a struct containing the method&amp;rsquo;s address and
some other data too. So the struct is too big to be assigned into a pointer.&lt;/p&gt;

&lt;p&gt;When I mention this to friends over beers, most people guess that it&amp;rsquo;s because
C++ needs to store two pointers: one for the address of the function, and one
for the &amp;ldquo;this&amp;rdquo; pointer. But nope, it&amp;rsquo;s not that. You need to pass the &amp;ldquo;this&amp;rdquo;
pointer on the left side of the &lt;code&gt;-&amp;gt;*&lt;/code&gt; operation. In fact, nobody seems to know
what else a C++ compiler might want to store besides the function address. My
guess is that it might also want to store the address of the &amp;ldquo;vtable&amp;rdquo; &amp;ndash; the
class definition/metadata.&lt;/p&gt;

&lt;p&gt;If you&amp;rsquo;ve been feeling nostalgic about the old days of &amp;ldquo;real coding&amp;rdquo; in C++,
maybe now you realize that you haven&amp;rsquo;t really been missing it. Sometimes the
present really is better than the past!&lt;/p&gt;

&lt;p&gt;(Photo credits: my dad&amp;rsquo;s painting, and a wikipedia arctile about the dust bowl.)&lt;/p&gt;
 
        <a href="http://flattr.com/thing/40430/Robey" target="_blank">
        <img src="http://api.flattr.com/button/button-compact-static-100x17.png" alt="Flattr this" title="Flattr this" border="0" />
        </a>
      </content>
    </entry>
  
    <entry>
      <title>Mensch 2.0</title>
      <link href="http://robey.lag.net/2012/08/22/mensch-2.html"/>
      <updated>2012-08-22T00:00:00-07:00</updated>
      <id>http://robey.lag.net/2012/08/22/mensch-2</id>
      <content type="html">
        &lt;p&gt;I recently picked up one of the new &amp;ldquo;retina&amp;rdquo; Macbooks, and it looks
incredible. There&amp;rsquo;s nothing magic about the hardware &amp;ndash; they simply doubled
the number of pixels in each dimension, as you can read about in
&lt;a href=&quot;http://arstechnica.com/apple/2012/07/os-x-10-8/16/&quot;&gt;this arstechnica review&lt;/a&gt;
of Mountain Lion. But the scaling effect on text is beautiful. Here&amp;rsquo;s what
it looks like blown up 8 times:&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;../../../images/mensch-demo-3.png&quot; alt=&quot;now&quot; /&gt;&lt;/p&gt;

&lt;p&gt;That&amp;rsquo;s a lot of pixels.&lt;/p&gt;

&lt;p&gt;The new sharpness highlighted a few, um, &amp;ldquo;rough edges&amp;rdquo; in the Mensch font
that I posted a few years ago. Back then, the only accessible font editor for
macs was a port of an old X11 Linux font editor. It crashed a lot, and getting
it to connect lines together was usually a five-minute process of trying the
same thing over and over until it worked.&lt;/p&gt;

&lt;p&gt;But a casual mention in a github blog post led me to an awesome new font
editor called &amp;ldquo;Glyphs&amp;rdquo;: &lt;a href=&quot;http://glyphsapp.com/&quot;&gt;Check it out!&lt;/a&gt; It&amp;rsquo;s
Mac-native, has a simple interface, great documentation, and (so far) hasn&amp;rsquo;t
crashed.&lt;/p&gt;

&lt;p&gt;Armed with Glyphs, I went through the current Menlo drop from Apple, and
re-created the same changes I had made to create Mensch. With so much more
control over the shapes, it came out a lot better. It might not be obvious
on a non-retina screen at a small point size, but it&amp;rsquo;s a pretty clear
improvement on the new screens. I&amp;rsquo;m still calling it Mensch, but it&amp;rsquo;s a
Mensch 2.0.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;../../../images/mensch-demo-1.jpg&quot; alt=&quot;some text&quot; /&gt;&lt;/p&gt;

&lt;p&gt;One thing I backed down on from the original version: The &amp;ldquo;angle brackets&amp;rdquo;
&amp;lt; and &gt; are reduced to the height of capital letters instead of being as tall
as the square brackets. Their excessive height &lt;em&gt;was&lt;/em&gt; a little distracting,
and I don&amp;rsquo;t think it added any more clarity than letter height gives them.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;../../../images/mensch-demo-2.png&quot; alt=&quot;some more text&quot; /&gt;&lt;/p&gt;

&lt;p&gt;There&amp;rsquo;s a bug in the new version of Font Book that causes the new Mensch font
to display a weird selection of characters when first importing, but it
doesn&amp;rsquo;t seem to affect its actual use.&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;../../../downloads/mensch2.otf&quot;&gt;Download Mensch 2.0&lt;/a&gt;&lt;/p&gt;
 
        <a href="http://flattr.com/thing/40430/Robey" target="_blank">
        <img src="http://api.flattr.com/button/button-compact-static-100x17.png" alt="Flattr this" title="Flattr this" border="0" />
        </a>
      </content>
    </entry>
  
    <entry>
      <title>Why Config?</title>
      <link href="http://robey.lag.net/2012/03/26/why-config.html"/>
      <updated>2012-03-26T00:00:00-07:00</updated>
      <id>http://robey.lag.net/2012/03/26/why-config</id>
      <content type="html">
        &lt;p&gt;When I first started playing with scala in 2008, I was dismayed by the state of server configuration in the java world. A lot of java servers were still using property files, or worse, XML. XML is meant to be easily parsed by computers, but is really hard for humans to read and edit, and tends to hide useful information in baroque syntax and line noise. The python world was still clinging to Windows-era &amp;ldquo;INI&amp;rdquo; files, and the ruby world had invented something called YAML, with its own odd syntax.&lt;/p&gt;

&lt;p&gt;[Alex Feinberg pointed out that the use of the term &amp;ldquo;config&amp;rdquo; can be overly general. In this post, I&amp;rsquo;m talking specifically about configuration used to bootstrap a cluster of machines all running the same server code. Shared configuration required by multiple server clusters is a different problem, and obviously not well-served by any solution that only works on the JVM.]&lt;/p&gt;

&lt;p&gt;We had gone through many iterations of config file formats at my previous job, as we moved from perl to C++ to java, but it was a very private company, terrified of open source, so we shared none of what we learned. I thought it was time to spead some best-practices around, so I wrote &amp;ldquo;configgy&amp;rdquo; lazily over a couple of months as I learned scala.&lt;/p&gt;

&lt;h2&gt;Configgy&lt;/h2&gt;

&lt;p&gt;The core ideas behind &amp;ldquo;configgy&amp;rdquo; were:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;A config file should be a text file, primarily readable by humans. It should be unambiguous and have minimal syntax.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;A server&amp;rsquo;s configuration should really just be a set of (string) keys and values. The values can be bools, ints, strings, lists of strings.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;You should be able to take blocks of these key/value sets and nest them, so subsystems can have their own isolated configuration.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;The API should be similarly minimal, like a typesafe hashtable, and should allow subsystems to &amp;ldquo;subscribe&amp;rdquo; to configuration values and get notified if they&amp;rsquo;ve changed.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;


&lt;p&gt;The end result was pretty successful, and we used it at Twitter for several years. An example chunk of a config file might look like this:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;port = 22133
timeout_msec = 100

log {
  filename = &quot;/var/log/kestrel/kestrel.log&quot;
  roll = &quot;daily&quot;
  level = &quot;info&quot;
}
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Unfortunately, I had gone in the wrong direction, and it took a while for the mounting evidence (and my coworkers) to convince me.&lt;/p&gt;

&lt;h2&gt;What&amp;rsquo;s wrong&lt;/h2&gt;

&lt;p&gt;&lt;img src=&quot;../../../images/rodent.jpg&quot; style=&quot;float:right&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Some of the problems with configgy show up in the config file example I pasted above:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;There&amp;rsquo;s no schema. &amp;ldquo;port&amp;rdquo; should be an int, but there&amp;rsquo;s no place to declare that. There&amp;rsquo;s no definition for what should be in the config file at all. What are the keys? What do they do? You have to document it separately in a text file, if you&amp;rsquo;re really ambitious.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;The available types aren&amp;rsquo;t sufficient. Durations are really common in server configuration because they specify timeouts, and there&amp;rsquo;s no real support for them. You have to drop sly hints in the field names (like &amp;ldquo;msec&amp;rdquo; for milliseconds) and hope people are paying close attention.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Extending the available types will never cover all cases. The &amp;ldquo;roll&amp;rdquo; field above can only have a few possible values, but there&amp;rsquo;s no simple way to define a new enumerated type like that.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;


&lt;p&gt;Other problems only show up in daily use:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;em&gt;validation&lt;/em&gt;: How do you validate that the config file won&amp;rsquo;t cause a server crash hours after it starts? There&amp;rsquo;s nothing forcing &amp;ldquo;timeout_msec&amp;rdquo; to be an int, so it may throw an exception minutes later, when the code first tries to call &lt;code&gt;.toInt&lt;/code&gt; on it.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;em&gt;defaults&lt;/em&gt;: What is the default timeout? Is there one? Configgy supported providing a default value in the API, but how do you know what that is when you&amp;rsquo;re editing the config file &amp;ndash; especially if you didn&amp;rsquo;t write the original code?&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;


&lt;p&gt;One of the biggest faults should get its own section, because I have a lot to say about it.&lt;/p&gt;

&lt;h2&gt;Reloading config files&lt;/h2&gt;

&lt;p&gt;Configgy had a lot of code to support reloading config files on the fly, allowing a server to &amp;ldquo;subscribe&amp;rdquo; to a key and change its behavior if a config file was reloaded. It seemed really clever at the time, but experience taught me and my coworkers that it&amp;rsquo;s a really bad idea in practice.&lt;/p&gt;

&lt;p&gt;How often do you change a config file on the fly and ask the server to reload it? And more importantly, when? Murphy&amp;rsquo;s Law tells us the answer: when something is broken, it&amp;rsquo;s the middle of the night, and it needs to be fixed immediately.&lt;/p&gt;

&lt;p&gt;But because we only did this in a crisis, the code was &lt;em&gt;effectively untested&lt;/em&gt;. If you aren&amp;rsquo;t regularly using some part of a server, you can&amp;rsquo;t trust it enough to depend on it in a crisis. In a crisis, I want only tools that I&amp;rsquo;ve used before and am confident in. It only takes a couple of incidents where reloading a config file doesn&amp;rsquo;t &lt;em&gt;actually&lt;/em&gt; fix the server&amp;rsquo;s behavior before your policy becomes: Fix the config file offline, then restart the server.&lt;/p&gt;

&lt;p&gt;The ability to reload configuration became just another moving part: something you had to think about, but would never actually use in a crunch.&lt;/p&gt;

&lt;p&gt;This could probably be solved by adding automated testing that changes your config file, asks the server to reload, and then re-runs a suite of tests. But it just didn&amp;rsquo;t seem worth it. As a practical matter, the server needs to startup cleanly after any kind of unclean shutdown (&amp;ldquo;kill -9&amp;rdquo; or a fire) &amp;ndash; and must be tested to do so &amp;ndash; so you don&amp;rsquo;t need any other feature for reloading the config file. Just change the file and kill the server. Now it&amp;rsquo;s running with the new config!&lt;/p&gt;

&lt;h2&gt;How to fix it&lt;/h2&gt;

&lt;p&gt;If you read my &lt;a href=&quot;http://robey.lag.net/2011/04/30/dissolving-patterns.html&quot;&gt;post from last year about patterns&lt;/a&gt;, you know where this is heading. There&amp;rsquo;s one obvious way to define a set of named, type-safe fields: write a scala trait. Your config file can then just be a scala file that you compile and evaluate when the server starts.&lt;/p&gt;

&lt;p&gt;Your config trait should be a builder that creates a server from config, like this:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;trait ServerConfig extends (() =&amp;gt; Server) {
  var port: Int = 9999
  var timeout: Option[Duration] = None

  def apply(): Server = new Server(port, timeout, ...)
}
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;The &lt;code&gt;apply&lt;/code&gt; method assembles a &lt;code&gt;Server&lt;/code&gt; from the configuration. After that, your config file can be:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;new ServerConfig {
  port = 12345
  timeout = 250.milliseconds
}
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;The important lines look just like the configgy version, and are executed as part of the constructor.&lt;/p&gt;

&lt;p&gt;Now you have a schema (the config trait), and every field has a type, declared in the trait and enforced by the scala compiler. If you need a specialized type, like an enum, you can make one. I especially like how readable timeouts become. It&amp;rsquo;s unambiguous that the duration is specified in milliseconds, and you could use seconds if you want.&lt;/p&gt;

&lt;h2&gt;How does it work?&lt;/h2&gt;

&lt;p&gt;&lt;img src=&quot;../../../images/statue.jpg&quot; style=&quot;float:right&quot; /&gt;&lt;/p&gt;

&lt;p&gt;The key is &lt;code&gt;Eval&lt;/code&gt;, a component of &lt;code&gt;util-eval&lt;/code&gt; that makes it easier to compile and execute scala code from inside the JVM. Scala already exposes this functionality &amp;ndash; the scala compiler runs on the JVM, after all, and the REPL needs to do line-by-line compilation &amp;ndash; but the API is arcane and marked with a &amp;ldquo;No serviceable parts inside&amp;rdquo; label. The &lt;code&gt;Eval&lt;/code&gt; class simplifies it to:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;scala&amp;gt; val eval = new Eval()
eval: com.twitter.util.Eval = com.twitter.util.Eval@1df5973b

scala&amp;gt; eval[Int](&quot;3 + 4&quot;)
res0: Int = 7
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;The result of evaluating a config file is a new &lt;code&gt;ServerConfig&lt;/code&gt; object (or similar), and calling &lt;code&gt;apply&lt;/code&gt; on that will return a fully-initialized &lt;code&gt;Server&lt;/code&gt; object, so loading the config file and starting the server boils down to:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;  val eval = new Eval()
  val config: ServerConfig = eval[ServerConfig](new File(&quot;...&quot;))
  val server: Server = config()
  server.start()
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;If you add some exception handling to log errors, you end up with the code inside &lt;code&gt;RuntimeEnvironment&lt;/code&gt; in &lt;a href=&quot;https://github.com/twitter/ostrich&quot;&gt;ostrich&lt;/a&gt;, which we use to bootstrap server startup from config files in a deployed server.&lt;/p&gt;

&lt;h2&gt;Sleight of hand&lt;/h2&gt;

&lt;p&gt;There are two problems I listed above that aren&amp;rsquo;t solved by this simple solution: validation and default values. So you have to add a little bit of code to finish up.&lt;/p&gt;

&lt;p&gt;If a config file can be compiled and executed, then it&amp;rsquo;s valid. The result of the evaluation is a config object (&lt;code&gt;ServerConfig&lt;/code&gt; in this example) that doesn&amp;rsquo;t have any side-effects and can be safely evaluated at compile time. So that&amp;rsquo;s what we do: the last phase of a build executes the server jar with a special &lt;code&gt;&quot;--validate&quot;&lt;/code&gt; option that compiles the config files and exits. If that succeeds, the config files are valid and they won&amp;rsquo;t crash the server in production.&lt;/p&gt;

&lt;p&gt;In the example above, all the fields had default values, which is not always what you want. For those cases, we defined a &lt;a href=&quot;https://github.com/twitter/util/blob/master/util-core/src/main/scala/com/twitter/util/Config.scala&quot;&gt;basic &lt;code&gt;Config&lt;/code&gt; trait&lt;/a&gt;. It allows you to mark a field as &lt;code&gt;required&lt;/code&gt; with no default value, or optional, or lazily computed.&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;trait ServerConfig extends Config[Server] {
  var port = required[Int]
  var timeout = optional[Duration]
}
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Implicits handle the conversion from a normal type to a &amp;ldquo;required&amp;rdquo; or &amp;ldquo;optional&amp;rdquo; type (optional types just use scala&amp;rsquo;s &lt;code&gt;Option&lt;/code&gt; class), so the config file looks the same.&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;Config&lt;/code&gt; trait fits completely in one file, with less than 100 code lines (according to &lt;a href=&quot;http://cloc.sourceforge.net/&quot;&gt;cloc&lt;/a&gt;). That&amp;rsquo;s an incredible improvement over configgy.&lt;/p&gt;

&lt;h2&gt;Postscript&lt;/h2&gt;

&lt;p&gt;This post is a little overdue, but better late than never. :-)&lt;/p&gt;

&lt;p&gt;I wrote this because it was important to me to share the knowledge, not because i did all (or even most) of the work. I carefully avoided naming coworkers while writing this post, because it disturbed the flow, but they all deserve callouts:&lt;/p&gt;

&lt;p&gt;John Kalucki first spelled out for me why the implementation of default values was bad. Matt Freels and Ed Ceaser implemented the first draft of the &lt;code&gt;Config&lt;/code&gt; class and pulled me in to help iterate on it. Nick Kallen opened my eyes to the dangers of depending on a server&amp;rsquo;s &amp;ldquo;shutdown&amp;rdquo; and &amp;ldquo;reload&amp;rdquo; behavior.&lt;/p&gt;
 
        <a href="http://flattr.com/thing/40430/Robey" target="_blank">
        <img src="http://api.flattr.com/button/button-compact-static-100x17.png" alt="Flattr this" title="Flattr this" border="0" />
        </a>
      </content>
    </entry>
  
    <entry>
      <title>Dissolving patterns</title>
      <link href="http://robey.lag.net/2011/04/30/dissolving-patterns.html"/>
      <updated>2011-04-30T00:00:00-07:00</updated>
      <id>http://robey.lag.net/2011/04/30/dissolving-patterns</id>
      <content type="html">
        &lt;p&gt;I forget where I first read about this meme, but I&amp;rsquo;ve been appreciating it more and more over
time:&lt;/p&gt;

&lt;blockquote&gt;&lt;p&gt;Once a programming pattern achieves widespread use, languages start to
absorb it into their structure.&lt;/p&gt;&lt;/blockquote&gt;

&lt;p&gt;Object-orientation is a pattern in C, because you have to use a library like
&lt;a href=&quot;http://en.wikipedia.org/wiki/GObject&quot;&gt;gobject&lt;/a&gt; to implement virtual method calls, and you have to
write code to that library&amp;rsquo;s conventions. In java, you get virtual method calls as default behavior.
It&amp;rsquo;s not a pattern; it&amp;rsquo;s part of the language.&lt;/p&gt;

&lt;p&gt;Iteration used to be a pattern in java, but by java 5, there was enough syntactic sugar to make
iteration seem like a natural part of the language. You don&amp;rsquo;t have to think about iterating; you can
do it with half a line of code. You don&amp;rsquo;t usually need to think about how to create iterable
objects, either, because the standard library has a set of methods to make it easy. It&amp;rsquo;s become a
part of the language.&lt;/p&gt;

&lt;p&gt;Another way to look at patterns is that they&amp;rsquo;re boilerplate you need to add to your code &amp;ndash;
boilerplate you could avoid (or make a lot smaller) if the pattern was integrated into the language.
So as a pattern becomes commonly accepted, it&amp;rsquo;s more likely to be added as a core feature, and cease
to be a pattern at all. I think this is part of the reason that high-level languages are terser than
low-level languages: patterns become syntax.&lt;/p&gt;

&lt;p&gt;There are two patterns that I think should go away in a scala (or any post-java language) world.&lt;/p&gt;

&lt;h2&gt;Factories&lt;/h2&gt;

&lt;p&gt;The factory pattern is used to abstract away object creation, usually so libraries can have
functionality injected. For example, a popular HTTP library for java uses a factory to allow clients
to replace or augment the socket library:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;interface SocketFactory {
  public Socket createSocket();
}
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;This is a cool feature, because it allows the library to be very configurable, but it ends up
creating a lot of boilerplate code when it&amp;rsquo;s used:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;class MySSLSocketFactory {
  public Socket createSocket() {
    return new MySSLSocket();
  }
}
...
Protocol p = new Protocol(&quot;https&quot;, new MySSLSocketFactory(), 443);
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Let&amp;rsquo;s look at the interface a bit more closely. It&amp;rsquo;s really just sugar for a single method which
takes zero or more parameters and returns a new object. In fact, let me suggest that it&amp;rsquo;s really
just another way of describing&amp;hellip; a function! But in higher-level languages, functions are
first-class objects, so we could define the factory that way instead:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;type SocketFactory = () =&amp;gt; Socket
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;And instead of creating a factory, we can just pass in our function for creating sockets:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;val protocol = new Protocol(&quot;https&quot;, { () =&amp;gt; new MySSLSocket() }, 443)
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Poof! All the boilerplate is gone. You don&amp;rsquo;t need a factory because a factory is just a function,
and the function is a factory. The pattern is integrated into the language already.&lt;/p&gt;

&lt;p&gt;So I propose that the next time you start to write a factory interface, you just use a function
instead.&lt;/p&gt;

&lt;h2&gt;Builders&lt;/h2&gt;

&lt;p&gt;That probably isn&amp;rsquo;t very controversial or shocking, but let me go one step further and tackle a
tougher pattern: the builder.&lt;/p&gt;

&lt;p&gt;Builders are used when an object may have a lot of initial state to configure. For example, if your
class constructor has 10 parameters, you probably want to create a builder so that constructing it
can be a little more self-documenting, and optional configuration can be omitted.&lt;/p&gt;

&lt;p&gt;As immutable objects become more popular, builders are also becoming a popular way to allow
multi-step construction in a mutable object before squirting out the final immutable object.&lt;/p&gt;

&lt;p&gt;Here&amp;rsquo;s an example from the android API. There are different code styles, but the most common one
seems to be a cascade of method calls, culminating in a final &lt;code&gt;create&lt;/code&gt; call:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;AlertDialog alert = new AlertDialog.Builder(this)
  .setTitle(&quot;Alert!&quot;).setMessage(&quot;lp on fire!&quot;)
  .setNegativeButton(&quot;Denial&quot;, null)
  .setPositiveButton(&quot;Acceptance&quot;, null)
  .create();
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;You have to admit, at least, that it&amp;rsquo;s a lot better (and easier to understand) than a huge
constructor call, which could end up looking something like:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;AlertDialog alert = new AlertDialog(this, &quot;Alert!&quot;, 0, &quot;lp on fire!&quot;, null, null, button1, ...)
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Anyway, you&amp;rsquo;ve probably already guessed what I&amp;rsquo;m going to say about that &lt;code&gt;create&lt;/code&gt; call: It&amp;rsquo;s a
factory function!&lt;/p&gt;

&lt;p&gt;But the cascading method calls can be fixed too. What if the builder class was replaced by a
configuration class with mutable fields? It might look like this:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;class Builder extends (() =&amp;gt; AlertDialog) {
  var title: String = &quot;&quot;
  var message: String = &quot;&quot;
  var positiveButton: Option[Button] = None
  ...
  def apply() = ...
}
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;The builder class is a factory function that generates new &lt;code&gt;AlertDialog&lt;/code&gt; objects &amp;ndash; that is, it&amp;rsquo;s a
function &lt;code&gt;() =&amp;gt; AlertDialog&lt;/code&gt; &amp;ndash; but it also has a bunch of optional, mutable configuration. Instead
of cascading method calls, you can use the constructor to override any fields you want to set:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;val builder = new Builder {
  title = &quot;Alert!&quot;
  message = &quot;lp on fire!&quot;
  positiveButton = Some(new Button(...))
}
val alert = builder()
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;I think this is even easier to read than the builder call. To avoid confusion, I call these classes
&lt;code&gt;Config&lt;/code&gt; instead of &lt;code&gt;Builder&lt;/code&gt;, but they have exactly the same effect: to create a (possibly
immutable) object out of mutable configuration.&lt;/p&gt;

&lt;p&gt;It looks like having functions as first-class objects lets us integrate at least two patterns into
the language, but there are a lot more to work on. For one, the delegator pattern seems to still
involve a lot of boilerplate in most languages. So there is more to be done! Onward and upward!&lt;/p&gt;
 
        <a href="http://flattr.com/thing/40430/Robey" target="_blank">
        <img src="http://api.flattr.com/button/button-compact-static-100x17.png" alt="Flattr this" title="Flattr this" border="0" />
        </a>
      </content>
    </entry>
  
    <entry>
      <title>Why AT&T Deserves To Fail</title>
      <link href="http://robey.lag.net/2010/07/03/att-deserves-to-fail.html"/>
      <updated>2010-07-03T00:00:00-07:00</updated>
      <id>http://robey.lag.net/2010/07/03/att-deserves-to-fail</id>
      <content type="html">
        &lt;p&gt;AT&amp;amp;T is a very large, very old company. It&amp;rsquo;s so old, it has the stock ticker symbol &amp;ldquo;T&amp;rdquo;. That&amp;rsquo;s
right, just &amp;ldquo;T&amp;rdquo;. It&amp;rsquo;s so large, the US government tried to break it up into a half dozen smaller
companies 25 years ago, and ultimately failed. But history is filled with very large, very old
institutions that eventually failed: the Roman empire, the Dutch East India company, and the
Atlantic slave trade, to name a few.&lt;/p&gt;

&lt;p&gt;Recently I bought an HTC Evo (Android) on the Sprint network. My plan was to try it for a few weeks,
and if the battery life was as bad as some reviews said it was, or the coverage was as bad as
AT&amp;amp;T&amp;rsquo;s, I would return it.&lt;/p&gt;

&lt;p&gt;I&amp;rsquo;ve barely had the thing for 48 hours and I can&amp;rsquo;t imagine going back.&lt;/p&gt;

&lt;p&gt;More than half of my joy is the phone itself. The iPhone has always been a step backward, since its
crippled OS means it can&amp;rsquo;t run a decent SSH terminal or chat client &amp;ndash; two of my three primary uses
for a mobile device. (It has a great browser, though.) The newly-named iOS 4 doesn&amp;rsquo;t fix that. We&amp;rsquo;ve
had multi-tasking on phones since 2002, but Apple can&amp;rsquo;t seem to get it working on hardware that
&lt;em&gt;laptops&lt;/em&gt; &lt;a href=&quot;http://en.wikipedia.org/wiki/PowerBook_G4#Aluminum_PowerBook_G4&quot;&gt;barely had in 2002&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;The Evo evokes a sense of wonder and infinite possibilities, not too different from how it felt as a
child to play with a computer for the first time. Unlike the fortress-like atmosphere of an iPhone,
the Android OS suggests that if you can think of something to try, it might just work. For example,
I browsed to a website offering an mp3, and clicked on the link just to see what would happen. The
song started &lt;em&gt;downloading&lt;/em&gt;! It showed up in the music player! I could listen to music on the
internet without going through the tedious process of docking and syncing with a laptop!&lt;/p&gt;

&lt;p&gt;Apple is not trying for this market, though. They&amp;rsquo;re aiming to be a shinier, more expensive RAZR; a
consumer phone that can&amp;rsquo;t do much, but can do it very well. And they&amp;rsquo;re very successful at it, to
gauge from their sales numbers. Very, &lt;em&gt;very&lt;/em&gt; successful. The iPhone is probably the most popular
phone in the world. People stood in line &lt;em&gt;14 hours&lt;/em&gt; this week to purchase a modest upgrade.&lt;/p&gt;

&lt;p&gt;If, say, a cellphone carrier were able to get an exclusive contract for selling the iPhone for the
first &lt;em&gt;five years&lt;/em&gt; of its meteoric rise, that carrier might very well make bank. They could become
larger than all the other carriers combined! They could add extra fees for the privilege of having
an iPhone, and expand their reach and coverage to hitherto unknown extent.&lt;/p&gt;

&lt;p&gt;AT&amp;amp;T &lt;em&gt;has&lt;/em&gt; this exclusive contract, and they &lt;em&gt;have&lt;/em&gt; the privilege fees. But they haven&amp;rsquo;t expanded
their coverage or their reach. They haven&amp;rsquo;t done anything, as far as I can tell, except shovel
wheelbarrows full of money into a Scrooge McDuck vault somewhere, while their name &amp;amp; brand have
become a joke. Whatever else AT&amp;amp;T did in the past, they now represent only &amp;ldquo;incompetent wireless
provider&amp;rdquo; in the mind of the consumer. How did this happen?&lt;/p&gt;

&lt;p&gt;I live in the &lt;a href=&quot;http://en.wikipedia.org/wiki/San_Francisco&quot;&gt;second-most densely populated city&lt;/a&gt; in
the US, with 6,700 people per square kilometer. In the three years I&amp;rsquo;ve been using AT&amp;amp;T&amp;rsquo;s cell
network, they have not managed to make a single improvement to their abyssmal coverage. Entire
neighborhoods, including popular ones like the Haight and the Mission, are giant dead zones. My
friends and I regularly use Skype to make voice calls, out of necessity. If you can&amp;rsquo;t cover the end
of a peninsula 10km on a side, something is seriously wrong. The only rational explanation is that
AT&amp;amp;T &lt;em&gt;is not trying&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;One excuse often offered is that &amp;ldquo;cities are hard to cover&amp;rdquo;. Sorry, I&amp;rsquo;m not buying it. If the task
is difficult, we&amp;rsquo;d be seeing progress, but slowly. Seeing no progress means the task is either
impossible or isn&amp;rsquo;t being attempted. Since Sprint and Verizon are able to provide excellent
coverage, I guess it&amp;rsquo;s not impossible. So, again, AT&amp;amp;T &lt;em&gt;is not trying&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;In fact, their coverage situation is dire throughout the bay area of California. Why would they care
to provide coverage to the bay area, though? Aside from it being the home of Apple and 7.4 million
people, there&amp;rsquo;s a really good PR reason why they might want to step up their game here. It&amp;rsquo;s the
home of nearly every tech pundit and blogger on the net. AT&amp;amp;T could improve coverage in every other
part of the US, and still get a continuous stream of bad press about their network, because these
journalists can&amp;rsquo;t make a phone call. It&amp;rsquo;s so self-destructive, it&amp;rsquo;s mind-boggling.&lt;/p&gt;

&lt;p&gt;Apple seems to have given up on AT&amp;amp;T. Their latest new features, like video chat, won&amp;rsquo;t even try to
use AT&amp;amp;T&amp;rsquo;s network. They&amp;rsquo;re just hoping that you&amp;rsquo;ll be in wifi coverage most of the time. And sales
of the wifi-only model of the iPad imply that a wifi-only iPhone would probably sell as well as the
AT&amp;amp;T one.&lt;/p&gt;

&lt;p&gt;All this money in the bank won&amp;rsquo;t save AT&amp;amp;T any more than it saved Microsoft. And it won&amp;rsquo;t buy them
happiness &amp;ndash; ask Scrooge McDuck about that. It might have bought them a future, but it&amp;rsquo;s probably
too late even for that, now.&lt;/p&gt;

&lt;p&gt;It doesn&amp;rsquo;t matter anymore, though. Yesterday, from my Evo, I sent a text message &lt;em&gt;from my bedroom&lt;/em&gt;!
The future is now!&lt;/p&gt;
 
        <a href="http://flattr.com/thing/40430/Robey" target="_blank">
        <img src="http://api.flattr.com/button/button-compact-static-100x17.png" alt="Flattr this" title="Flattr this" border="0" />
        </a>
      </content>
    </entry>
  
    <entry>
      <title>Mensch -- A coding font</title>
      <link href="http://robey.lag.net/2010/06/21/mensch-font.html"/>
      <updated>2010-06-21T00:00:00-07:00</updated>
      <id>http://robey.lag.net/2010/06/21/mensch-font</id>
      <content type="html">
        &lt;p&gt;The latest MacOS release (10.6, or &amp;ldquo;Snow Leopard&amp;rdquo;) comes with a new monospace font. It&amp;rsquo;s called
&amp;ldquo;Menlo&amp;rdquo; and it&amp;rsquo;s a slightly modified form of the standard Linux font (with appropriately weightly
Linux name) &amp;ldquo;DejaVu Sans Serif Mono&amp;rdquo;, which is itself an updated form of Bitstream Vera Sans Mono.
Apple&amp;rsquo;s modifications are a definite improvement to my eyes, mostly because they thicken up some of
the wispier glyphs from DejaVu, like the underline and period. There&amp;rsquo;s a &lt;a href=&quot;http://www.leancrew.com/all-this/2009/10/the-compleat-menlovera-sans-comparison/&quot;&gt;great comparison over here&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;One thing that bothered me, though, is that they turned the zero into a 1980s-style &amp;ldquo;slashed
circle&amp;rdquo;. Unhip, daddy-o! Naturally I searched for a font editor, and the best one I found was Font
Forge, an old Linux app ported to the Mac but still requiring X11. So that&amp;rsquo;s two ways OS X is
borrowing from Linux for font support. What&amp;rsquo;s up with that? Was there an elite cadre of fontistas
working on Linux machines in a secret bunker? Linux is, um, not usually known for its great
designers.&lt;/p&gt;

&lt;p&gt;I couldn&amp;rsquo;t limit my tweaking to the zero glyph, so in the end I made about a dozen changes.
Bitstream released these fonts with a very open license that only requires that you change the name
if you change anything about the font, so I&amp;rsquo;m releasing my changes with the same license, as the
font &amp;ldquo;Mensch&amp;rdquo;.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;../../../images/mensch-differences.png&quot; alt=&quot;comparison with menlo&quot; /&gt;&lt;/p&gt;

&lt;p&gt;A summary of the changes I made:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Zero is back to being a circle with a dot in the middle.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;The ampersand&amp;rsquo;s loop was closed. That was also bugging me.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Three is rendered in the gothic style, because the gothic style is clearly superior.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Lowercase L is drawn in a more traditional style (the Menlo variant looks bizarre to me), and one
is turned gothic. I think the original artist drew the L weirdly to make it extremely clear that
it&amp;rsquo;s not a one, but if you draw a gothic one, the difference is obvious even with a simpler L.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;The bang, question, lowercase I, and lowercase J are made friendlier by turning the dots into
actual circles, not just blocks.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Angle brackets are embiggened to facilitate languages like Java and C++ that use them to enclose
class names. They parallel parens and square brackets in size now.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Q and lowercase Q are made more distinct. Lowercase Q gets a little more spunk. (This was a bit
gratuitous.)&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;


&lt;p&gt;Here&amp;rsquo;s a sample of Mensch in use in code:&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;../../../images/mensch-example.png&quot; alt=&quot;example code&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Doesn&amp;rsquo;t it look cool? Don&amp;rsquo;t you want it now? Here&amp;rsquo;s the link!&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;../../../downloads/mensch.ttf&quot;&gt;mensch.ttf&lt;/a&gt;&lt;/p&gt;
 
        <a href="http://flattr.com/thing/40430/Robey" target="_blank">
        <img src="http://api.flattr.com/button/button-compact-static-100x17.png" alt="Flattr this" title="Flattr this" border="0" />
        </a>
      </content>
    </entry>
  
    <entry>
      <title>A very tiny, monospace, bitmap font</title>
      <link href="http://robey.lag.net/2010/01/23/tiny-monospace-font.html"/>
      <updated>2010-01-23T00:00:00-08:00</updated>
      <id>http://robey.lag.net/2010/01/23/tiny-monospace-font</id>
      <content type="html">
        &lt;p&gt;Long ago, when making an SSH client for a phone, we needed the tiniest possible monospace font we
could find that was still basically legible. Brian Swetland &amp;ndash; who was also the instigator of this
side project &amp;ndash; had made a 4x6 font (3x5 usable pixels) for a
&lt;a href=&quot;http://vt100.tarunz.org/&quot;&gt;Palm Pilot VT100 emulator&lt;/a&gt;. Here&amp;rsquo;s what it looks like, blown up four times:&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;../../../images/tom-thumb-original.png&quot; alt=&quot;original font&quot; /&gt;&lt;/p&gt;

&lt;p&gt;When I first tried it out doing things like reading email and editing code, a couple of things
bugged me. The uppercase letters were great. The lowercase letters had looked fine individually, but
when used in long strings together, they tended to look like a child&amp;rsquo;s writing. I eventually figured
out that this was because they all had different middle heights, and modified them so that they had
a fairly tall mid-height (one pixel shorter than uppercase) but were all consistent. This made some
of the individual letters (like &amp;ldquo;x&amp;rdquo;) look odder, but it made them much easier to read as a whole. It
also let the &amp;ldquo;a&amp;rdquo; and &amp;ldquo;g&amp;rdquo; look a lot more stylish.&lt;/p&gt;

&lt;p&gt;The other thing that bothered me was the digits, which I think were intentionally modeled on the
7-segment LED of an alarm clock. Again, they looked fine on their own or as part of a long string of
digits, but when they were in the middle of a line like &amp;ldquo;Date: 23 Jan 2010&amp;rdquo;, they stuck out a lot. I
pretty much just went in with a belt sander and sanded off the corners so they would seem more
rounded.&lt;/p&gt;

&lt;p&gt;The final version, which we jokingly called &amp;ldquo;Tom Thumb&amp;rdquo;, is below:&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;../../../images/tom-thumb-new.png&quot; alt=&quot;modified font&quot; /&gt;&lt;/p&gt;

&lt;p&gt;And here&amp;rsquo;s a dumb comparison of a line of text, with the modified form on top and the original
underneath:&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;../../../images/tom-thumb-comparison.png&quot; alt=&quot;Hello World!&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Brian&amp;rsquo;s page implies that his font was licensed under the &lt;a href=&quot;http://vt100.tarunz.org/LICENSE&quot;&gt;MIT license&lt;/a&gt;,
so since I did these
modifications in my free time, the same license applies here. Feel free to download the BDF file
below if you would find this useful, or would like to modify it further for some other nefarious
purposes. (&lt;em&gt;Update from 2015: As per comments below, Brian has authorized his font to be released under the CC0 or CC-BY 3.0 license. Therefore, this font may also be used under either CC0 or CC-BY 3.0 license.&lt;/em&gt;)&lt;/p&gt;

&lt;p&gt;The BDF actually includes a sprinkling of Latin-1 characters too, but the pixel limitations hit
those characters a lot harder than ASCII, so&amp;hellip; be forewarned. :)&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;../../../downloads/tom-thumb.bdf&quot;&gt;tom-thumb.bdf&lt;/a&gt;&lt;/p&gt;
 
        <a href="http://flattr.com/thing/40430/Robey" target="_blank">
        <img src="http://api.flattr.com/button/button-compact-static-100x17.png" alt="Flattr this" title="Flattr this" border="0" />
        </a>
      </content>
    </entry>
  
    <entry>
      <title>More real-world git</title>
      <link href="http://robey.lag.net/2009/11/29/more-git.html"/>
      <updated>2009-11-29T00:00:00-08:00</updated>
      <id>http://robey.lag.net/2009/11/29/more-git</id>
      <content type="html">
        &lt;p&gt;Git is really confusing for new users who have come over from subversion or
perforce. On one hand, I can admire, in a sort of detached objective way,
Linus&amp;rsquo;s commitment to making the tool bare-bones and focusing on trying to
make the command-line tools as fast as possible. On the other hand, many of
the defaults are maddeningly obscure, and there are large gaps where the the
starship&amp;rsquo;s hallway just ends in a catwalk and piles of exposed wiring. &amp;ldquo;Watch
your step here. We haven&amp;rsquo;t felt like finishing this part.&amp;rdquo;&lt;/p&gt;

&lt;p&gt;So, cool that git has reached a critical mass where it&amp;rsquo;s bringing DVCS
(&amp;ldquo;distributed version control systems&amp;rdquo;) to people who never would have tried
them before. But it means that, as opposed to &lt;a href=&quot;http://bazaar-vcs.org/en/&quot;&gt;bazaar&lt;/a&gt;, we need
to share a lot of knowledge and best practices in order to make it work
smoothly. Consider this a sequel to &lt;a href=&quot;http://robey.lag.net/2008/07/13/git-for-the-real-world.html&quot;&gt;my last git
post&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;../../../images/coffee.png&quot; style=&quot;float:right&quot;&gt;&lt;/p&gt;

&lt;h2&gt;Single master&lt;/h2&gt;

&lt;p&gt;A few times I&amp;#8217;ve heard people argue that if you&amp;rsquo;re using git (or any
DVCS) and you have a central repository, then &amp;ldquo;You&amp;rsquo;re Doing It Wrong&amp;rdquo;. I
disagree.&lt;/p&gt;

&lt;p&gt;I think most software projects, whether they are a library, a server, or a
website, have a single linear series of releases. Toaster 1.3.2 is followed by
Toaster 1.3.3, etc. On this macro scale, each release is meant to be an
improvement or progression over the previous one. If you have this kind of
system, then you&amp;rsquo;re probably going to have a single repository somewhere which
holds the &amp;ldquo;authoritative&amp;rdquo; copies production or release branches, even though
lots of people will have local copies of them.&lt;/p&gt;

&lt;p&gt;DVCS makes it easy to have a large cloud of coders, each with their own copy
of the source, equally authoritative from git&amp;rsquo;s point of view, and therefore
makes it easy to fork projects, which is pretty useful in open source. But it
doesn&amp;rsquo;t require you to treat each repository as equally authoritative in your
workflow. It works just fine with the model of a single centralized
repository. It would be foolish if it &lt;em&gt;didn&amp;rsquo;t&lt;/em&gt;, since that&amp;rsquo;s the way almost
every software project works.&lt;/p&gt;

&lt;p&gt;The key is that you can fork a branch from the &amp;ldquo;master&amp;rdquo; branch, experiment for
an hour on the train, and then if you want, you can merge back in, keeping all
of your change history. If you can hack on things wherever and whenever you
want, and sync back up later, You&amp;rsquo;re Doing It Right.&lt;/p&gt;

&lt;h2&gt;Why you shouldn&amp;rsquo;t fast-forward&lt;/h2&gt;

&lt;p&gt;As far as I know, git is the only DVCS that has a &amp;ldquo;fast-forward&amp;rdquo; merge
feature. Maybe that&amp;rsquo;s why they have it turned on by default. Please, git
maintainers, change this default &lt;em&gt;because it is wrong&lt;/em&gt;. It&amp;rsquo;s a clever feature,
and when you want it, it&amp;rsquo;s a nice tool to have around, but default behavior
should always be the most commonly-wanted behavior, and normal
(non-fast-forward) merges are the most commonly-wanted behavior for a merge.&lt;/p&gt;

&lt;p&gt;I didn&amp;rsquo;t explain fast-forward merges well last time, so I&amp;#8217;m going to try
again. Let&amp;rsquo;s imagine you write software for the jukebox in a Waffle House. You
have a pretty small codebase so far.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;../../../images/no-ff-1.png&quot; alt=&quot;two commits&quot; /&gt;&lt;/p&gt;

&lt;p&gt;and you decide you want to try hacking on the randomizer code, so that when it
plays songs at random, it&amp;rsquo;s more likely to play songs with &amp;ldquo;Waffle House&amp;rdquo; in
the name. You make a branch.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;../../../images/no-ff-2.png&quot; alt=&quot;new branch&quot; /&gt;&lt;/p&gt;

&lt;p&gt;And you hack on it for a while, and it works!&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;../../../images/no-ff-3.png&quot; alt=&quot;hack hack hack&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Meanwhile, nobody has been working on the main branch, so nothing has happened
there. It&amp;rsquo;s time to merge back in so you can release this awesome new code. If
you do this with &lt;strong&gt;&lt;code&gt;git merge&lt;/code&gt;&lt;/strong&gt;, it will do a fast-forward merge, meaning it
will just ignore the existence of your branch and pretend that you were
working on the master branch all along. Most importantly, it will &lt;em&gt;not&lt;/em&gt; create
a merge point that you can identify later. The information that you ever had a
feature branch is gone.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;../../../images/no-ff-4.png&quot; alt=&quot;fast-forward&quot; /&gt;&lt;/p&gt;

&lt;p&gt;If you want to revert this feature later (possibly because it&amp;rsquo;s driving the
staff crazy), you have to figure out which changes were involved, and revert
them one by one.&lt;/p&gt;

&lt;p&gt;However, if you did a &amp;ldquo;normal&amp;rdquo; merge, using &lt;strong&gt;&lt;code&gt;git merge --no-ff&lt;/code&gt;&lt;/strong&gt;, there
will be a specific revision marking the merge.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;../../../images/no-ff-5.png&quot; alt=&quot;normal merge&quot; /&gt;&lt;/p&gt;

&lt;p&gt;No history is lost. You can see everything that happened on the feature branch
if you like, and you can also revert the entire branch by reverting the merge.&lt;/p&gt;

&lt;h2&gt;Cross merging&lt;/h2&gt;

&lt;p&gt;One nice feature of DVCS is cheap branching. After figuring out that creating
and merging branches is as easy as making a commit, most people jump right in
to the workflow of creating a new branch for every bugfix or feature. But you
can still get stuck in the &amp;ldquo;star model&amp;rdquo;, where every branch is forked and
merged only to the master branch. And,
&lt;a href=&quot;http://davidyang.posterous.com/git-and-workflow&quot;&gt;as David Yang pointed out&lt;/a&gt;,
if you have a long-term branch, merging it into master can cause a giant
conflict that has to be resolved at the last minute.&lt;/p&gt;

&lt;p&gt;It doesn&amp;rsquo;t have to be that way though. You can and should merge the master
branch into your branch often. This works because DVCS like git use &amp;ldquo;merge
strategies&amp;rdquo; that look for the most recent common ancestor revision, and play
through changes from that point forward. Every time you merge master into your
branch, you have a more recent common ancestor (marked with &lt;code&gt;*&lt;/code&gt; on the diagram
below), so there is less to merge, and conflicts are resolved on your branch.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;../../../images/merge.png&quot; alt=&quot;cross merging&quot; /&gt;&lt;/p&gt;

&lt;p&gt;If you do the last merge right before you merge back into master, it won&amp;rsquo;t
even be possible to have conflicts, because you took care of them all. Our
deploy system uses this fact, and auto-rejects any branch that won&amp;rsquo;t merge
without conflict. It&amp;rsquo;s the branch owner&amp;rsquo;s responsibility to keep each branch
merged up to date.&lt;/p&gt;

&lt;p&gt;You can also cross-merge between two unrelated branches, which is helpful if
they&amp;rsquo;re dependent on each other. (Maybe fixing bug 13 requires bug 12 to be
fixed too.) This has the side effect of making the two branches
interdependent, but if they were already interdependent, you&amp;rsquo;re fine.&lt;/p&gt;

&lt;p&gt;Okay, that&amp;rsquo;s all for this installment!&lt;/p&gt;
 
        <a href="http://flattr.com/thing/40430/Robey" target="_blank">
        <img src="http://api.flattr.com/button/button-compact-static-100x17.png" alt="Flattr this" title="Flattr this" border="0" />
        </a>
      </content>
    </entry>
  
    <entry>
      <title>Fanout queues in kestrel 1.2</title>
      <link href="http://robey.lag.net/2009/10/10/fanout-queues.html"/>
      <updated>2009-10-10T00:00:00-07:00</updated>
      <id>http://robey.lag.net/2009/10/10/fanout-queues</id>
      <content type="html">
        &lt;p&gt;I bumped kestrel to version 1.2 this week and there are a few new features:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Queue files are loaded at startup time now, before opening the listening
port.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;You can explicitly abort an outstanding transcational &lt;code&gt;GET&lt;/code&gt; by passing the
&lt;code&gt;/abort&lt;/code&gt; option (in the same way as &lt;code&gt;/open&lt;/code&gt; or &lt;code&gt;/close&lt;/code&gt;).&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;You can also peek at the current head item on a queue with &lt;code&gt;/peek&lt;/code&gt;.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;New options &lt;code&gt;max_item_size&lt;/code&gt; and &lt;code&gt;sync_journal&lt;/code&gt;.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Queues can be deleted with &lt;code&gt;DELETE&lt;/code&gt;, which just forgets every item and
erases any journal file (ie: fast &amp;amp; unrecoverable).&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Some bugs in stats reporting were fixed.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Hopefully the documentation is much better. There&amp;rsquo;s a
&lt;a href=&quot;http://github.com/robey/kestrel/blob/master/docs/guide.md&quot;&gt;guide&lt;/a&gt; now.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;


&lt;p&gt;Thanks to Clement, Zachary Kim, Blair Zajac, and Frederic Jean for submitting
patches!&lt;/p&gt;

&lt;p&gt;Special thanks to Justin Azoff, who&amp;#8217;s responsible for the coolest new feature:
fanout queues. My coworkers had been asking about for this feature for a
while, and he posted a branch on github which added them in a way that makes
sense to me, so I pulled it in with minor changes. Here&amp;rsquo;s how they work:&lt;/p&gt;

&lt;p&gt;A fanout queue is a &amp;ldquo;parent&amp;rdquo; queue that has &amp;ldquo;children&amp;rdquo; queues. Whenever an
item is added to the parent, the same item is added automatically to each
child. The children each have their own journal files, and are essentially
independent queues. An item removed from one child doesn&amp;rsquo;t affect any other
children. In fact, you can even add items directly to a child if you want,
bypassing the fanout. The primary distinction is that &lt;code&gt;SET&lt;/code&gt;s to the parent
are repeated to each child automatically.&lt;/p&gt;

&lt;p&gt;A child queue is created automatically by referring to a queue with a &lt;code&gt;+&lt;/code&gt; in
its name. For example, a queue named &amp;ldquo;orders+audit&amp;rdquo; is considered to be a
child of the &amp;ldquo;orders&amp;rdquo; queue. Once a child is created, it starts receiving new
items immediately, but existing items in the parent are not copied over. (The
child&amp;rsquo;s history begins now.) Fanout stops when a child is &lt;code&gt;DELETE&lt;/code&gt;d.&lt;/p&gt;

&lt;p&gt;Children use the same configuration as their parent, to make things easier.
There&amp;rsquo;s no specific configuration for a child. Also, you can expect fanout
queues to use more disk space and memory, since items are being copied around
muliple times.&lt;/p&gt;

&lt;p&gt;Hopefully the simplicity of the implementation makes it easy to reason about,
which I think is more important than having a lot of clever tricks or magic.&lt;/p&gt;

&lt;p&gt;Kestrel is, as always, hosted here: &lt;strong&gt;&lt;a href=&quot;http://github.com/robey/kestrel&quot;&gt;http://github.com/robey/kestrel&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;
 
        <a href="http://flattr.com/thing/40430/Robey" target="_blank">
        <img src="http://api.flattr.com/button/button-compact-static-100x17.png" alt="Flattr this" title="Flattr this" border="0" />
        </a>
      </content>
    </entry>
  
    <entry>
      <title>Follow-up on Scala on Android</title>
      <link href="http://robey.lag.net/2009/07/19/followup-android.html"/>
      <updated>2009-07-19T00:00:00-07:00</updated>
      <id>http://robey.lag.net/2009/07/19/followup-android</id>
      <content type="html">
        &lt;p&gt;Dan Bornstein had a correction about my guesswork on how dx works, and I got permission to post it
here. I said:&lt;/p&gt;

&lt;blockquote&gt;&lt;p&gt;The end result is a little wasteful: even a tiny &amp;ldquo;hello world&amp;rdquo; app is 800K, probably because of
that big ol&apos; scala library. I suspect dex is proactively throwing away classes that I didn&amp;rsquo;t
use, or it would be even bigger.&lt;/p&gt;&lt;/blockquote&gt;

&lt;p&gt;Dan replies:&lt;/p&gt;

&lt;blockquote&gt;&lt;p&gt;Actually, dx doesn&amp;rsquo;t do any sort of tree-shaking. It&amp;rsquo;s just that I
obsessed over making the dex format compact, and I got a bit of help
on that front from mikef who designed a super-tight encoding for debug
info (line numbers, local variables, etc.).&lt;/p&gt;

&lt;p&gt;An &lt;em&gt;uncompressed&lt;/em&gt; dex file is usually a little smaller (5% or so) than
a corresponding (compressed) jar file, and for distribution a
&lt;em&gt;compressed&lt;/em&gt; dex file is generally about 40-45% the size of &lt;em&gt;that&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;For comparison on the distribution front, a compressed pack200 is
still usually a bit better than a compressed dex file, weighing in at
30-35% of the original compressed jar size, a win which it gets by
translating class files into a compressability-optimized intermediate
format (doing stuff like collating immediate integer constants out of
bytecode streams). The distinction here is that the dex format loses a
bit of compressability, trading that for suitability to be directly
executed.&lt;/p&gt;

&lt;p&gt;We decided that the overhead (both in terms of code and runtime) of
doing something like pack200 wasn&amp;rsquo;t worth it for us, at least not yet,
because most apps don&amp;rsquo;t actually have that much code (much more likely
to be heavy with media), though if people start regularly including
language runtimes with their apps, we may want to revise.&lt;/p&gt;

&lt;p&gt;Oh, a much more minor tidbit: You can pass dx options for the
underlying JVM by prefixing them with &amp;ldquo;-J&amp;rdquo;, e.g. &amp;ldquo;-JXmx2000m&amp;rdquo; or
what-have-you.&lt;/p&gt;&lt;/blockquote&gt;
 
        <a href="http://flattr.com/thing/40430/Robey" target="_blank">
        <img src="http://api.flattr.com/button/button-compact-static-100x17.png" alt="Flattr this" title="Flattr this" border="0" />
        </a>
      </content>
    </entry>
  
    <entry>
      <title>Actors talk for SDForum</title>
      <link href="http://robey.lag.net/2009/06/25/actors-talk.html"/>
      <updated>2009-06-25T00:00:00-07:00</updated>
      <id>http://robey.lag.net/2009/06/25/actors-talk</id>
      <content type="html">
        &lt;p&gt;Last night I got to give a
&lt;a href=&quot;http://sdforum.org/index.cfm?fuseaction=Calendar.eventDetail&amp;amp;eventID=13413&quot;&gt;short talk at SDForum&lt;/a&gt;
on &amp;ldquo;solving real problems with actors&amp;rdquo;, or more
specifically, why I got interested in using scala actors, how they&amp;rsquo;re used in naggati and kestrel,
and what I learned about where they&amp;rsquo;re useful and not. It was fun, even though I was a little
nervous &amp;ndash; they had me speaking after Carl Hewitt, one of the instigators of the actor model,
and Frank Sommers, who&amp;rsquo;s writing a book about actors in scala.&lt;/p&gt;

&lt;p&gt;Here are the slides:
&lt;a href=&quot;http://robey.lag.net/docs/robey-actors-sdforum.pdf&quot;&gt;http://robey.lag.net/docs/robey-actors-sdforum.pdf&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Thanks to everyone who came, and everyone who chatted afterwards! It was worth the drive. :)&lt;/p&gt;
 
        <a href="http://flattr.com/thing/40430/Robey" target="_blank">
        <img src="http://api.flattr.com/button/button-compact-static-100x17.png" alt="Flattr this" title="Flattr this" border="0" />
        </a>
      </content>
    </entry>
  
    <entry>
      <title>Performance bug in kestrel 1.1</title>
      <link href="http://robey.lag.net/2009/05/18/kestrel-bug.html"/>
      <updated>2009-05-18T00:00:00-07:00</updated>
      <id>http://robey.lag.net/2009/05/18/kestrel-bug</id>
      <content type="html">
        &lt;p&gt;If you&amp;rsquo;re using (or have tried to use) kestrel 1.1, you should upgrade to 1.1.1
(&lt;a href=&quot;http://github.com/robey/kestrel/tree/master&quot;&gt;in github&lt;/a&gt;) for a performance fix.&lt;/p&gt;

&lt;p&gt;Kestrel uses &lt;a href=&quot;http://github.com/robey/naggati/tree/master&quot;&gt;naggati&lt;/a&gt;, an actor-adapter for
&lt;a href=&quot;http://mina.apache.org/&quot;&gt;mina&lt;/a&gt;, to handle I/O and session management. Mina is a java library
for handling thousands of open connections across NIO, and naggati converts mina events from
java-style &amp;ldquo;listener method calls&amp;rdquo; to actor messages. I wrote all about mina &amp;amp; naggati in
&lt;a href=&quot;http://robey.lag.net/2009/03/02/actors-mina-and-naggati.html&quot;&gt;another article&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;One feature added to naggati 0.6 was the ability to filter out mina events you didn&amp;rsquo;t care about. So
if, for example, you didn&amp;rsquo;t care to receive an event message every time mina finished transmitting a
block of data, you could filter out those messages:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;IoHandlerActorAdapter.filter(session) -= classOf[MinaMessage.MessageSent]
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Potentially this saves you a lot of unwanted actor messages that you&amp;rsquo;d just ignore anyway, causing
fewer context switches. If the feature works correctly&amp;hellip; aye, there&amp;rsquo;s the rub.&lt;/p&gt;

&lt;p&gt;Naggati 0.6 would accidentally overwrite any filter changes that happened during an actor&amp;rsquo;s
constructor. Kestrel&amp;rsquo;s session actors changed their filters in the constructor, and so their filter
changes were lost. This caused kestrel actors to receive reams of unwanted messages like
&lt;code&gt;MessageSent&lt;/code&gt;, which by itself would only be a minor annoyance, and would have the same performance
behavior as kestrel 1.0.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;But&lt;/em&gt;, in actors, if you don&amp;rsquo;t pattern match on a message type, and you receive a message of that
type, the message just sits in your queue forever. Long-lived connections would eventually have
thousands of these unwanted &lt;code&gt;MessageSent&lt;/code&gt; messages, which had to be &lt;em&gt;linearly&lt;/em&gt; traversed to get to
interesting messages. Scanning this queue on every I/O event eventually slowed down a long-lived
session to a crawl &amp;ndash; and it consumed memory in the process.&lt;/p&gt;

&lt;p&gt;This bug is now fixed in naggati 0.7 and kestrel 1.1.1. Kudos to John Kalucki, who found the bug
during his own stress tests and persevered when I couldn&amp;rsquo;t reproduce it myself.&lt;/p&gt;
 
        <a href="http://flattr.com/thing/40430/Robey" target="_blank">
        <img src="http://api.flattr.com/button/button-compact-static-100x17.png" alt="Flattr this" title="Flattr this" border="0" />
        </a>
      </content>
    </entry>
  
    <entry>
      <title>Sidekick LX party</title>
      <link href="http://robey.lag.net/2009/05/15/sidekick-lx.html"/>
      <updated>2009-05-15T00:00:00-07:00</updated>
      <id>http://robey.lag.net/2009/05/15/sidekick-lx</id>
      <content type="html">
        &lt;p&gt;When Nick, Evan and I stumbled out of &amp;ldquo;Star Trek&amp;rdquo; at the Metreon last night, it was 1am. Nick
announced that there was some kind of party at the Mezzanine, and Jack was there, but it seemed
pretty late, and my iPhone said there was a final bart train in 10 minutes, so I decided to clock
out and go home. Nick and Evan went on to the club.&lt;/p&gt;

&lt;p&gt;All 4 bart entrances on Market around Powell were gated up, though. (How exactly is one supposed to
take the last bart train?) So I texted back that I was coming anyway and went to the Mezzanine in
Mint Plaza. The place was set up like an LA bar in decline, with bouncers and a bunch of signs
celebrating the &amp;ldquo;Sidekick LX&amp;rdquo;, which is apparently the name of the final Sidekick. I wasn&amp;rsquo;t sure I
was at the right place and had to text Nick a bit before I decided to go in.&lt;/p&gt;

&lt;p&gt;It was packed, even at 1am. There was no cover and it was an open bar filled with all kinds of
kitchy decorations to celebrate the launch of Danger&amp;rsquo;s final phone in some sort of fake
Metropolis-slash-amalgamation of all American cities (plus an English phone booth). One of the first
things I witnessed was a set of fake &amp;ldquo;telephone poles&amp;rdquo; fall on top of partiers, light bulbs tinkling
under our feet. I immediately took this as a metaphor for Danger.&lt;/p&gt;

&lt;p&gt;There were no other Danger people there, and a very buxom woman wearing a Sidekick LX shirt wasn&amp;rsquo;t
even sure what Danger might be. But never mind, the drinks were free, and DJ Jazzy Jeff was on
stage. Another guy was &amp;ldquo;MC&quot;ing, which appeared to mean that for several hours he had to walk around
on stage shouting &quot;What! What! DJ Jazzy Jeff in the house! Say what! Yeaaaaah!&amp;rdquo;&lt;/p&gt;

&lt;p&gt;Everyone in the audience was taking pictures of each other and texting &amp;ndash; using blackberries and
iPhones. The only Sidekick I saw anywhere was in the hands of a drunk T-Mobile rep. But Twitter was
represented! A looping movie behind the &amp;ldquo;MC&amp;rdquo; showed a bird flying around, and a Sidekick that opened
up to reveal 3 apps: Facebook, Myspace (?!), and Twitter. Neet! Jack teased me a few times about the
work I&amp;rsquo;d put into making a push-notification service for the Sidekick, which they were too
disorganized to make use of for six months until we finally just threw the code away. I think the
current Sidekick Twitter app just uses the same polling API as everyone else. Not a metaphor: That&amp;rsquo;s
a good example of how poor Danger&amp;rsquo;s follow-through was.&lt;/p&gt;

&lt;p&gt;This all could very well have been a dream or nightmare, or both combined. Certainly an event that
combines Twitter, Danger, DJ Jazzy Jeff, and free drinks sounds highly improbable. But I must report
it as I remember it, because that is the only way I know how.&lt;/p&gt;
 
        <a href="http://flattr.com/thing/40430/Robey" target="_blank">
        <img src="http://api.flattr.com/button/button-compact-static-100x17.png" alt="Flattr this" title="Flattr this" border="0" />
        </a>
      </content>
    </entry>
  
    <entry>
      <title>Does anyone actually use JMX?</title>
      <link href="http://robey.lag.net/2009/03/29/anyone-use-jmx.html"/>
      <updated>2009-03-29T00:00:00-07:00</updated>
      <id>http://robey.lag.net/2009/03/29/anyone-use-jmx</id>
      <content type="html">
        &lt;p&gt;In java 5 update 6, or 1.5.0_06, or whatever goofy release naming scheme
they&amp;rsquo;re using now, there&amp;rsquo;s a cool replacement for jconsole called &amp;ldquo;visualvm&amp;rdquo;.
(On my mac, it didn&amp;rsquo;t come with the installed java, but it can easily be
&lt;a href=&quot;https://visualvm.dev.java.net/&quot;&gt;downloaded&lt;/a&gt;.) It cleans up jconsole a
little bit, and merges in some of the other tools. You can monitor, take heap
snapshots, and even do an extremely skeletal form of profiling.&lt;/p&gt;

&lt;p&gt;We were tinkering with hooking up some of our servers&apos; stats to monitoring
tools by exposing them as &amp;ldquo;mbeans&amp;rdquo; across JMX (Java Management Xtreme), and
someone suggested that it would be nice if the server&amp;rsquo;s configuration could be
viewed and edited through the same console interface. So during some of the
more lucid moments of my two-week-long cold, I tried hooking up a JMX
interface to &lt;a href=&quot;http://github.com/robey/configgy/&quot;&gt;configgy&lt;/a&gt; to do just that.&lt;/p&gt;

&lt;p&gt;It hasn&amp;rsquo;t gone extremely well.&lt;/p&gt;

&lt;p&gt;Java &amp;ndash; and JMX in particular &amp;ndash; has reams of documentation, but most of it
assumes you are a drooling infant or recent PHP convert. Quite a lot of it
assumes you want to write your own replacement for jconsole or visualvm. Very
little of it is written for someone who may just want to hook up management
tools to an existing app or server. This seems strange when java is used so
heavily for servers.&lt;/p&gt;

&lt;p&gt;I finally figured out that the best interface for a tree of config nodes was
to create a tree of &lt;code&gt;DynamicMBean&lt;/code&gt; objects which report their attributes as
being the attributes on the config node. This works pretty well. The interface
through visualvm won&amp;rsquo;t win any awards (and would make a UX person weep openly)
but functions basically the way you expect and lets you discover and edit
things in a straightforward way.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/images/configgy-jmx.png&quot; alt=&quot;not bad, for java&quot; /&gt;&lt;/p&gt;

&lt;p&gt;The fatal flaw in the UI is that if you add a new config item, visualvm
doesn&amp;rsquo;t update the display tab to show the new attribute. (Jconsole behaves
similarly.) At some level, it does appear to know to re-fetch the &amp;ldquo;mbeans&amp;rdquo; for
the config tree, because I can see it doing that in the debugger. But it
doesn&amp;rsquo;t use this information to update the display.&lt;/p&gt;

&lt;p&gt;Looks like I have 2 options:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;Register &amp;ldquo;mbeans&amp;rdquo; as the config nodes, and just live with the fact that
they won&amp;rsquo;t be updated for new attributes. If you add a new attribute,
you&amp;rsquo;ll have to disconnect visualvm and reconnect it to see everything.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Any time any config attribute changes, unregister and re-register the
&amp;ldquo;mbeans&amp;rdquo; for config nodes. This makes visualvm destroy all open tabs to
config nodes and rebuild the tree of config nodes in the left panel. You
have to open the nodes back up to see the changes.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;


&lt;p&gt;For now, I&amp;rsquo;m leaning toward #1 but both options make me sad. The punchline is
this article I found while searching around on google, since I was convinced I
must be doing it wrong:&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;http://forums.sun.com/thread.jspa?threadID=5218394&quot;&gt;http://forums.sun.com/thread.jspa?threadID=5218394&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The thread summary seems to be: &amp;ldquo;We have documented a way for dynamic &amp;lsquo;mbeans&amp;rsquo;
to indicate that their attributes may change. We did not code our own tools to
follow our own documentation so no existing tool uses this hint. Has our
incompetence convinced you that you really want to do what you want to do, or
are you eyeing that python book with a bit more interest now?&amp;rdquo;&lt;/p&gt;

&lt;p&gt;Is there anyone out there that actually uses JMX for real?&lt;/p&gt;
 
        <a href="http://flattr.com/thing/40430/Robey" target="_blank">
        <img src="http://api.flattr.com/button/button-compact-static-100x17.png" alt="Flattr this" title="Flattr this" border="0" />
        </a>
      </content>
    </entry>
  
    <entry>
      <title>Actors, Mina, and Naggati</title>
      <link href="http://robey.lag.net/2009/03/02/actors-mina-and-naggati.html"/>
      <updated>2009-03-02T00:00:00-08:00</updated>
      <id>http://robey.lag.net/2009/03/02/actors-mina-and-naggati</id>
      <content type="html">
        &lt;p&gt;A few weeks ago, Jorge Ortiz gave a good talk at BASE about actors. I want to
summarize a bit of that and explain why I wrote naggati, and why I think
mina-plus-actors is a big deal.&lt;/p&gt;

&lt;h2&gt;The history&lt;/h2&gt;

&lt;p&gt;In the 90s, we server coders wrote daemons using the fork/exec process model.
Apache still does it this way, though you can switch to threaded models in the
current version.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/images/naggati1.png&quot; alt=&quot;fork/exec model&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Having a bunch of processes makes coordination difficult (you have to use
shared memory, pipes, or something similar) but works well for a web server
where there isn&amp;rsquo;t really any shared state except configuration, and you can
just respawn new processes if the configuration changes.&lt;/p&gt;

&lt;p&gt;For a chat server, you&amp;rsquo;d like a lot of shared state and communication between
the various sessions. So in the late 90s (early 2000s on Linux), we started
using threads. Each incoming connection spawns a new thread.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/images/naggati2.png&quot; alt=&quot;each session gets its own thread&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Each session is exactly one thread. Because threads all share the same memory
space, communication between sessions is easy. You just have to make sure to
use locks and condition variables, and to get the locking logic right &amp;ndash; which
can be tricky.&lt;/p&gt;

&lt;p&gt;When you start to have a lot of sessions, the number of active threads begins
to get a little unmanagable. At a past job, we had a daemon that would handle
between 3000-4000 sessions this way. We couldn&amp;rsquo;t push it past that, because
the OS wasn&amp;rsquo;t able to allocate stack space for more than about 4000 threads,
and the task switching overhead was getting pretty ridiculous anyway.&lt;/p&gt;

&lt;p&gt;Most sessions are blocked waiting for new data most of the time, so in the
mid-2000s, server coders migrated to a thread-pool model.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/images/naggati3.png&quot; alt=&quot;thread pool&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Java even included a good thread pool library in java 5. In this model, you
can have thousands of open sessions or socket connections, but you farm out
work across a smaller pool of threads. Usually you have one or two threads in
a socket &lt;code&gt;poll()&lt;/code&gt; call (or &lt;code&gt;Selector&lt;/code&gt; in java) across all the open sockets,
and when incoming data arrives, it posts a work item into a queue, which gets
handled by the next available thread from the pool.&lt;/p&gt;

&lt;h2&gt;Here&amp;rsquo;s where mina comes in&lt;/h2&gt;

&lt;p&gt;&lt;a href=&quot;http://mina.apache.org/&quot;&gt;Mina&lt;/a&gt; takes this thread-pool pattern and pulls it
out into a reusable library. You can register a socket with mina and get an
&lt;code&gt;IoSession&lt;/code&gt; object back. There&amp;rsquo;s a &lt;code&gt;Selector&lt;/code&gt; running in its own thread, and
when an I/O event happens on one of your registered sockets, mina calls an
event method on your &lt;code&gt;IoHandler&lt;/code&gt;, passing in the &lt;code&gt;IoSession&lt;/code&gt;. These methods
represent events like &amp;ldquo;new data has arrived&amp;rdquo; or &amp;ldquo;some data you sent has been
successfully transmitted&amp;rdquo;, and they are called from within a thread pool, or
other executor of your choosing.&lt;/p&gt;

&lt;p&gt;The great thing mina adds to this mix is the idea of a &amp;ldquo;protocol decoder&amp;rdquo;.
Instead of handling I/O events in your session and doing stateful buffering
and protocol decoding there, mina lets you write a &lt;code&gt;ProtocolFilter&lt;/code&gt; that
receives incoming data as a byte buffer. This filter can do the buffering and
decoding, and pass decoded objects on to the session. For example, a web
server could have a decoder that takes byte buffers and generates
&lt;code&gt;HttpRequest&lt;/code&gt;s.&lt;/p&gt;

&lt;p&gt;The protocol decoding happens in a special set of I/O processor threads
maintained by the mina library, so your &lt;code&gt;IoHandler&lt;/code&gt; only gets events for fully
decoded objects, and the handler code can be small and simple. In the web
server example, an &lt;code&gt;IoHandler&lt;/code&gt; would receive &lt;code&gt;HttpRequest&lt;/code&gt; objects as events
that run in a worker thread from a thread pool. The repsonse can be created
and queued for writing, and then the event is over. Since the queued work
items are small, discrete tasks that finish quickly, many active sessions can
be handled across a much smaller number of threads.&lt;/p&gt;

&lt;p&gt;There are only two big speedbumps with this system:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;You&amp;rsquo;re using threads, so you need to be very careful about locking and all
the other threading issues.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;The protocol decoder is isolated into its own filter class, but it still
has to be stateful and buffered. So it will still be ugly and gnarly.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;


&lt;h2&gt;Enter actors&amp;hellip;&lt;/h2&gt;

&lt;p&gt;Actors solve problem 1. There are
&lt;a href=&quot;http://www.stanford.edu/class/cs94si/Concurrency.pdf&quot;&gt;several&lt;/a&gt;
&lt;a href=&quot;http://www.scala-lang.org/node/242&quot;&gt;good&lt;/a&gt;
&lt;a href=&quot;http://java.dzone.com/articles/scala-threadless-concurrent&quot;&gt;articles&lt;/a&gt; about
actors out there, so I won&amp;rsquo;t belabor the point. With actors, you can write
code in a way similar to writing threaded code, but all communication happens
through message passing. The actor library promises that any actor will only
be running in one thread at a time, so you can avoid using locks entirely if
you want. Shared state can be passed around as &amp;ldquo;messages&amp;rdquo; that are immutable
objects.&lt;/p&gt;

&lt;p&gt;There&amp;rsquo;s a pretty clear one-to-one mapping between the events that mina would
like to notify you about, and messages passed to an actor. It&amp;rsquo;s
straightforward enough that I put it into naggati as a helper class called
&lt;a href=&quot;http://github.com/robey/naggati/blob/7e9236bd6c5e7646afc6def397b034c7b5ce3a85/src/main/scala/net/lag/naggati/IoHandlerActorAdapter.scala&quot;&gt;IoHandlerActorAdapter&lt;/a&gt;.
It creates an &lt;code&gt;IoHandler&lt;/code&gt; that handles every event by sending a corresponding
message to the actor handling that session. (For example, the
&lt;code&gt;messageReceived&lt;/code&gt; method causes &lt;code&gt;MinaMessage.MessageReceived&lt;/code&gt; to be sent.)&lt;/p&gt;

&lt;p&gt;This line in kestrel is all that&amp;rsquo;s needed to tell mina to create a new actor
for each incoming connection:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;acceptor.setHandler(new IoHandlerActorAdapter(session =&amp;gt; new KestrelHandler(session, config)))
&lt;/code&gt;&lt;/pre&gt;

&lt;h2&gt;&amp;hellip;and naggati&lt;/h2&gt;

&lt;p&gt;Mina&amp;rsquo;s written in java, so they can&amp;rsquo;t do much about the way protocol filters
need to be written, beyond giving you some tools to store state between calls
and some base classes you can use to get implementations of some common bits
(like reading a line). But scala&amp;rsquo;s syntax supports attaching code blocks to
method calls as &lt;code&gt;Function&lt;/code&gt; objects, so we can write code that looks sequential
but is actually a series of continuations.&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;http://github.com/robey/naggati/&quot;&gt;Naggati&lt;/a&gt; is a library that makes it easy to
build protocol filters for mina 2.0 using this sequential style. A DSL allows
you to write the decoder in sequence, but each decoding step is actually a
state in a state machine, and when one step is finished decoding, it calls the
code block for the next step.&lt;/p&gt;

&lt;p&gt;As an example, let&amp;rsquo;s say there&amp;rsquo;s a simple protocol that sends packets. Each
packet starts with an (ascii) count of the number of bytes in the packet,
followed by a linefeed, and then the actual bytes. (This is how HTTP chunked
encoding works.) We could write the decoder like this:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;case class DataBlob(data: Array[Byte])

val decode = readLine { line =&amp;gt;
  readByteBuffer(line.toInt) { data =&amp;gt;
    state.out.write(DataBlob(data))
    End
  }
}
val decoder = new Decoder(decode)
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;The first line just defines a case class for the decoded objects we&amp;rsquo;re going
to be throwing to an actor inside a &lt;code&gt;MinaMessage.MessageReceived&lt;/code&gt; event.&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;decode&lt;/code&gt; step is where it gets interesting. It just calls &lt;code&gt;readLine&lt;/code&gt; with
a block of code that will process that line when it&amp;rsquo;s read. &lt;code&gt;readLine&lt;/code&gt; returns
a &lt;code&gt;Step&lt;/code&gt; object that contains that code block and some logic for reading bytes
from mina&amp;rsquo;s buffers until a linefeed is found. Once a complete line has been
read, &lt;code&gt;readLine&lt;/code&gt; passes it to the saved code block.&lt;/p&gt;

&lt;p&gt;In this example, that code block just contains another call (&lt;code&gt;readByteBuffer&lt;/code&gt;)
which returns a &lt;code&gt;Step&lt;/code&gt; that reads a certain number of bytes and then passes
them on to the attached code block. The nested code block takes that byte
array and sends it back to mina as a decoded object, to be handed off to a
session actor. &lt;code&gt;End&lt;/code&gt; is a special state object that means decoding is
complete, and the decoder should reset and start over at the beginning again.&lt;/p&gt;

&lt;p&gt;We&amp;rsquo;ve written a tiny state machine here, which buffers data as it arrives and
progresses through each state as the previous state is completed.
&lt;em&gt;But we didn&amp;rsquo;t have to write it that way&lt;/em&gt;. By passing code blocks around, we
got to write a very simple, sequential description of the protocol without
worrying about callbacks or buffers.&lt;/p&gt;

&lt;p&gt;There are a couple of more in-depth examples in the naggati source code,
including an ASN.1 tag decoder, and a simple HTTP request decoder. They&amp;rsquo;re too
long to quote here, but they demonstrate things like using a value from one
decoded state to help decode a later state. Kestrel is another good example,
because it uses nagatti to decode memcache requests in a pretty small chunk of
code.&lt;/p&gt;

&lt;p&gt;With actors, mina, and naggati, I think the promise of a simple programming
model for servers with thousands of connections is here. You can spend your
time thinking about and coding up the actual logic of a server, and not worry
so much about how to juggle all those sockets and threads.&lt;/p&gt;

&lt;p&gt;Hopefully in this tiny space I&amp;rsquo;ve convinced you too.&lt;/p&gt;
 
        <a href="http://flattr.com/thing/40430/Robey" target="_blank">
        <img src="http://api.flattr.com/button/button-compact-static-100x17.png" alt="Flattr this" title="Flattr this" border="0" />
        </a>
      </content>
    </entry>
  
    <entry>
      <title>Paramiko is on github now</title>
      <link href="http://robey.lag.net/2009/02/16/paramiko-is-on-github-now.html"/>
      <updated>2009-02-16T00:00:00-08:00</updated>
      <id>http://robey.lag.net/2009/02/16/paramiko-is-on-github-now</id>
      <content type="html">
        &lt;h2&gt;A story&lt;/h2&gt;

&lt;p&gt;A few years ago, at Danger, I wrote an SSH client for the Hiptop (or Sidekick)
phone, which we gave away to developers for free as a demonstration of our API
and the cool things you could do with it. Later, the developer program would
be effectively shut down, and the app would be renamed &amp;ldquo;Terminal Client&amp;rdquo; and
sold to hapless users for $10. But I didn&amp;rsquo;t know that yet.&lt;/p&gt;

&lt;p&gt;The protocol implementation was awful. SSH protocol &amp;ldquo;documentation&amp;rdquo; was just a
handful of poorly written RFC drafts that described things in seemingly random
order. I hacked on some java code until I got it mostly functioning and
left it at that. But it was so buggy and bare-bones that it often would only
connect to certain OpenSSH daemon versions, and this eventually bothered me
enough that I wanted to fix it.&lt;/p&gt;

&lt;p&gt;Python was my favorite language at the time. The syntax is so simple and clean
that I feel like I&amp;rsquo;m writing in pseudocode. It&amp;rsquo;s a very close match to &amp;ldquo;the
way I think&amp;rdquo; when I&amp;rsquo;m trying to solve a problem, so there&amp;rsquo;s a very low
impedance between what I think and what I type. If I&amp;rsquo;m trying to sketch out a
rough draft of code, I usually do it in python as a prototype. And since the
SSH protocol seemed like a difficult problem to me, I decided I should try to
write an SSH library in python, as a prototype for doing it in java.&lt;/p&gt;

&lt;p&gt;The basic idea was to use a thread to handle the protocol level of the socket,
so that SSH&amp;rsquo;s packet windowing requests would get immediate responses, and
supply an API to the client that looked just like a normal python file. Data
should arrive, get handled by the protocol thread, and stuffed into a buffer
so that a client &lt;code&gt;read&lt;/code&gt; could get it. The &lt;code&gt;read&lt;/code&gt; would trigger window feedback
to the server, but the client could go do other stuff while waiting for data.&lt;/p&gt;

&lt;p&gt;It worked beautifully. I called it &lt;a href=&quot;http://www.lag.net/paramiko&quot;&gt;paramiko&lt;/a&gt; as
a dorky esperanto pun and released it, and after a while, to my moderate
surprise, people were using it. I didn&amp;rsquo;t really anticipate that it would be
useful for automating tasks for working with server machines and clusters,
though it&amp;rsquo;s kind of obvious in retrospect.&lt;/p&gt;

&lt;p&gt;Python&amp;rsquo;s thread model (the dreaded Global Interpreter Lock) isn&amp;rsquo;t awesome, but
when threads are mostly blocked on I/O, they&amp;rsquo;re good enough. The
&lt;a href=&quot;http://bazaar-vcs.org/bazaar&quot;&gt;bazaar&lt;/a&gt; team obsessed about performance, and
helped find and solve some real bottlenecks, so that in the end, paramiko was
slower than OpenSSH, but not by much.&lt;/p&gt;

&lt;p&gt;Over time, the feature set exploded. Now it can be an SSH client or server, or
an SFTP client or server, and has a few experimental SFTP features and a few
made-up ones (just to see if they were useful). I wanted to try writing a
standalone SFTP server based on it, for making little file-server sandboxes,
but&amp;hellip; I only have so much free time. :)&lt;/p&gt;

&lt;p&gt;I did end up using what I learned to write &amp;ldquo;jaramiko&amp;rdquo;, a java library for SSH,
and used that in later releases of the Sidekick SSH client, but it was never
really as powerful or successful as paramiko. In retrospect, it&amp;rsquo;s obvious why:
Java is not even remotely as expressive or concise as python, so most of the
java code is boilerplate that obscures the real logic. It&amp;rsquo;s hard to keep
up-to-date and maintain, much less add new features to.&lt;/p&gt;

&lt;h2&gt;What now?&lt;/h2&gt;

&lt;p&gt;I haven&amp;rsquo;t made a new release of paramiko since July. It feels like even longer
than that. Really, to me, the library is finished. I&amp;rsquo;d like to fix any
remaining bugs in it, but I don&amp;rsquo;t get many bug reports any more, and most of
the mailing list support questions are answered by other users.&lt;/p&gt;

&lt;p&gt;I don&amp;rsquo;t want the project to die. I just have to admit to myself that I&amp;rsquo;m not
really taking a leading role in it anymore. So I&amp;rsquo;ve migrated the repository to
git and put it on github here:
&lt;a href=&quot;github.com/robey/paramiko&quot;&gt;github.com/robey/paramiko&lt;/a&gt; Anyone can fork it
there and submit patches, and I&amp;rsquo;ll make regular releases as long as there are
still bugs to fix, or new features that look cool.&lt;/p&gt;

&lt;p&gt;Why git? I like bazaar better (see some previous rants on this blog) but the
rest of the world has chosen git, and I don&amp;rsquo;t have the energy to keep fighting
that fight. It&amp;rsquo;s also easier for me if I can use the same VCS everywhere.
Keeping the project on github, in front of my face, will make it less likely
to bitrot. At least, that&amp;rsquo;s my hope.&lt;/p&gt;
 
        <a href="http://flattr.com/thing/40430/Robey" target="_blank">
        <img src="http://api.flattr.com/button/button-compact-static-100x17.png" alt="Flattr this" title="Flattr this" border="0" />
        </a>
      </content>
    </entry>
  
    <entry>
      <title>Scala on Android</title>
      <link href="http://robey.lag.net/2009/01/19/scala-on-android.html"/>
      <updated>2009-01-19T00:00:00-08:00</updated>
      <id>http://robey.lag.net/2009/01/19/scala-on-android</id>
      <content type="html">
        &lt;p&gt;Chris DiBona gave me a free G-phone after an open-source talk last week
(thanks!) with the admonishment that I write an app for it. I&amp;rsquo;m going to give
it an effort, at least!&lt;/p&gt;

&lt;p&gt;My first task was to figure out the scala-android build process, because that
will make coding much easier. Turns out to be easier than the instructions I
found online, so I thought I&amp;rsquo;d share.&lt;/p&gt;

&lt;p&gt;You don&amp;rsquo;t have to use Eclipse like the instructions say. You can use the ant
build file, but you have to modify it to find and compile using the scala
compiler.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;First&lt;/em&gt;, copy &lt;strong&gt;&lt;code&gt;scala-compiler.jar&lt;/code&gt;&lt;/strong&gt; and &lt;strong&gt;&lt;code&gt;scala-library.jar&lt;/code&gt;&lt;/strong&gt; out from
your scala-home and into your android project folder. Since the compiler is
only needed for building, and the library is the only one you&amp;rsquo;ll need
installed, I made a folder for the compiler and put the library in &lt;strong&gt;&lt;code&gt;libs/&lt;/code&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;$ mkdir scala-compiler
$ cp $SCALA_HOME/lib/scala-compiler.jar scala-compiler/
$ cp $SCALA_HOME/lib/scala-library.jar libs/
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;&lt;em&gt;Second&lt;/em&gt;, edit &lt;strong&gt;&lt;code&gt;build.xml&lt;/code&gt;&lt;/strong&gt; and change the compile task to look like this:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;&amp;lt;target name=&quot;compile&quot; depends=&quot;dirs, resource-src, aidl&quot;&amp;gt;
    &amp;lt;javac encoding=&quot;ascii&quot; target=&quot;1.5&quot; debug=&quot;true&quot; extdirs=&quot;&quot;
           srcdir=&quot;${srcdir}&quot; includes=&quot;**/*.java&quot;
           destdir=&quot;${outdir-classes}&quot;
           bootclasspath=&quot;${android-jar}&quot;&amp;gt;
        &amp;lt;classpath&amp;gt;
            &amp;lt;fileset dir=&quot;${external-libs}&quot; includes=&quot;*.jar&quot;/&amp;gt;
        &amp;lt;/classpath&amp;gt;
    &amp;lt;/javac&amp;gt;

    &amp;lt;taskdef resource=&quot;scala/tools/ant/antlib.xml&quot;
             classpath=&quot;scala-compiler/scala-compiler.jar:${external-libs-ospath}/scala-library.jar&quot; /&amp;gt;
    &amp;lt;scalac force=&quot;changed&quot; deprecation=&quot;on&quot;
            srcdir=&quot;${srcdir}&quot; includes=&quot;**/*.scala&quot;
            destdir=&quot;${outdir-classes}&quot;
            bootclasspath=&quot;${android-jar}&quot;&amp;gt;
        &amp;lt;classpath&amp;gt;
            &amp;lt;fileset dir=&quot;${external-libs}&quot; includes=&quot;*.jar&quot;/&amp;gt;
        &amp;lt;/classpath&amp;gt;
    &amp;lt;/scalac&amp;gt;
&amp;lt;/target&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;&lt;em&gt;Third,&lt;/em&gt; you need to edit &lt;strong&gt;&lt;code&gt;dx&lt;/code&gt;&lt;/strong&gt; from the android toolkit so that it gets
lots of memory. Uncomment the line with the java heap option and give it a
&lt;em&gt;lot&lt;/em&gt; of memory, like 512MB (&lt;strong&gt;&lt;code&gt;&quot;-Xmx=512m&quot;&lt;/code&gt;&lt;/strong&gt;). It needs this because dex is
going to convert the entire scala library into dalvik. Without a lot of
memory, it will run out of heap space.&lt;/p&gt;

&lt;p&gt;The end result is a little wasteful: even a tiny &amp;ldquo;hello world&amp;rdquo; app is 800K,
probably because of that big ol&apos; scala library. I suspect dex is proactively
throwing away classes that I didn&amp;rsquo;t use, or it would be even bigger.&lt;/p&gt;
 
        <a href="http://flattr.com/thing/40430/Robey" target="_blank">
        <img src="http://api.flattr.com/button/button-compact-static-100x17.png" alt="Flattr this" title="Flattr this" border="0" />
        </a>
      </content>
    </entry>
  
    <entry>
      <title>Java SE6 on Leopard</title>
      <link href="http://robey.lag.net/2008/12/01/java-se6-on-leopard.html"/>
      <updated>2008-12-01T00:00:00-08:00</updated>
      <id>http://robey.lag.net/2008/12/01/java-se6-on-leopard</id>
      <content type="html">
        &lt;p&gt;I could not find this anywhere on google in one place, but I pieced it
together from clues Steve found by poring over a half dozen other blogs.&lt;/p&gt;

&lt;p&gt;To get Java 6 to run on Leopard, you must go into
&lt;strong&gt;&lt;code&gt;/System/Library/Frameworks/JavaVM.framework/Versions&lt;/code&gt;&lt;/strong&gt; and blow away the
&lt;strong&gt;&lt;code&gt;Current&lt;/code&gt;&lt;/strong&gt; and &lt;strong&gt;&lt;code&gt;CurrentJDK&lt;/code&gt;&lt;/strong&gt; symlinks. Make them point to &lt;strong&gt;&lt;code&gt;A&lt;/code&gt;&lt;/strong&gt;:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;$ sudo rm Current CurrentJDK
$ sudo ln -s A Current
$ sudo ln -s A CurrentJDK
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Now launch the &lt;strong&gt;Java Preferences&lt;/strong&gt; app and move the JDK order to the way you
want it.&lt;/p&gt;

&lt;p&gt;Setting the symlinks manually to 1.5 or 1.6 will make text apps work, but
jconsole will blow chunks. It seems like the &lt;strong&gt;Java Preferences&lt;/strong&gt; app changes
&amp;ldquo;what&amp;rsquo;s in &lt;strong&gt;&lt;code&gt;A&lt;/code&gt;&lt;/strong&gt;&amp;rdquo; and then the symlinks make that work.&lt;/p&gt;

&lt;p&gt;If you have the symlinks set up in the pre-Leopard way, the prefs app won&amp;rsquo;t
fix them.&lt;/p&gt;

&lt;p&gt;Sigh. Apple.&lt;/p&gt;
 
        <a href="http://flattr.com/thing/40430/Robey" target="_blank">
        <img src="http://api.flattr.com/button/button-compact-static-100x17.png" alt="Flattr this" title="Flattr this" border="0" />
        </a>
      </content>
    </entry>
  
    <entry>
      <title>Scarling &#187; Kestrel</title>
      <link href="http://robey.lag.net/2008/11/27/scarling-to-kestrel.html"/>
      <updated>2008-11-27T00:00:00-08:00</updated>
      <id>http://robey.lag.net/2008/11/27/scarling-to-kestrel</id>
      <content type="html">
        &lt;p&gt;Ever since we deployed scarling in production, its name has progressed from
being a stale joke to an annoyance. It started out as a test of porting
starling to scala, but as features have been added and it&amp;rsquo;s been hardened by
the real world, it has needed its own identity. I wanted to stay with the bird
theme, because I think it&amp;rsquo;s cute, so after spending several days mulling over
possible new names, I&amp;rsquo;ve settled on &amp;ldquo;kestrel&amp;rdquo;.&lt;/p&gt;

&lt;p&gt;Poof! And so it is. What was scarling is now kestrel. I&amp;rsquo;ve updated the code
and github page:
&lt;a href=&quot;http://github.com/robey/kestrel/&quot;&gt;http://github.com/robey/kestrel/&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Meanwhile, over the last couple of weeks, I&amp;rsquo;ve added three big features.&lt;/p&gt;

&lt;h2&gt;Big Queues&lt;/h2&gt;

&lt;p&gt;One of the working assumptions of kestrel is that queues are normally empty. A
healthy system has more consumers than producers, so new work items are
gobbled up as fast as they come in, and we can usually keep all queued items
in memory, for the rare times there are any items queued at all.&lt;/p&gt;

&lt;p&gt;However, you may have an event &amp;ndash; like a realigning US presidential election
&amp;ndash; which causes brief &amp;ldquo;high traffic&amp;rdquo; bursts that temporarily overwhelm
consumers. It became clear at Twitter that we needed to have a graceful
soft-landing for these bursts, to prevent kestrel from running out of memory
or needing manual intervention.&lt;/p&gt;

&lt;p&gt;In kestrel&amp;rsquo;s git-head, now, when a queue passes a memory limit (128MB by
default), that queue will be dropped into what I call &amp;ldquo;read-behind mode&amp;rdquo;. New
items are added to the queue by writing them into the queue&amp;rsquo;s journal, but not
kept around in memory. Instead, we just keep the first 128MB of the queue head
in memory, and track a second file pointer to our journal. As items are read
from the queue, this new file pointer replays the journal from behind, filling
the queue back up until it either catches up with the write pointer or fills
up 128MB again.&lt;/p&gt;

&lt;p&gt;In effect, we&amp;rsquo;re keeping a window of the head of the queue in memory, and
using the journal as a disk store for the rest. It nicely caps memory
consumption and the added disk I/O can be amortized out across consumers.&lt;/p&gt;

&lt;p&gt;You probably don&amp;rsquo;t want to let an out-of-control queue grow forever because it
will fill up your disk, but this should make it cope well with short-term
spikes and give you one less thing to worry about when the snake is trying to
swallow the pig.&lt;/p&gt;

&lt;h2&gt;Blocking fetches&lt;/h2&gt;

&lt;p&gt;Something that&amp;rsquo;s bothered me about using the memcache protocol is that there&amp;rsquo;s
no way for a consumer to do a blocking fetch from a queue. If an item is
immediately available, kestrel will give it to you. If not, you&amp;rsquo;ll immediately
get a &amp;ldquo;nothing&amp;rdquo; response. Since, like I just said above, you always want to
have more consumers/workers than work items, these consumers swarm all over
the cluster, asking for work and immediately being sent away empty-handed.
Just to keep them from going crazy, we have ruby client code that looks
something like this:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;while !(response = QUEUE.get(queue_name))
  sleep 0.25
end
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Good grief. If we&amp;rsquo;re going to let the workers take a nap on the job, we could
at least make it happen while blocking on a queue fetch.&lt;/p&gt;

&lt;p&gt;So I did a little sneaky thing with queue names in the memcache &amp;ldquo;get&amp;rdquo; command
by letting clients add options to the end, separated by slashes. Slashes
aren&amp;rsquo;t allowed in filenames anyway so they were never valid in queue names.
Then I made a timeout option, so a client can ask to block for work for some
amount of time:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;while !(response = QUEUE.get(&quot;&amp;lt;b&amp;gt;#{queue_name}/t=250&amp;lt;/b&amp;gt;&quot;)); end
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;The &amp;ldquo;&lt;strong&gt;&lt;code&gt;t=250&lt;/code&gt;&lt;/strong&gt;&amp;rdquo; option means &amp;ldquo;if there&amp;rsquo;s nothing in the queue right now, I&amp;rsquo;m
willing to wait up to 250 milliseconds for something to arrive&amp;rdquo;. After that
timeout, if there&amp;rsquo;s still nothing, kestrel will answer with the usual
empty-response. It&amp;rsquo;s important here to make sure that your memcache client is
set to have a read-timeout larger than the timeout you send in the &amp;ldquo;get&amp;rdquo;
request.&lt;/p&gt;

&lt;p&gt;This was the easiest thing to implement after I worked out how. Each queue
just has a kernel-style wait-list of clients attached to it. If a client makes
a timeout-style &amp;ldquo;get&amp;rdquo; request, and the queue is empty, we just put the client
on the wait-list and the client&amp;rsquo;s actor does a &lt;code&gt;receiveWithin(timeout)&lt;/code&gt; to
wait for a message saying something new has arrived. When items are put on the
queue, the first wait-list client is removed from the wait-list and notified.&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;ManyClients&lt;/code&gt; load test exercises this by having 100 (or 500) clients pile
on to a queue with blocking fetches while a single producer slowly trickles
out data. It seems to work like a charm.&lt;/p&gt;

&lt;h2&gt;Reliable Fetch&lt;/h2&gt;

&lt;p&gt;Writing something into a queue is pretty reliable. The client does a &amp;ldquo;set&amp;rdquo;
operation, and if it worked, kestrel responds &amp;ldquo;&lt;code&gt;STORED&lt;/code&gt;&amp;rdquo;. Naturally, it only
sends that response after the item has been written into the queue&amp;rsquo;s journal
file. The &amp;ldquo;&lt;code&gt;STORED&lt;/code&gt;&amp;rdquo; response means kestrel has taken responsibility for the
item.&lt;/p&gt;

&lt;p&gt;Fetching from a queue is not such a happy story. When kestrel sends an item to
a client, it will never get an acknowledgement or confirmation, and has to
blithely assume that the client got all the data okay and took responsibility
for it. If a client loses its connection during the data transfer, or crashes
right after receiving a work item, that item is gone forever.&lt;/p&gt;

&lt;p&gt;So I added an &amp;ldquo;open&amp;rdquo; option to &amp;ldquo;get&amp;rdquo; which opens a tentative fetch on a queue.
If an item is available, kestrel will remove it from the queue and send it to
the client as usual. But it will also set the item aside and prepare to
&amp;ldquo;un-get&amp;rdquo; it if the client disconnects without confirming it. So a tentative
fetch is started with:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;QUEUE.get(&quot;#{queue_name}/open&quot;)
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;and confirmed with:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;QUEUE.get(&quot;#{queue_name}/close&quot;)
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;which returns nothing. For efficiency, you can also confirm a previous fetch
and get the next item in one operation (avoiding an extra round-trip):&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;QUEUE.get(&quot;#{queue_name}/close/open&quot;)
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Each client connection may only have one outstanding tentative fetch, and if a
connection is dropped, any tentatively-fetched item will be put back on the
head of the queue and given to the next available consumer.&lt;/p&gt;

&lt;p&gt;I want to briefly make a distinction here between confirming that a client
receives an enqueued item and confirming that some useful work was done on it.
Kestrel can really only concern itself with the former. As a good queue
server, it would like confirmation that a client has accepted responsibility
for an item before that item is erased from the queue and journal. But it has
no way of confirming that &amp;ldquo;something useful&amp;rdquo; was done with that item. You
still need to write careful client code to ensure that an item isn&amp;rsquo;t lost
after it&amp;rsquo;s received.&lt;/p&gt;

&lt;p&gt;Using reliable fetch means you are protected from losing items, at the
expense of potentially receiving duplicates &amp;ndash; that&amp;rsquo;s the trade-off. A client
may successfully handle a fetched item but crash before confirming it to
kestrel, and the item may then be given to another client. I think this is a
good trade-off, though. If you know you may handle some items twice, you can
design your system so that duplicate work is harmless &amp;ndash; versus the case where
you may lose items and don&amp;rsquo;t have any recourse.&lt;/p&gt;

&lt;h2&gt;Summary&lt;/h2&gt;

&lt;p&gt;With these three new features, you should be able to survive large bursts of
traffic more easily (with big queues), allow incoming items to be processed
immediately by the next available consumer (with blocking fetches), and
deliver items reliably even to flaky consumers (with reliable fetch). They
expanded the code size 50%, from 1000 lines to 1500, but I think they were
worth it, because they solve several limitations inherited from starling.&lt;/p&gt;
 
        <a href="http://flattr.com/thing/40430/Robey" target="_blank">
        <img src="http://api.flattr.com/button/button-compact-static-100x17.png" alt="Flattr this" title="Flattr this" border="0" />
        </a>
      </content>
    </entry>
  
    <entry>
      <title>Coder Dvorak</title>
      <link href="http://robey.lag.net/2008/09/20/coder-dvorak.html"/>
      <updated>2008-09-20T00:00:00-07:00</updated>
      <id>http://robey.lag.net/2008/09/20/coder-dvorak</id>
      <content type="html">
        &lt;p&gt;Some kind of bug was spreading around at work a few weeks ago and got me
interested in alternate keyboard layouts again. Several of my co-workers use
Dvorak, which never really interested me. But Evan pointed me to a page on
&amp;ldquo;programmer dvorak&amp;rdquo; and suddenly my interest was piqued.&lt;/p&gt;

&lt;p&gt;Dvorak rearranges the letter keys so that letters used more frequently in
english are closer to the home row, and &lt;a href=&quot;http://www.kaufmann.no/roland/dvorak/&quot;&gt;Progammer
dvorak&lt;/a&gt; continues that concept into the
symbol keys and attempts to rearrange them so that symbols frequently used in
code are close at hand. The stroke of genius that makes it worthwhile is that
he &lt;em&gt;moves the number keys up to shifted positions&lt;/em&gt;, making space for more
non-shifted symbols. I don&amp;rsquo;t hit the number 8 nearly as much as I hit
underline, plus, or the &amp;ldquo;squiggly braces&amp;rdquo;.&lt;/p&gt;

&lt;p&gt;Unfortunately, he then moves the number keys into a jumbled-up order so that
they&amp;rsquo;re no longer in incrementing or any other intuitive order. I&amp;rsquo;m not sure
why. (I later found out that this is apparently the original Dvorak number
layout which nobody uses.)&lt;/p&gt;

&lt;p&gt;Being the type of person I am, I decided I could do better, so I constructed a
&amp;ldquo;coder dvorak&amp;rdquo; based on this idea, but keeping the number keys in order, and
moving symbols to positions that make sense for a modern language. (There&amp;rsquo;s
not much need to keep &lt;strong&gt;&lt;code&gt;$&lt;/code&gt;&lt;/strong&gt; nearby unless you still do a lot of perl.)&lt;/p&gt;

&lt;p&gt;I grouped the symbol keys into four loose categories, the first being &amp;ldquo;paired&amp;rdquo;
(like parentheses), and the other three ordered from &amp;ldquo;most used&amp;rdquo; to &amp;ldquo;least
used&amp;rdquo;. Then after trying it out for a few days, I re-assigned several symbols
because I made some mistakes in guessing frequency of use &amp;ndash; both period and
slash were used way more than i thought, for example.&lt;/p&gt;

&lt;p&gt;The layout I finally adopted, unchanged for a month now, is below:&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/images/cdv.png&quot; alt=&quot;coder dvorak layout&quot; /&gt;&lt;/p&gt;

&lt;p&gt;I used the awesome &lt;a href=&quot;http://scripts.sil.org/cms/scripts/page.php?site_id=nrsi&amp;amp;amp;id=ukelele&quot;&gt;Ukelele&lt;/a&gt;
to create the Mac keyboard layout file, which can just be dropped into
&lt;strong&gt;&lt;code&gt;~/Library/Keyboard Layouts/&lt;/code&gt;&lt;/strong&gt; in your home folder.&lt;/p&gt;

&lt;p&gt;A lot of the design came from whiskey-inspired ideas from Britt and Evan.
Originally, I was going to put the paired keys on symmetric sides of the
keyboard, like having &amp;ldquo;&lt;strong&gt;&lt;code&gt;(&lt;/code&gt;&lt;/strong&gt;&amp;rdquo; on &lt;strong&gt;&lt;code&gt;5&lt;/code&gt;&lt;/strong&gt; and &amp;ldquo;&lt;strong&gt;&lt;code&gt;)&lt;/code&gt;&lt;/strong&gt;&amp;rdquo; on &lt;strong&gt;&lt;code&gt;7&lt;/code&gt;&lt;/strong&gt;, which we
all convinced ourselves made sense. But after trying that for a day, it was
clearly wrong. It turns out that by the time my fingers jump the two rows from
the home row to the number row, the finger I use to hit a key isn&amp;rsquo;t 100%
deterministic. It depends on what else I&amp;rsquo;ve been typing. The home row
&amp;ldquo;bindings&amp;rdquo; don&amp;rsquo;t hold as tightly up there. So it was as if I&amp;rsquo;d put the
symmetric keys randomly apart from each other.&lt;/p&gt;

&lt;p&gt;Some placements worked out better than I expected. The underline key (used
heavily in ruby, python, and scala) almost couldn&amp;rsquo;t be in a more accessible
place. Similarly, period and slash ended up in great places, and putting bang
(&lt;strong&gt;&lt;code&gt;!&lt;/code&gt;&lt;/strong&gt;) and question (&lt;strong&gt;&lt;code&gt;?&lt;/code&gt;&lt;/strong&gt;) on the same key is strangely intuitive.&lt;/p&gt;

&lt;p&gt;The thing I have the most trouble with, after about 6 weeks, is the Dvorak
letter layout.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;1. Dvorak is right-handed-centric.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Great, because I&amp;rsquo;m right-handed. But it&amp;rsquo;s not that simple! Look at your QWERTY
keyboard: more letters are centered around the left hand than the right.
QWERTY even devotes one of the 8 precious home-row positions to &lt;em&gt;semi-colon&lt;/em&gt;
on the right hand &amp;ndash; hardly a frequently used english key! (Most english
writers have never even learned correct usage of the semi-colon.)&lt;/p&gt;

&lt;p&gt;I never realized, until typing on Dvorak, that QWERTY has made my left hand a
much stronger typer. Dvorak relies on the right hand a lot more, and I was in
the strange position of having my right hand get tired pretty quickly for the
first couple of weeks.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;2. English has a different distribution than a programming language.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;It mostly works, but there are a few cases that sting. Words like &amp;ldquo;if&amp;rdquo; and
&amp;ldquo;while&amp;rdquo; appear &lt;em&gt;all the time&lt;/em&gt; in code, but are difficult to type in Dvorak
because F and W are in awkward places. A real coder layout would probably
reorganize the keys to match actual words used in programming languages, but I
chickened out. It seemed like a very large gratuitous change.&lt;/p&gt;

&lt;p&gt;The worst is &amp;ldquo;I&amp;rdquo; versus &amp;ldquo;U&amp;rdquo;. &amp;ldquo;I&amp;rdquo; is used all over the place in coding. It&amp;rsquo;s
also the most common loop variable name. So it should have been on the home
row instead of &amp;ldquo;U&amp;rdquo;, which is rarely used.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Anyway&amp;hellip;&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;I&amp;rsquo;m liking it so far. I may change my mind in another month or so, because I&amp;rsquo;m
pretty hard to please, but it&amp;rsquo;s working well for now.&lt;/p&gt;

&lt;p&gt;The keyboard layout can be downloaded here:
&lt;a href=&quot;http://robey.lag.net/downloads/coder_dvorak/coder-dvorak.keylayout&quot;&gt;coder-dvorak.keylayout&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Update - Nov 2013&lt;/em&gt;: Evan Weaver has provided a Windows keyboard file also: &lt;a href=&quot;http://robey.lag.net/downloads/coder_dvorak/coder-dvorak.klc&quot;&gt;coder-dvorak.klc&lt;/a&gt;&lt;/p&gt;
 
        <a href="http://flattr.com/thing/40430/Robey" target="_blank">
        <img src="http://api.flattr.com/button/button-compact-static-100x17.png" alt="Flattr this" title="Flattr this" border="0" />
        </a>
      </content>
    </entry>
  
    <entry>
      <title>OS X Leopard JNI Link Error</title>
      <link href="http://robey.lag.net/2008/09/02/jni-link-error.html"/>
      <updated>2008-09-02T00:00:00-07:00</updated>
      <id>http://robey.lag.net/2008/09/02/jni-link-error</id>
      <content type="html">
        &lt;p&gt;I just spent a long time tracking this down, and nobody else on google had
ever reported a solution. So I&amp;rsquo;m posting this so the next person wit h this
problem can find this post.&lt;/p&gt;

&lt;p&gt;If you see this error when linking something in JNI:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;$ gcc -dynamiclib -o libDirectorySyncer.jnilib target/c/dsync.o -framework JavaVM
ld: framework not found JavaVM
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;it&amp;rsquo;s because leopard has messed up your JDK folder:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;$ ls -l /System/Library/Frameworks/JavaVM.framework/Versions/Current
/System/Library/Frameworks/JavaVM.framework/Versions/Current@ -&amp;gt; 1.6.0
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Wrong! It needs to be pointing to &amp;ldquo;A&amp;rdquo;. No idea why.&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;$ cd /System/Library/Frameworks/JavaVM.framework/Versions/
$ sudo rm Current
$ sudo ln -s A Current
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;That will fix it. Yay!&lt;/p&gt;
 
        <a href="http://flattr.com/thing/40430/Robey" target="_blank">
        <img src="http://api.flattr.com/button/button-compact-static-100x17.png" alt="Flattr this" title="Flattr this" border="0" />
        </a>
      </content>
    </entry>
  
    <entry>
      <title>CJC Prime Number Sieve</title>
      <link href="http://robey.lag.net/2008/08/27/cjc-prime-number-sieve.html"/>
      <updated>2008-08-27T00:00:00-07:00</updated>
      <id>http://robey.lag.net/2008/08/27/cjc-prime-number-sieve</id>
      <content type="html">
        &lt;p&gt;Apologies in advance. This is probably the geekiest post I&amp;#8217;ve ever done.&lt;/p&gt;

&lt;p&gt;To get an SSH client working &amp;ndash; with a reasonable response time &amp;ndash; on a 200mhz
ARM chip a few years ago, I had to optimize some crazy things. One of those
things was the generation of prime numbers, which are needed to create new
public keys.&lt;/p&gt;

&lt;p&gt;You may have heard that it&amp;rsquo;s very difficult to factor large numbers. This is
true, but it&amp;rsquo;s actually a lot easier to determine whether a large number is
&amp;ldquo;probably prime&amp;rdquo;. Most prime number generators create a random number from a
secure source of entropy and then run it through a Miller-Rabin test, which
can identify composite (non-prime) numbers. If the test doesn&amp;rsquo;t prove that a
number is composite, then there&amp;rsquo;s at least a &amp;frac34; chance that it&amp;rsquo;s prime. You
can perform the test multiple times to improve those odds. More info here:
&lt;a href=&quot;http://en.wikipedia.org/wiki/Miller-Rabin_test&quot;&gt;Miller-Rabin test&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The Miller-Rabin test can be pretty time consuming, though, and since you may
need to run it against many random numbers before you&amp;rsquo;ll find one that&amp;rsquo;s
prime, it would be nice to weed out obvious composites beforehand. For
example, you wouldn&amp;rsquo;t want to test an even number since that&amp;rsquo;s obviously
divisible by 2. So here&amp;rsquo;s a shortcut I came up with that I call the &amp;ldquo;CJC prime
number sieve&amp;rdquo;.&lt;/p&gt;

&lt;h2&gt;The Sum-of-Digits Trick&lt;/h2&gt;

&lt;p&gt;I thought I would be able to gloss over this part of the explanation by
throwing out a few links and saying &amp;ldquo;go read about the (name) theorem!&amp;rdquo; But a
google search only turns up some anecdotal descriptions, and wikipedia barely
devotes an entire sentence to it (here:
&lt;a href=&quot;http://en.wikipedia.org/wiki/Modular_arithmetic#Applications&quot;&gt;Modular Arithmetic&lt;/a&gt;).&lt;/p&gt;

&lt;p&gt;There&amp;rsquo;s a fairly well-known trick for finding out if a number is divisible by
3: add the digits, and if the sum of the digits is divisible by 3, so is the
original number. If it&amp;rsquo;s not, the original number is not. For example, 4401 is
divisible by 3 because 4 + 4 + 0 + 1 = 9, and 9 is divisible by 3. 512 is not,
because 5 + 1 + 2 = 8, and 8 is not divisible by 3. (This trick also works for
11 and 9 but these are emo numbers that don&amp;rsquo;t get as much attention.)&lt;/p&gt;

&lt;p&gt;So why does this work? As you can guess from the wikipedia link above, it has
to do with modular arithmetic. In (mod k) space, the only numbers that exist
are integers from 0 to k - 1. Coders recognize this as being the way all int
math works on a computer: a byte can represent a number &amp;ldquo;mod 256&amp;rdquo;. It turns
out that in (mod k) space, you can cancel out a factor if that factor is
&lt;em&gt;relatively prime&lt;/em&gt; to k.&lt;/p&gt;

&lt;p&gt;Say what? Okay, &amp;ldquo;relatively prime&amp;rdquo; just means two numbers don&amp;rsquo;t share any
factors. 9 and 10 are relatively prime because 10 = 2 x 5, and 9 = 3 x 3. But
4 and 6 aren&amp;rsquo;t, because they share the factor 2.&lt;/p&gt;

&lt;p&gt;Sooo&amp;hellip; since:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;20 = 2 (mod 9)
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;and 20 is relatively prime to 9, you can figure out 40 mod 9 by factoring out
the 20, and replacing it with its equivalent in (mod 9) space, 2:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;40 = 2 * 20
2 * 20 = 2 * 2 = 4 (mod 9)
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;The reason this works well for finding numbers divisible by 3 is that:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;4401 = (4 * 1000) + (4 * 100) + (0 * 10) + 1
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;and:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;10 = 1 (mod 3)
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Aha! So factoring all the 10s out and replacing them with 1s gives us:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;(4 * 1000) + (4 * 100) + (0 * 10) + 1 (mod 3)
(4 * 1) + (4 * 1) + (0 * 1) + 1 (mod 3)
4 + 4 + 0 + 1 (mod 3)
9 (mod 3)
0 (mod 3)
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;and any number that&amp;rsquo;s 0 in (mod 3) is of course divisible by 3.&lt;/p&gt;

&lt;p&gt;The reason 9 and 11 work is that 10 mod 9 = 1, and 10 mod 11 = -1. (The -1
means you have to do alternate add/subtracts instead of just summing the
digits, but it&amp;rsquo;s not worth obsessing over in this article.)&lt;/p&gt;

&lt;h2&gt;Making a sieve&lt;/h2&gt;

&lt;p&gt;So that&amp;rsquo;s exciting&amp;hellip; if you do a lot of dividing by 3. But how does this help
discover primes?&lt;/p&gt;

&lt;p&gt;Well if computers worked in base 10 instead of 2, we&amp;#8217;d now have a pretty fast
way of determining if a really large number were divisible by 3. And I hope
you won&amp;rsquo;t think I&amp;rsquo;m being pedantic if I point out here that if you make up a
random number, it has about 1/3 chance of being divisible by 3. :)&lt;/p&gt;

&lt;p&gt;Let&amp;rsquo;s say instead of working in base 10, we were working in some other base B
that was relatively prime to a lot of interesting numbers. Ideally we&amp;#8217;d like
to be in a base B such that&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;B = 1 (mod n)
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;for as many n as possible. One nice coincidence is that&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;256 =
255 + 1 =
(3 * 5 * 17) + 1
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;or&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;256 = 1 (mod 3) and
256 = 1 (mod 5) and
256 = 1 (mod 17)
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;That means that in base 256, summing the digits will tell you quickly if 3, 5,
or 17 is a factor. Summing the base-256 digits of a number also goes by the
name &amp;ldquo;adding the bytes in the binary representation&amp;rdquo;. It actually helps a lot,
as you can see from timings at the end of this article.&lt;/p&gt;

&lt;p&gt;If we&amp;rsquo;re willing to leave powers of 2, though, we can do better. It just so
happens that we can construct a base that&amp;rsquo;s relatively prime to a handful of
small primes, yet is close to a power of 2. The key is noticing that, in the
256 case above, multiplying a few primes together and then adding 1 created a
number that was both relatively prime to all those primes, and was equal to 1
in each of the primes&amp;#8217; (mod k) spaces.&lt;/p&gt;

&lt;p&gt;Think of it this way. If A, B, and C are all prime, then A x B x C will equal
0 in (mod A) because it&amp;rsquo;s a multiple of A. Same goes for B and C for the same
reason. Adding 1 makes it equal 1 in all three (mod k) as long as the primes
are all greater than 2. And that also means the resulting number is no longer
a multiple of A, B, or C, which makes our new number relatively prime to them.
In short, we can construct a base that&amp;rsquo;s relatively prime to a set of primes,
and is equal to 1 in each of the primes&amp;#8217; &amp;ldquo;mod spaces&amp;rdquo;, by just multiplying the
primes together and adding 1.&lt;/p&gt;

&lt;p&gt;We want the base to be close to a power of 2 to preserve our entropy source.
If we grab 8 bits (0 - 255) from a secure random pool, but we want a smaller
base like 250, we have two choices. We can mod the random byte (&lt;code&gt;rand % 250&lt;/code&gt;)
to wrap into range, or we can just discard and retry when we get a byte
that&amp;rsquo;s out of our preferred range. If we mod-and-wrap, though, we&amp;rsquo;re giving
more weight to results in the wrapped part &amp;ndash; numbers like 1 are going to be
more common because both 1 and 251 will mod-wrap to them. That ruins the
&amp;ldquo;secure&amp;rdquo; part of our randomness, so we need to go with the discard option. And
if we have to discard some bytes, we&amp;#8217;d like to pick ranges to minimize the
chance of a byte being discarded, which means choosing ranges that are as
close to a power-of-2 range as possible.&lt;/p&gt;

&lt;p&gt;One nice possibility is:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;3 * 5 * 7 * 11 * 13 * 17 * 19**2 * 23 + 1 = 2119382266 = 0x7e5334fa
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;That&amp;rsquo;s a base that covers 98.7% of the 31-bit range, so it won&amp;rsquo;t cause many
random digits to be discarded, and it&amp;rsquo;s relatively prime to the first 8 primes
excluding 2. (We can ensure that a number isn&amp;rsquo;t divisible by 2 by just setting
its lowest bit to 1 &amp;ndash; a bonus for working in base 2!)&lt;/p&gt;

&lt;h2&gt;Let&amp;rsquo;s Go!&lt;/h2&gt;

&lt;p&gt;At this point, the code should just write itself. To generate a 1024-bit
random prime, we need to figure out how many &amp;ldquo;digits&amp;rdquo; that would be in a
base-2119382266 number, and what the range would be on the highest digit. We&amp;rsquo;ll
lose some of the 1024-bit range because our new base doesn&amp;rsquo;t map exactly to
the desired range, but we&amp;rsquo;ll never lose more than a single bit&amp;rsquo;s worth.
(There&amp;rsquo;s probably a fancy proof for this, but if you think about it, you can
reason it out pretty quickly in your head.) You already lose 2 bits for any
prime, because you need to set the high bit to ensure a prime number of the
desired size, and you need to set the low bit to ensure an odd number, as
mentioned above.&lt;/p&gt;

&lt;p&gt;For a 1024-bit prime, that means a 34-digit number with the highest digit set
to 2. For a 2048-bit prime, it&amp;rsquo;s a 67-digit number with the highest digit
between 5 and 8 inclusive. (You can play around with other sizes by calling
&lt;code&gt;computeParams&lt;/code&gt; in the attached code.)&lt;/p&gt;

&lt;p&gt;We can then generate, for a 1024-bit prime, 33 &amp;ldquo;digits&amp;rdquo; of 32-bit machine
words, masking off the high bit and retrying any time we get a &amp;ldquo;digit&amp;rdquo; bigger
than (base - 1). Set the high &amp;ldquo;digit&amp;rdquo; to 2 (or select a digit at random for
other bit choices) and we&amp;rsquo;re done.&lt;/p&gt;

&lt;p&gt;A quick shortcut here: Normally we should sum the digits, and then find the
mod of that sum against each of our 8 primes. However, we already have a
really convenient thing here: base - 1 is a multiple of all of 8 primes (by
design), so we can mod the sum by (base - 1) as we add, and not lose any
information, keeping the sum small enough to fit into a 32-bit word.&lt;/p&gt;

&lt;p&gt;After summing, a few small mod operations tell us if the generated number is
divisible by 3, 5, 7, 11, 13, 17, 19, or 23. If it is, we can loop back and
generate another number immediately, skipping the Miller-Rabin prime test. If
it passes, we still dump it into Miller-Rabin for final verification &amp;ndash; the
sum check just lets us quickly discard any simple composites.&lt;/p&gt;

&lt;h2&gt;Code and Results&lt;/h2&gt;

&lt;p&gt;I wrote a proof-of-concept in scala, and hosted it in git here:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;git clone http://www.lag.net/robey/code/cjc/
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;It includes an implementation of CJC in base 2119382266, alongside a prime
number generator that just uses the standard Miller-Rabin prime test by
itself, and a variant of the standard M-R sieve that checks the base-256
primes (3, 5, 17) first.&lt;/p&gt;

&lt;p&gt;The test code generates 5 primes from each algorithm, using a random number
seed given on the command line. (By the way,
&lt;em&gt;never use the built-in random number generator&lt;/em&gt; like this code does! Use a
secure one. I
used a seeded generator so the results would be repeatable, which is exactly
what you don&amp;rsquo;t want in the real world.) I&amp;#8217;ve posted my own results in a chart
below: Using the base-256 check alone gives a 2x speedup, and using CJC gives
over 3x! The primary increase, according to the second chart, appears to be
due to cutting back on calls to the Miller-Rabin algorithm. The more
candidates we can discard before trying M-R, the better.&lt;/p&gt;

&lt;p&gt;(By the way, ignore how long these algorithms are taking in wall-clock time. I
ran them in a standard JVM without JIT. In real life, you would definitely
want this to be in JIT or possibly even C &amp;ndash; horrors!)&lt;/p&gt;

&lt;p&gt;Anyway, hopefully this is an interesting technique for filtering primes. And
the name CJC? It&amp;rsquo;s named after my friend Communist J. Cat.&lt;/p&gt;

&lt;hr /&gt;

&lt;p&gt;&lt;img src=&quot;/images/cjc-graph.png&quot; title=&quot;&quot; alt=&quot;results graph&quot; /&gt;&lt;/p&gt;
 
        <a href="http://flattr.com/thing/40430/Robey" target="_blank">
        <img src="http://api.flattr.com/button/button-compact-static-100x17.png" alt="Flattr this" title="Flattr this" border="0" />
        </a>
      </content>
    </entry>
  
    <entry>
      <title>Git for the real world</title>
      <link href="http://robey.lag.net/2008/07/13/git-for-the-real-world.html"/>
      <updated>2008-07-13T00:00:00-07:00</updated>
      <id>http://robey.lag.net/2008/07/13/git-for-the-real-world</id>
      <content type="html">
        &lt;p&gt;Now that we&amp;rsquo;ve been using git at Twitter for a couple of months, we&amp;rsquo;ve
overcome several crippling problems and misunderstandings about how to use it
properly. There are dozens of &amp;ldquo;intros&amp;rdquo; and &amp;ldquo;tutorials&amp;rdquo; to git online, but at
some point you need to know more than just the basics of DVCS and the map to
svn commands &amp;ndash; you need to know practical considerations of real-world usage.
None of the intros or tutorials had this stuff, so I thought I&amp;rsquo;d share what we
learned.&lt;/p&gt;

&lt;p&gt;Git&amp;rsquo;s command-line interface is hands-down the worst of any DVCS (except the
archaic &lt;code&gt;tla&lt;/code&gt;). There are inconsistencies: Some commands will expect you to
type &amp;ldquo;origin/master&amp;rdquo;, while others will want &amp;ldquo;origin master&amp;rdquo;. Other commands
should never ever be used, but are presented in the documentation as if
they&amp;rsquo;re part of a normal usage pattern. Some commands are useless in their
default form and need several command-line options to make them work right.&lt;/p&gt;

&lt;p&gt;I ended up writing a wrapper script to cover up a lot of these flaws, which I
consider an &amp;ldquo;ultimate fail&amp;rdquo; for a UI. But I&amp;rsquo;m still not sure the script is a
good idea, since it may make me forget all the quirks I need to keep in mind
when the script isn&amp;rsquo;t around.&lt;/p&gt;

&lt;h2&gt;Don&amp;rsquo;t change history&lt;/h2&gt;

&lt;p&gt;Two commands you should avoid: &lt;strong&gt;&lt;code&gt;git rebase&lt;/code&gt;&lt;/strong&gt; and &lt;strong&gt;&lt;code&gt;git reset&lt;/code&gt;&lt;/strong&gt;. Some of
the tutorials will tell you that &lt;strong&gt;&lt;code&gt;rebase&lt;/code&gt;&lt;/strong&gt; is one of the first commands you
should learn. Lies! &lt;strong&gt;&lt;code&gt;rebase&lt;/code&gt;&lt;/strong&gt; is a way to trick you into creating merge
conflicts.&lt;/p&gt;

&lt;p&gt;When you rebase, you are erasing every local commit you&amp;rsquo;ve made, and turning
them into patches (as if you were back on CVS). After syncing your repository
up with the remote one, your patches are re-applied one by one. Presto! you&amp;rsquo;ve
changed history.&lt;/p&gt;

&lt;p&gt;The only reason I can think of for doing this is if you&amp;rsquo;re not comfortable
doing merges. But DVCS is all about merges, so you should just get used to
doing them. A merge provides a little signpost to everyone else about your
branch. Don&amp;rsquo;t fear the merge &amp;ndash; love it! It records exactly how your local
work should be rectified with remote changes, without requiring you to keep
tweaking your patch.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;code&gt;reset&lt;/code&gt;&lt;/strong&gt; is even worse. It erases commits from your history, which will
very likely make your local repository different from everyone else&amp;rsquo;s, and
guarantee future conflicts or even an inability to push in the future. Some
people will say you should learn &lt;strong&gt;&lt;code&gt;reset&lt;/code&gt;&lt;/strong&gt; so you can use it in a panic
situation, but if you&amp;rsquo;re panicking, you&amp;rsquo;re more likely to make things worse,
so stop. Calm down. You have time to think and solve the problem in a
rational way.&lt;/p&gt;

&lt;p&gt;My problem with these two commands is that they violate a core philosophy of
DVCS: Everyone has their own view of the repository, but these views obey
entropy and flow in only one time direction. When they meet, they merge. Doing
a &lt;strong&gt;&lt;code&gt;rebase&lt;/code&gt;&lt;/strong&gt; or &lt;strong&gt;&lt;code&gt;reset&lt;/code&gt;&lt;/strong&gt; goes back in time and changes the past. They
should be in a separate tool, like &amp;ldquo;git-fix&amp;rdquo; or &amp;ldquo;git-hack&amp;rdquo;.&lt;/p&gt;

&lt;h2&gt;The story matters more than the chronology&lt;/h2&gt;

&lt;p&gt;Have you ever read a history book that said &amp;ldquo;In 1812, the British empire
shelled the tiny new American capital. Meanwhile, Napoleon marched across
Europe. In China, &amp;hellip;&amp;rdquo;? Hopefully not, that would suck. Telling a thread of
the story from beginning to end is more important than placing every single
event in its exact chronological order. The default format for &lt;strong&gt;&lt;code&gt;git log&lt;/code&gt;&lt;/strong&gt;
reorders commits by their exact date and time, so you need to be aware of
that and not get confused.&lt;/p&gt;

&lt;p&gt;Say, for example, you made a local branch, and made 3 local commits: L1, L2,
and L3. Meanwhile, someone else is working on a different feature on their
branch, and does commits R1 and R2. After you merge (M1), git is likely to
show you a history like this:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;M1 -&amp;gt; R2 -&amp;gt; L3 -&amp;gt; L2 -&amp;gt; R1 -&amp;gt; L1
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Huh? What? Why are my local commits intermixed with my co-worker&amp;rsquo;s commits?
The merge must have messed up! Crap! Time to &lt;strong&gt;&lt;code&gt;git reset&lt;/code&gt;&lt;/strong&gt; and destroy
everything, right? No! Stop! Don&amp;rsquo;t do it. It&amp;rsquo;s a trap! Git is lying by
omission &amp;ndash; it&amp;rsquo;s telling the literal, actual truth, but it&amp;rsquo;s telling it to you
in a way that makes it confusing. Git is re-ordering the history to make sure
every commit is shown in its actual time order, not the story order.&lt;/p&gt;

&lt;p&gt;You should probably just go ahead and alias &lt;strong&gt;&lt;code&gt;log&lt;/code&gt;&lt;/strong&gt; to:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;git log --topo-order --decorate
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;That tells git to show things in &amp;ldquo;topological&amp;rdquo; (story) order, and to also mark
where various branches are sitting. I usually find it useful to take that one
step further:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;git log --topo-order --decorate --first-parent
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;That tells git to show things in story order &lt;em&gt;and&lt;/em&gt; to tell that story from
&lt;em&gt;my point of view&lt;/em&gt;. It&amp;rsquo;s sometimes interesting to see every commit that one of
your coworkers did in their branch, but often you just want to see the
merge-commit and move on. &lt;strong&gt;&lt;code&gt;&quot;-- first-parent&quot;&lt;/code&gt;&lt;/strong&gt; tells git
to skip over the details of every branch that isn&amp;rsquo;t a linear parent of yours.
Generally this means you&amp;rsquo;ll see a simplified history of what&amp;rsquo;s been going on,
without the intricacies of what happened on forked branches while they were
forked off.&lt;/p&gt;

&lt;p&gt;If you want to see all the threads of history intertwined, I suggest using a
graphical tool like gitk instead of git-log.&lt;/p&gt;

&lt;h2&gt;Don&amp;rsquo;t fast-forward &amp;ndash; live every moment&lt;/h2&gt;

&lt;p&gt;This one is pretty confusing. And it sucks, because this concept doesn&amp;rsquo;t even
exist in other DVCS. I think it&amp;rsquo;s another symptom of &amp;ldquo;fear of merge&amp;rdquo;.
Basically, sometimes when you ask git to merge branch A into branch B, it will
decide that it doesn&amp;rsquo;t want to merge and it will instead turn A and B into
clones of each other.&lt;/p&gt;

&lt;p&gt;For example, let&amp;rsquo;s pretend you made a branch of &amp;ldquo;master&amp;rdquo; called &amp;ldquo;feature&amp;rdquo; and
did a few commits on it, and are now ready to merge it back into master. If no
other work has happened on the master branch, git will try to out-clever you.
It thinks: &amp;ldquo;Well, nobody else has worked on the master branch, so I could just
&lt;em&gt;make the feature branch become the new master branch&lt;/em&gt; and
that would be logically equivalent.&amp;rdquo; So after the merge, you&amp;rsquo;ll see every
single commit you made, as if you had done them directly on the master branch.
Git has cloned your feature branch into the new master branch.&lt;/p&gt;

&lt;p&gt;This might not be so bad if there are only a couple of people working on the
project, but there are a few side effects: Your branch has effectively
vanished from history. There is no longer any indication that you were working
on a side branch; it looks like you were working directly on master. And if it
turns out that there were bugs in your new feature (which, you know, sometimes
happens), you can&amp;rsquo;t reverse the merge-commit because
&lt;em&gt;there is no merge-commit&lt;/em&gt;. You will have to reverse every single commit you
made, in reverse order, or worse.&lt;/p&gt;

&lt;p&gt;So really, you want git to always create a merge-commit when you do a merge.
For this, you have to ask it nicely:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;git merge --no-ff
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;(Git calls the history erasing &amp;ldquo;fast-forwarding&amp;rdquo;.)&lt;/p&gt;

&lt;h2&gt;A few other things&lt;/h2&gt;

&lt;p&gt;To remove a branch from a remote repository after it&amp;rsquo;s been merged and
deployed, you have to push the branch with a colon in front of the branch
name. This has become a running joke in the office: &amp;ldquo;Colon means delete.&amp;rdquo;
Look, don&amp;rsquo;t ask me, I&amp;rsquo;m not Linus. That&amp;rsquo;s just how it works.&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;git push origin :stale_completed_branch
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;When other people remove branches, they won&amp;rsquo;t be removed from your local copy
of the repository. To take care of this housekeeping, you need to express a
fruit preference:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;git remote prune origin
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Again, don&amp;rsquo;t ask. I don&amp;rsquo;t know why. That&amp;rsquo;s just how it is.&lt;/p&gt;

&lt;p&gt;I have a few ranty topics on how git is implemented and used, and how that
compares with the older DVCS (especially bazaar), but I&amp;rsquo;ll save that for some
other time. If you&amp;rsquo;re using git, hopefully this information is useful.&lt;/p&gt;
 
        <a href="http://flattr.com/thing/40430/Robey" target="_blank">
        <img src="http://api.flattr.com/button/button-compact-static-100x17.png" alt="Flattr this" title="Flattr this" border="0" />
        </a>
      </content>
    </entry>
  
    <entry>
      <title>Git gripes</title>
      <link href="http://robey.lag.net/2008/05/11/git-gripes.html"/>
      <updated>2008-05-11T00:00:00-07:00</updated>
      <id>http://robey.lag.net/2008/05/11/git-gripes</id>
      <content type="html">
        &lt;p&gt;I have to get this rant off my chest.&lt;/p&gt;

&lt;p&gt;Why does git insist on making up new terminology for features that are in all
DVCS, and already have commonly accepted names?&lt;/p&gt;

&lt;p&gt;Last week during a presentation, I almost choked when someone showed off a git
feature where you can temporarily shelve uncommitted changes. It&amp;rsquo;s called
&amp;ldquo;git stash&amp;rdquo;. Stash?! Mercurial and bazaar at least agree that this is called,
um, shelve. Since you are shelving. I don&amp;rsquo;t have a bag of heroin to stash,
Linus. Just patches. To shelve. Now until the end of time I will need to
remember which term to use when talking to git people or the rest of the
universe.&lt;/p&gt;

&lt;p&gt;In git, when you commit, you are actually staging. (Git doesn&amp;rsquo;t consider a
commit to be truly committed until you&amp;rsquo;ve posted it to someone else&amp;rsquo;s repos
itory &amp;ndash; a charming bit of communism.) A staged commit is, to git, a cached
commit. Wikipedia tells me a cache is a copy of data that&amp;rsquo;s already stored
elsewhere, but nevermind, that definition doesn&amp;rsquo;t apply in the gitverse.
Commit = staged; staged = cached; got it?&lt;/p&gt;

&lt;p&gt;To switch branches in a working tree, you &amp;ldquo;checkout&amp;rdquo; in git. You also
&amp;ldquo;checkout&amp;rdquo; to create a new working tree for a branch. The manpage for
&amp;ldquo;git-check out&amp;rdquo; can&amp;rsquo;t even avoid sounding confused by this, and admits that
the former usage really &amp;ldquo;switches branches&amp;rdquo;. Let&amp;rsquo;s see if we can think of a
good term for switching branches. How about &amp;ldquo;switch&amp;rdquo;? Hey look, that&amp;rsquo;s what
everyone else calls it! Must be a very odd coincidence. To branch is to
&amp;ldquo;clone&amp;rdquo;; to revert is to &amp;ldquo;clean&amp;rdquo;. Not even the simplest of terms escape
newspeak.&lt;/p&gt;

&lt;p&gt;I want to end on a positive note, so I will say that compared to every other
DVCS, git is fast. I frequently have no idea what it&amp;rsquo;s doing (is &amp;ldquo;deltifying&amp;rdquo;
really a word?), or if it&amp;rsquo;s doing what I&amp;rsquo;d like it to do, but it&amp;rsquo;s doing it
very very quickly. Maybe there&amp;rsquo;s a metaphor there.&lt;/p&gt;
 
        <a href="http://flattr.com/thing/40430/Robey" target="_blank">
        <img src="http://api.flattr.com/button/button-compact-static-100x17.png" alt="Flattr this" title="Flattr this" border="0" />
        </a>
      </content>
    </entry>
  
    <entry>
      <title>Scarling</title>
      <link href="http://robey.lag.net/2008/05/07/scarling.html"/>
      <updated>2008-05-07T00:00:00-07:00</updated>
      <id>http://robey.lag.net/2008/05/07/scarling</id>
      <content type="html">
        &lt;p&gt;I recently spent bits of my free time porting
&lt;a href=&quot;http://rubyforge.org/projects/starling/&quot;&gt;Starling&lt;/a&gt; to scala,
and thought I&amp;rsquo;d post the story here in case anyone else finds it enlightening
or interesting.&lt;/p&gt;

&lt;p&gt;Starling is a simple, reliable message-queue server written in ruby. It uses
MemCache protocol, so almost any language can already speak to it. You can
set up multiple starling servers, and just like a memcache pool, the servers
don&amp;rsquo;t need to know anything about each other. If clients pick a server at
random for each operation, it appears to be a single loosely-ordered queue,
with each server holding its own part. Starling is used extensively at
Twitter.&lt;/p&gt;

&lt;p&gt;I&amp;rsquo;ve been tinkering with scala since December, and have been building a
&lt;a href=&quot;http://github.com/robey/configgy/tree/master&quot;&gt;config/logging library&lt;/a&gt;
in my spare time. It was easy to pick up since I&amp;rsquo;ve been using
java and python for many years, and scala seems to nicely synthesize the
styles of those two languages. I felt like I was ready to try a meaningful
project, and Starling is potentially the kind of project that could gain a lot
from running on the JVM. At a mere 1000 lines of ruby, it was also a nice
managable size.&lt;/p&gt;

&lt;h2&gt;First chunk&lt;/h2&gt;

&lt;p&gt;I&amp;rsquo;m a bottom-up coder, so I started with the PersistentQueue class. It&amp;rsquo;s the
guts of Starling: a FIFO queue backed by a journal, and the means to rotate
and replay that journal when necessary. For this class, I was able to do
nearly a direct copy, just converting ruby syntax and library calls into scala
ones. Only a few places tripped me up:&lt;/p&gt;

&lt;p&gt;Scala, like java, has no equivalent of the &amp;ldquo;pack&amp;rdquo; function that&amp;rsquo;s in all of
the perl/python/ruby languages. I actually had to write a 10-line class to
write a little-endian int into a stream, and another 10-line class to read
one. Ack! That wasn&amp;rsquo;t an auspicious start, and gave me pause. Everything that
makes people run from java to higher-level languages was there: You&amp;rsquo;re given
only the most basic, fundamental tools to do I/O, and serializing data is
treated like some strange, rare operation.&lt;/p&gt;

&lt;p&gt;Aside from that, it went smoothly, though. The payoff was when I downloaded a
troublesome 500MB journal file from a running starling server and ran it
through the scala journal replayer. Starling would take about a half hour to
process the log (and frequently crash the ruby interpreter). &amp;ldquo;Scarling&amp;rdquo; (as I
call my scala version) was able to process the log in &lt;em&gt;23 seconds&lt;/em&gt;. Exciting!&lt;/p&gt;

&lt;p&gt;Next up was QueueCollection, which is what it sounds like: a collection of all
the persistent queues, and methods for getting stats on them. Starling does
some trickery here to avoid races around queues that are replaying journals. I
made a few false starts, trying to either duplicate the logic or improve it,
before I decided the really clever thing would be to make each queue an actor.
Once I made that leap, the code practically wrote itself, and I stopped for a
week.&lt;/p&gt;

&lt;h2&gt;Second chunk&lt;/h2&gt;

&lt;p&gt;The remainder of Starling is front-end code for handling connections, speaking
memcache protocol, and interfacing with QueueCollection. I needed to break
away from porting code at this point, because Starling uses a ruby wrapper
around EventMachine, a fast asynchronous event I/O library. New incoming
connections create a Handler object and send it events when new data arrives.
I was sure this was a place to use actors, but I wasn&amp;rsquo;t sure how much of the
I/O code I&amp;rsquo;d need to write. (I wrote most of ziggurat, Danger&amp;rsquo;s async I/O
library, so I&amp;rsquo;m not scared of writing an I/O library, but it would be really
time-consuming and non-fun.)&lt;/p&gt;

&lt;p&gt;Googling for &amp;ldquo;java EventMachine&amp;rdquo; turned up links to an apache project called
Mina. Aha! This was pretty much exactly what I was looking for. In fact, it
closely resembles a ziggurat-derived library my friend Matt is working on,
since they both use the idea of pushing protocol encoders into the I/O event
engine. Mina not only creates a new &amp;ldquo;session&amp;rdquo; object for incoming connections,
it can decode the wire protocol inside its own worker threads, and notify your
session of I/O events by sending it fully-decoded objects.&lt;/p&gt;

&lt;p&gt;This model is so close to how actors work that it just made my mouth water. I
just needed some kind of gasket! More googling revealed that one (and only
one) person had already done this work, and written a scala wrapper for Mina
that turned &amp;ldquo;I/O events&amp;rdquo; into actor messages. Well actually, he did it as a
patch against Mina instead of a wrapper, for ill-explained reasons. Oh, and
the patch fails to compile. Oh, and all the links on his project page are
broken. Oh, and also he has no posted email address. FAIL. I made an attempt
to reach him through blog comments (ugh) and decided to do this one on my own.&lt;/p&gt;

&lt;p&gt;Luckily, once I read enough of the (actually semi-decent) Mina docs, I was
able to connect Mina to actors in less than 50 lines of code. I told you: the
two models (Mina and actors) really are made for each other. I hope someone
ends up writing a working wrapper for it. Or heck, just use mine as a starting
point.&lt;/p&gt;

&lt;p&gt;The last piece was a memcache protocol handler, written to Mina&amp;rsquo;s API. I found
one from a project called jmemcached, ported the bits I needed into scala,
fixed it up to use some of scala&amp;rsquo;s nicer collections like ArrayBuffer[Byte],
and impatiently patched the wrole thing together for some trial runs.&lt;/p&gt;

&lt;h2&gt;First Results&lt;/h2&gt;

&lt;p&gt;The first results were pretty discouraging. I wrote a quick test script to
open a connection and do 10,000 queue SETs, and on my old Macbook Pro,
Starling could do them in under 4 seconds. My scala port could do them in 30.
This is roughly a factor of 10 worse &amp;ndash; an order of magnitude. Miserable
failure. What was I doing wrong?&lt;/p&gt;

&lt;p&gt;Scala doesn&amp;rsquo;t have many (any?) performance benchmarking tools, but java does,
and these java tools don&amp;rsquo;t seem to care if your jar was made by java or scala.
I fixed a few small things, but wasn&amp;rsquo;t making much progress. My inexperience
with hprof made me fix the least important things first, but the last two
were worth telling about.&lt;/p&gt;

&lt;p&gt;Using an actor for each queue was overkill. Reading from or writing to a queue
is such a fast operation that the message-passing for &amp;ldquo;please write to this
queue&amp;rdquo;, &amp;ldquo;okay done&amp;rdquo; was deadly. I reluctantly scrapped the actor code there
and used simple locks for the queues, and shaved off several seconds. The
client connections were already actors, so it was just adding too much
overhead to have the queues themselves be separate actors.&lt;/p&gt;

&lt;p&gt;The biggest gain, which took me the longest time to find, and made me feel the
most foolish, was in the memcache protocol decoder. I thought I was being
really clever by sending incoming data into a scala ArrayBuffer[Byte] and
doing functional operations on it. Those operations are sometimes slow as
molasses! One, &amp;ldquo;trimStart&amp;rdquo;, was using up 1 millsecond per queue push, or 10
seconds of total test time all by itself.&lt;/p&gt;

&lt;p&gt;Begrudgingly, I dove into my memcache protocol decoder and decided to do
things the Mina way instead of trying to be clever. Using Mina&amp;rsquo;s ByteBuffer
class slashed times dramatically, and suddenly my scala code was as fast as
Starling (less than 4 seconds). I actually spent a couple of days fretting
about the poor performance before this &amp;ldquo;eureka&amp;rdquo; moment, and was very relieved
to find out that the slowness was entirely due to my own brain damage, and
not to anything in scala or actors.&lt;/p&gt;

&lt;h2&gt;Better Results&lt;/h2&gt;

&lt;p&gt;&amp;ldquo;As fast as ruby&amp;rdquo; may not sound impressive. In some circles, it&amp;rsquo;s actually an
insult. But for this test, I felt good. First, Starling doesn&amp;rsquo;t do anything
intensive in ruby. It uses ruby&amp;rsquo;s expressiveness and its libraries to make a
small server that&amp;rsquo;s mostly disk I/O and network I/O bound. EventMachine does
a bang-on job of network I/O so there&amp;rsquo;s little room for improvement.&lt;/p&gt;

&lt;p&gt;However&amp;hellip; My test was effectively written to play to Starling&amp;rsquo;s strengths.
Since Starling runs in a single thread on a single process (STSP), it excels
at handling a single client which makes a lot of requests, but waits for a
response between each request. The advantage of the JVM appeared when I
changed the test to emulate 100 clients doing 100 queries each.&lt;/p&gt;

&lt;p&gt;To Starling, this is exactly the same test (10,000 queries, handled
sequentially) so it gets approximately the same result (less than four
seconds). Mina-plus-actors starts to shine here, though, and finishes in under
&lt;strong&gt;two&lt;/strong&gt; seconds. It&amp;rsquo;s able to juggle queue work with I/O threads. Success!&lt;/p&gt;

&lt;h2&gt;Conclusion&lt;/h2&gt;

&lt;p&gt;I&amp;rsquo;ve heard there&amp;rsquo;s a big migration of ruby people to scala, and so the first
thing I would say to the ruby people is that this is no panacea. It&amp;rsquo;s not ruby
on a JVM; it&amp;rsquo;s an entirely new langauge, with much stronger java roots than
any other language, so familiarity with java is probably more helpful than
python or ruby. On the other hand, if ruby whetted your appetite for
functional programming, scala has more of that than ruby and python combined,
and seems to live up to its promise of exposing the wonders of java&amp;rsquo;s
scalability and rock-solid virtual machine and garbage collector.&lt;/p&gt;

&lt;p&gt;The main stumbling blocks I hit were the same ones others have talked about:
scarcity of tools, and a lack of pure-scala libraries &amp;ndash; both probably due to
the language being so new. Coming from java, it felt great to express myself
with python conciseness. It was like opening up the space capsule and
breathing fresh air again. Coming from ruby, it was reassuring to write for a
platform and libraries that are solid and well-tested, not just an &amp;ldquo;overnight
project&amp;rdquo; like many of the core ruby libraries appear to be.&lt;/p&gt;

&lt;p&gt;Oh, and in the end, my Starling port was only a little over 900 lines long. I
think if I added proper config file support like Starling has, it would end up
being roughly the same number of lines (1000), even though I had to write a
few large pieces (like the memcache codec) that aren&amp;rsquo;t necessary in ruby.&lt;/p&gt;

&lt;p&gt;The end result, which I plan to keep playing with and expanding, is here:
http://github.com/robey/scarling/tree/master&lt;/p&gt;
 
        <a href="http://flattr.com/thing/40430/Robey" target="_blank">
        <img src="http://api.flattr.com/button/button-compact-static-100x17.png" alt="Flattr this" title="Flattr this" border="0" />
        </a>
      </content>
    </entry>
  
    <entry>
      <title>Scala infatuation</title>
      <link href="http://robey.lag.net/2008/03/16/scala-infatuation.html"/>
      <updated>2008-03-16T00:00:00-07:00</updated>
      <id>http://robey.lag.net/2008/03/16/scala-infatuation</id>
      <content type="html">
        &lt;p&gt;Why my recent infatuation with scala? (Actually, since it&amp;rsquo;s reaching a half
year, I guess it can no longer be called an infatuation.) Here&amp;rsquo;s my answer in
the form of a quick example. I want to determine the average of a list of
timings for something.&lt;/p&gt;

&lt;p&gt;In python:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;timings = [1.2, 1.5, 1.3, 1.5]
reduce(lambda a, b: a + b, timings, 0.0) / len(timings)
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;In ruby:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;timings = [1.2, 1.5, 1.3, 1.5]
timings.inject(0.0) { |a, b| a + b } / timings.length
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Besides demonstrating that ruby is just python with different spelling, this
shows they both have some powerful built-in functions and syntax. I can type
one line for calculating the average and move on to the real point of my code,
whatever that is.&lt;/p&gt;

&lt;p&gt;Here it is in scala:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;var timings = Array(1.2, 1.5, 1.3, 1.5)
timings.foldLeft(0.0) { (a, b) =&amp;gt; a + b } / timings.size
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;It&amp;rsquo;s pretty much the same! I can type code that is very close to the
pseudocode in my head, and move on.&lt;/p&gt;

&lt;p&gt;Whether intentionally or not, scala is borrowing very heavily from the &amp;ldquo;high
level&amp;rdquo; language features of python (and ruby). But it&amp;rsquo;s running on top of the
JVM, which is still the best combination of interpreter machine + libraries
out there. Python&amp;rsquo;s VM is amateur at best, and ruby&amp;rsquo;s is even worse. This way
is like getting my reeces cup, two great tastes that taste great together: a
high-level, pseudocode language on top of a racecar engine.&lt;/p&gt;

&lt;p&gt;I suspect this is the main reason scala has been getting a lot of attention
recently, in spite of the gaping lack of decent documentation or tools.&lt;/p&gt;

&lt;p&gt;Oh yeah, here&amp;rsquo;s that same code in java. I&amp;rsquo;m not including the creation of the
array, because that takes 5 lines all by itself, and wouldn&amp;rsquo;t be fair to
compare:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;// assume omitted var: List&amp;lt;Double&amp;gt; timings.
double sum = 0.0;
for (double d : timings) {
    sum += d;
}
double average = sum / timings.size();
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;For java versions before 1.5, it&amp;rsquo;s a lot worse.&lt;/p&gt;

&lt;p&gt;Incidentally, last night I found a
&lt;a href=&quot;http://www.codecommit.com/blog/scala/roundup-scala-for-java-refugees&quot;&gt;nice introductory article on scala&lt;/a&gt;,
which I skimmed and recommend.&lt;/p&gt;
 
        <a href="http://flattr.com/thing/40430/Robey" target="_blank">
        <img src="http://api.flattr.com/button/button-compact-static-100x17.png" alt="Flattr this" title="Flattr this" border="0" />
        </a>
      </content>
    </entry>
  
</feed>
