<![CDATA[Defining Terms]]> 2016-09-02T19:07:03+02:00 http://definingterms.com/ Octopress <![CDATA[Pivotal Tracker Git Hook]]> 2013-08-03T09:56:00+02:00 http://definingterms.com/2013/08/03/pivotal-tracker-git-hook At work we use Pivotal Tracker to manage some of our projects and we like to use the Post-Commit Hook Integration. Basically, if you put the Pivotal Tracker story number in your commit message, it will associate the commit with the story. It’s a nice feature that makes it easy to tie your code changes to features.

The problem is that I often forget to include the story number in my commit message. So, I wrote a small git commit-msg hook to check for a story number. If the message does not include one, the commit is aborted. I’ve been using the hook for a while and it’s been very helpful, so I’m publishing it.

The code is available on Github under an MIT license:

https://github.com/aag/pt-story-git-hook

]]>
<![CDATA[Pitfalls of Ruby Mixins]]> 2013-03-23T20:42:00+01:00 http://definingterms.com/2013/03/23/pitfalls-of-ruby-mixins Multiple Inheritance

Mixins are Ruby’s way of dealing with the multiple inheritance problem. If inheritance expresses an is-a relationship, the problem occurs when a class is more than one thing. For example, it’s easy to express that an Employee is a Person by making the Employee class inherit from the Person class. But what if Employees are also EmailReporters, who can email their status to their manager? How do you express that?

1
2
3
4
5
6
7
8
9
10
11
12
  class EmailReporter
    def send_report
      # Send an email
    end
  end

  class Person
  end

  class Employee < Person
    # How can this also be an EmailReporter?
  end

Other languages solve this problem by allowing a single class to inherit from multiple other classes, or by using interfaces. Ruby is a single-inheritance language, but solves this problem with mixins.

Mixins

Mixins are a way of adding a set of methods and constants to a class, without using class inheritance. The include method lets you include a module’s contents in a class definition. In addition to inheriting from one other class, classes can include any number of mixins. In our example, the Employee class can inherit from the Person class, but include the EmailReporter module as a mixin. Then, any methods and constants that are defined in the EmailReporter module are added to the Employee class.

1
2
3
4
5
6
7
8
9
10
11
12
  module EmailReporter
    def send_report
      # Send an email
    end
  end

  class Person
  end

  class Employee < Person
    include EmailReporter
  end

Mixins have simplicity as their primary strength. They let us share code between classes without some of the problems of multiple inheritance, which can be complex and sometimes ambiguous. They let us easily create lightweight bundles of methods that can be included in any class where they’re needed. This functionality is simple and convenient, but not without its problems.

Pitfall #1

Mixins have at least two major pitfalls. The first pitfall stems from how mixins are implemented. What really happens when you call the include method with a module? It seems like the module’s methods are injected into the current class, but that’s not actually how it works. Instead, the module is inserted into the inheritance chain, directly above the class where it’s included. Then, when one of the methods in the mixin is called, the interpreter starts going up the inheritance chain looking for the method, and when it gets to the mixin module, the method is found and called.

You can see in the above diagram that the EmailReporter module is represented right above the Employee class in the hierarchy, by the class with a dotted line around it. But where does this new class come from? The Ruby interpreter creates an anonymous class called an include class (or proxy class) that is a wrapper for the module, and this class is inserted into the class hierarchy, directly above the class where it’s included.

This all works great, except when a module defines a method that already exists in some other module or class in the hierarchy. When that happens, whichever definition is lowest in the hierarchy silently shadows, or covers up, all the other methods. That means the behavior of a method call can be determined not just by the class hierarchy and which modules are included, but the order of the include statements.

Let’s expand our previous class hierarchy to show an example of this:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
  module EmailReporter
    def send_report
      # Send an email
    end
  end

  module PDFReporter
    def send_report
      # Write a PDF file
    end
  end

  class Person
  end

  class Employee < Person
    include EmailReporter
    include PDFReporter
  end

  class Vehicle
  end

  class Car < Vehicle
    include PDFReporter
    include EmailReporter
  end

In this hierarchy, we have added Vehicle and Car classes to our previous hierarchy. Also, in addition to the EmailReporter module which emails reports, we have a PDFReporter module which writes reports to PDF files.

Because the Employee and Car class include the EmailReporter and PDFReporter modules in a different order, calls to the send_report method have different effects:

1
2
3
4
5
  an_employee = Employee.new
  a_car = Car.new

  an_employee.send_report # Writes a PDF
  a_car.send_report       # Sends an email

This dependence on statement ordering can be confusing and can make debugging more difficult. And this issue isn’t restricted to just modules interacting with each other. Methods defined in a class definition will silently shadow methods in included modules, and methods defined on classes higher up in the hierarchy will be silently shadowed by any modules lower down in the hierarchy.

Pitfall #2

The second pitfall of mixins is that they break encapsulation, so they can make code more entangled and make code changes harder. Consider the case of the standard Ruby Comparable module. When this module is included in a class, it expects the class to define a <=> method, which the module uses to define the <, <=, ==, >=, and > operators, as well as the between? method.

The Comparable module is very convenient, but consider what would happen if it changed so that it expected a compare_to method instead of <=>. This change would necessitate changing every class that includes Comparable. This is unlikely to happen with a standard Ruby module like Comparable, but it is fairly likely to happen with the modules you create in your application, especially at the beginning of development when you’re still figuring out how the different classes and modules should interact.

Instead of using mixins, it’s often better to create a new class and call methods on an instance of that class. Then, if the internals of the new class change, you can usually make sure the changes are wrapped in whatever method was originally being used, so the calling code doesn’t have to change.

Conclusion

In general, mixins are a good solution to the multiple inheritance problem. They can be very useful and make code sharing between classes easier than other solutions like interfaces or true multiple inheritance. However, when using mixins, you have to be aware of the potential pitfalls. Since mixins silently shadow methods, you have to be careful with method names and the order of include calls. Also, since mixins break encapsulation and can make changes difficult, you may want to consider using an instance of a class to perform the same function, especially early on in new projects.

]]>
<![CDATA[Go tools with tmpfs]]> 2012-07-25T00:00:00+02:00 http://definingterms.com/2012/07/25/go-tools-with-tmpfs My desktop computer runs Linux and has an SSD and plenty of ram, so I’ve mounted /tmp to a tmpfs RAM disk, as others have suggested. This is nice because it makes things faster and cuts down on writes to the SSD, but it causes problems with some of the go tools.

Both go run and gotour compile binaries to /tmp and try to run them from there. When /tmp is a tmpfs volume, you will get errors like this:

1
2
$ go run hello.go
fork/exec /tmp/go-build995932098/command-line-arguments/_obj/a.out: permission denied

One solution is to set the tmp directory to a location that’s not in a ramdisk, just in the shell you’re using to run go. In a bash shell, you can do that with these commands:

1
2
$ mkdir ~/tmp
$ export TMPDIR=~/tmp/

Then the go commands will work correctly:

1
2
$ go run hello.go
hello, world

You will have to export TMPDIR each time you open a new shell in which you want to use the problematic go tools.

]]>
<![CDATA[Windows Shell Bug]]> 2009-11-25T00:00:00+01:00 http://definingterms.com/2009/11/25/windows-shell-bug At work, we build one of our projects with Makefiles. In one of these Makefiles, we have this line:

1
IF NOT EXIST "$(OUTDIR)" mkdir "$(OUTDIR)"

This should create the output directory if it doesn’t exist. The line would hang the build on my development box from time to time, so I decided to track down what the problem was. It turns out, IF NOT EXIST will sometimes hang if there are quotes around the filepath, at least on Windows XP. You can verify this with a simple perl script:

1
2
3
for (;;) {
    system("cmd /c IF NOT EXIST \"\\Windows\" echo nodir");
}

Running that script will cause the cmd to hang after a short amount of time (usually less than a minute).

But, if you run this script, it will continue forever:

1
2
3
for (;;) {
    system("cmd /c IF NOT EXIST \\Windows echo nodir");
}

In our case, the filepath will never contain any spaces, so the solution was to just remove the quotes from the IF NOT EXIST command in the Makefile.

]]>
<![CDATA[EngineYard SHA-1 Competition]]> 2009-08-19T00:00:00+02:00 http://definingterms.com/2009/08/19/engineyard-sha-1-competition A few weeks ago, EngineYard held a programming competition. Basically, the contest was to see who could get a SHA-1 hash closest to a given hash. I thought it might be fun to see how well I could do with a minimal implementation, so I coded up something in C.

My goal was not to write the most efficient program possible, but to see what results I could get from a reasonable design and no major optimizations. So, I wrote about 160 lines of C code, using OpenSSL for the hashing and the old K&R bit counting method. Depending on how long the message plaintext was, this got me about 1 to 1.5 million attempts per second per core on my 3.0 Ghz Core 2 Duo. The winning CPU-based entry, which was written by D. J. Bernstein, contained an optimized SHA-1 implementation and got around 10 million hashes per second per core. So, I was about an order of magnitude off, which seems reasonable to me.

It turns out the really fast implementations were all on GPUs. Both the winner and the runner up used Nvidia’s CUDA for fast GPGPU processing, which was cool to see.

I ran my program for most of the 30 hours of the competition. How did I do? My best result was 37 bits off of the goal, which put me 7 away from the winner.

]]>
<![CDATA[C#, The Ternary Operator, and Mono]]> 2009-08-18T00:00:00+02:00 http://definingterms.com/2009/08/18/c-the-ternary-operator-and-mono The Quiz

One of my coworkers recently sent out this C# programming quiz:

1
2
3
4
5
6
7
static void Main(string[] args)
{
    object x = null;
    object y = (short)4;
    x = (y is System.Int32) ? (System.Int32)y : (System.Int16)y;
    Console.WriteLine(x.GetType());
}

What is printed out?
Try it.
Explain why you were wrong.

If you run the code, you get this output:

1
System.Int32

The code snippet as it stands doesn’t make it clear exactly where the unexpected behavior is. This is a little more clear:

1
2
3
4
5
6
7
static void Main(string[] args)
{
    object x = null;
    object y = (short)4;
    x = false ? (System.Int32)y : (System.Int16)y;
    Console.WriteLine(x.GetType());
}

This code outputs the same thing as the above snippet. So why does this snippet output System.Int32, when x clearly gets set to (System.Int16)4 ? The answer is in the C# implementation of the ternary operator.

The Answer

In line 5 of the second example above, x is set to the result of the expression on the right side of the equals sign. Since the thing on the right is an expression, it must have a single type.

The C# Language Specification, in section 14.13, spells out how the type of the expression is determined:

The second and third operands of the ?: operator control the type of the conditional expression. Let X and Y be the types of the second and third operands. Then,

  • If X and Y are the same type, then this is the type of the conditional expression.
  • Otherwise, if an implicit conversion exists from X to Y, but not from Y to X, then Y is the type of the conditional expression.
  • Otherwise, if an implicit conversion exists from Y to X, but not from X to Y, then X is the type of the conditional expression.
  • Otherwise, no expression type can be determined, and a compile-time error occurs.

In our example, since there’s an implicit cast from an Int16 to an Int32, but not an implicit cast from an Int32 to an Int16, the compiler says the type of the expression must be Int32. Then, when our Int16 is returned, it’s typecast to an Int32.

More Types

The spec makes it pretty clear what is supposed to happen if there’s an implicit conversion from one of the operands to the other, but not the other way around. But what happens if there’s an implicit conversion in both directions? According to the spec, none of the first three conditions are met, so the compiler must output an error. There is an implicit conversion from a byte to int, and also one from const int to byte, as long as the int is small enough to fit into the byte. So, let’s try compiling this:

1
2
3
4
5
6
7
8
9
10
static void Main(string[] args)
{
    const int i = 1;
    const byte b = 2;

    object x = null;
    x = true ? i : b;

    Console.WriteLine(x.GetType());
}

The Bug

If you compile this with the .NET 3.5 compiler, it compiles without errors. There’s a warning about hardcoding true into the ternary operator, but nothing about the types. So, the compiler does not conform to the C# language spec. That’s a bug, but it’s not that shocking. There are other places where the .NET compiler doesn’t conform to the spec. It seems that Microsoft has a policy to leave such bugs in, so as to not break compatibility with existing code, so it will probably stay that way for the foreseeable future.

Mono

This got me wondering if the Mono compiler properly supports the spec. So, I tried compiling with the Mono 2.0 C# compiler. Here’s what you get:

1
2
Program.cs(13,17): error CS0172: Can not compute type of conditional expression as `int' and `byte' convert implicitly to each other
Compilation failed: 1 error(s), 0 warnings

So it looks like Mono conforms to the spec in this case. It’s a bit amusing that an open source project supports the spec better than Microsoft itself, but there are probably also cases where it goes the other way. However, this means that the Mono implementation is incompatible with the .NET implementation of C#. Now, this particular incompatibility is unlikely to come up that often, since there aren’t many types that have two-way implicit conversions with each other, but it’s something to consider.

The Law

The legal implications of this bug are perhaps the most interesting part. A few weeks ago, there was a lot of talk about the Mono patent situation. This has now been largely resolved with Microsoft putting C# and the CLR under its Community Promise. However, the Community Promise only applies to a given implementation “to the extent it conforms to one of the Covered Specifications.” If an implementation does not conform to the specification, it is not covered by the promise.

You can probably see where I’m going with this. If Mono decided to support compatibility with the .NET compiler by breaking from the spec and implementing the ternary type bug the same way Microsoft has, it might be giving up its protection against patent lawsuits. In order to be legally safer, it’s probably wiser for Mono to stick to the spec and break compatibility with the .NET compiler. This is significant, because the more situations like this crop up, the harder it will be for programmers to port their .NET code to Mono. There’s not much that the mono project can do about this, but it’s unfortunate that the legal situation forces their hand on compatibility.

]]>
<![CDATA[Moving from Apache to Nginx]]> 2009-04-21T00:00:00+02:00 http://definingterms.com/2009/04/21/moving-from-apache-to-nginx I’ve been having problems with too much memory usage on the 256 slice I use to serve my web pages. I was using Apache and mod_php, and the Apache processes were growing large enough that I could only have 4 of them running at once, which killed any hope of decent concurrency. I decided to switch to using PHP with FastCGI and after some research decided to go with nginx. The switch has now been made and page generation is faster, the server can handle greater concurrency, and memory usage is under control.

I actually ended up using nginx, PHP, PHP-FPM, and xcache. I’m running 8 instances of PHP and 2 nginx worker processes. First, I got started by using the step-by-step instructions I found on someone’s blog. After the initial setup, there was still a lot of configuration to do, some of which was not trivial. Below are some notes from my experience:

  1. When setting up FastCGI processes for PHP, make sure the firewall isn’t blocking access to the port the FastCGI servers are listening on. If your firewall is filtering packets to the port, you’ll get a “504 Gateway Time-out” page from nginx whenever you try to access a PHP page. To open up the port, if you’re using iptables, add something to your iptables startup script like this:

    1
    
    iptables -A INPUT -p tcp -s localhost --dport 9000 -j ACCEPT
  2. Somewhere I saw a redirect example to eliminate the www from URLs that caused me to add this to the config file:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    
    server {
        listen          80;
        server_name     www.definingterms.com;
        rewrite         ^/(.*) http://definingterms.com/%1 permanent;
    }
    
    server {
        listen          80 default;
        server_name     definingterms.com;
        [...]
    }

    I’m not sure why I thought I needed this, but it was messing up the loading of static images on this blog. The right thing to do is just list multiple server_names for the host, and let WordPress handle the redirect:

    1
    2
    3
    4
    5
    
    server {
        listen          80 default;
        server_name     definingterms.com www.definingterms.com;
        [...]
    }
  3. Moving most of my sites from Apache to nginx was easy, but there was the problem of rewrite rules. A lot of the software I use (e.g. Wordpress, Mediawiki, Gallery) needs rewrite rules. If you’re using Apache, there’s always an example .htaccess file either in the documentation, or in some user forum. However, the nginx rewrite rules work differently, and you can’t always find an example config, so it took some time and brain power to get them all right. Actually, this is true for all parts of the nginx configuration. The English documentation is sparse and it’s sometimes hard to find examples of what you want to do.

  4. nginx doesn’t have CGI support. If you’ve got those one or two sites that use non-PHP CGI, you’ll have to set up a FastCGI instance for each language you want to support. For example, I had a copy of ViewVC running, which is written in Python. With Apache, it was just using CGI. With nginx, I’d have to constantly run a whole Python FastCGI process for the rare event when someone wants to browse ViewVC.

In the end, I think the move to nginx was worth it purely for the performance gains, since it keeps me from having to pay for a heftier VM every month. But, it did take a fair amount of work and if I had slightly more complex needs, it might not have been a good fit for me.

]]>
<![CDATA[Secure Passwords Not Allowed]]> 2009-04-11T00:00:00+02:00 http://definingterms.com/2009/04/11/secure-passwords-not-allowed For quite a while now, I’ve been using a tiered password system for all of the websites where I have accounts. I knew this was bad practice, but it was easy. Recently there have been a number of stories about websites’ databases being leaked, which made me seriously consider doing something better. Password managers have never impressed me much, both because of the security issues of storing all of your passwords in a central location and the danger of losing the database and not being able to reconstruct it. But, when I came across PasswordMaker, I liked what I saw.

Instead of storing the passwords, they’re generated on the fly using a cryptographically secure method. The software is all open source, so you know what’s going on and can reconstruct it if you need to. Finally, there’s also a very convenient browser plugin for Firefox that I can install everywhere. So, I finally bit the bullet and got away from my tiered password system by moving all of my online accounts to using passwords generated by PasswordMaker.

If I’m going to go through all of that trouble, I might as well use a secure password, right? So I decided to use passwords with letters, numbers, and punctuation. That shouldn’t be anything special, it’s just the standard recommendation for password security. Some systems even have that as a minimum requirement.

What surprised me was that a huge number of websites I use don’t allow passwords with punctuation, 20% in fact. Out of the 97 sites where I tried to update my account, 19 of them would not allow it. These ranged from hip web 2.0 sites like digg.com to big, corporate sites like geico.com. Here’s the full list:

So now I have to use a different set of characters for my passwords at these sites. Fortunately, PasswordMaker lets me configure different profiles for different sites, so I can set it up once and forget about it. But, why should I have to do that, especially when it makes my account less secure?

It seems like it just requires more work from the website makers to restrict certain characters, and I can’t think of any good reason to do so. It might make sense to restrict passwords to ASCII characters if their system doesn’t fully support Unicode. But disallowing all punctuation just doesn’t make any sense. The programmers might be worried about allowing escape characters in passwords, but it seems like it would be just as much work to protect the system against them internally as making an additional demand on the user.

If we’re going to expect users to have secure passwords, we need to allow them to do so. I’d like to see the above sites change their password policies, and I want any new sites to allow long, complex passwords.

]]>
<![CDATA[Dinosaur Remix]]> 2009-04-02T00:00:00+02:00 http://definingterms.com/2009/04/02/dinosaur-remix I like Dinosaur Comics. Since the drawings and panels are the same in every comic, I thought of the idea of trying to mix and match panels from different comics to see what comes out. It turns out, Ryan North had already done something similar, but I decided to implement my idea anyway. Here’s the result:

Dinosaur Remix

Dinosaur Remix lets you randomly mix together panels, but also lock in certain panels to make a comic you like. Then you can add clever alt text and save it or send it to a dinosaur-loving friend!

It’s written in Python, PHP, and JavaScript. It was my first chance to really use jQuery, which is just about as awesome as everyone says it is. All of the code is available on GitHub.

]]>
<![CDATA[Translation Hacks]]> 2008-10-03T00:00:00+02:00 http://definingterms.com/2008/10/03/translation-hacks Not so long ago, the only help available when translating text from one language to another was a dictionary and a grammar book. That’s how it was when I started learning German. Now, there are a number of tools online to help you in your bilingual quest, but you have to be clever to get the most use out of them. My examples will be in German, but these techniques can be applied to most languages that have a strong online presence.

  • A Good Dictionary - This is still your first line of defense against the hostile hoards of foreign words. For German, the best is clearly LEO. The reason it’s better than your trusty Langenscheidt’s or Oxford-Duden is that it’s user created and maintained, so you get idioms, slang, and current events.

  • Google for Grammar - If you don’t know which of two or three possible variants is the correct one, Google all of them and see if one has many more hits than the rest. Important here: put the phrase in quotes. This is especially good for things like which preposition to use with more common words. Let’s say you want to translate “I’m going to Chicago.” Which preposition do you use? Try searching for a similar phrase (in this case, altered for geographic relevance) and see if one stands out. Go to google.de and click the “Seiten auf Deutsch” (Pages in German) button. Then try three reasonable guesses:

    1. “gehe zu Berlin”: 7 hits
    2. “gehe nach Berlin”: 2,890 hits
    3. “gehe bei Berlin”: 1 hit

    It looks like we have a clear winner. You can be pretty confident translating your sentence as “Ich gehe nach Chicago”. However, this isn’t always foolproof. If you had searched for “gehe in Berlin” you would have gotten 576 hits and the results wouldn’t have been quite as clear. But, after reading the first few hits, you’d have realized that it’s not what you’re looking for.

  • Wikipedia - This is especially good for technical terms. Suppose you want to talk about the famous Quicksort algorithm in German. LEO won’t help you. So, go to the English Wikipedia page for Quicksort. Then, look down on the left side of the page in the “languages” box. Click “Deutsch” (if it exists) and you’ll be taken to the equivalent German page. In this case, you find out that Quicksort is the same in English and German, so now you can (not) translate it with confidence.

  • Names - You read a foreign name and you’re not sure what gender it is. Sometimes that doesn’t matter, but if you want to talk about this person, it sure is useful to be able to use pronouns. So, to figure it out, do a Google image search, preferably at the Google site for the country, and look at the results. Example: Johannes vs. Johanna (I read this somewhere online, but I’m not sure where. It’s especially helpful for Asian names.)

  • Machine Translation - I list this one last because it’s generally the least helpful. The two main free sites are Google Translate and Babelfish. These sites are slowly getting better, but right now they’re still of limited value. They’re good if you want to read something in a language you don’t know at all or it would take you a long time to do the translation yourself and you just want to get the gist of the text.

]]>
<![CDATA[Adventures in Translation]]> 2008-07-25T00:00:00+02:00 http://definingterms.com/2008/07/25/adventures-in-translation Yesterday, I came across this wonderful sentence while reading “Das Parfum” by Patrick Süskind:

Und wenn er auch wußte, daß er den Besitz dieses Duftes mit seinem anschließenden Verlust würde entsetzlich teuer bezahlen müssen, so schienen ihm doch Besitz und Verlust begehrenswerter als der lapidare Verzicht auf beides.

This can be roughly translated as:

And even knowing that the possession of this scent would require him to subsequently pay the terribly high price of its loss, the possession and loss seemed more desirable than the lapidary relinquishment of both.

The interesting part of the sentence is “daß er den Besitz dieses Duftes mit seinem anschließenden Verlust würde entsetzlich teuer bezahlen müssen”. In a word-for-word translation, this is “that he the possession of this scent with its subsequent loss would terribly expensive pay have to”.

In general, English and German have similar sentence structure and word order. But occasionally you see a German sentence that makes you think the author took a sentence, tied it in a knot, and threw it onto the page. Translation of such sentences requires not only translating the meaning into English, but untying the knot so that the English-speaking reader can parse it. And that’s the fun part.

]]>
<![CDATA[Simple Canvas Example]]> 2008-03-31T00:00:00+02:00 http://definingterms.com/2008/03/31/simple-canvas-example Here is a simple example of drawing pixels (rather than paths) to a canvas element with JavaScript. The algorithm goes left to right and draws across the canvas, and for each pixel column draws two blue pixels, one for the top half of the circle and one for the bottom half. Then, because this results in sparse drawing for the far left and right edges of the circle, it does another pass from top to bottom, doing the same thing with red pixels. The result is a circle with gradient colors, showing which pass drew more of the circle.

It’s been tested in Firefox 2 and 3, and I think it should work in recent versions of Safari and Opera.

]]>
<![CDATA[RT Update]]> 2008-03-25T00:00:00+01:00 http://definingterms.com/2008/03/25/rt-update I wrote a few weeks ago about how Rotten Tomatoes did a redesign of their site that broke my primary use case. Since then, they have done an update that makes things a lot better for me, though it’s still not as convenient as the original design. Right now, if you hover over any of the tabs for different groups of ratings, you get a popup that tells you that group’s percentage of positive reviews. In my case, I’m interested in the Top Critics group:

Hovering over the Top Critics tab on RT

While this does allow you to compare the percentages much more easily, it’s not quite perfect. On the plus side, it displays both percentages at the same time and it’s quite easy to discover. Anyone who is interested in the Top Critics information will move to click on the tab header, and when they move the pointer over it, they’ll see the popup.

On the downside, it does require fairly precise mousing (and holding the mouse still) for the whole time you want to read the number. This makes it much less accessible to those who have trouble acquiring small targets and keeping the pointer still, such as the elderly or disabled using a mouse. Additionally, you have to use the pointer to see it, which makes it inaccessible to those navigating with just the keyboard.

]]>
<![CDATA[Ticketmaster Price Doubling]]> 2008-03-24T00:00:00+01:00 http://definingterms.com/2008/03/24/ticketmaster-price-doubling Ticketmaster has long charged too much in service fees, but this is the first time I’ve seen them almost double the price of a ticket. This is what I saw this morning:

Ticketmaster Order

Ticketmaster made the price go from $15.00 to $27.30, and that’s if I print off the ticket on my printer. If I wanted to have a ticket mailed to me, it would cost even more. That’s just out of control. When I saw that, I closed my browser window and decided to buy a ticket at the door and risk it selling out.

In contrast, I had a very good experience at etix, where they charged a $2.50 service fee per ticket. I think that’s reasonable and I wish more venues and artists would use etix and force Ticketmaster to respond to some competition.

]]>
<![CDATA[Windows Live SkyDrive]]> 2008-02-22T00:00:00+01:00 http://definingterms.com/2008/02/22/windows-live-skydrive I haven’t really gotten into the whole online backup thing. I’m not sure I want to spend a week uploading my files on my cable Internet connection, only to depend on some company keeping my files safe and private.

But, yesterday it was announced that Microsoft’s new online backup/file sharing service has come out of beta. It’s free and all you need is a Windows LiveID. I have one of those, so I thought I’d take a minute to try it out.

I was tweaking my .bashrc a couple of days ago, so I thought I’d upload that. It’s a nice small file, so it shouldn’t take long to upload, and it might be useful to have it accessible from a web browser.

So, I downloaded it to my local machine. It was pretty easy to figure out how to upload it to a folder on my SkyDrive, and I just had to pick it from the hard drive using a file browser.

Upload Form

Just click upload and we’re all set!

None of your files were uploaded?

Clicking on the “Learn why uploading may fail” link was not helpful. My file doesn’t violate any of the rules on the page.

But then I remembered, Windows doesn’t like it if you start a filename with a dot. You can copy a file around that starts with a dot, but you can’t rename files in Windows Explorer to start with dots. Of course, the service surely uses Windows servers, so I bet it has something to do with that. How could I find out if that was the real problem? How about renaming the file to not have the dot and retry?

No dot filename has been uploaded

Wonderful. But now I want to be able to download it with the real filename, so I can just drop it on a Linux machine and go. So I tried to rename it.

Rename message

Oh, now I get a real error message. At least I know what the problem is.

But that’s a pretty silly restriction to not allow filenames that start or end with dots. I understand that there’s an arbitrary restriction on those files from Windows Explorer, but you can store dotfiles on NTFS partitions without a problem. So the programmers had to add extra code to explicitly disallow these files for no good reason. Why?

]]>
<![CDATA[Night Watch]]> 2008-01-29T00:00:00+01:00 http://definingterms.com/2008/01/29/night-watch I saw Night Watch a few days ago. The film wasn’t bad; it had great cinematography and decent effects. Sadly, the story was a dim shadow of the one in the book, but I suppose that’s to be expected.

The most interesting part of the movie, for me, was the subtitling. I watched the DVD with the Russian audio and English subtitles. The subtitles were beautiful, dynamic, and surprising. The font was nice to look at and easy to read, even on my 27” SDTV. The words appeared and disappeared in unexpected ways on the screen. For example, sometimes they would be revealed from behind a character as he moved across the screen. Other times, multiple phrases would fade in and out at different times at different places on the screen. They were not constrained to the bottom of the screen: they would appear at any place on the screen. During conversations, the lines of each character would appear near the person on the screen, so it was easy to tell who said what. One of the most interesting presentations was of “The Call”, the siren song of the vampire to her victim. The words (e.g. “Come to me”) would appear on the screen blood-red, then swirl away like drops in a stream.

Time magazine has an interesting writeup about subtitles that mentions Night Watch, and has a poor quality screenshot of the subtitling of The Call. A DVD Times post has a number of other screenshots that show the subtitles.

]]>
<![CDATA[Rotten Tomatoes Redesign]]> 2008-01-20T00:00:00+01:00 http://definingterms.com/2008/01/20/rotten-tomatoes-redesign Rotten Tomatoes recently did a site redesign. It looks a lot shinier, but it broke my primary use case. Here’s what I used to do when I went to the page for a particular movie:

  1. Read the fresh percentage for All Critics.
  2. Read the fresh percentage for the Top Critics.
  3. Compare the two percentages.

Old Rotten Tomatoes Layout

Why do I use RT in this way? Because I have found that if the All Critics percentage is fairly high (over 75%) and the Top Critics percentage is significantly higher (at least 7 or 8%), then I will very likely enjoy the movie. However, even if the All Critics percentage is fairly high, but the Top Critics is significantly lower, I probably won’t like the movie. The key here is that I find the delta of the two percentages to be a better indicator than either of them individually.

Now, with the new Rotten Tomatoes site, my workflow has changed to this:

  1. Read the fresh percentage for All Critics.
  2. Click on Top Critics.
  3. Read the fresh percentage for the Top Critics.
  4. Recall the All Critics percentage from memory (where difficulty increases based on page load time and how many movies I’ve already looked at in this browsing session).
  5. Compare the two percentages.

New Rotten Tomatoes Layout - All Reviewers

New Rotten Tomatoes Layout - Cream

I like this workflow a lot less because it creates three negative effects for me:

  • It takes more work to do what I want to do. I have to click on the “Top Critics” tab, whereas before I didn’t have to click on anything.
  • It takes longer to do what I want to do, since I have to click on the Top Critics tab and wait for the second page to load. On a fast connection, and when RT is running quickly, this isn’t that big of a deal since the time is very short. However, on a slow connection or if the RT servers are having problems, I have to wait a long time.
  • I have to remember something. To put it in the terms that Don Norman uses in his book The Design of Everyday Things, knowledge that was previously in the world must now be kept in the head. Norman identifies this as a design flaw (at least for this use case), because it is a lot harder to remember the number than to read it. This is especially true if it takes a long time to load the Top Critics page or if I decide to read other things (like the review of a particular critic) between when I read the first number and when I read the second.

I can think of three reasons why the new layout was done the way it was:

  • Usability: Almost no one compares the two percentages. If there are only three people in the world that compare the two percentages, but lots of people like to read the film news and look at photos, then the change makes sense. Removing the Top Critics sidebar from the main page freed up space for more frequently used things.
  • Greed: Because lots of people want to compare the two percentages, RT can get twice as many page views (and therefore more ad impressions and clicks) by putting the two percentages on different pages.
  • Ignorance: They either don’t know how many people are comparing the two percentages, or they don’t know that splitting them up into two pages decreases usability.

If I had to guess, I would give RT the benefit of the doubt and say that they made the change for increased usability. The site does a lot of things right when it comes to usability, so they probably got this right, as well. It still annoys me when I have to use it, though.

]]>
<![CDATA[Maximize, Zoom, and the Art of Window Management]]> 2008-01-16T00:00:00+01:00 http://definingterms.com/2008/01/16/maximize-zoom-and-the-art-of-window-management A while back, Jeff Atwood wrote about the “maximize” behavior in Windows and Mac OS. The subject: There’s a button on the top-right of each window in Microsoft Windows that resizes the window to fill the screen. There’s a green button on the top-left of each window in Mac OS with a + on it, that Windows users often think will cause the window to fill the screen, but it actually resizes the window to its “best size”. Apple calls this Zoom.

In my experience, MS Windows users hate the Mac way of doing things, and Mac users hate the Windows way of doing things. The comments on Jeff’s post reinforce this impression. I have often wondered why this little difference causes such strong reactions. I’m pretty sure it has to do with the taskbar/dock.

In MS Windows, each window has an associated button on the taskbar1. These buttons stay in the same order2 and in the same place3. This means that no matter what you do to a window, whether you maximize, minimize, resize, or move it, there is always a part of the window showing: the taskbar button. No window can ever be completely hidden. You can get to every open window with a single click. And since the buttons are always in the same place, you can use spatial relationships to remember which window is which, in addition to the icon and text label on each button. So, Windows users like to maximize windows, because you get the maximum amount of screen space for the program you’re using, but navigating between windows is still fast and easy.

In Mac OS X, that isn’t the case. There is no button on the toolbar for a window (only entire programs, which often have multiple windows). Windows can be completely hidden behind each other. Then, if you want to see one of the windows that isn’t on top, you have to move all of the windows above it. Since this is the case, users have to take it upon themselves to ensure that they can always see a piece of each window. This results in not wanting to maximize any windows. If they do that, all of the other windows will be completely hidden and it will be a lot of work to navigate between them.

Recent versions of Mac OS X have a feature that is an attempt to work around this limitation: Exposé. Press a function key (or move your mouse pointer to a specific corner of the screen) and all of your windows shrink down to thumbnail views so you can click on the one you want. This works fairly well if you a) don’t have many windows open, and b) are using windows that look distinctive from one another. But, if you have so many windows open that each one is tiny, it doesn’t help you much. Similarly, if you have 10 windows open from each application, you can’t tell which one you want by looking at thumbnails of them. Here’s what a Windows Exposé clone might look like on my desktop if I’m working on a programming project:

As you can see, the windows are so small that it’s hard to make out what is on each one, unless it is something distinctive like the video in the bottom right corner. Also, a number of windows look the same, so if I want to find that one command prompt window, which of the black squares do I click on?

But even if these problems didn’t exist, Exposé would still be more work to use than clicking on windows in the taskbar. The taskbar requires only one click, Exposé requires either a mouse move to a corner or a keyboard button press, plus a mouse click.

Of course, the Windows taskbar isn’t perfect either. Once there are enough windows open, there is almost no text on each taskbar button, so you can’t tell different windows from the same application apart.

Even so, I still think the Windows maximize button is way better than that stupid zoom.

Footnotes

  1. Unless you use the default “Group similar taskbar buttons” setting in Windows XP and later. back
  2. Except in Windows Vista where the buttons rearrange themselves to group windows from the same program together. back
  3. They shrink and grow to accommodate more and less buttons, changing their size and absolute position somewhat, but the relative positions of the buttons to each other are maintained. back
]]>
<![CDATA[Penguicon Reading List]]> 2007-04-25T00:00:00+02:00 http://definingterms.com/2007/04/25/penguicon-reading-list Many of the Penguicon panelists referenced extra reading materials over the weekend. I wrote many of them down, and I hope to read what I can. Unfortunately, I can’t seem to find enough time to read these days, but I hope to get better at that.

Here’s the list, broken down by the panel or presentation where they were mentioned:

Life Extension: Good News, Bad News, Weird News - Christine Peterson

Constructed Languages - Matt Arnold, Ron Hale-Evans, Catherine Devlin

The Future of Spyware - Bruce Schneier and Charles Stross

Posthuman, A Lousy Marketing Concept - Christine Peterson, Jason Ahlquist, Karl Schroeder, Ron Hale-Evans

Design Better Airport Security with OSS Methods - Christine Peterson and Bruce Schneier

Limited Female Roles in Fantasy, Comics, & Sci Fi - Sarah Monette, Elizabeth Bear, John Scalzi, The Ferrett, M. Keaton

Technology As Legislation - Karl Schroeder, Charles Stross

]]>
<![CDATA[Penguicon 5.0]]> 2007-04-25T00:00:00+02:00 http://definingterms.com/2007/04/25/penguicon-50 Last weekend Olivia and I went to Penguicon. Olivia has already done a recap from a non-geek’s perspective. Here are my thoughts from a slightly different perspective.

I have geek cred. Played CCG’s in Junior High. Started programming TI-BASIC as a freshman in high school. Read a bunch of fantasy and science fiction. Started going to LANs at 16 and played in online Counter-Strike leagues for half a dozen seasons. I’ve been using Linux for over 6 years, both on the desktop and server. I program computers for a living. But my first con was a whole new experience.

The People

Olivia commented on the social etiquette. I wasn’t surprised by the sense of humor or loudness. But one thing I noticed is that there were few if any social protocols. In daily life, most of our social interactions are guided by culture-specific protocols. If I meet someone for the first time, there are expectations for what we will say and what we will do with our bodies. In the US, I’d give my name, probably shake hands, and possibly finish up with something like “Nice to meet you.” At the con, such protocols were neither followed in personal interactions or group settings. I noticed a few times when it seemed the presenter/panelists were fighting with the audience for the right to speak, but there was no clear way for either one to get the floor.

This lack of protocols is both good and bad. The good side is that people who don’t understand, can’t perform, or just don’t want to participate in the accepted social protocols don’t stand out. It also gives people more freedom in how they express themselves and form relationships. The bad side is that those who expect the protocols will be followed will be confused and uncomfortable. Also, the point of social protocols is to ease interactions. If we cut out the protocols, we lose this ease as well.

Personally, I found this lack of protocols jarring. I think this was especially true because, aside from Olivia, I didn’t know anyone at the con, but most of the other people knew a number of other attendees already. You don’t really need general protocols when you’re hanging out with your friends, but if you’re with strangers and trying to meet new people, they can be essential.

Another thing I noticed patterns in was the physical bodies of the other attendees.

I’m not the only one to notice the general chubbiness of the attendees. I’m a fat-friendly guy, and this is clearly a case of the pot calling the kettle black, but it made me sad to see so many smart and interesting people not taking care of their bodies. I remember one panel where a panelist was winded just from walking down the hall from the last room he was in.

On the other hand, it made me really glad that many of the women were quite comfortable with their over-sized bodies. Instead of hiding themselves behind huge, baggy clothes like many do, they were wearing sexy, revealing clothes. With all of the damage done by modern America’s obsession with the thin body, I hope this indicated an overall self-confidence with respect to body image. I hope geek culture creates women who see through the lines fed to them by fashion magazines and advertisements, and who can see that they truly are beautiful, no matter what their size.

The small surface-area facial hair on men was out of control. My estimate is that at least half of the men in attendance had a goatee, mustache, soul patch, chin beard, or combination thereof. This was way more than I see among the general populace, and I wonder why these adornments were so popular. I don’t have any good theories yet.

The Panels

Almost all of the panels were very interesting, and there was quite a variety of style and feel among them. Bruce Schneier liked to give a presentation, ignoring upheld hands and questions until a period at the end. Christine Peterson monologued, but accepted questions throughout. Many of the panels were like conversations between the panelists, with occasional interjections from the audience. I found all of these styles interesting and rewarding. The only thing I didn’t like, as I mentioned above, was when an audience member or two would try to dominate the presenter or panel, and there was no clear way to resolve the tension.

I went to technical panels and sci-fi panels, though I leaned more heavily towards the technical ones. Only a couple of the panels were about Linux specifically, but I was fine with that. The worst part of the programming was that there were almost always multiple things going on at the same time that I wanted to go to, and I had to choose between them. But, as Matt Arnold said at the closing ceremonies, this is a problem we want to have.

After Hours

We hung out in the ConSuite some and perused the room parties. The liquid nitrogen ice cream was fun and yummy. We had a few good conversations with people, but for the most part the room parties were disappointing. This was probably caused by a combination of a couple of things: we went to panels until late in the evenings (around midnight), and we didn’t know anybody. We met a few people, but I get the feeling that it would’ve been more fun if we’d known more when we arrived. Many of people at the con were “regulars”, either at all of the local cons or Penguicon in particular.

Conclusion

Overall, I liked my first con. The whole weekend was a barrage of interesting sights, sounds, and thoughts. I’m not sure yet whether I’ll be attending any other cons in the area, or even Penguicon 6.0, but I’m glad I went to this one.

]]>