Monday, March 20, 2006

Dinosaurs

My daughter, 4 years old: Daddy, are dinosaurs kosher?
Me: No.
My daughter: Not even little purple ones?

Monday, February 13, 2006

"Model" in MVC

The "Model" in Model-View-Controller architecture does not refer to the application data model. It refers to the user interface model underlying each widget.

Think of a text box that accepts date values. When the user types "2006-" and then pauses, the application doesn't yet have a date, so it doesn't have anything to put in its data model. The string "2006-" isn't stored somewhere in the view; it's stored in the model that backs the UI.

To integrate your UI and your data model, you've got to use data binding code, like the jgoodies derived data binding code. It would seem that MVC is more about UI framework implementation than interface.

This explains why it's so cumbersome to switch between GUI widgets that would appear to represent the same data, like a select box and a group of radio buttons. It'd actually be against the MVC philosophy to support this, because it'd put artificial constraints on the respective widget models.

Monday, November 28, 2005

Consistent Types

There's a problem with inconsistent downcalling, which I've been hankering after for a bit, and which C# supports using the "new" keyword.

The problem is that extension classes aren't really subtypes of extended classes anymore. They violate the Liskov Substitution Principle.

Interfaces for encapsulation don't have this problem.

(Though it'd be great if all languages had something like c#'s "override" keyword :).)

UPDATE: I was mistaken. Different methods are called on an object in different static "contexts". For example:

((ArtisticCowboy)joe).draw() runs one method, and
((Cowboy)joe).draw() runs another.

This is what C# does, but I don't know if it's wise.

Thursday, November 17, 2005

Future Refactoring UI

Refactoring tools have a good case of programmer automorphism. These tools present silly lists of operations like "decompose conditional" and "encapsulate downcast."

Really, automatic refactoring means the computer automatically makes all appropriate changes to accompany your change. It's all about moving and renaming. The tools should get rid of their complicated interfaces, and just support a mode "don't let me introduce any errors."

Simple changes are easy to spot, but moves need to be done with Cut&Paste. For example, cutting from one place and pasting to another should fix up the pasted code to work in the new location. It should also fix up callers to the code at the original location so that they now call to the new location. The user shouldn't have to specify what type of code is moving, or what type of move it's making.

If this could be made fast enough, programmers might want to always work this way. They'd just have to get in the habit of defining before using, and deleting usages before deleting definitions.

Wednesday, November 16, 2005

Everyone is Like Me, and bad UI

User interfaces suck because programmers think users care about programs.

Users do not care about programs. They think, "Just do it," and, "Get out of my face." Programmers love their programs, so they think everyone else does too. For example, they even write programs that hassle users to make implementation decisions.

In general, every person thinks that everyone is just like himself. Worse, every person thinks that everyone is like himself right now. In the linked example, even the developers won't care about the implementation a year after they've coded.

There is a word for this, though it seems seldom used: automorphism

Sunday, October 30, 2005

Interfaces for Encapsulation

The python people haven't succinctly explained why python doesn't need "private", "protected", and "public". In one sentence, python doesn't need visibility modifiers becase...

With sufficiently good refactoring support, encapsulation decisions don't affect code evolution.

Especially according to the XP design principle of collective code ownership, it's easy to change callers of an interface when the interface changes. Though people reading the code will need to understand the changes, that's far more efficient than making artificial barriers to reuse. Encapsulation is powerful; forced encapsulation is onerous.

This is true for a single organization, no matter how large its code base. Once code is "published" however, all bets are off. Code obviously can't be refactored across administrative boundaries. That being the case, we should care about "published" instead of "public".

For encapsulation of published code, separate interfaces are much more useful than visibility keywords. A class with a single public method is better represented by a separate interface containing a single method. When that interface is published, it never changes. In Java for example, the old interface could be kept in a separate jar file, which clients can continue using even after extended versions become available.

More originally, we should allow extending code through an interface. Extending through an interface means that new code will never downcall to a method that isn't in the interface. This is an elegant solution to the fragile base class problem. (Someone recently showed me the cute new c# modifiers "new" and "override". They protect against accidental downcalls, but they don't protect against replacment of methods called by collaborating classes.)

Extending through an interface might also help with downcalling into unrelated methods with mixins and multiple inheritance. For example, to create an "artistic cowboy" with multiple inheritance, we'll inherit from "artist" and "cowboy". Though we want his artistic nature to be dominant, we don't want the cowboy method "drawAndShoot()" to downcall into the artist method "draw()". We can achieve this by extending artist through an interface that excludes "draw()".

Monday, October 10, 2005

DRM and the Little Guy

Maybe published work isn't best treated like property, but publishers will certainly fight to keep it that way. Physical media have been pretty good at proxying ownership of information. If general purpose computers can't do as well, then publishers will just adopt special purpose devices instead. Besides keeping consumption cumbersome and inefficient, this'll give binding power to corporations, but not to individuals.

A general purpose DRM system can have a significant impact on society. If we're going to allow our computers to enter into contracts for us, we need some safeguards to avoid creating an information dystopia. The restrictions that we allow publishers to place on consumers should themselves be restricted. Generally, it shouldn't be possible for publishers to artbitrarily revoke access to their work. The set of digitally managed "rights" should be standard, easy to understand, and when possible, it should not require an ongoing relationship with the publisher.

This task is more difficult from the technology standpoint, and it'll detract from the generality of the full DRM dream, but it could work.

Friday, October 07, 2005

Money and Politics

So long as the only means of engaging in political dialogue is through purchasing expensive television advertising, money will continue by one means or another to dominate American politics.
--Al Gore

Templates for Environments

(The more surprising points are below.) Templates are useful for maintaining different deploy environments. Any large system needs to have a painless way to run in different environments, at least one "production" environment and one non-production environment. Examples of things that change between environments are: machine names, port numbers, database names.

Manually switching code from one environment to another is tedious and error-prone, but not all tools can make it completely automatic in all cases (for example, enabling stored procedures to run against differently named databases). Theoretically, templates are also be useful for unifying environment configuration across languages, but they're really essential for languages that don't support the necessary abstraction.

Even on platforms that have the necessary support, environment management can get gnarly. For example, java has a great configuration mechanism in the form of "properties" and the improved "preferences". If different sets of property files are used, however, it's easy for the non-production property sets to get out-of-date. The solution is to ensure that only a small fraction of properties are environment specific, and put only those in a separate file.

Templates generally break tools for live editing. For example, you can't "alter table" in a test database and easily have that change apply to your template. Or use a gui wizard to maintain templatized xml files for your application servers. We'd like to be able to "round-trip" templates, to be able to automatically generate templates from live files, as well as generate live files from templates. For this to be easy, the templates must meet two requirements:
  1. there must be a one-to-one correspondence between template variables and the values in the environment used to generate templates.
  2. template values must be unique.
An exampe of #1 is that a test environment must have as many different machine names as there are in production, even if those machine names are just aliases. Otherwise, the test environment will lose information.

An example of #2 is that a machine can't be named "foo" because substituting a template variable like "@FOO_MACHINE@" will also substitute "buffoon" and "foot".

Otherwise, the template generation will have to get complicated.

Tuesday, August 09, 2005

Google Maps

Google maps should support saving and restoring locations.

It should also support taking the union of the sets of locations created by different API sites.

Wednesday, August 03, 2005

Mixin Requirements

Proper mixins require two funny features:
  • never down-calling into unrelated mixins
  • a mechanism for disambiguating constructor parameters
Example 1:
class artist:
def draw(self): ...
class cowboy:
def draw(self): ...
def drawAndShoot(): self.draw() ...
artisticCowboy = mixin(artist, cowboy)()
artisticCowboy.draw() should call artist.draw,
but artisticCowboy.drawAndShoot() should call cowboy.draw,
without needing to be explicitly specified

Example 2:
class file:
def __init__(self, root): ...
class plant:
def __init__(self, root): ...
we need some mechanism for specifying plant's and file's constructor parameters independently

UPDATE: Silly me, number one would be great for multiple inheritance also.

Tuesday, August 02, 2005

Improving the GUI Editor 2

A standard XML format for representing GUIs would be a tremendous boon.

It would solve the biggest problems with current GUI builders: round-trip-ability and lockin.

It would enable a single builder to easily support GUIs that run with different languages and widget sets, including HTML.

The standard should specify the least common denominator, as well as extra features and their fall-backs. It shouldn't specify bindings or fancy template support, but it should specify how builders maintain information for features that they don't handle.

Monday, July 25, 2005

Mixins instead of Traits

On reflection (no pun intended), I can't see what advantage Traits have over mixins in a dynamic language like python. Specifically, python doesn't seem to be stuck with a total ordering.

import copy
def mixin(*classes):
c=copy.copy(classes[0])
if len(classes) > 1:
c.__bases__ += classes[1:]
return c()

class a:
def f(self): return "a.f"
def g(self): return "a.g"
class b:
def f(self): return "b.f"
def g(self): return "b.g"
class c:
def g(self): return a.g(self)

obj=mixin(c, b, a)
assert(obj.f() == "b.f")
assert(obj.g() == "a.g")

Friday, July 22, 2005

Improve the GUI Editor

Beware the GUI Editor only for a little while. For one thing, Sun is finally fixing wysiwyg layout with GroupLayout and assorted swing changes, and demonstrated in netbeans. For most of Beware's other complaints, all we really need is good template support, just like what we've been using with html for a while.

Just like with html, users usually won't care about the api for manipulating their presentation, but that's OK. (The favored api for html is the javascript dom.)

Monday, July 18, 2005

Python Shell

In the quest for best re-use, I'd like my "shell" programming language to be my main programming language, and to just support some syntactic sugar and extra functionality for interactive use.

Windowing systems obsolesce job control, leaving tab completion, history, and prompting as the important shell functionality. Python's readline bindings can handle the first two.

LazyPython and IPython both allow ommitting parantheses, commas, and quotes around function parameters. They use standard python's sys.excepthook, so that they only extend python syntax that would've illegal anyway.

This has two problems. First, there are cases that don't work, like calling a method without parameters. Second and more importantly, excepthook still throws an exception, and so discards context. That means you can't do:for i in range(n): some_convenient_method i.

So in order to do it right, we'll have to hack the interpreter, and while we're at it, we could even support working directly with the input. For example, you type some_convenient_method and then a space, and the interpreter inserts a paranthesis. You always have legal python code. IPython prints the legal python code after you hit return, which isn't as nice.

Incidentally, until we have interfaces or inference, tab completion can only work with already instantiated objects. (For example you can't complete list().a to list().append.)

Wednesday, July 13, 2005

Electronic Paper

Should be on my link blog, but wow, Fujitsu is demonstrating electronic paper!

Highlights: as easy-to-read as paper, extremely low-power, flexible, color. Product to be available between one and two years (April 2006 to March 2007).

Friday, June 24, 2005

Is It You?

Rule of thumb:
if you have a bad experience with someone, it's just him.
if you have a bad experience with everyone, it's you.

Tuesday, June 21, 2005

Oppressive Corporate Firewalls

If you're behind an obnoxious corporate firewall, that doesn't allow any internet access except through a web proxy, you can still get out to your unix account.

Putty supports SSL tunnelling via SSL out-of-the-box:
  • on your server, add "Port 443" to your sshd_config
  • in putty new session, specify 443 in the port box, and
  • in its Connection/Proxy category, check HTTP and specify your proxy info

Monday, June 20, 2005

Perl Best Practices (for corporate coders)

In general, use perl for glue code and reports, not for business logic.

Perl code should be as simple as possible. That means:
  • Use as few language features as possible.
  • Use as few lines as possible, as long as they're readable.
  • Don't overdesign.
  • Don't try to write perl that looks like java.
Avoid rewriting functionality that is present in the standard library.

Separate functionality out into multiple small scripts, the smallest meaningful rerunnable units. For example, have one script handle generating a report and another script handle distributing it.

Always "use strict".

Avoid using $_ in loops except for regular expressions.

Avoid reversed flow control operators except for error handling ("doSomething or die()").

Avoid redundant comments.

Avoid overloading on context. (e.g. sub fu { wantarray() ? X() : Y() })

Avoid special symbol variables. Use the long versions and "use English" (e.g. "$INPUT_RECORD_SEPARATOR" instead of $/). Comment appropriately.

Avoid using shell tools (e.g "awk", "grep", and even "date" and "cp"). If perl can do it, do it in perl.

Prefer "my" over "local".

Put "my" declarations in the tightest possible scope.

Have users of modules explicitly import the tokens that they want (e.g. "use SomeModule qw( SomeFunc $SomVar )").

Avoid writing huge modules with lots of independent functionality; people are afraid to change them.

Avoid writing modules altogether, unless you're absolutely sure that your code will be reused.

If you're using references, have the first character of the expression reflect the type of the expression (e.g. use "$somearrayref->[3]" instead of "@$somearrayref[3]").

If your "configuration" is sufficiently complex (or unchanging) just define at the top of your script.

Wednesday, June 08, 2005

Next Generation Web

The next generation web will be all about abstractions for handling foreign code.

Of all the desirable features for a development platform, one of the most desirable is the ability to write and deploy code quickly and easily. This is how people explain the success of the web and web applications like the google suite.

The next generation web will protect users even from malicious code without requiring much greater responsibility. The new security will have to support three classes of features:
  • manage state
  • allow the code from one site to affect the user's experience of other sites (like greasemonkey for example)
  • clearly determine what site is responsible for a given interaction (to combat phishing for example)
Users will never be hassled "are you sure you want to install this extension?"; foreign code will have access to a powerful set of operations that yet poses no threat to the user. On the other hand, users will have to learn something of a new approach just to be able to understand what they'll be seeing.