Public perception of the labor-saving potential of computers

While my family and I were at a restaurant waiting for our food, my sister talked about a potential temporary job that would involve data entry to convert records from one database system to another (possibly along with other activities). I immediately thought that this was the kind of thing that should be handled with a little programming, not tedious and error-prone data entry. I said as much, and her response was twofold. First, she pointed out that the data-entry job would involve error checking against paper records. I didn't respond to this, but it seems to me that there would still be value in automating the actual data entry even if manual error checking remains. However, she also speculated that the company might be able to pay less for this one-time data-entry job than for a programmer to write a conversion program. We don't have enough information about this particular job to say anything definite about this, but I pointed out that the conversion program might be very simple and quick to write, possibly reducing the necessary work by several orders of magnitude. She acknowledged this, and we agreed that we won't know if this job can be automated until she interviews. But this conversation got me wondering if most non-technologists truly understand the labor-saving potential of computers, and if so, what attitude they have toward it.

This wasn't the first conversation in which I brought up the labor-saving potential of computers. My sample size may be too small, but judging by conversations I've had with my conservative middle-class American family, it seems to me that non-technologists don't think much about how much tedious work could be saved by programming computers to do more of it. Assuming my perception is accurate, why is this so? More importantly, what can we programmers and other tech-savvy types do about it?

One obvious hypothesis is that most people don't think about the possibility of saving labor through programming because they have only ever been exposed to closed, inscrutable, proprietary software. Indeed, in the situation I discussed at the outset, the old database system and/or the new one might be proprietary, which would make automated migration more difficult. The increased difficulty might be enough that manual data entry really would be better in this case. But even merely perceived opacity is probably enough to ensure that the decision-makers won't think about the potential for automation. Sticking with the database migration example, suppose that under the hood, the old system was based on the Microsoft Jet embedded database engine, and the new one is based on SQLite. (I choose these examples because neither is prominently visible to a typical user, unlike, say, MySQL or MS SQL Server.) I could probably figure out the schemas of both systems and write a conversion script. But it would not occur to anyone with decision-making power that this is feasible, because as far as they are aware, both systems are sealed, opaque boxes. But if more business applications were free software, and the implications of software freedom were well understood, then perhaps more business owners and managers would realize the full potential to automate straightforward tasks through programming.

Another possibility is that people associate programming exclusively with large, multi-developer, months-long software projects. Of course, some programming languages, tools, and processes are designed with this kind of thing in mind, and one might argue that some even encourage it. Michael O. Church's essay "Java Shop Politics" springs to mind. In this light, I consider it fortunate that languages which lend themselves to small, succinct, quickly-written programs are in vogue now. Some of these languages may be deficient for programming in the large, but that just means that programmers and managers alike need to avoid the trap of wanting one language to rule them all.

Another potential reason why people don't think about the full potential to save labor through programming is that they might think of programming as a highly specialized, maybe even elitist, profession with a high barrier to entry. I dare say that some programming ought to be this way, such as development of safety-critical software, and even development of mass-market commercial software. But a high barrier to entry, whether real or merely perceived, may prevent people from thinking of programming as a way to eliminate some gruntwork. It really doesn't help when we programmers look down our noses at certain languages, such as Visual Basic, as declasse or only fit for those loser wanna-be programmers. Whatever we may think of such languages, we have to admit that they have been useful in lowering the barrier to entry for many programmers, thus enabling many more useful programs to be written. (I confess some disdain for PHP, which I justify by pointing out the security vulnerabilities that are common in PHP code.) Luckily, these days, we can promote languages that are easy to learn and are good for quick, one-off programs, but don't encourage practices that lead to low-quality or unmaintainable software.

But what if more people did understand the full potential of computers to eliminate certain kinds of straightforward, tedious, repetitive work? Would they actually welcome this? I can only speculate. But here in the US, we're recovering from an economical recession (or so I'm told; I haven't experienced any effects of this myself). During the most recent election season here, there was a lot of talk about the need to create more jobs. If more people understood the full labor-saving potential of computers, then mightn't many short-sighted people (and the politicians who pander to them) demand that we somehow put a stop to this job-destroying technological advancement? I'm reminded of Stanislav Datskovskiy's essay "Roman Lisp". Might it actually be a good thing that social networks, content consumption, and other consumer-oriented fluff are distracting people from the true potential of computers?

I have no answers, only questions and speculation.

Heroku's erosion resistance

Heroku is doing several things right. The Twelve-Factor App is a succinct, well-considered set of guidelines for building robust, scalable web applications, and Heroku has done a pretty good job of building a platform based on these guidelines. Of particular interest is Heroku's emphasis on erosion resistance and explicit contracts. Heroku has certainly done a better job of meeting these ideals than I would likely do in cobbling together a web app deployment system as part of my work. I am therefore seriously thinking about using Heroku at work.

However, having spent some time looking at the platform, I can think of some ways to significantly improve Heroku's erosion resistance. So I offer this post as constructive criticism in the hope that it will lead to a better platform.

The basic problem is that the GNU/Linux system underlying Heroku's current Celadon Cedar stack is made of an apparently haphazard collection of packages. Heroku does not appear to have paid close attention to its stated goals of erosion resistance and explicit contracts. As if it already recognizes this shortcoming, Heroku has not updated this GNU/Linux system since October 31, 2011.

What evidence do I have that Heroku paid insufficient attention to erosion resistance and explicit contracts while selecting packages for Cedar? Here are a few examples:

  • Cedar's base system includes OpenSSL 0.9.8, which did not have a stable ABI. My evidence that the ABI was not stable is that the Linux Standard Base project rejected OpenSSL. It seems to me that this will force Heroku to stick with OpenSSL 0.9.8, or patches based on it, for as long as Cedar is supported. What will happen when end-of-life is declared for the 0.9.8 branch?

  • Cedar's base system includes Ruby 1.9.2p290. I don't know much about Ruby, but I've seen evidence that a seemingly minor update to the Ruby implementation can introduce unexpected breakage. So I would not be comfortable incorporating Ruby into the bedrock of an erosion-resistant platform. Will Heroku need to continue including Ruby 1.9.2p290, or a carefully patched derivative thereof, in Cedar as long as that stack is supported? I notice that Heroku's Ruby buildpack provides a way to bundle a specific version of Ruby with the application slug, though this isn't yet the default behavior.

  • Cedar's base system includes ImageMagick, and not just the libraries, but the command-line utilities. This makes it all too easy to violate the twelve-factor methodology's rule against invoking command-line utilities that are not bundled with the application build. Ironically, ImageMagick is one of the utilities mentioned in factor II (Dependencies).

I believe I've now demonstrated that Heroku didn't pay enough attention to erosion resistance and explicit contracts while selecting packages for Cedar's base system. I suggested earlier that Heroku might already be aware of this, because it has not updated Cedar's base system since October 31, 2011. Incidentally, this was long before Heroku declared Cedar ready for general use. What are the consequences of this early freezing of the base system?

It seems to me that the consequence that truly matters is a complete lack of security updates for the packages in the base system. For example, Ubuntu has issued 4 updates to OpenSSL for Ubuntu 10.04 (on which Cedar is based) since Heroku froze the Cedar base system, and all of these updates are security-related. OpenSSL is quite well-known for requiring frequent security updates. So if I were in Heroku's position, I don't think I would incorporate OpenSSL into the bedrock of my platform unless I was sure that I could back it up with frequent security updates for as long as I supported the platform. Given the unstable ABI of OpenSSL, at least version 0.9.8, I would be doubly cautious about including OpenSSL in the base system of an erosion-resistant platform.

So what would I do? Well, I'm afraid that my proposed changes would require a new Heroku stack, and Heroku has stated that it has no plans to replace Cedar. So in the unlikely event that Heroku will have any interest in implementing my suggestions, I guess this statement might give Heroku a bit of a PR problem. Still, it wouldn't be right for me to criticize something without offering my ideas for improving it. Incidentally, I'm not imaginative enough to suggest a name for Cedar+1.

First, I would radically pare down the runtime base system. Let's start with the shared libraries. I would only provide Debian stable builds of these libraries: glibc (technically eglibc), libgcc_s, libstdc++, and NSS. All of these are in the Linux Standard Base, though they're a small subset of what the LSB offers. The first four form the minimum set of libraries needed to build C and C++ programs for GNU/Linux and have been ABI-stable for years. NSS handles the important and sensitive task of implementing cryptography, and we app developers really should not be responsible for crypto any more than necessary. A quick look at the search results for libnss3 at packages.ubuntu.com suggests that NSS has been ABI-stable since Ubuntu 8.04; this, the LSB project's decision to include NSS, and the Fedora project's decision to standardize on NSS are good enough for me. Why use Debian stable? Debian is well-known for being among the most conservative of major GNU/Linux distributions, and this is surely a good thing for the bedrock of an erosion-resistant platform. To keep the runtime base system lean and to avoid bringing in extraneous components which muddy the contract between platform and app, the runtime base system would only include the runtime libraries, not the corresponding development packages.

What about the shell and command-line utilities? I would provide BusyBox and nothing more. Heroku's dynos are based on LXC, and the process with PID 1 (currently called ps-run) seems to live outside the LXC container. So the base system for a Heroku dyno doesn't need all the components that are necessary to boot a full-blown GNU/Linux machine, whether physical or virtual. This minimalism will effectively enforce the aforementioned rule against invoking non-essential command-line utilities without bundling them in the app build. Besides that, it simply provides a more comprehensive contract between the platform and the application.

Of course, this runtime base system would be inadequate for running build tools such as Heroku's slug compiler and Vulcan. So I would provide a separate system image to use at build time. This one would include the full Debian stable base system (using the same stable version of Debian from which I got the runtime libraries), and at least these packages: build-essential and libnss3-dev. I'd probably throw in some build-time niceties such as the Autotools suite, Perl, curl, Git, and even Ruby and Python. But please note that I would be careful about which -dev packages are in the build-time system, to help ensure that the resulting build can be run on the runtime system. Web dynos and worker dynos would always use the runtime system. The runtime system would also be the default for one-off dynos, but I would also offer the build-time system for those, to enable build tools such as Vulcan.

To summarize, by being very explicit about what goes in the base system and what stays out, I believe it would be possible to create a much more erosion-resistant platform. I would be happy if any current or aspiring platform-as-a-service provider took these ideas and ran with them, but I would be most pleased if Heroku saw fit to do this itself. As I said at the outset, I think Heroku has some great ideas and is doing a pretty good job of implementing them. I look forward to using Heroku to relieve myself and my successors of some administrative chores as we build more robust web applications.

Side effects, strings, and spawned processes

About a week ago, I was reading the book Programming in Scala, because my friend Nolan likes Scala a lot, and I wanted to give it a try. Chapter 7, "Built-in Control Structures," ends with an example of refactoring a program from an imperative style to a more functional style. As I was reading, the following paragraph made me stop and think:

"The imperative style reveals itself in Listing 7.18 in two ways. First, invoking printMultiTable has a side effect: printing a multiplication table to the standard output. In Listing 7.19, we refactored the function so that it returns the multiplication table as a string. Since the function no longer prints, we renamed it multiTable. As mentioned previously, one advantage of side-effect-free functions is they are easier to unit test. To test printMultiTable, you would need to somehow redefine print and println so you could check the output for correctness. You could test multiTable more easily, by checking its string result."

I should admit up front that I was approaching Scala with a serious bias against its host platform, the Java Virtual Machine. To me, the JVM had gained a reputation for being big and memory-hungry, and for encouraging systems that consisted of a single, monolithic process including everything and the kitchen sink. I further disliked the JVM because its memory usage and startup time made the Unix ideal of small, focused, short-lived processes untenable.

So I was predisposed to think that Scala programmers, constrained by the JVM, would approach some problems in the wrong way. And that is exactly what I thought when I read the paragraph quoted above. The authors stated that the imperative-style example would be difficult to test because it would require one to override Scala's basic functions for writing to standard output. And I thought, "Only if you run your tests inside the same process." It occurred to me that the Unixy way to test this program would be to run it from another process which would receive and check its output. I remembered reading about a tool called "expect" which could do tests this way.

So it seemed to me that when approaching it the Unix way, writing to standard output wasn't a side effect at all. This got me thinking about shell programming. It occurred to me that from a shell script's point of view, a process invocation was like a function call, and what the process wrote to standard output wasn't a side effect, but simply the function's return value. Indeed, from this point of view, global variables and mutable collections inside a process wouldn't be a big deal, because they would be like local variables in a function. Accompanying these thoughts was a feeling of superiority; I felt pretty good about having come to see things the Unix way. I saw Scala as a nice language trapped in a terrible environment that warped one's perspective by making the Unix way impractical.

These thoughts stayed in the back of my mind as I moved onto other things. Over the next few days, I learned a little more about Scala and the available Web application frameworks for it. One difference between the Lift and Play frameworks was particularly striking. Whereas Play's default template system uses string concatenation (with auto-escaping of HTML entities to prevent XSS attacks), Lift's default template system parses the template into a DOM and manipulates that DOM. The approach that Play uses is much more common, but it seems to me that Lift's approach is more correct.

Contemplating this difference made me think of Glyph Lefkowitz's essay Data In, Garbage Out, in which he convincingly argued that structured data, including HTML, should be manipulated as structured data, not cobbled together (potentially incorrectly) by concatenating strings. I think now most of us web developers, including those of us working with the more popular Python template systems, have gotten this wrong. The auto-escaping in our template systems may shield us from most, if not all, XSS attacks, but it's still all too easy for us to slip up and write a template that produces ill-formed markup.

The night after I reread Glyph's post, my thoughts returned to the question of whether writing text to standard output is a side effect to be avoided, or just the normal outcome of the short-lived processes that are the Unix ideal. And I suddenly realized that what I had considered the Unix ideal was in fact not ideal at all, because it consists of a lot of string manipulation. The Unix shell may provide a programming language, but for all practical purposes, it's a language in which the only data type is a string. That's no way to program. I think I already understood that on some level, since I don't do much shell programming on a daily basis and have often thought that larger shell scripts tend to be flimsy. But thinking about Glyph's blog post on strings drove the point home. Indeed, I realized that the authors of Programming in Scala didn't go far enough with the example that concludes chapter 7. A function that returns a multiplication table as a map (I believe the correct Scala type notation would be "Map[(Int, Int), Int]") would be far easier to test than a function that returns the table as a string.

With that, I got to thinking that Stanislav might have been right to call Unix archaic. He had linked to The UNIX-HATERS Handbook, so I read it. In chapter 8, "csh, pipes, and find," I found confirmation of my recent conclusion that passing strings between processes was a poor substitute for passing structured data between functions:

"At the risk of sounding like a hopeless dream keeper of the intergalactic space, we submit that the correct model is procedure call (either local or remote) in a language that allows first-class structures (which C gained during its adolescence) and functional composition. Pipes are good for simple hacks, like passing around simple text streams, but not for building robust software. For example, an early paper on pipes showed how a spelling checker could be implemented by piping together several simple programs. It was a tour de force of simplicity, but a horrible way to check the spelling (let alone correct it) of a document. Pipes in shell scripts are optimized for micro-hacking. They give programmers the ability to kludge up simple solutions that are very fragile. That’s because pipes create dependencies between the two programs: you can’t change the output format of one without changing the input routines of the other."

So the way I had just come to view the practice of passing strings between processes was correct; others had realized it long ago (this book was published in 1994).

Having willingly given up my real religion last year, I was ready to have my lesser faith in Unix challenged. So I approached The UNIX-HATERS Handbook with an open mind, wanting to know how much of what I thought I knew about Unix was wrong. Reading this book was quite a revelation. Some things have clearly improved since 1994; Sendmail isn't nearly so widely used, Usenet is mostly forgotten, and the GNU utilities seem to be generally better than their original Unix counterparts. But it seemed to me that we had been duped into thinking of Unix as the pinnacle of reliability and good operating system design. Had Windows (especially pre-XP) really set our expectations that low?

I didn't have to look far to find a challenge to one of my most dogmatically held beliefs about Unix. In chapter 1, in a list of myths about Unix, was the sentence, "Processes are cheap." To a Unix aficionado, this sentence succinctly encapsulates the belief that because of the implementation of the fork() system call, most notably the use of copy-on-write virtual memory pages, it is feasible to have a large number of processes, ideally short-lived processes, all running the same program. Unix lovers consider this multiprocess approach superior to multithreading, because it is more resilient to failures in individual processes, and in some cases (when dealing with C programs) also more secure. To this day, the Postfix mail transport agent uses a separate process for each SMTP connection (both incoming and outgoing), and the Dovecot POP3/IMAP server uses a separate process for each session. In fact, Dovecot uses one process for the login sequence, then another for the POP3/IMAP session itself, to be really secure.

I was already starting to wonder if Unix processes were truly cheap, even when running programs written in C, because of a series of recent incidents on my employer's mail server, which runs Postfix and Dovecot. Seeing that sentence listed among Unix myths answered the question definitively; processes weren't cheap in the 80s to early 90s, when most programs were written in C. If processes that run C programs seem at all cheap now, it's probably because CPU power and RAM have continued to grow more abundant, and most of us have gotten used to software that wastes these resources.

Chapter 12, "Security," discussed how easy it is for multiple processes to bring down a system. The section "Denial of Service" presented the fork bomb (though not by that name), a super-simple program that exploits fork() to bring any Unix system to a halt. But what really got my attention was this passage:

"Not exciting enough? Well, thanks to the design of the Unix network system, you can paralyze any Unix computer on the network by remote control, without even logging in. Simply write a program to open 50 connections to the sendmail daemon on a remote computer and send random garbage down these pipes. Users of the remote machine will experience a sudden, unexplained slowdown. If the random data cause the remote sendmail program to crash and dump core, the target machine will run even slower."

I knew that Sendmail used the process-per-connection model of concurrency, as do Postfix and Dovecot. But did it really only take 50 SMTP connections to bring down a system? This further confirmed that there was no golden age of cheap processes on Unix. Processes weren't cheap in 1994, and they're not cheap now. And now, interpreters, JIT compilers, and certain automatic memory management techniques make processes even less cheap.

That was Wednesday night. The following evening, there was another load spike that brought my employer's main mail server down. After rebooting the (virtual) machine, I wondered, not for the first time, if any major email provider was running a mail server with a process-per-connection concurrency model. Some probing revealed that Google, Yahoo, Microsoft, Comcast, and GMX are all running custom SMTP servers, not an off-the-shelf Unix SMTP server like Postfix, qmail, or Sendmail. And Apple is running an email server product from Oracle. Of course, I don't know this for sure, but I'm willing to bet a small amount that all of these servers are multithreaded and/or event-driven, not using a process per connection.

Friday, as a result of that latest mail server failure, my attention turned to making our flagship Web application more resilient to such failures. This application, which is written in Python, had been using the process-per-conection model to handle HTTP requests for years. I tried the event-driven model (using Eventlet) a little over a year ago, with disastrous consequences; simulating threads using coroutines and monkey-patching of Python libraries was clearly too risky a change. And if I remember correctly, my previous unsuccessful attempt at multithreading for this application had been in 2007. But I had known for months that it was far too easy for a failure of one subsystem, such as the mail server, to exhaust the relatively small pool of worker processes. And now, my resistance to the multithreaded approach was almost gone.

But I still had to convince myself that multithreading was a good solution. After all, some Python web developers seemed to believe rather strongly that the only two good solutions were process-per-connection and event-driven. And after all, PHP isn't multithreaded, and there are huge sites running PHP. But wait a minute; those sites, such as Wikipedia and WordPress.com, have workloads that are disproportionatly read-only. These sites can put a caching layer in front of PHP, rendering moot the question of whether PHP uses processes or threads. And what about Facebook? They use PHP, but they did their own implementation, and it's multithreaded. And wasn't it obvious that bytecode interpretation, reference counting, and some kinds of garbage collection all thwart a Unix system's attempts to share memory among processes, and that JIT compilation would also have this effect? Wasn't it obvious that with a language like Python, memory usage was bound to be far from optimal in the process-per-connection model? Surely it wasn't a coincidence that in the runtime environments with the most sophisticated virtual machines, namely Java and .NET, Web applications used the multithreaded model without exception. With my last doubts resolved, and having discussed the matter with management, I proceeded to move our flagship Web application to the multithreaded model.

I completed the transition yesterday afternoon, then spent a few hours away from the computer. During that time, I started having second thoughts about what I had just done. Surely I had just started on a slippery slope that would end in unmanageable, kitchen-sink behemoths, as in the JVM ecosystem that I had loathed just a week before. But I was tired (indeed, I had a short nap yesterday afternoon), so I probably wasn't being especially rational. Still, those thoughts bothered me.

I had to prove to myself, again, that threads really were much cheaper than processes, enough so to warrant the potentially increased difficulty of debugging. I wrote two Python programs, one that spawned 4096 threads which did nothing but sleep for 5 minutes, and another which did the same thing with 4096 forked processes. The memory usage of the fork-based program was at least an order of magnitude greater, and this was a program whose child processes didn't really do anything. If each of those 4096 processes had, say, imported a large module, I suspect that this would have immediately brought my local Linux VM to its knees. But the test brought that VM down soon enough, when the 4096 processes all tried to exit. I suspect that this happened because each process ran Python's full shutdown routine, which decreased the reference counts of all objects and deallocated them. This surely triggered the copy-on-write semantics, causing a massive increase in memory allocation. So, yes, it was obvious that a large number of processes wasn't feasible with Python.

Finally, I thought about the fork bomb attack presented in chapter 12 of The UNIX-HATERS Handbook, and wondered if something just as bad could be done with threads. To make sure that Python's global interpreter lock didn't invalidate the results, I did this experiment in C. I wrote a small program, threadbomb.c, which replicated the behavior of a fork bomb but with threads instead of processes. Within 30 seconds of running the program, or maybe more like 15 seconds, the system was rendered unusable. But to my surprise, that state only lasted for a couple of minutes; the program was then aborted, and all was back to normal. I then wrote and ran the conventional fork bomb, which rendered the system unusable even faster. Only this time, there was no recovery. +1 for threads, at least on Linux.

So why have I written this long, rambling essay? Well, I've heard that the best way to organize one's thoughts is to write them down. I want to make sure I'm thinking clearly about the subjects I've covered here, so I figured I'd write about it. If anyone is still reading, the best advice I can give is this: Question every assumption and belief, especially the ones you've never questioned before. Be willing to try new approaches; you might find that they're better than you had assumed.

Why I reject Christianity; what I now believe

As my immediate family and closest friends already know, I decided last year to reject the Christian world view. My reason is simple: not enough evidence. The Bible is not consistent with itself, let alone with what we can observe of reality, be it history, science, or the reality of suffering all over the world. There is no strong evidence that Jesus is who the Bible claims he is, or that he rose from the dead. Some Christians point to a personal experience of positive change in their lives as evidence. But that doesn't lend any weight to Christianity, because people of all religions claim to have experiences which they interpret as validation of their religion. And faith, which is belief without sufficient evidence, is a cop-out.

Of course, these are just assertions, and my rejection of Christianity would not be rational if I didn't back those assertions up. The nice thing about the Web is that I can simply link to some more detailed treatments of these subjects. So here are a few links to get you started. I may not agree with all of these authors on every single point, but I'm in substantial agreement with them.

Yes, I'm unabashedly linking to the writings of vocal atheists, and I've read many more such writings than I've linked to here (along with Christian apologetics). My Christian parents and other family members have expressed their concern that I've opened my mind to the influence of the devil, and have asked that I refrain from doing so. I agreed to refrain for a time last year, but not anymore. I believe that the very idea of Satanic influence is simply Christianity's built-in defense against skepticism. If Christianity were true, then my belief should have withstood my study of arguments from both sides.

Some Christians may assert that I am rejecting Christianity because I want to live a selfish, immoral life, or because I don't want to be accountable to my creator. That is emphatically not the case. I'm not perfect, but I want to live an upright, moral life. In fact, if you ever notice that I'm using my new beliefs to justify an act that is clearly immoral or overly selfish, then please call me out on it. Furthermore, if there is evidence that we humans were created by some intelligent being, that this being is still alive, and that this being cares how we live our lives, then I'd love to receive guidance from this being. But I don't know of any compelling evidence for such a being, so it seems foolish to organize my life around a belief that the Bible is true.

So what do I believe instead?

At the most basic level, I believe that beliefs should be backed by logic and evidence. In other words, beliefs should be internally coherent and should be consistent with observable reality. What are my logic and evidence for this belief? Well, logic and evidence, in the form of science, have worked pretty well for us in the last few centuries. And we use logic and evidence to determine the truth or falsehood of ordinary factual claims. So why not apply the same standard consistently? In particular, why accept faith as a valid answer for the biggest questions we face, when we wouldn't accept it for more mundane things?

I believe that morality is all about maximizing overall well-being for all conscious creatures, most notably humans but also including many animals. On a more practical level, I believe it's fine to pursue one's personal goals, but only to a point; we need to be considerate of others. In particular, we need to avoid doing to others what we would not want done to ourselves. All manner of moral guidelines can be derived from these principles. Some moral choices are pretty clear-cut; some are not. And it seems to me that the Bible is of little value as a guide to morality. Of course, I'm not setting myself up as any kind of moral authority; this is just my current understanding of morality. And I'm still working on practicing these principles in my own life.

I believe that, in the absence of evidence for a god or an afterlife, we should live as though we're on our own and this life is all there is. This, I think, is where my beliefs collide most directly with Christianity. Christians believe that this world is ultimately doomed, and that it's most important to prepare for eternity, meaning the world and the life after this one. Frankly, I'm afraid that if the first part of that belief is taken to heart, it may become a self-fulfilling prophecy, especially with strong Christians occupying positions of power in the most powerful country on Earth. A belief that God will eventually set things right also seems to encourage apathy about the state of this world; at least it did that in me for a time. I now believe that this world and this life are all we can be certain that we have, and when we see something wrong with this world, we should consider what we can do, if anything, to make it better. In particular, in a country like the US that has at least a semblance of democratic government, it really matters whom we vote for and what causes we support.

And that's why I'm writing this blog post. It really matters what we believe and what we do about those beliefs. I will try not to be pushy or obnoxious about this; I know I can't make my Christian family and friends see things as I now do. And I'm doing my best to continue to live peacefully with my Christian family and friends, whom I still love. But I will not keep quiet about my beliefs anymore. If you're a Christian, I urge you to think calmly and rationally about what I'm writing here, and follow the links above to learn more. And feel free to respond. But most of all, let's all try to make this world a better one for all of us. It sounds trite, but I truly believe it's the best goal to which we can aspire.

Situational ethics

I previously wrote about my attempts to balance pragmatism with a certain kind of idealism. Last night I had to weigh these things again, only this time, my relationship with my parents entered the equation.

For Valentine's Day, my parents bought me a Redbox gift voucher, good for 10 movie rentals. No doubt they chose this gift because we had rented a couple of movies in the previous month and had enjoyed them together. But this created a conflict with my desire to avoid feeding the ethically bankrupt movie industry, who after all just tried to sabotage free expression on the Internet with SOPA and PIPA. What to do?

Now, the second time we rented a movie was after the famous anti-PIPA black-out, and I had misgivings about renting the movie. I said something like, "Why are we renting a movie, when the movie industry just tried to censor the Internet?" And Mom simply said, perhaps in an exasperated tone, "Because we want to watch a movie." So maybe I didn't express the dilemma well enough, but she didn't get it, and we rented the movie.

So some may blame me for caving in the last time. Perhaps if I hadn't acquiesced, I wouldn't have been confronted with the dilemma of what to do with the Redbox gift voucher. But come Valentine's Day, it was too late to undo what I had done, and thinking about what I should have done a week or two ago is probably not healthy.

So I had the gift voucher, and last night, it was time to make a decision; our previous movie rentals had been on Friday nights. I had two choices: accept the gift, rent a movie, make my parents and myself happy, and cast one vote for the movie industry and its practices; or reject the gift, disappoint or even upset my parents, pass up a potentially enjoyable form of entertainment, and cast one vote against the movie industry. If I rejected the gift this first time, perhaps we could have requested a refund for the whole gift voucher.

My vote, for or against the movie industry, would be infinitesimally small; I'm just one person among the millions who rent movies. Still, I'd like to believe that if enough of us stop feeding the movie industry, then that industry will lose its clout in our government, and thus its ability to sabotage the Internet and general-purpose computers. Conversely, if enough of us continue to feed the industry, by renting or buying movies, then the industry will retain its corrupting power.

If I were choosing whether or not to watch a movie by myself, then the above would be the only thing I needed to consider. But as I said, my relationship with my parents was also a factor. My choice would have a far greater impact on that relationship than it would have on the movie industry's power over the Internet. I'm well aware that my reasoned rejection of Christianity last year was a major blow for my parents, so I have made a conscious effort to be on good terms with them in every other way that I can. And because I still live with my parents, despite being 31 years old (a problem which I know I eventually must address), my relationship with my parents is one of the most important relationships in my life.

So we rented and watched a movie last night, and enjoyed it. And, I suppose, we helped reinforce the movie industry's power in our society.

I guess this post is an attempt to justify my decision. I admit I've given the decision more thought this morning than I did last night. So did I make the right choice? I really want to know, because I have 9 more opportunities to make a different choice.

Pragmatism and idealism

Lately I've been trying to find the right balance between pragmatism and idealism, particularly when it comes to issues regarding freedom and technology. If I were to consistently live by the ideals that I'd like to support, then I would need to:

  • use only free software
  • develop only free software, or not develop any software at all
  • not use any DRM-encumbered service, ever
  • completely avoid patent-encumbered software, e.g. MP3 players and encoders
  • use software on my own computers instead of centralized Internet services wherever possible
  • not feed the big media companies, who try to sabotage free expression on the Internet with things like SOPA and PIPA

And maybe I've forgotten a thing or two.

Needless to say, the first two items alone would require me to quit my job as lead programmer at a small software company, because I both use and develop proprietary software. That's not something I can easily do, nor is it something I particularly want to do. If nothing else, I can't be sure that I'd be able to find another job.

So pragmatism and idealism are at odds in my life. Still, I'm taking some small steps toward the above ideals.

Last October, I began resisting DRM, though I've wavered a few times since then. (I bought one Kindle book in November, which I haven't yet read, and I've used Amazon Video on Demand a few times.) I haven't completely given up on audiobooks; Simply Audiobooks provides a relatively small selection of audiobooks as MP3 downloads.

One thing I've just started working on is to not feed the big media companies. That means not giving them money, and not lending my ears to their advertisers. This is a tough one; a lot of the music I listen on is from major record labels, and there are even a few TV shows I like (particularly The Big Bang Theory). But I'm starting to increase my support for independent musicians; for example, last Sunday, I bought all of Jonathan Coulton's albums. And one way to enjoy mainstream music without feeding the big record labels is to buy used CD's from individual sellers. I've just started to do this. Still, the instant gratification of MP3 downloads is awfully tempting. Just today, I bought an album as an MP3 download, but at least I used 7digital, which doesn't require a proprietary downloader.

Perhaps the problem is that my idealism isn't really my own. I've bought into the rhetoric of those who oppose proprietary software, DRM, software patents, certain centralized Internet services, and so forth; but I haven't experienced first-hand what's apparently wrong with these things. DRM, for example, has only bitten me when I've been careless with my player authorizations; that was clearly my own fault. And as for proprietary software, it seems to me that proprietary software can be OK if the software company makes an effort to provide a good product on fair terms. So maybe people like Richard Stallman, Bradley Kuhn, and the Defective by Design team are just being hopelessly idealistic. But they might say that I need to sacrifice some conveniences or even my current job in order to stand on principles.

Anyway, I'm not going to do anything rash, especially when it comes to my work. But when it comes to entertainment and leisure activities, I'm going to keep resisting the lures of big companies and their questionable practices.

Page 1 / 1