rlucas.net: The Next Generation Rotating Header Image

July, 2006:

Broken Quoting of Spaces in Table Names in Ruby’s ActiveRecord

Two-part posting.

1. The hot-shit developer boys at http://dev.rubyonrails.org apparently use Python (Trac) for their bug-tracking system, and for extra chuckles, it’s broken.

From http://dev.rubyonrails.org/newticket#preview

(removed a Python stack trace that came down to a NOT NULL constraint violation in the underlying database — the error message was messing up the blog formatting software.)

Not the most helpful when I’m trying to post a bug report!

2. So, I’m posting by bug report below. Essentially, having spaces in your table names throws a major monkey wrench in the “convention over configuration” mantra of Ruby on Rails.

I might fix this, if I can find the time (the lack thereof being why, in the first place, Rails seemed so appealing). If so, I will post a patch.

Legacy apps being built to SQL Server databases may find spaces in table names. These can be addressed superficially by a:

set_table_name '"Spacey Table"'  

or

set_table_name '[Spacey Table]'  

This approach makes parent classes behave properly when directly interpolating table_name into a string, avoiding such errors as:

Invalid object name 'Company'.: SELECT count(*) AS count_all FROM Spacey Table   

HOWEVER, pre-escaping the table names in this way breaks the SQLServer ConnectionAdapter’s ability to get info out of SQL Server, as in sqlserver_adapter.rb line 246 (line breaks added):

sql = "SELECT COLUMN_NAME as ColName, COLUMN_DEFAULT as DefaultValue,  DATA_TYPE as ColType, IS_NULLABLE As IsNullable,  COL_LENGTH('#{table_name}', COLUMN_NAME) as Length,  COLUMNPROPERTY(OBJECT_ID('#{table_name}'), COLUMN_NAME, 'IsIdentity')  as IsIdentity, NUMERIC_SCALE as Scale  FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_NAME = '#{table_name}'"  

As you can see, here it will try to match ‘Spacey Table’ = ‘[Spacey Table]’ for the brackets case (or ‘”Spacey Table”‘ for double quotes).

Also, get_table_name(sql) will have trouble with this.

To make this work without breaking encapsulation will probably require using an escaped table_name and then selectively unescaping it for the SQL Server-specific uses.

All in all, MSFT’s behavior is fairly satanic on this; see below for a link describing syntax and escaping. Note that the only backwards-compatible solution is to SET QUOTED_IDENTIFIER ON and then use “This Table”.”This Column” notation, in order not to run up against problems with SQL Server < 6.5.

http://msdn.microsoft.com/library/default.asp?url=/library/en-us/acdata/ac_8_con_03_89rn.asp

Password Policies Must Be Disclosed!

Most all web applications require some sort of username and password to login. However, you never know upon signing up how the application (site, service, whatever) will treat your password. – Option 1: The app does what all good applications, having been entrusted with your password, ought to do: it passes it through a one-way hash function (ideally with a random salt), and stores /only/ that hash code. There is *no* mathematically feasible way to retrieve your password, given only the hash code (although in some cases dictionary attacks work). Hence, if you forget your password, they have to send you a new one, but at no time does a second human have a chance to see your chosen password. – Option 2: The app is brain-dead, and stores your password in plain-text, (or in a symmetrically encrypted form where the decryption key is programmatically available to the app). These boneheads become recognizable when, upon using the “forgot password” functionality, they /send back your original chosen password in unencrypted email!/ (Dear reader, it should hardly be necessary to describe why this is a problem, but consider that in our wireless age, every unencrypted communication may as well be considered public knowledge.) There are exceptions, of course, where option 2 is quite reasonable; the venerable mailing list manager Majordomo tells you up front, “/Do not use a valuable password as it will occasionally be emailed back to you in cleartext/,” which tells you right up front what the situation is. Yet, any number of ostensibly professionally-run web apps — /many of whom anticipate being the lucky recipient of my credit card number to consummate a transaction/ — cannot be bothered either to properly protect my password or to inform me about their practices. *Therefore, I propose:* a “Password Statement”, as an adjust to or embedded within a site’s privacy and security policies, that describes how they plan on treating your shared secret (password). This statement should be summarized in a one-sentence line next to the password box on the registration dialog, with a link to more information (much as has become the /de facto/ standard for a statement about spam policies). Finally, I propose a voluntary “seal” program whereby a TRUSTe- or Verisign secure site-like seal is made available, subject to a benign entity’s copyright and trademark protection, to both signify a site’s password policy at a glance and to serve as a link to the password statement.

VC Annoyance: Term Sheets Excluded from Closing Book

The Closing Book of a financing is the definitive collection of all documents relied upon in conducting a financing. It will generally have a “snapshot” of critical documents before and just after the financing, such as the original Articles of Incorporation dated one day, and the “amended and restarted” articles dated the next. Other agreements such as Investor Rights Agreements and Stock Purchase Agreements are included as well.

However, much to the chagrin of analysts like myself who often have to go back to the closing book for reference purposes, the actual term sheet often is not included in the closing book! This is most frustrating, since as a practical matter it is usually more relevant to discuss “term sheet to term sheet” when comparing terms or negotiating a subsequent round, rather than referring to definitive legal documentation (I estimate that the ratio of words and pages in a term sheet to those in the definitive docs based upon the term sheet is around 1:250).

I believe this is because attorneys are loathe to include anything in the closing book that might give even a thin entering wedge of challenging the definitive docs. Specifically, if a term sheet is included, a party might contend that the term sheet was the “parent” of the documents that followed, and should therefore inform the interpretation or construction of the definitive docs.

This may be a legitimate concern, but damn it, lawyers, couldn’t you just stamp: “non-binding, subject to the definitive documentation” in red all over the term sheet and stick it in the closing book??

Simple Patterns

       Mutt understands the following simple patterns:         ~A           all messages        ~b EXPR      messages which contain EXPR in the message body        ~B EXPR      messages which contain EXPR in the whole message        ~c EXPR      messages carbon-copied to EXPR        ~C EXPR      message is either to: or cc: EXPR        ~d MIN-MAX   messages with "date-sent" in a Date range        ~D           deleted messages        ~e EXPR      message which contains EXPR in the "Sender" field        ~E           expired messages        ~f EXPR      messages originating from EXPR        ~F           flagged messages        ~g           PGP signed messages        ~G           PGP encrypted messages        ~h EXPR      messages which contain EXPR in the message header        ~H EXPR      messages with spam tags matching EXPR        ~i EXPR      message which match EXPR in the "Message-ID" field        ~k           message contains PGP key material        ~l           message is addressed to a known mailing list        ~L EXPR      message is either originated or received by EXPR        ~m MIN-MAX   message in the range MIN to MAX        ~n MIN-MAX   messages with a score in the range MIN to MAX        ~N           new messages        ~O           old messages        ~p           message is addressed to you (consults $alternates)        ~P           message is from you (consults $alternates)        ~Q           messages which have been replied to        ~r MIN-MAX   messages with "date-received" in a Date range        ~R           read messages        ~s EXPR      messages having EXPR in the "Subject" field.        ~S           superseded messages        ~t EXPR      messages addressed to EXPR        ~T           tagged messages        ~u           message is addressed to a subscribed mailing list        ~U           unread messages        ~v           message is part of a collapsed thread.        ~V           cryptographically verified messages        ~x EXPR      messages which contain EXPR in the "References" field        ~y EXPR      messages which contain EXPR in the "X-Label" field        ~z MIN-MAX   messages with a size in the range MIN to MAX        ~=           duplicated messages (see $duplicate_threads)        ~$           unreferenced message (requries threaded view)         In the above, EXPR is a regular expression.         With the ~m, ~n, and ~z operators, you can also specify ranges in the        forms <MAX, >MIN, MIN-, and -MAX.     Matching dates        The ~d and ~r operators are used to match date ranges, which are        interpreted to be given in your local time zone.         A  date is of the form DD[/MM[/[cc]YY]], that is, a two-digit date,        optionally followed by a two-digit month, optionally followed by a year        specifications.  Omitted fields default to the current month and year.  (source: man (5) muttrc) 

Movielink is Sorry.

In speaking with folks in the P2P and content delivery space, the name Movielink pops up fairly frequently. I’m not a great follower of the cinema, but when I do want to see a film at home, something within me is repulsed at the idea of letting Blockbuster have another shot at extorting a “purchase” out of me when I have a perfectly good 6 Mbps downstream link to my home.

Also, I no longer have a roommate with 3/4 of a terabyte of movies on a file share in the apartment.

So I recently checked out Movielink’s website. I was unimpressed with how they chose to start our market conversation. Here is literally the very first thing they decided to say to me:

Sorry, but in order to enjoy the Movielink service you must use Internet Explorer 5.0 or higher, which supports certain technologies we utilize for downloading movies. Click here to get the latest version of Internet Explorer. We do not support Mozilla or Netscape. We apologize for any inconvenience this may cause.

(from http://www.movielink.com/store/web/error/siteentry/browserError.jsp)

Yes, Movielink, you are sorry. A sad, sorry sack of software that refuses to use standards, and cultivates customer contempt.

The business side of me is dumbfounded that a comparatively well-funded (backed by a consortium of major movie studios) and ostensibly tech-heavy company has nobody at the helm when it comes to customer experience. (Earth to Movielink execs: even if the specialized DRM you want people to use is incompatible with my browser, a semi-skilled salesman takes that first “no” and uses it to begin the conversation to convert me.)

The tech side of me wants to propose a new RFC for promulgation through the Internet Society: services that require proprietary, non-standard software MUST NOT listen on ports 80 (http) and 443 (https).

Feedback Rant Disclaimer: I’m Trying to Be Constructive

In the past several weeks I have had the opportunity to alpha-test, or beta-test, or other-Greek-letter test an abnormally large number of sofware products and web sites.

Not coincidentally, I have also had occasion to write a number of “user experience horror story” rants directed into various types of feedback forms, support@whatever.cxm addresses, and the like.

If you are the recipient of one such rants, I am writing this disclaimer for you to let you know a bit of where I’m coming from, in the hopes that you will take my feedback in the constructive spirit in which it was intended.

I love technology and I want to love your software.

I work for a software VC, and I’m an occasional contributor to various open-source (and proprietary) software projects. I install new software all the time, and only in a tiny fraction of a minority do I have any direct or indirect financial interest. So, I wrote my feedback rant mostly to try and be helpful; it’s part of my personal ethic of fighting entropy.

I managed a web app company for a few years, and I know some pitfalls to avoid.

I am by no means a guru, but if I rant at you about something specific to your technology, you might want to listen up. There’s a chance it’s a problem I’ve already fixed, or paid people to fix (or both, repeatedly, in some sad cases), and I want to save you that pain.

Other users will not be as nice.

Sometimes I state my case forcefully to get your attention. Other users will typically not be so nice — they will silently leave, or worse, save their vitriol for public fora (or worst yet, for private ones that you cannot see).

The frustrated user is the one to whom you owe your attentions.

Consider that if a user gets to the point where he is frustrated with your software and actively sending you feedback about that frustration, he has already demonstrated that he is patient (he was not frustrated at first) and persistent (if he were not, he would not have become frustrated but would merely have left). Do not turn a deaf ear! That same motivation for continuing past the point of frustration may be a motivation to spend lots of money with you, to contribute to your project, or otherwise to reach a mutual benefit — but only if you listen and act!

In closing, let me say that I’ve read a lot of user feedback, and not all constructive. My feedback rant is intended in a spirit of constructive criticism, and I ask that you receive it thus.

Plan Less, Write More

As a backlash to the overwhelming crappiness of most blogs (and, frankly, out of embarassment at the fairly poor initial quality of my naive early blog efforts), I have been overthinking blogging. As a result, my $HOME has ten outlines and half-written articles and over-written blog entires that have musroomed into manuscripts. My resolution: plan less, write more. This is the blog version of the agile software mantra: release early, release often. The paradox, of course, is learning to be disciplined about being /less disciplined/. Part of what brings this on is the experience of reading blogs regularly for the first time over the last few weeks, and discovering that the novelty and turnover of content is /not/, in fact, a strict tradeoff with quality. For example, there are some VC blogs that are infrequent and crappy (I am in too good a mood this morning to name names, although, gentle reader, it does not escape your correspondent that this very blog may hew closer than is comfortable to that description). Then, there are [http://avc.blogs.com/a_vc/ VC blogs] that are prolific /and/ good. Doubtless, the best bloggers could refine and revise for some marginal gain in quality. But the decreasing marginal returns of extra structure and revision would be outweighted by having them put out yet another quality — though not perfect — piece of writing. My other resolution: dispense with a surfeit of caution. Or, to paraphrase “Uncle Joe” Stalin, you can’t make an omelet without breaking some eggs. If making a point involves a deserved harangue of one rogue or another, I will deliver it. And building on the first resolution, if exposing a bit of passion or intensity means a typo ecsapes the editor’s pencil, so be it. For example, David Cowan [http://whohastimeforthis.blogspot.com/2006/04/created-by-school-teacher.html lays the smack down on a charlatan] in a blog entry so clearly motivated by passionate interest that the reader cannot help but be capitivated and delighted, despite the fact that the entire entry is a typographical and structural monstrosity. Final resolution: no more than one “gentle reader” comment per posting.

Vim 7 is Incompatible with the Vimspell Plugin

On my Cygwin environment on Win XP, Vim 7 appears to run fine with one exception: the vimspell.vim plugin. It apepars that Vimspell conflicts with the new built-in spell check functionality in Vim 7. The symptom of this is that one starts to type and a massive amount of doubled or missed letters start to appear (and, no, I was not drunk when I noticed this). Removing the vimspell.vim plugin works fine.

However, I like to use a consistent ~/.vim directory across all my shells, so that I can store it in CVS and enjoy the same settings on every system. To do this across a heterogeneous environment of Vim 6 and Vim 7 boxen, I have made the following change to vimspell.vim:

61c61 < if exists("loaded_vimspell") || &compatible --- > if exists("loaded_vimspell") || &compatible || v:version >= 700  

This will short-circuit out of vimspell before it gets loading if the version is Vim 7.0 or above.