Choosing method names for a cache interface

As part of the overhaul of the WilsonORWrapper, I’m adding a cache service. To do this right, I need to implement an ICacheClient interface. This interface will define the methods and properties which any cache client will need to implement.

Sounds simple on the surface, but I quickly ran into a problem. What do you call your methods? Consider the following possibilities for naming four core methods.

  • Retrieving an item from the cache: Get, Retrieve, Load, Fetch, Read, Select.
  • Placing an item in the cache: Put, Set, Add, Insert, Save, Update.
  • Determining if an item exists in the cache: Contains, Exists, Has.
  • Remove an item from the cache: Remove, Delete, Clear.
  • Clear all items from the cache: Flush, Clear, ClearAll, DeleteAll, RemoveAll.

The worst part of determining a naming convention is that you are generally stuck with it once you choose it, unless you want to implement breaking changes into your application.

Most of the names above were found in some cache API currently in existence today. (I did a Google search to find as many as possible.) Some of them are not recommended because their usage is uncommon (such as Fetch, unless you have a DogCacheClient). I’d also stay away from the *All methods — they sound good on paper, but the difference between Remove and RemoveAll is quite big, and you can call the wrong one if not paying sufficient attention.

With those left over, you can organize them into groups based on similarity of use in well-known applications, languages, and APIs.

  • SQL Style: Select, Insert, Update, Exists, Delete, Clear.
    This style is good if you expect to have separate Insert and Update methods, where Insert can only add new items, and Update is used to change existing items.
  • Collection Style: Get, Add, Contains, Remove, Clear.
    The common naming used in Microsoft and Java collections.
  • Simple Style: Get, Put, Has, Remove, Clear.
    Short and sweet. You can arguably combine Remove and Clear if you’re brave.

Which one should I use for the WilsonORWrapper? One thought is to use the SQL style, since this is a wrapper for an O/R mapper, which is closely tied to SQL. However, I don’t want separate Insert and Update methods. Also, the point of the wrapper is to allow people to write in code, not in SQL, so the relationship to SQL should not dictate style.

That leaves us with the simple style and the collections style. NHibernate uses the simple style in their Cache API. Microsoft’s System.Collections namespace uses the collection style. I’ll go with a combined version: Get, Set, Contains, Remove, Clear, mostly for the reason that users of WilsonORWrapper are probably more familiar with Microsoft Collections than NHibernate, and because I prefer Set over Add.
Have you seen, or used, other naming conventions in your travels?

Firefox truncates long tables when printing

I stumbled across a weird bug in Firefox today — a bug that apparently has been around for quite some time, as it was originally reported on 2005-05-20.

If you have a table which is longer than the page, in certain situations, when printing the page, a page break is forced before the table, and only the first visible page of the table prints, with the rest of the content disappearing altogether.

The original bug report describes it rather well:

… The first [page] contains material preceding the table, the second [page] contains most but not all of the table, and the third [page] is empty.

The bug was confirmed on 2005-06-19, but no fixes followed. On 2006-07-31 a user alluded to a workaround:

From further tests, you can see that the bug happens when BOTH THE FOLLOWING
CONDITIONS are respected:

A) The page contains an <h1> title
B) The table in the page contains a <caption>caption

The web page in my project which was exhibiting this bug had an h1 at the top of the page and a caption at the top of the offending table. Removing the caption from the markup fixed the problem, as did applying the display:none style to the caption.

It’s a frustrating bug, but once you know the workaround, it’s easy to deal with.

An IE6-compatible solution for :hover

Something I like to incorporate on web sites with tables is automatic background highlighting of the row that the mouse is hovering over. This is easy to do with CSS:

table.hover tr:hover
{
background-color:#ffffcc;
}

All you need to do is give your table tag the hover class, and your mouseover hover background color works!

In all browsers except IE6, of course. IE6 only supports the :hover pseudo-class on anchor () tags. (There’s lots of other things that IE doesn’t support or supports wrong, but that’s a story for another day.)

How can we get IE6 to hover our table rows? By using a little JavaScript and the Prototype library. Our solution requires two steps:

  1. Write some code to automatically detect mouseover and mouseout events on table rows, applying and removing a CSS class to the rows as the events occur.
  2. Add the CSS class to our CSS file.

First we’ll add a tr.hover declaration to our CSS.

table.hover tr:hover, table.hover tr.hover
{
background-color:#ffffcc;
}

Notice that I kept the table.hover parent selector; this is important, as we’ll use that to ensure we only apply our hover code to table rows in tables that have the hover class.1

To get the class added (and removed) from our table rows, we use Prototype to find all elements that match the CSS selector table.hover tr, and for each one, hook a function to the onmouseover and onmouseout properties.

$$('table.hover tr').each( function(e) {
e.onmouseover += function() {
Element.addClassName(e, 'hover');
};
e.onmouseout += function() {
Element.removeClassName(e, 'hover');
}
});

Problem #1: The code above is applied to all browsers. We only need it applied to versions of IE prior to 6.0. A simple hack for this was found at Ajaxian, and is added below.

if (!window.XMLHttpRequest)
{
$$('table.hover tr').each( function(e) {
e.onmouseover += function()
{
Element.addClassName(e, 'hover');
};
e.onmouseout += function()
{
Element.removeClassName(e, 'hover');
}
});
}

Problem #2: What if our event model already declared an event on the onmouseover or onmouseout properties? The script above would clear any existing event handlers. The solution is to use Prototype’s Event.observe method to hook the functions.

if (!window.XMLHttpRequest)
{
$$('table.hover tr').each( function(e) {
Event.observe(e, 'mouseover', function() {
Element.addClassName(e, 'hover');
});
Event.observe(e, 'mouseout', function() {
Element.removeClassName(e, 'hover');
});
});
}

Problem #3: If the JavaScript runs before the page loads, it may not apply the event handlers to our table. This is also resolved by using Event.observe to run the above code only after the window loads.

if (!window.XMLHttpRequest)
{
Event.observe(window, 'load', function() {
$$('table.hover tr').each( function(e) {
Event.observe(e, 'mouseover', function() {
Element.addClassName(e, 'hover');
});
Event.observe(e, 'mouseout', function() {
Element.removeClassName(e, 'hover');
});
)};
)};
}

There you have it — a :hover hack for IE6 that doesn’t break IE7 or Firefox. It should work with all other modern browsers, though some old browsers may have issues with it. If you know of any browsers which break with this solution, let me know.


1 The use of the class name hover caused a problem when including YUI’s Button CSS code. In their CSS, they have a CSS selector for .yuibutton.hover. Apparently, IE6’s issue with these selectors caused my entire table to pick up the CSS from .yuibutton.hover. To fix this, I renamed YUI’s CSS selector to .yuibutton.yuihover and updated their JavaScript (just search/replace 'hover' with 'yuihover').

Interview and resume tips (and horror stories)

Andrew Tetlaw, blogger at Dexagogo and author of many great JavaScript libraries, recently had this to say:

Telephone interviews are hard.

They most certainly are, from both ends of the receiver.

Back from 1997 through 2003, I gave well over a hundred technical interviews for a recruiting company. They (the recruiters) would call me up, give me the candidate’s name, resume, and contact information, and tell me about the position they were in consideration for. It was my job to figure out if they were qualified.

About a third of the people I interviewed were not qualified for the jobs they were applying for. Another third were qualified, but not solid candidates. The last third, those members of the lucky pie slice, got my approval to be put in front of a potential employer.

The reasons why people were not qualified varied. Some were over their head (applying for jobs beyond their skill sets). Some thought they knew what they didn’t. Some had barely any IT qualifications whatsoever. This was the 1990’s, after all, a time when paper MCSE’s were flooding the country faster than monkeys attack a truck full of bananas.

In the process of interviewing people, I learned a lot about what to say (and not say) in an interview, and what to put (and not put) on your resume. I tried to educate people to these finer points when I realized they needed some tutoring. Some highlights follow.

If you don’t know anything about it, don’t bring it up.
Me: “So, tell me what you know about [insert technology name here].”
Them: “Uh, I don’t know anything about that.”
Me: “But it’s on your resume.”
Them: “The recruiter told me to put it there.”
Me: “Is the recruiter on the interview with you?”
Them: “No.”
Me: “Then take it off your resume.”

If you put it on your resume, be ready to talk about it, even if it’s irrelevant to the job.
Me: “I see you took a class in robotics in trade school. Can you tell me a bit about it?”
Them: “Well, um, I really don’t remember much about it.”
Me: “Then take it off your resume.”

Read your resume.
Me: “Can you tell me about your experience with [insert product name here]?”
Them: “I don’t have any.”
Me: “It says on your resume that you have experience with it.”
Them: “How did that get there?”

Sometimes, even if it’s true, don’t say it.
Me: “So, why did you leave your last job?”
Them: “I didn’t get along with my boss.”
Me: “Why is that?”
Them: “He was an idiot.”

Confidence is good, but don’t get cocky.
Me: “So, tell me what your biggest professional failure is?”
Them: “I never made a mistake.”
Me: “Congratulations, you just made your first one.”

Be well-rounded. If you’re not, become well-rounded.
Me: “What’s the last book you read?”
Them: “I don’t read books.”

As unbelievable as it may seem, those are direct adaptations of real situations that I encountered over the years.

Do you have any interview tips or horror stories?

Customizing TableKit to stripe column groups

I’m a big fan of TableKit, a JavaScript library (based on Prototype) that provides client-side sorting, row striping, column resizing, and more. (Check out their demo to see more.) There’s one feature I needed on a recent project that was missing: the ability to stripe column groups (defined with the colgroup tag) with alternating background colors (as you would stripe rows of alternating colors). It was easy to add this functionality to TableKit by adding the following JavaScript code to the TableKit library.

TableKit.ColGroups = {
	stripe : function(table) {
		var colgroups = table.getElementsBySelector('colgroup');
		colgroups.each(function(cg,i) {
			TableKit.ColGroups.addStripeClass(table,cg,i);
		});
	},
	addStripeClass : function(t,cg,i) {
		t = t || cg.up('table');
		var op = TableKit.option('colgroupEvenClass colgroupOddClass', t.id);
		$(cg).removeClassName(op[0]).removeClassName(op[1]).addClassName(
			((i+1)%2 === 0 ? op[0] : op[1]));
	},
	hide : function(colgroup) {
		Element.setStyle(colgroup,{visibility:'collapse'});
	}
};

The code above expects two new TableKit options, named colgroupEvenClass and colgroupOddClass. To add those as available options to TableKit, find the section of code below and add the two lines named colgroupEvenClass and colgroupOddClass.

	...
	options : {
		autoLoad : true,
		stripe : true,
		sortable : true,
		resizable : true,
		editable : true,
		rowEvenClass : 'roweven',
		rowOddClass : 'rowodd',
		sortableSelector : ['table.sortable'],
		columnClass : 'sortcol',
		descendingClass : 'sortdesc',
		ascendingClass : 'sortasc',
		noSortClass : 'nosort',
		sortFirstAscendingClass : 'sortfirstasc',
		sortFirstDecendingClass : 'sortfirstdesc',
		resizableSelector : ['table.resizable'],
		minWidth : 10,
		showHandle : true,
		resizeOnHandleClass : 'resize-handle-active',
		editableSelector : ['table.editable'],
		formClassName : 'editable-cell-form',
		noEditClass : 'noedit',
		editAjaxURI : '/',
		editAjaxOptions : {},
		colgroupEvenClass : 'colgroupeven',
		colgroupOddClass : 'colgroupodd'
	},
	...

With that, you can now stripe your column groups by doing the following. The example below assumes a table whose id is mytable.

TableKit.ColGroups.stripe($('mytable'));

That command will apply two classes to your colgroup tags — by default, colgroupEven and colgroupOdd. Most modern browsers will pass down the background color for a colgroup to its table cells, "striping" your column groups.

CodePlex: Did they forget to back up a server?

CSSFriendly, the ASP.Net CSS Friendly Control Adapters, is an open source project I contribute to. Source code, issue tracking, and other services are provided using CodePlex, Microsoft’s alternative to SourceForge. Since last week, our source control server (Team Foundation Server, or TFS) has been down.

The reason for the downtime, as reported by someone on the CodePlex team:

At 3pm PDT on April 11th an operator error occurred that caused source control and issue tracker data on one of the Microsoft CodePlex servers to be accidentally overwritten. During the standard data recovery effort, a recovery backup configuration oversight was discovered in the routine backup process for this CodePlex server which is currently impacting immediate restoration of the data.

Fortunately, thanks to my years of experience in medium and large organizations, I can translate this into layman terms:

At 3pm PDT on April 11th someone screwed up and accidentally blew out one of the CodePlex servers. When we looked for the backup tapes, we realized that this server was never being backed up, forcing us to use expensive and time-consuming data recovery services to get the data back without too much egg on our faces.

Granted, this is speculation, but it’s the only plausible reason why you can’t get a server back online in four days. Fortunately our project has only been going for a few weeks, and we don’t have a significant history of source code changes or work items. Still, this does not give me any confidence in using CodePlex for any other projects, especially considering my excellent experience with Hosted-Projects.com and the availability of Google Code and SourceForge.

PC World’s “50 Best Tech Products of All Time” — how many have you used?

PC World 50 Best Tech Products

PC World has just published an article, “The 50 Best Tech Products of All Time” — a fun walk down memory lane. How many of the 50 products listed have you used? I’ve used the following…

  • Netscape Navigator (my preferred browser until IE 6.0)
  • Napster (sparingly)
  • Lotus 1-2-3 for DOS (I am a dinosaur)
  • Hayes Smartmodem (my first modem was 300 baud, and I remember getting my first 2400 baud modem — it was the first time data loaded faster than I could read it)
  • Motorola StarTAC (thanks to a past employer, before they sued me — long story)
  • WordPerfect 5.1 (funny how “show codes” looked a bit like HTML today)
  • Tetris (who hasn’t?)
  • Palm Pilot 1000 (I was an early adopter)
  • id Software Doom (idkfx, etc.)
  • Microsoft Windows 95 (“Start me up!”)
  • Nintendo Game Boy (see Tetris above)
  • Iomega Zip Drive (100MB seemed like so much back then)
  • CompuServe (my brother used the free hour we got without me being around, and I was so pissed off)
  • Blizzard World of Warcraft (me and my 8 million friends)
  • Aldus PageMaker (it was so impressive at the time)
  • Nintendo Entertainment System (so many hours wasted thanks to this device)
  • McAfee VirusScan (preferred by most employers)
  • Apple HyperCard (more powerful and advanced than most realize)
  • Epson MX-80 (love those dot crunching sounds)
  • Microsoft Excel (one of the best things to come out of Microsoft)

What are my three selections which didn’t make it on the list? Continue reading

Scripting SQL database builds

A project I’m working on requires importing data from hundreds of megabytes of delimited text files into a staging database, then converting and migrating the data into an operations database. (Forgive the naming conventions. The “staging” database is used as an intermediary between the text files and the final database. The “operations” database is the one the application uses.)

What’s the best way to do automate this? Ideally, I need to be able to re-run the import at any time, preferably with a single command. The process should purge the staging database, rebuild tables (since schemas may change), reload all data, and run the necessary migration scripts. Since the final product is merely a web interface to the imported data, there is no harm in wiping and recreating everything from scratch, as there is no “user data” of note. (Actually there is, but it is isolated from this process.)

The solution I came up with used a series of SQL scripts executed using sqlcmd (part of MS SQL 2005; use osql for older versions) and data import tasks using bcp (part of MS SQL), all tied together using batch files. Continue reading