How the Internet really works: a story. With an incisive footnote about net neutrality.

Note: long, super-dorky and technical, but you should probably read the first paragraph at least.

I’m repeating the content of Footnote 9 here, because it’s the important takeaway: Stateful package inspection can be used to do a lot of nefarious things. Like, I once used it to redirect all unauthorized traffic on my wifi network to the web site of the World Beard and Mustache Championships (google it); and another person used it to edit all web pages loaded by unauthorized browsers so that all images appeared upside-down (http://www.ex-parrot.com/pete/upside-down-ternet.html). But you can also imagine it being used to do things like, “replace content from CNN.com with a random page from brietbart.com”, for example. That would be evil, but really obvious and you’d probably immediately suspect that something weird is going on. But stateful packet inspection can do things that would be just as evil but harder to notice. Like, “if a page is coming from CNN.com, delay all messages by 100 milliseconds”. If added to your router, or (much worse!) to the router on the ISP’s side of your Internet connection, then such a rule would make your web browser basically unusable for browsing CNN.com, but brietbart would still load just fine. And if you weren’t super-motivated to figure out why that was happening, you might just ignore the problem and not bother reading CNN, which is sometimes considered to be a left-leaning news source. And this is the kind of thing that “net neutrality” is really needed to prevent. Internet service providers should be allowed to slow down your connection if you’re genuinely using too much bandwidth and interfering with others’ ability to use their connections. But they should not be allowed to slow down your connection just because they don’t like the politics of the web sites you’re connecting to; or just because you’re connecting to Netflix.com which competes with their in-house ShittyISPTv.com. And those are things they totally could do with stateful packet inspection.

Back to the main content…

(I’m kind of writing this for the guys at the Reply All podcast, who seem a little naive about how the Internet really works for people who produce a podcast about… “the Internet”.)

My answer to the question above, based on a generic “browser” like, eg, curl (footnote 3):

  • First, preliminary notes:
    • A computer (a PC, or a laptop, or a router, whatever) can have one or more network interfaces. A network interface is a hardware thing that connects the machine to a local network where it can talk to other machines on that local network – usually between one and, say, a hundred other machines. (One machine if it’s your laptop and your workstation in your den, a hundred machines if it’s your company’s office.) A local network is a physical thing that enables computers to communicate with other computers connected to the same local network. For example, an Ethernet card in a desktop computer is a network interface that connects to other computers via Ethernet cables; similarly, WiFi USB dongle is a network interface that connects computers via short-range radio signals. Most machines have only one network interface, but many machines have more than one, and this fact is critical to understanding what “the Internet” is.
    • A machine with two network interfaces can be connected to two different local networks. And therefore, in principle, it could move data from one of those networks to another, by reading the data from one network interface and then sending that data on the other. In the case of your wifi router, one of those local networks is your wifi network that your laptop connects to, and the other is the shitty Comcast DSL connection your ISP provides. And in fact, this is what the “Internet” is: it is a network of networks, connected to each other via computers with multiple network interfaces. And the really magical thing about the Internet is that it lets a machine on one local network send messages to a machine on a different local network, even if there are a thousand local networks (and consequently 999 machines with multiple network interfaces) between them over which that message must pass. Considering how complex this process is, it is unbelievably reliable.
    • People who know a little bit about the internet usually have some factoid in their mind like “Every machine on the internet has a unique IP address, which is a number that identifies that machine among all others.” That’s not quite true. In reality, every network interface has a unique IP address. “IP” stands for “internet protocol”, which is the message protocol that actually allows data to make its way from network to network. (Footnote 1).
    • For the purposes of this exercise, let’s say that both the client machine and the server machine have only one network interface each. The client’s interface IP (that is, on the machine running the browser program) is 9.8.7.6, and the server’s IP is 10.20.30.40. Furthermore, let’s say the human-understandable name of the server machine is “server.name”. Or maybe “ietf.org”. No, let’s stick with “server.name” for now.
    • Let’s also say the URL (Universal Resource Locator) of the requested page looks like: “http://server.name/desired/url“. This is a string of characters in memory owned by the browser program. If the browser in use is curl, it would be memory reserved by the OS for the program’s command line, since curl is a command-line application that takes a URL as an argument.
    • When I mention “OS” in this document, I’m referring to the “operating system” of the machine on which a program is running. Like, Windows or Linux or MacOS. And when I say “OS kernel” I mean the actual code that implements the OS. One of the really important jobs of the OS kernel is to provide services that allow programs to perform the tasks I’m talking about. Like, instead of every individual program having to understand how to set up a TCP connection and track all the data associated with it, the OS knows how to do that. Programs running “on” the OS have a way to say “Hey OS, please make a TCP connection for me”, and the OS hands over a special “token” (usually just a unique magic number, made up on the spot) that the program can use to manipulate the connection. Those ways of interacting with the OS are called “system calls” or “entry points”. An OS provides hundreds or thousands of system calls to do various tasks that are best provided by a central entity rather than by each individual program. Kind of like: delivering Social Security checks is a service best provided by a central entity (the government), but making a sandwich out of the food you bought with your SS check is something you’d probably rather handle yourself. The program, in this metaphor, is you making a sandwich, and the OS is the government, and the system call is someone at the SSA mailing you your SS check. Or maybe the system call is you calling up the government to find out why your SS check is late, and then them mailing it to you. It’s not a perfect metaphor!
    • Finally, the Internet is a “packet-switched” network, which means that all data travels over the Internet in small packages that are routed and delivered independently. And those little packages are not even guaranteed to reach their destination. Remarkably, some of the communication protocols developed to work within those restrictions are able to guarantee that very long messages are delivered intact, in order, and with no missing pieces. I’ll explain how in more detail below.
  • Now to the actual meat of the process:
  • The browser builds an HTTP request in memory. That request is basically a string that looks like “GET HTTP 1.0 /desired/url”. That’s what an HTTP GET request looks like, according to the specification of the HyperText Transfer Protocol (footnote 2). This request will ultimately be delivered to the server that owns the page and will explain to that server exactly which web page the client wants it to deliver. But to deliver its HTTP request to the web server, the browser will need to make a network connection to the web server. This will be done using the TCP/IP protocol.
  • TCP is the Transmission Control Protocol, and TCP/IP is what we call it when TCP messages travel over an underlying IP network. TCP is a reliable stream protocol, which means you can use it to send arbitrary streams of data – such as, for example, the contents of a file – and that data is guaranteed to end up at the destination in the correct order and with no missing pieces. If that cannot be done for some reason, the connection will fail, which is what we want – TCP connections are supposed to be reliable, and if our connection can’t operate in a reliable way, it needs to die immediately so we can know there’s a problem. And note that even though from, for instance, the browser’s perspective it can use a TCP connection to send or receive arbitrary amounts of ordered data, this doesn’t change the fact that the Internet is a packet-switched network: in reality, all that data gets chopped up into little messages, sent and received in some order that is not necessarily the order the sending program sends the original data in, and re-assembled and put back in order at the destination. It’s kind of like if you were writing a 50-page letter to send via the Postal Service, but instead of mailing the whole thing in one giant manila envelope, you mail each individual page in a single envelope, and each envelope is marked “page 1”, “page 2”, etc. When they have all the pieces, the recipient can re-assemble the complete document, and if they find out that, say, page 5 is missing, they can send you a letter saying, “Hey I didn’t get page 5, can you send it again?” In the case of TCP, the OS kernel handles all the pesky details of ordering, assembly, and making sure all the pieces are present.
  • The browser establishes a TCP/IP connection to server.name on TCP port 80. There’s a lot (a lot) going on in that statement.
    • First, the browser has to convert the name server.name to a numeric Internet Protocol address (footnote 9). In a typical case, this means calling an OS system call that (ultimately) sends a Domain Name Service request message to whatever IP address is configured as the DNS server for the local network interface. This is a complex task in itself and I don’t know all the details of how DNS works, but in essence, a DNS server is a machine that either knows the numeric IP associated with the name server.name, or knows how to ask another machine that knows how to get that information. So it finds that IP address and sends it back to 9.8.7.6. The result is a simple 4-byte integer value representing the IP address (footnote 4), which is usually written as a dotted quad like 10.20.30.40. From now on, just remember that the machine name server.name corresponds to the IP address 10.20.30.40.
    • Important side note: this idea that “either I know how to do this thing myself, or I know how to ask another machine that knows how to do the thing” is a pervasive pattern in the infrastructure of the Internet. And kind of also in human organizations, I guess, but it is very formal and explicit in the case of the internet, in a number of different contexts.
    • The browser creates a socket, which means asking the OS kernel (via a system call) to create a data structure associated with the browser process that will be used for TCP communication. From the browser’s perspective, the socket is just a number that it can use in network operations to send and receive data. The OS kernel knows the association between the socket number and its internal data structures that track the connection.
    • The browser tells the OS kernel to connect the socket to 10.20.30.40, TCP port 80. (A “port” is just a number that represents a particular process running on the server machine, and it’s also part of every TCP protocol message. Conventionally, web servers use port number 80.) The OS has a lot of work to do to fulfill that request:
      • It has to figure out which physical network interface the connection will be made through. That is, which cable or wifi connection is the appropriate one for this connection’s data to travel through. This is a “routing” question, and it’s another instance of the pervasive pattern mentioned above, as we will see. Routing is performed at the Internet Protocol level, and works in terms of numeric IP addresses.

        The kernel consults its routing table, which, in essence, associates any numeric IP address with the appropriate network interface and next hop IP address. The routing table is configured (typically) when the machine boots and brings up its network interface(s), and can either be statically (manually) configured, or automatically configured via some mechanism like Dynamic Host Configuration Protocol (DHCP) or IPv6 auto-configuration. I’m not going to go into any further detail about that; just be aware that DHCP is one way that a machine can acquire routing information (it’s probably the way your laptop gets its routes), and that there are other ways this can happen.

        For any given target IP address, there are exactly three possibilities that the routing table can know about:

        1. The target address is directly reachable via a local network interface – that is, the target address is that of a machine directly attached to the local wifi or wired network, in which case the next hop is simply the target address; or
        2. The target address is not directly reachable via a local network interface, but the routing table specifies the address of another machine that (a) knows how to deliver data to the target address, and (b) is reachable via a local network interface. That machine is called the “router” for traffic passing through the network interface, and the router’s IP is the next hop; or
        3. The routing table doesn’t know how to reach the target address, in which case the whole network operation fails and the OS tells the browser process “Sorry, I couldn’t set up that connection, I don’t know the route”. (This rarely happens.)

        To be more precise, the routing table maps prefixes (footnote 5) of IP addresses to network interfaces – eg, it might know that any IP starting with “192.168” should use interface 2. It doesn’t have to have a comprehensive catalog of every IP address on the whole internet; all it needs to know is (a) the correct network interface for each prefix corresponding to a local, directly-connected network, and (b) the correct (local) router IP and network interface for any non-local network prefix.

        Most importantly, a routing table can have a “default” route, which means, “If none of the other route table entries matches this address (prefix), use the interface and router for the default route.” In other words, the routing table either knows which interface to deliver data on, or it knows which machine (router) to send data to in order to get it delivered. This is the “pervasive pattern” mentioned above.
      • In this case, let’s assume (as is typical) that the routing table doesn’t know anything about the address 10.20.30.40, and so the connection needs to go via the default route, via the router machine specified in the routing table. Let’s say the default router machine’s address is 9.8.0.1. That address is the next hop address for the target address 10.20.30.40: the local machine’s OS kernel must send traffic to the router at 9.8.0.1, and assume the router knows how to deliver it to its destination. The router could be a consumer router box, like an Airport or a Netgear box you’d buy at Office Depot; or it could be a regular PC that’s set up to perform routing; or a number of other possibilities. (It literally could be a guy with a cage full of homing pigeons and a notebook full of pigeon routing data. Like, this has actually been done: https://en.wikipedia.org/wiki/IP_over_Avian_Carriers)
      • The OS for 9.8.7.6 must now send a message to the next-hop address saying, “Hey, I’m trying to talk to 10.20.30.40 port 80, please pass this request along to them and hook me up.”
        • At this point the OS kernel knows it needs to send this request to a machine on a local network (9.8.0.1), and it knows which of its own physical network interfaces to talk to that machine on. But how does it talk to the target network interface on the 9.8.0.1 router? That is, how does it physically transmit data from its own network interface to another machine’s interface on a local network?
        • Every network interface has a physical address, which is essentially a number unique to that specific hardware interface and which that interface can recognize when a data packet with that physical address appears on the network. (Luckily, there are a lot of numbers to pick from, so we don’t really need to worry about duplicate physical addresses. Very large ranges of physical address numbers are assigned to manufacturers of network equipment by a central authority, the Internet Committee on Assigned Names and Numbers, so that each interface device manufactured can be assigned a unique physical address.) When a message goes across the wire (in the case of an Ethernet network, for example), this wiggles the electrical voltage in a way that corresponds to the contents of the message. The first few wiggles will correspond to the physical address of the target interface, and that specific pattern of wiggles will cause that interface to pay attention to the message. This electrical response is built into the network hardware itself.
        • The local OS kernel needs to send a message to the physical address of 9.8.0.1’s network interface, but how does it know that address?  This is the local address resolution problem, and it is solved by the Address Resolution Protocol (ARP).
        • The local machine (9.8.7.6) sends a broadcast ARP request on the local physical network. This is a message that all connected network interfaces on the local net will receive and process, using the physical network’s “broadcast address”. The broadcast address is a special sequence of voltage wiggles that all network interfaces are programmed to pay attention to, in addition to their own specific physical address. So to send a broadcast message, you don’t need to know all the physical addresses on your local network. You can just send a message saying “EVERYBODY LISTEN! I need the physical address corresponding to IP address 9.8.0.1! Send that to my physical address, which is xxxYYYzzz!”
        • 9.8.0.1’s OS kernel (along with everyone else on the local net) sees that message. Since 9.8.0.1 knows its own physical address, it responds by sending its own physical address back to the source of the broadcast ARP message (xxxYYYzzz in this case). None of the other local machines know the answer to the ARP question, so they just ignore it. (In reality, these ARP requests aren’t needed for every message that any machine sends – usually each machine remembers the answers to ARP requests for a while so that it doesn’t have to ask over and over again.)
        • Side note: ARP is not an example of the “pervasive pattern”. All ARP requests happen entirely over some local network, among machines that are, so to speak, mutually acquainted with one another. There’s never a need to defer an ARP request to some more-distant machine.
      • Now that the browser machine (9.8.7.6) has the physical address of 9.8.0.1, it can send its “Connect me to 10.20.30.40 TCP port 80” request to that machine.
      • The router machine at 9.8.0.1 receives that request and then the whole routing process happens again, from 9.8.0.1’s perspective. It has to figure out the next hop for the “Connect to 10.20.30.40” request it just received, which again is either going to be an address on a local directly-connected network,  or a router that knows how to send the request on to its destination.
      • Eventually, after how ever many routing decisions and hops and ARP messages are required, that request arrives at the proper network interface at the server machine, 10.20.30.40. The complete content of that request is, essentially, “Hi 10.20.30.40, I’m 9.8.7.6 and I want to establish a TCP connection to you at port 80”. Technically this is expressed in the form of a “SYN” message, which means “SYNthesize (create) a new connection”.
      • The OS kernel on 10.20.30.40 verifies that there is a server process “listening” on TCP port 80 (if there isn’t, the network connection will fail and that failure reported back to the browser on 9.8.7.6, which is another whole process that I’m not going to go into right now). It builds the appropriate internal data structures to track the new connection.
      • Now 10.20.30.40 knows the identity of the machine trying to connect (9.8.7.6, which was included in the connection request), so it can route its reply back to that machine. Routing happens again, starting at the 10.20.30.40 machine, and the reply, a “SYN/ACK” (acknowledgement of SYN) message, travels back to 9.8.7.6, over however many intermediate “hops” are required. (Usually, but not necessarily, this would involve the same sequence of local networks and routers as the original request, but in the opposite order. But if, for example, someone unplugged one of the routers involved, a different route might be found to get data back to 9.8.7.6. Or, the return route might just fail and the TCP connection would then fail.)
      • When it sees the SYN/ACK reply, the 9.8.7.6 OS says “Yay, my connection is accepted!”, and replies with an “ACK” message. When 10.20.30.40 receives that message, it fills out any remaining information necessary to track the interaction with 9.8.7.6.
      • 10.20.30.40 creates a new socket which it gives to the web server application to represent this new connection, and this completes the connection process. Note that there is no ongoing electrical connection between 9.8.7.6 and 10.20.30.40; the connection consists entirely of data structures in each OS’s kernel that allow them to build and interpret messages associated with the network connection and associate those messages with the sockets on each side of the connection.
      • The web server process takes the new socket, which it acquired via an accept() system call into the OS kernel – the server process calls accept() very frequently, asking the kernel “are there any new connections for me?” The web server saves the socket number in a place where it can conveniently read data coming from the socket and write data to it.
      • Every message that gets sent between these two machines on this connection will go through the routing process described above, but all the browser cares about is that when it sends data on its socket, that data ends up at the web server process at 10.20.30.40; and all the web server process cares about is that when it sends data on its own socket, that data will end up at the browser process on 9.8.7.6. Those programs don’t have to be concerned with routing or network transport; that is the OS’s problem. So a socket is just a number, but it represents a rather complex underlying process for moving data between two machines, which is always at work behind the scenes whenever a TCP connection is active. (This is also kind of analogous to the Marxist concept of “commodity fetishism”, where a manufactured object reflects, in a hidden way, the astronomical amount of complexity and human effort that went into making it.)
      • The OS kernel on 9.8.7.6 also associated a TCP port number with the socket it created at the browser’s request; most likely it chose that port number at random (more or less). Let’s say that port number is 12345. Then the “name” of this TCP connection, unique across the entire internet, is “9.8.7.6:12345::10.20.30.40:80”. No other TCP connection corresponds to those specific IP addresses and their respective port numbers. Every TCP message passed along this connection will contain this name, and thus all the machines involved (the end points and the routers) know exactly where each message came from and where it’s going, and can always figure out the necessary “next hop”.
    • Now that a connection is established, the browser can send its HTTP request (which, recall, is the string “GET HTTP 1.0 /desired/url”). It makes a “write” request into its OS kernel on its TCP socket, with that message as the content. That request gets packaged as one or more TCP messages associated with the connection. Those messages are routed to their destination as described above. They may be delivered in a different order than they were sent, or they may not be delivered at all (in which case 9.8.7.6 might need to re-send them after a period of time – the details are handled by the TCP protocol logic in the OS kernels of the machines involved, and those details are what makes TCP a “reliable” protocol. The receiving machine can always tell whether a message is complete and in the correct order, and can ask the sender to re-send any missing pieces). In any case, the OS kernel at 10.20.30.40 eventually receives all the messages associated with the HTTP request, assembles them in the proper order, and feeds them to the socket that it created for the web server process. Importantly, the OS does not care at all what the contents of the message are – its only job is to deliver it on to the web server process (footnotes 7 and 8 – these are the incisive ones).
    • The web server notices that its socket is ready to read data, and it makes a “read” request to its OS kernel, and reads the message “GET HTTP 1.0 /desired/url”. (How does the web server notice that the socket is readable? Typically this involves an OS system call called “select()”, which lets a program ask the OS, “Is there anything interesting happening with this socket?” But really a program is usually managing a bunch of requests from different network connections, so it can actually ask, “Is anything interesting happening with any of the sockets I care about, and if so, which ones?”)
    • At this point, depending on the web server in use, there are a lot of different things that could happen. But let’s assume that “/desired/url” actually refers to a file called “hello.html” on the web server machine. The web server process figures this out somehow – the details are internal to the web server, but it might be as simple as a table in memory that says,

      URL /x = file y
      URL /w = file z
      URL /desired/url = file hello.html
      [etc].

      (Note: usually it isn’t that simple.)
    • The web server asks its OS kernel to open file hello.html. That is also a rather complex process, although perhaps not quite as complex as routing.
      • A file is one or more chunks of data sitting on a disk. All those chunks are linked together in a particular order, and are somehow associated (in this case) with the name “hello.html”. The details of the arrangement of data on the disk are specific to the “file system” in use (or more idiomatically, filesystem). A filesystem is just a set of rules for organizing and naming data in blocks on a storage device (like a hard disk). The OS knows about the file system and how to interpret that data on the disk properly. It also knows all the details for actually writing and reading data on the disk, which I’m not going to get into here.
      • When the OS opens the file on behalf of the web server process, it gives the web server a number (called a “file descriptor”) representing the open file, and builds the necessary internal data structures to track the association between the file descriptor and the on-disk data. The web server can now use the file descriptor to read the data from the file, using the OS’s “read” system call. A file descriptor is basically the same kind of thing as a socket, only it represents a disk file rather than a network connection.
      • The web server makes “read” system calls to the OS to read the data out of the file. Usually each of those requests asks for a fixed amount of data, for example, “Please give me the next 1024 bytes of data from this file descriptor, after the last piece I read”.
      • Each time it successfully reads data from the file, it writes that data to the socket representing the TCP connection to 9.8.7.6.
      • The browser at 9.8.7.6 makes a series of “read” requests on its socket and reads the messages coming across the connection, which (amazingly!) correspond to the contents (in order) of the file “hello.html” on the web server.
      • Once the browser has received all the data, it displays the resulting web page to the user. In the case of the curl program, it just dumps the page text out to the command terminal. In the case of a browser like Firefox, there is a very complicated set of rules that the browser uses to convert the HTML text in the file to the pretty page you see in your browser window. For example, if there’s a part of the page text that looks like “<title>I am the title</title>” (pronounced “left-angle-bracket title right-angle-bracket I am the title left-angle-bracket slash title right-angle bracket”, or slightly more conveniently, “title-tag I am the title close-title-tag”), that will cause “I am the title” to appear in the title area of the browser window for that page. I could write more about how all that works, but it’s getting a little beyond the main point of this post, which is more along the lines of “How does the internet actually work.”
      • Normally, once the browser has read the page contents, it will close the socket connection. This causes another set of special TCP messages to be exchanged between 9.8.7.6 and 10.20.30.40 to say, “Hey, I’m done with this connection, please shut it down”, and both OS’s will clean up the data structures tracking the connection. If either the browser or the web server program try to use their respective sockets after that, they will get an error that basically means “this socket isn’t connected”.
      • While this story has concentrated on the specific case of a web browser communicating with a web server via TCP/IP, it’s important to realize that all interaction between programs over the internet uses the same routing and transport facilities provided by the IP protocol. There areother protocols besides TCP that work over IP; the other most common one is the User Datagram Protocol, ur UDP, which allows programs to send short (usually < 2000 characters) messages with no persistent connection and no guarantee of ordering or delivery. That sounds pretty useless compared to TCP, but there are a lot of cases where it’s super-useful – for example, when you want to send short events to alert another program of some condition, and you’re willing to manager any necessary redundancy and ordering issues yourself (within your program).
  • So, that’s basically it. Except the footnotes. Read on if interested.

Footnotes:

  1. The IP addresses of network interfaces can change, and sometimes do, but there’s additional magic at work to be sure that none of the machines involved get confused about this. It’s pretty safe to assume that during any particular interaction that happens over the internet, the IP addresses of the machines involved won’t change. But for example, I mentioned above that when a machine is first booted, it figures out its routes using the DHCP protocol. This is a protocol that works between a computer and a router on a local network that lets a new-born OS kernel figure out what IP address it should use, which DNS server it should consult for name resolution, and so forth. DHCP stands for Dynamic Host Configuration Protocol, and that “dynamic” part is important: it means that usually, the router just picks some local IP address that it knows isn’t in use and assigns it to the interface being configured. And probably every consumer router uses DHCP, to save users from having to understand any of the stuff in this post. So one way that your machine’s IP address can change is that probably, every time you reboot your machine it ends up with a new IP. You can see this in the “advanced network settings” in your computer’s control panel.
  2. The HTTP protocol spec, which you can read here https://www.ietf.org/rfc/rfc2068.txt if you’re interested in all the details. Most standards that govern internet operation are freely published as “RFC” documents on the ietf.org site. “IETF” stands for Internet Engineering Task Force, and they are the people that manage most of the technical standards on which the Internet is based. (There’s also the World Wide Web Consortium, which is responsible for standards relevant to the web, but they don’t deal with low-level networking stuff. They deal with things like, “How exactly should a browser convert HTML text into nice page images” and things like that.) “RFC” stands for “Request for Comment”, which is ordinarily the first step of developing a standard that will be published as an OFFICIAL STANDARD DOCUMENT. But in IETF-world even confirmed standards are called “RFC whatever”. It’s just a tradition.
  3. curl is a super-handy utility you can run from a terminal window (for example, a DOS prompt in Windows) to fetch the contents of a particular web page and print them out as plain text. You can download it from https://curl.haxx.se/
  4. IPv4 vs IPv6 addresses: today there are, broadly, two different “versions” of the Internet running kind of in parallel. One is based on the old Internet Protocol standard, IPv4. The other is based on a newer standard, IPv6. (We don’t talk about IPv5.) The primary difference between them is that IPv4 addresses are 32 bits long (32 digits in base 2, using only 1 and 0 digits), which allows for about 4 billion unique IP addresses. It turns out that isn’t enough and we’re running out pretty rapidly – like, there will come a time very soon when it isn’t possible to assign a machine a new, unique IPv4 address. IPv6 addresses are 128 bits long, which allows us to assign a unique IPv6 address to, approximately, every molecule in the Solar System, so we probably don’t need to worry about running out of those. Anyway, it’s pretty likely that your machine’s network interface has both an IPv4 and an IPv6 address assigned, and routing will use the IPv6 address when that’s possible. The routing process is essentially the same in both cases, it’s just the format of the addresses that is different.
  5. Also, we’ve figured out “ways” to deal with the shortage of IPv4 addresses. Mainly this involves re-using a lot of those addresses inside “walled private gardens” in ways that we know are generally safe. The fact that an IP address inside one garden might be the same as one in another garden is unimportant, because the routers in the middle can use clever techniques to prevent those two machines from needing to know each other’s real IP addresses, even when they have to talk to each other. Almost all consumer home routers treat the machines on the “home” network as one of these walled gardens, which is why five million people can buy iPhones every day and hook them up to their wifi networks and that actually works. It’s really smart and cool but would take another ten pages to explain well. Google “IP masquerading” and “Network address translation” if you’re curious. Also “proxies” are an older and less smart way to do basically the same thing the network address translation does.
  6. How routing tables really work. Hmm, never mind, it’s too complicated and doesn’t really add much to the overall story. (And I don’t want to re-number all the footnotes because WordPress doesn’t make that especially easy to do. Or maybe I just haven’t figured out the easy way.)
  7. I said the OS doesn’t care about the contents of TCP messages, it only passes them along to the programs on either end of the connection. That isn’t strictly true, because of something called “stateful packet inspection”. Most OSs have a “firewall” component that allows users or administrators to supply rules that prevent bad hombres from sending yucky messages to their machines. Often those rules are just based on the sender, for example you could have a rule that says “don’t accept any traffic from any of the IP addresses on this list” (a “blacklist”), or one that says “only accept traffic from this list of IPs (a “whitelist”, which is somewhat less convenient to administer because there are like ten billion machines connected to the internet now). But you might want a rule that says, “don’t load any images from web pages if they’re going to these specific local IP addresses” (like, maybe you are super-paranoid about your kids accidentally downloading porn, or, perhaps, you want them to just hate the internet completely). And in that case, you need stateful packet inspection, because the OS’s firewall needs to be able to notice when a “please download this image” message goes by and kill that sucker dead. It can’t do that just by looking at the message addresses, it has to look inside the message and see the content.
  8. Stateful packet inspection can be used to do a lot of nefarious things. Like, I once used it to redirect all unauthorized traffic on my wifi network to the web site of the World Beard and Mustache Championships (google it). But you can also imagine it being used to do things like, “replace content from CNN.com with a random page from brietbart.com”, for example. Or things that would be just as evil but harder to notice. Like, “if a page is coming from CNN.com, delay all messages by 100 milliseconds”. If added to your router, or (much worse!) to the router on the ISP’s side of your Internet connection, then such a rule would make your web browser basically unusable for browsing CNN.com, but brietbart would still load just fine. And if you weren’t super-motivated to figure out why that was happening, you might just ignore the problem and not bother reading CNN, which is sometimes considered to be a left-leaning news source. And this is the kind of thing that “net neutrality” is really needed to prevent. Internet service providers should be allowed to slow down your connection if you’re genuinely using too much bandwidth and interfering with others’ ability to use their connections. But they should not be allowed to slow down your connection just because they don’t like the politics of the web sites you’re connecting to; or just because you’re connecting to Netflix.com which competes with their in-house ShittyISPTv.com. And those are things they totally could do with stateful packet inspection.
  9. Why can’t we just use names directly, rather than converting them to IP addresses first? Well… it’s complicated, and I may not be aware of the really really true reason, but here are what I consider some good reasons: First, the address parts of IP messages are very convenient to process if they have a fixed size, but domain names can be nearly any length, so having site names embedded in every Internet message would be a pain for OSs to deal with – it would add a lot of complexity for very little gain (this is probably the really really true reason). Second, not all machines even have names – your laptop probably doesn’t have a name that could be used unambiguously in network messages, for example, but it definitely has an IP address if it’s connected to a network. Third, people care about names in ways that they don’t care about numbers – you probably would love it if you, PJ Vogt of Reply All, could host your personal web site on a server named pjvogt.net, but you probably don’t give a shit what the IP address associated with that name is. So we want people to be able to care about their Internet site names, but we don’t want the underlying technical infrastructure to have to care about them very much. (Except that stateful packet inspection does care about names, potentially.) The Domain Name Service is basically a way of “factoring names out” of the internet equation so that everything can carry on in a name-agnostic way.

All Programming Is Language Design

“All programming is language design.”

I’m surprised there aren’t ten dozen solid Google hits for that sentence.

What follows is a collection of early thoughts about this idea. I do intend to follow up with some more specific and explicit examples, which I’ll be posting soon.

I came across the phrase “language-oriented programming” a couple days ago. Forth and Lisp advocates have been talking about this idea for decades. I’m no expert on LOP as a paradigm, and clear explanations of it seem pretty thin on the ground. But having been exposed extensively to the Lisp and Forth communities, and having read a good few of the foundational texts of those communities (Brodie, Hoyt, Graham, SICP), I feel I have a pretty good idea what LOP advocates are talking about. It means extending your implementation language to build a domain-specific language in which expressing the solution to your problem is straightforward. You’re not (or not necessarily) building interpreters or compilers; rather, the main focus of LOP involves extending the base language to encompass the domain of interest. The clearest example of this that I can think of is Leo Brodie’s high-level control structure for a clothes washer’s Forth firmware (from Starting Forth):

: CYCLE   WASH SPIN RINSE SPIN ;

which defines the word CYCLE to execute the words (subroutines) WASH, SPIN, RINSE, and SPIN, in that order. Those words invoke others that, ultimately, poke at the hardware necessary to make the washer behave in the manner that is self-evident from the high-level code. There would most likely be additional high-level Forth words defined to adjust global parameters of the washer behavior, such as water temperature and agitation intensity, and those words, like WASH and SPIN, would have self-evident meanings in the domain of washing-machine control.

It seems to me that all programming can and should be approached in this manner. You can do this even if your implementation language isn’t among the ones LOP advocates… um, advocate.

Don’t Repeat Yourself is almost the same idea looked at from a different point of view: if you see an operation being repeated more than once, factor it out – that is, write a function or class or template that cleanly encapsulates that operation. In most languages in popular use today, such a refactoring makes the operation a primitive, indistinguishable syntactically from the contents of the language’s standard library. In languages like Haskell that heavily reward composability, perspicacious factoring can result in remarkably compact and clear code. (Or remarkably dense and hard-to-understand code, depending on your point of view and level of experience. In the specific case of Haskell I’m in the second camp at present – I know just enough to be dangerous. Confused and dangerous.)

LOP seems something akin to anticipatory DRY, or top-down factor-finding. Rather than simply noticing code that can be factored out, the programmer begins by deciding what vocabulary would be most useful. But most of us just call that “design”.

One thing that can be done fairly easily in Lisp and (to some extent) Forth but which is not so easy in most mainstream languages is to embed completely different programming paradigms within your implementation. For example, it’s pretty straightforward to build a unification engine in Lisp that can be applied directly to s-expressions, and then build logic programming facilities a la Prolog on that foundation. You’d end up with a first-order-predicate-logic theorem prover that could be applied directly to Lisp objects from within normal Lisp code. Or you could use Lisp’s macro facility to embed idiomatic Prolog syntax in your Lisp code and capture the results as normal Lisp objects (atoms, lists). This is so because Lisp gives you direct access to the AST and the compiler from user code. (Homoiconicity helps a lot.) To do something similar in C++, you would basically have to implement a complete Prolog interpreter, and once you’d done so you wouldn’t be able to use it directly from your C++ code. Instead, you’d need to define an API by which C++ entities that represent Prolog terms get passed to and from the Prolog engine. There is a fine line here – most Lisp programmers, I suspect, would not go as far as embedding syntactic Prolog within Lisp code, because they probably prefer Lisp syntax (which anyway isn’t that different from Prolog); and a sufficiently motivated and knowledgeable C++ programmer could probably figure out how to do it in C++. I’m just saying that in Lisp it’s natural to build such facilities, ones that change the basic nature of programming, and that’s not so true in C++ and other mainstream languages. The point is that Lisp allows you to leverage a form of “language-orientation” that is qualitatively different than what most mainstream languages permit. Opinions differ (amazingly!) on whether this is a Good Thing.

Notwithstanding the previous paragraph, both high level design and low level refactoring are language design acts, no matter what the implementation language and no matter how conscious the programmer is of this process. Their goal is to make the code more able to concisely express ideas in the problem domain. Really good code reads like statements in or about the domain – in other words

salesBonusWinner = highestNetSalesPerson(salesPersons);  // Block A

is preferable to

// Block B
salesPersons.sort(x,y => compare(y.getNetSales(),x.getNetSales());
p = salesPersons[0];

because ten years from now, a maintainer reading Block A does not have to think for even one millisecond in order to understand what it is doing. Wrapping block B in a function that allows you to write block A is a good thing because it makes the code more understandable.

It might also be a bad thing, from a different point of view. You’ve introduced the overhead of an additional function call, so performance might suffer. If highestNetSales isn’t called a few times in the code base, you may have more rather than less code to maintain. Personally, at this point in my 20-plus-year career I’m inclined to factor meaningful function names out of any code whose purpose isn’t obvious at a glance, even if those functions only end up getting used once. Making code understandable is far, far more important, from a human-labor perspective, than eking out every iota of performance from constantly-speedier hardware, or minimizing the absolute size of a code base as measured in lines of code.

Of course this assumes that function and method names reflect their behavior. But if you’re not prioritizing function names that allow readers to understand behavior, you’re headed for trouble and you are going to get what you deserve. That means, in particular, that if your code relies pervasively on side effects that are difficult to make evident in reasonably brief function names, you are likely to have a hard time factoring your code in a “language oriented” manner. Or, turning that upside down, the idea of LOP seems to implicitly emphasize minimization and segregation of side effects, which is a good principle in general.

(Side note: Javascript has some features that make LOP easier, notably functions that are both first-class and higher-order. But the very business of Javascript is manipulation of the DOM, which is essentially a giant stateful blackboard whose primary reason for existence is to reify side effects. That means great care is needed to write JS that isolates those side effects and provides meaningful names to the code that implements them.)

Maybe the point of LOP is to make name selection an obvious priority. This is really all about getting programmers to pay attention to factoring and naming. Software engineering luminaries talk constantly about the importance of naming. The LOP advocate responds, “Well, sure. You’re designing a language. On what planet would the words that make up that language not be an important consideration?”

And furthermore, you’re not just designing a language: you’re designing a language whose audience will be composed largely of foreign language speakers. (Personally, I’m crap at human languages – I’m too introverted to actually enjoy the process of not being good at communication, of trying to understand and figure out whether I’m being understood given limited proficiency. So this metaphor may be worth what you pay for it. But anyway…) Hardly anyone is going to sit down in front of your code for the first time and be an expert on both the implementation technology and the target domain. From a maintenance perspective, selecting names that allow that gap to be bridged is super-duper important. Even if Joe Maintainer is highly experienced in the implementation technology or the domain or even both, they need roadmarks that allow them to locate domain concepts in the code. If the code is just a ball-of-implementation with no obvious relationships to the domain, Joe is going to hate you. If you can’t think of an obviously good name for a function, that’s a pretty good clue that it’s doing too much or not carving the domain at the joints, and you need to think further about the language you’re designing.

None of this should be taken to mean that I think good naming will solve every problem. We need to remember and apply the basic principles of program design, SOLID and DRY and all the rest. We need to use the facilities of our implementation language idiomatically so that others will be able to read and understand our code at that level easily. No amount of name shuffling will save you from a tangled and deeply nested class hierarchy. Sometimes you need to apply major refactoring to get to the point where viewing your code as a domain-centric language even makes sense. But you are always building a language, either well or poorly, when you write code.

All of the above is just a long-winded way of saying that the statement “All programming is language design” is, in my view, obviously true. Designers and programmers should always be thinking about the structure and vocabulary of the language they are designing and how it makes the relationship between code and domain more or less transparent. “Always be thinking about”, not just “think about” – it’s inevitably an ongoing process, not something you can do once at design time or whatever. And we shouldn’t think that doing “language-oriented programming” requires any particular language or technology. We’re doing language design all the time, whether we like it or not, so we should learn to do it well. If we don’t, we’ll do it badly and reap the consequences.

References

All the material below is available to read on-line. Of course, you can always choose to support the authors by buying a physical copy.

The appearance of complexity

This is a screenshot of the “galaxy” screen saver from Jamie Zawinski’s xscreensavers collection (which is free and you can run it on any device you like as long as it isn’t Windows – but it does work on iPhones and Androids and Macs and has dozens of more-or-less fascinating screen savers, contributed by many people). “Galaxy” is an impressive-behaving bit of code: it simulates galaxies made up of hundreds (thousands?) of individual stars interacting and (mainly) colliding with one another. (The galaxies colliding, that is.) Each star is represented as a dimensionless point, so there aren’t any actual collisions between stars, but the gravitational effects are really interesting to watch and it looks like a huge amount of effort must have gone into just getting the gravitational dynamics right.

Plus there’s the fact that this is an OpenGL program. That means (1) it’s very very fast (if your computer has a good graphics card, which don’t worry about it, it does unless you are still nursing along a machine you cobbled together from parts in 2008 [raises hand]), but (2) there’s a whole pile of incidental complexity involved in managing all the interactions with the graphics subsystem, 3D models of the objects involved (wait aren’t they dimensionless points?), etc. Looking at it from a programmer’s perspective, I thought, “Wow, if I can understand how that thing works, that’d be pretty cool and my life might once again begin to have a glimmer of meaning. Which since I can’t really eat anything today because chemo, would be a nice change.”

It’s less than 300 lines of code.

Wait what?

Yeah it’s just a trivial hack really. Some guy at CERN probably wrote it during lunch back in 1993 or so.

You are f**kin’ with me.

No really, the source code is right here. It’s really very simple.

It’s true. 214 actual lines of code in galaxy.c. The vast majority of which compute gravitational dynamics (doing it seriously wrong to get some additional speed), and only maybe five lines of which have anything to do with pushing graphics to the display. It basically computes the position of each star during each frame and then calls a routine that bulk-paints a point cloud to the display. That display routine is part of the xscreensaver library, which makes talking to OpenGL hardware very very easy (as long as all you really care about is writing screen savers).

It’s interesting how it computes the position of each star: all it does is figure out the attraction between each star and the center-of-mass of each galaxy. Then it uses that attraction to update the velocity of each star and uses that velocity to compute the star’s position in 3D space in the next video frame (this is all basically multiplication and addition). So even though there are thousands of stars, it doesn’t care how they interact with each other, just how they interact with the big blobs of mass, the galaxies. And that means that rather than computing (literally) many millions of gravitational interactions for each video frame, it can do a few thousand, which is hardly any at all for today’s CPUs, which are like, “Jeez enough with the adds and multiplies, at least let me do a cosine!”. It doesn’t bother looking at the interactions between individual stars, because (a) they’re dominated by the far-more-massive galaxies (or more accurately, it uses a notional idea of each galaxy’s location and mass as a proxy for the collective gravitational influence of the stars that make up the galaxy), and (b) this is just a screen saver so who the heck is ever going to care that the exact trajectory of a simulated star across their screen is a little off? Or totally wrong? Nobody! Only some obsessive nerd who thinks screen savers should have some relation to reality!!

And then it does the same thing to compute the future position and velocity of each galaxy. Which means that as the stars get flung around by gravity, each “galaxy” probably ends up being modeled by a point in 3D space that has very little to do with the actual centroid of the stars that comprise it. So that’s another way that both star and galaxy positions will end up in completely unrealistic places. But again, who cares? The point is to look cool, not be an accurate simulation of gravitational dynamics.

Also there is some dodgy math that I don’t think implements the G equation really strictly correctly. Have I said “Who cares?” enough times yet? Hey dude, you’re the one writing a thousand-word blog post about this.

So “galaxy” achieves the appearance of great complexity with two strategies:

  1. Gravitational dynamics are genuinely very simple to compute, and the code takes some interesting shortcuts to make them even more simple. But simple rules can lead to interesting complex behavior (that link being IMO the canonical example); in fact this happens all the time.
  2. It’s built on top of an infrastructure (the xscreensaver library) that hides a gigantic amount of complexity from the programmer. I’m just starting to learn OpenGL (because, haha, I am writing an Android game to take my mind off the cancer), and sheesh, that’s some complicated sh*t. Vertex shaders and fragment shaders and shader language and 3D models and oh my.

You’re probably waiting for some super-deep metaphor here about how our daily life seems so simple, but it’s built atop unbelievably complicated dehumanizing institutions, and how those institutions seem like we should understand how they work but ultimately in practice end up drifting into weird patterns and behaviors that who could have ever predicted, but the simplicity of love also leads to interesting complexities and so forth. But nah, this is a pure geek post. Specifically, I wanted to record for posterity in a public place that these were the dependencies I needed to install on my Ubuntu 16.04 machine in order to build the latest xscreensaver from source (the actual package names, suitable for apt-get):

  • build-essential (Edit: I had previously written the incorrect name build-essentials.)
  • intltool
  • libgl1-mesa-dev
  • libgles2-mesa
  • freeglut3
  • freeglut3-dev
  • libjpeg-dev
  • libxft-dev
  • libgtk2.0-dev
  • libgdk-pixbuf2.0-dev
  • libxml2-dev
  • libglade2-dev

And if you have an Ubuntu Linux 16.04 machine (and honestly why wouldn’t you?), you can install xscreensaver by downloading the source from here, opening a terminal window, doing sudo apt install build-essential (repeat for all the other packages named above, or just do them all in one command if that’s what you’re into), then do

tar xzvf ~/Downloads/xscreensaver*.tar.gz ; cd xscreensaver* ; ./configure ; make ; sudo make install ; xscreensaver-demo

I promise to post something more substantial, let’s say, this coming weekend.

Insurance is crazy

Holy sh*t.

In my first post about leukemia, I mentioned that I expected the amount billed by my care providers to exceed half a million dollars over the course of my treatment.

This has already occurred, six weeks into a 21-month treatment regimen. I have a claim from Providence Memorial Hospital in El Paso for $380,000, covering a two-week hospital stay. I have another from MD Anderson for $107,000, which I think covers another two weeks of hospitalization. (It is actually impossible to tell from the information I have available which exact services are included in each bill.) While I haven’t taken the time to add up the dozens of smaller claims, I’d be shocked if the total isn’t north of $500K.

Both of those huge claims are in “pending” status, meaning Blue Cross/Blue Shield hasn’t decided yet whether to pay them. That makes me nervous. However, the pattern with most of the smaller claims is that BCBS has paid 5% to 10% of the billed amount, and left me with either nothing, or another 5% owed.  If that’s consistent then I may be looking at bills in the $25000 range so far – but since I have an individual $4000 annual out-of-pocket cap, I’m probably safe even from a $10,000 bill.

Nice that I had the foresight to pay into my corporate insurance plan for twenty years – a plan that I have never needed in any significant way until now. I am incredibly lucky to have had the ability to do that. I guess. I mean, I’d probably feel luckier if I lived in Norway right now?

So, to be clear about how this works, in the U.S.:

  1. Hospitals and other health care providers know they are going to get screwed by the insurance companies.
  2. Therefore they charge gigantic fees that far exceed the actual costs of providing care (in most cases, anyway.  There are cases where treatment really is new and expensive because the developers of the treatment are trying to recoup their development costs, and in my case I will be getting at least one such treatment – but that hasn’t happened yet. All the care I’ve received so far has been very standard. The chemo regimen I’m on is 15 years old).
  3. The insurer pays a small fraction of the entire bill. Since that fraction is a contractual agreement between provider and insurer (which providers sign onto because they know that as far as getting paid the insurance companies are the only game in town), the provider accepts what they can get and moves on.
  4. The result is that providers get paid a reasonable amount by insurance companies to provide care…
  5. But people without insurance get billed $500,000 for care that actually cost somewhere in the neighborhood of $20,000 to $30,000 to provide.

I want to live in a world where this BS is eradicated.

To be clear, I think being hospitalized and under top-notch care 24/7 for an entire month is definitely worth $30,000. Think about all the people involved, who have lives and need to be paid for their time. I am a huge drain on society right now, and I can’t begrudge paying for that. I am enormously grateful for the doctors, nurses, custodial staff, techs, NPs, PAs, food service providers, and everyone else who has made my care possible. Not to mention the developers of the various drugs that are keeping me from dying of opportunistic viral or bacterial infections, the developers of the chemo drugs, and the developers of the monoclonal antibody treatment I’ll receive later on. I would guess all of those things cost many billions of dollars to create, so my piece of that bill seems pretty reasonable.

I just wish the whole riverdance of insurance ridiculousness could be destroyed.

I’m just thinking out loud here…

Unfortunately, it is a huge coordination problem. Providers can’t just start asking for reasonable amounts from insurance companies, because the insurance companies will just pay 10% of whatever is billed and providers would starve in the streets. Insurance companies can’t afford to start paying a larger fraction of what providers bill them, because they would go bankrupt and wouldn’t be able to pay any claims at all, and providers and insurance-company employees would starve in the streets. Nobody can afford to pay these bills without insurance. And providers can’t just start charging their actual costs to people without insurance (while continuing to charge $whatever-they-think-they-can-get-away-with to insurance companies) because… well wait, why can’t they? Because… that would create an incentive for people to forego insurance, which would create a high-risk population of insurance buyers and push costs higher.

I’m not sure about that last part. If providers charged reasonable amounts for “normal” care, and we let people buy catastrophic insurance policies for right-side-of-the-bell-curve cases like my own, then why couldn’t we end up in a world where most health care is reasonably priced and affordable?

Of course, the thoughts above are completely naive and I need to do more research. I’ll be in the hospital for the next week without a lot to do, so maybe I’ll have time for that.

On having a PICC

I’m… kind of a cyborg now. Well not really, but I have a piece of really cool technology semi-permanently integrated with my body. It’s this thing:

A PICC: Peripherally Inserted Central Catheter. The central catheter part means that it extends directly into the superior vena cava, the largest vein entering my heart. The peripherally inserted part means that it was inserted through a vein in my arm, rather than being directly inserted into the heart through my breastbone (a “tunneled” catheter). (Which sounds a lot more uncomfortable than a PICC.) Mine is a “bilumen” PICC – it provides two input/output channels for blood and medication, which is why there are two IV ports attached to it.

The docs need a way to get chemo drugs into my body without causing unnecessary trauma. Normal intravenous catheters, like the ones they install in your arm or hand to do blood draws and so forth when you’re admitted to the hospital for things other than cancer, aren’t suitable, because the smaller veins tend to get very irritated when confronted by chemotherapy compounds. Central catheters allow drugs to be delivered directly to the heart. (At one point I received a morphine injection through the PICC. This was the most immediate pain relief I have ever experienced.)

I got to watch the insertion procedure, and it was fascinating. The RN who performed the procedure specializes in PICC insertion, and has done thousands of them (hi Tony). I was able to watch on the ultrasound monitor as he located the vein within my arm that would receive the PICC. Then he inserted a wire that punctured that vein and was subsequently used to guide the PICC filament itself into the vein. Once the PICC filament was in the vein, he had to guide it through the vein across my shoulder, into my neck, and down into the heart, which took some cooperation from me. The ultrasound machine was equipped with a system that tracked the PICC filament and produced a visual alert when the end of the filament entered the superior vena cava.

The best thing about having a PICC is that I no longer have to get poked with needles for blood draws. During my first two weeks of treatment, both my arms were black and blue almost from elbow to wrist, because they had to draw blood approximately every twelve hours. My platelet count (platelets are cells that help blood to clot) was so low that every tiny needle entry caused a gigantic bruise, and the phlebotomists were having a really bad time finding my veins amidst all the carnage. Even after getting the PICC installed, the hospital’s policy didn’t let them actually use it to draw blood. At MD Anderson, however, they are a lot more laid back about such things and regularly draw directly from the PICC instead of poking me.

The worst thing about having a PICC is that (a) it must be kept dry at all times, since a wet PICC insertion point is an avenue for infection to directly enter the heart; but (b) the area around the PICC must be thoroughly bathed on a daily basis in order to avoid infection, as must any part of my body that might touch the PICC. This adds up to a giant pain in the ass: I have to shower every day without getting this thing wet. It’s taken me a while to devise a method of securely covering the insertion point with a waterproof barrier using only my left hand. I could blow $50 on a sketchy PICC line cover that may or may not actually be waterproof, depending on which reviewer you believe. But what I’ve actually been doing is covering it with a pair of Band Aid waterproof pads, then surrounding the pads with a border of waterproof tape to cover any gaps where the Band Aid pad might have folded or crumpled as I applied it. That seems to be working OK so far – no sign of infection, anyway.

Contra contra GMI

A few weeks ago, while sitting in Providence Memorial Hospital waiting for my first chemo treatment, I came across a series of WaPo articles comprising a dialog among various economists (and others) about Guaranteed Minimum Income. I’m sympathetic to GMI, since I believe that even without excessive financialization, the real economy will become less and less dependent on human labor in the future. That’s problematic, but in my opinion perhaps not as much so as one might think, and a GMI might open paths for humans to contribute meaningfully even to an economy that no longer requires any of their raw labor in order to function.

One of the “con GMI” pieces was entitled “The Terrible Cost of Universal Basic Income”. It makes a ridiculous argument, which I ridicule below. Here’s the link:

https://www.washingtonpost.com/news/in-theory/wp/2015/10/01/selling-out-civil-society/?utm_term=.ee014f985fef

Here is an extended quote containing the argument I find so ridiculous:

A no-strings-attached material cushion would allow otherwise working drones the chance for more leisure, and the opportunity to invest their time and money more freely.

But the freedom of no longer being needed is a vicious gift to give, and “no strings attached” money is rarely as costless as it seems. When we enter the marketplace, ties are formed between people: between employer and employee, between customer and salesperson, between coworkers and suppliers and the sandwich shop next door. These transactions and interactions are the threads that bind individuals together at the most granular level, weaving them into the multi-layered, tight-knit, resilient fabric of civil society. And it is necessity — our reliance on work to provide for our material concerns — that draws us into that essential weave.

A universal basic income, however, would not connect us to each other. Rather than knitting us to our coworkers, our employees, our collaborators and our families, a basic income would tie every American directly back to Washington, via millions of isolated and attenuated threads. It might sound grand to be able to give a check to every citizen. But if we would need to unravel the social fabric to get there, it’s a cost we should not hope to afford.

The author is Jonathan Coppage, “a visiting senior fellow at the R Street Institute […] and contributor to The American Conservative”. (I like The American Conservative generally, although I disagree with a lot of their positions. They’re the sort of sane people one might want to have in charge of the GOP.)

Why in the world does Mr Coppage think that people living on a GMI won’t “enter the marketplace”? Of course they will, because they need the same things everyone else does! That is the whole point of a GMI! Food and smartphones and diapers and hangouts with friends. I would predict that a person living on GMI to support their water-clock passion, or whatever, will have nearly identically as complex a social and economic network as an office drone or a hedge-fund manager. It just might not happen in the same kinds of physical spaces. In fact, it might take place in spaces that are healthier for the humans so engaged.

Mr Coppage seems to see no value in any human relationship that isn’t somehow based on money. The “social fabric” is not comprised only, or even mostly, of monetary or market-based connections. It is about family, friendships, civic organizations, and many many other factors and institutions. One major advantage of a GMI is that it would, at least to some degree, relieve regular people from the constant need to think about money, and allow them to allocate their mental, emotional, and creative resources in new and interesting ways. A privilege that people like Mr Coppage have most likely enjoyed from the day they were born, and perhaps therefore remain blind to its value.

Test post

(I recommend visiting the Archive page and starting at the first post, “I know the world I want to live in,” if this is the post you see on my home page.)

WordPress is acting weird – my Archive page doesn’t show all the posts. There are only three, how hard can it be, WP? Specifically, it only shows ONE post no matter which month or category one selects. Hmm. This is probably an example of how PHP sucks, in some way.

Conclusion: all recent archive page templates for WordPress are terrible. The Display Posts Shortcode plugin, however, solves the problem neatly.

Enter ALL

I’m going to describe what it felt like, subjectively, to get sick with Acute Lymphocytic Leukemia (Pre-B). I do this first, because it’s kind of interesting, and second, to convey this important message: if you have a collection of symptoms that don’t make sense to you, don’t just assume it’s some weird manifestation of the flu or something. Go to the ER.

(Edit: In June 2018 I learned I was misdiagnosed initially. In fact I have “early-precursor T-cell ALL”, which is apparently quite rare. In July 2018 I received a bone marrow stem cell transplant. Things have subsequently gone pretty well. I am currently on leave from work and living on the fairly generous disability insurance provided as part of my employer’s health care package.)

I do not expect that my experience here is typical. I strongly suspect this disease can manifest in many different ways, at least initially. It is ultimately caused by a point mutation in a bone-marrow stem cell somewhere in one’s body. For me, that appears to have occurred in my right thigh, but if it occurred somewhere else, the experience would have been quite different.

Initial symptom

Sometime in early January, I stood up from my couch, and in my right hip I had a feeling that something was just… not right. Like the joint wasn’t going to support my weight. There was also a particular quality of very mild pain involved, as if I’d been kicked in the genitals maybe twenty minutes earlier. For men, that is a very specific feeling – only in this case it was coming from my hip, not from my junk.

I suffer from chronic gout, which predisposes me to related inflammatory diseases, particularly rheumatoid arthritis. I was about to turn 50 years old, so a reasonable hypothesis was that the half-century joyride was over and this hip thing was an early manifestation of RA. But weirdly, the very first thought that crossed my mind was, “Huh, I wonder if I have cancer?” A thought I immediately dismissed really hard.

Later symptoms

I’m a somewhat athletic guy (or was before all of this). Typically I do some kind of fairly intense physical activity for 45 minutes to 2 hours, at least five days a week. Running, mountain biking, rowing. I was able to continue to do those things over the next few weeks, but they became increasingly difficult because the pain in my right hip began to extend down into my thigh, and became steadily worse. I started taking a lot of naproxen (Aleve) to control the pain, especially at night (this is not a good thing to do long term). Eventually I found that if I was lying in bed on my back, I could lift my left leg normally to a near-vertical position, but I could not lift my right leg more than an inch or two. It hurt, but also there was no strength in the muscles on that side. Despite this, I could still walk basically normally, which allowed me to continue to minimize the impact of the symptom.

Appetite

About two weeks after the initial hip pain, my appetite tanked hard, and this symptom started literally overnight. I ate a normal meal one evening, and the next day didn’t eat anything at all. I was not even a little bit interested in eating or drinking anything. However, after a couple of days I discovered that if I did try to eat, I found myself absolutely ravenous and enjoyed the food a lot. This was, without doubt, the strangest set of subjective feelings I have ever had. I could walk past the refrigerator 40 times in a row with complete disinterest, but if the impulse to open the door happened to hit and I actually looked at the food, I’d eat an entire frozen pizza in one sitting and love it.

At some point after my appetite went away, I began waking at night with feelings of intense hunger, but still without the urge to eat. These episodes were accompanied by breathing problems: if I yawned or took a very deep breath, I would experience a sharp pain in the left side of my abdomen, as if my rib cage was pressing directly into my lung. I later learned that the actual cause of this was that my spleen was extremely enlarged. That’s a very dangerous condition, especially for someone who does things like ride bicycles on scary rocky trails and sometimes falls off, because if you rupture your spleen you can bleed out and die in minutes. Luckily, by this time my leg felt bad enough a lot of the time that I’d pretty much quit exercising at all.

What actually sent me to the ER

None of the above seemed like enough reason to see a doctor, to me. I’m medical-avoidant in general, just because I hate being told that whatever’s wrong with me is just what I thought it was and there’s not much to be done (because usually what’s wrong with me is a cold or something nasty like Norovirus that will pass in a couple days anyway). Also, I had just seen my primary care doctor a week or so before the initial symptom and had been given a clean bill of health at that time (although I never did get the blood work done that she asked for, which would probably have accelerated my diagnosis). So I was not super-interested in going back to her about this complex of weird symptoms. I was half-convinced that I just had some strange manifestation of the flu (which was obviously a rationalization in retrospect).

On February 13, 2018, my right thigh was hurting so much at about 7:00 PM that I was certain I’d never be able to get to sleep. Combined with some reading I’d been doing about flu-related sepsis, this was enough to prompt my brain into “Really Worry” mode. So I called up my lovely partner Aurolyn and asked her to drive me to the ER at Providence Memorial Hospital in El Paso, TX.

The Diagnosis

I only mentioned the leg and abdomen pain to the ER staff. They did some blood draws and admitted me with an unexplained high white-blood cell count (45, typical is 3.5 to 5 or something like that).

While I was being admitted, I was pretty tired, and the painkillers they gave me after installing me in my room made me pretty loopy. But I do remember hearing the word “oncologist” from at least one doctor during the first five hours of my admission.

The next day (Feb 14, Valentine’s Day), I was visited by Dr Zening He, who informed me that I definitely had some variety of Acute Lymphocytic Leukemia. The exact details would have to await the results of the bone marrow biopsy that Dr He would perform the next day. He told me that my blast cell count was over 60,000, which is a definite signal of some form of acute leukemia.

My response: “Doctor, can we consider the possibility that this could be mononucleosis?”

Hope springs eternal.

My take-away from all this is: I will never again ignore a collection of symptoms that seem random and unconnected. Unless I’m having a problem that I definitely recognize as “mostly harmless” (common cold etc.), I shall hie me to a physician.

And a touch on “the world I want to live in”: I have great insurance. My entire course of treatment, involving several rounds of chemotherapy, an experimental monoclonal antibody, and a year of follow-up mini-chemo treatments, will allegedly reduce my chance of relapse to under 20%, and will likely end up costing me less than ten thousand dollars out-of-pocket. (And I just paid off that $10000 student loan from my MS degree, thanks universe.) I suspect the amount charged by medical providers will exceed half a million dollors, but the amount actually paid to providers by my insurance company will be under $20000, based on this piece by Adam Ruins Everything, which is exactly how I thought health-care charging works after seeing a few of my Mom’s medical bills and the associated insurance statements.

It seems possible to treat these conditions economically. $30000 to cure cancer? That is a bargain. The medical establishment, the insurance establishment, and the government appear to be locked into a dark equilibrium that currently makes it impossible for people who lack great insurance to actually get treated in an economical way. But everyone deserves to be treated when they contract a life-threatening illness. And that’s the world I’d prefer to live in. More about that later.

I know the world I want to live in

Hello, world!

Per the About page, this is intended to be a blog about the future, how it can be good, and how we can get there. But it’s also likely, for a while, to be about leukemia and the experience of being a leukemia patient. In other words, some of these posts will be more about the “I want to live” part than the “world I want” part.

Partly this is performance anxiety – I mean, if I can’t at least approach the awesomeness of SlateStarCodex or Wait But Why in a blog about real-world issues, what’s even the point? And I can’t, there’s just no way. But I’m starting to be convinced that I have useful stuff to say about this, even if my presentation or my arguments fall short. And the only way to test that and improve my understanding is to go out there and say it and get feedback from the world and the people in it. This is a huge change for me, but hey, getting diagnosed with a life-threatening disease is kind of a big pusher-out-of-one’s-comfort-zone. So do expect future posts, soonish, about that magical future world that I want my children to live in. But for now, the next couple are probably going to be about leukemia.

Another factor, though, is that leukemia is just really relevant to me right now. Being a leukemia patient is super interesting, as well as scary, and I think a subjective account of this experience will interest others.

Catch you later – probably today – with my first non-trivial post 🙂