Microformat Proposal: Coding Experience

When I'm working, even in a language I know well, I often search for how to do something; either because I don't know or because I feel there's a better way (as @ed_atwell says, "I don't know, but I bet my friends Larry and Sergei do). My personal system for filtering code search results looks something like:

  1. Blogs I trust
  2. Personal blogs
  3. Development sites (e.g., 4guysfromrolla.com, etc.)
  4. Mailing lists and newsgroups1
  5. Forums
  6. Expert Sexchange

Regardless of where it comes from, there's no way to know if it's right. It's human nature to use the first thing that works (if under deadline, even the first thing that kinda works will do). As Jeff Atwood has pointed out (twice) , the danger is you might be copying off the paper of someone dumber than you2. Because of this, I'd like to propose a microformat (assuming one doesn't already exist, given I didn't bother to check with Larry and Sergei) to indicate an author's experience with a language.

Immediate disclaimer: I realize this is a programming solution to a human nature problem and those never work, but bear with me, because my hope isn't to fix the problem, but to provide some metadata that will let machines do the work for us so we can stay lazy. Given that is in line with Newton's First Law, this will obviously be a huge success.

The format doesn't need to be very complicated. In fact, I'd prefer if it just provided a few bits of raw data that could be remixed by search engines however they see best. The data provided would stay the same but the algorithms could be tweaked for better results (though that would require feedback), providing an incentive for search engines to consume the format. Make the data something rough, broad and quick to fill out, like years of experience with the language and a simple measure of number of lines written (e.g., none, 10, 100, 1,000, 10,000, a whole bunch). There are any number of issues with using Lines of Code (LoC) as a metric (mainly that an idiot can say in 1,000 lines what a smarter person can say in 10), but if the ranges are broad enough, it should dampen the effect.

Bolt this format onto syntax highlighting engines; this blog, for example, uses WP-Syntax to format the few, poor code samples I provide— one more panel in the plugin admin that allowed me to store a hash of [language name, years, lines of code] would allow the plugin to provide that information in any page using the languages and output a visible box on the page so inexperienced users who come to the page and see my code could know it was terrible without knowing it was terrible. Add it into the syntax formatters for popular forum software (and allow users to specify their experience) and every code argument in a forum post becomes a little easier to follow.

The format doesn't tell you if a snippet is correct, it just gives you some background information (assuming the author is honest in their self-reporting). The danger would be users trusting a snippet blindly because the author has 10 (bad) years of experience (a sort of "Appeal to authority") while better code from "newer" users goes ignored. That's a human nature problem and obviously you can't solve those with programming (/broad wink).

1. I'd rank these higher, especially official groups for languages and systems except for two reasons:

  1. They tend to be so ill-formatted and the ability to follow threads varies wildly from site to site
  2. The advice can be good but dated: it's easy to find perfectly legitimate Python answers from 2000 or so. While the answer is fine, it's possible there's a newer idiom and in a language like Python, where there's "one right way", the right way will be the way that the language has been optimized to work.

2. Basically unrelated story that I've crammed in because I always tell it because it cracks me up: in high school, we had to go to the local public high to take the SATs. The person sitting next to me scribbled furiously throughout the test and was always the first one finished (which frustrated me to no end). When we were walking out, he turned to us and said, "Dude, I just made pretty pictures with the bubbles."

1 Comment

Cheating at The Beatles: Rock Band

My favorite thing about the game is the harmonizing and the way it increases the feeling that you're really in a band, but if you're all about the score (or bereft of friends), feel free to take advantage of these two pieces of information:

  1. The different singers do not have to sing different parts
  2. The multiple scores are based solely on having multiple microphones

In this case, 1 + 2 equals, "If you stick three microphones in front of your face and start wailing, you'll be credited as three singers, including the double and triple bonuses". Kids, you're only cheating yourselves.

1 Comment

Django/ Pinax: Problems With Login() in Unit Tests

This is the first in what promise to be a number of "Stupid Django Tricks" where the "stupid" is me and not Django. I was having a good deal of trouble creating unit tests for authenticated views (i.e., pages that require a user to be logged in) for the Pinax project I've been working on. I dug up two problems, one of which is on Pinax and one that's entirely on me:

  1. Pinax's settings.py file does not provide a setting for AUTHENTICATION_BACKENDS, so the test client's login method doesn't know how to log your user in. Specify "AUTHENTICATION_BACKENDS = ('django.contrib.auth.backends.ModelBackend',)" in your settings file. Actually, I lied. That's the default value for the setting; having gone back and re-run my tests without it specified, everything works, which means the only idiot here is the guy who . . .
  2. Don't create users by specifying the password directly in the declaration (e.g., user = User(username='Dummy', password='goodluck')). Use the set_password() User method to properly set the password.

I've run into a fair number of issues working in Django where Google wasn't helpful. I think 90% of those issues were because no one else was dumb enough to make such an obvious mistake. The other 10% were typos.

No Comments

Monty Back, Rommel Still Dead

Bob Montgomery is doing the color for today's Red Sox game and I can't figure out how to feel about it. Monty and the late Ned Martin were the voice of the Red Sox (on WSBK TV38) when I was growing up and it's strangely transporting to hear him again. He's done some Pawsox games, but it's hearing him back, like Jake Taylor (a fellow catcher) getting one last chance with the parent club. And it's like he's never left: same dulcet tones, knows the team, not a sign of age (unless you get a look at the tombstone of a gut he's developed in retirement).

It wasn't until about year 3 of the Don Orsillo Experience that I realized I'd seriously undervalued Sean McDonough. Orsillo is fine, but he's a generic Connecticut School of Broadcasting voice. Close your eyes and he could be talking about the Kansas City Royals. Sean McDonough's only sin for me (beyond the too-goofy adulation of Remy) was not being Ned Martin. Hearing Monty makes me feel like I'm ten, I've got a whole summer in front of me and there's nothing to worry about for the foreseeable future*. And that shit will get you killed.

* Of course, there were no World Series wins back then either

No Comments

Free to a Harmonix Home, Rock Band Idea

Why doesn't Rock Band allow you to create additional cities and venues? Nothing fancy, just the ability to set a city name and country, then create some venues. Venues would just let you select from the existing arenas and clubs1 (the 3D animation tool for user-created venues feels like more of an RB3 thing). It seems like an obvious idea for selling more content: allow for users to download cities from other users or Harmonix, but require them to have x downloaded songs to be able to use the city. Maybe the venue creation could have a recommended genre for what types of songs to choose from a user's collection, but not require specific songs.

Except in one case: if a label wanted to set up a "city" that contained historic venues a group played at on their rise to stardom and require you to buy various tracks to use them, that seems like a really cool way for labels to increase artists' sales in Rock Band (or Guitar Hero). It'd be like a low-cost version of Rock Band: Beatles for any group that cared to take the time/ money to get the venues created.

1. I am, of course, ignoring the legal issues that could arise from letting people create venues with names like "This place in my hometown sucks b@!!s", but it's my post and I'll do so if I want to.

1 Comment

YUI Rich Text Editor in Django Admin

This ain't exactly rocket science, but it took me an embarrassing amount of time to get there, so I'm posting the code for next time. This will turn a given textarea in your admin area into a WYSIWYG. It's got a fairly small feature set, but that's only because I've stripped most of them out. You can add them back in by taking a look at the documentation. Per the Django docs, create an admin folder under one of your templates directories, then add subfolders for the app and model (though you can do just one if you want it to apply to all forms in the app or do neither to apply to all apps and models in your site) and add this as "change_form.html" (it took me an extra 10 minutes to get this done because I was sure it should be named "change_form.py" in spite of copious amounts of documentation that said otherwise):

 
{% extends "admin/change_form.html" %}
 
{% block extrahead %}{{ block.super }}
<!-- Skin CSS file -->
<link rel="stylesheet" type="text/css" href="http://yui.yahooapis.com/2.5.1/build/assets/skins/sam/skin.css">
<!-- Utility Dependencies -->
<script type="text/javascript" src="http://yui.yahooapis.com/2.5.1/build/yahoo-dom-event/yahoo-dom-event.js"></script>
<script type="text/javascript" src="http://yui.yahooapis.com/2.5.1/build/element/element-beta-min.js"></script>
<!-- Needed for Menus, Buttons and Overlays used in the Toolbar -->
<script src="http://yui.yahooapis.com/2.5.1/build/container/container_core-min.js"></script>
<script type="text/javascript" src="http://yui.yahooapis.com/2.5.1/build/menu/menu-min.js"></script>
<script type="text/javascript" src="http://yui.yahooapis.com/2.5.1/build/button/button-min.js"></script>
<!-- Source file for Rich Text Editor-->
<script src="http://yui.yahooapis.com/2.5.1/build/editor/editor-beta-min.js"></script>
<script type="text/javascript">
		// YUI editor
		var editor = new YAHOO.widget.Editor("id_content", {
			handleSubmit: true,
			toolbar: {
        buttonType: 'advanced',
        buttons: [
            { group: 'fontstyle', label: 'Font',
                buttons: [
                    { type: 'select', label: 'Arial', value: 'fontname',
disabled: true,
                        menu: [
                            { text: 'Arial', checked: true },
                            { text: 'Verdana' }
                        ]
                    },
                    { type: 'spin', label: '10', value: 'fontsize', range: [
10, 16 ], disabled: true },
					{ type: 'color', label: 'Font Color', value: 'forecolor', disabled: true }
                ]
            },
            { type: 'separator' },
            { group: 'textstyle', label: 'Font Style',
                buttons: [
                    { type: 'push', label: 'Bold CTRL + SHIFT + B', value: 'bold' },
                    { type: 'push', label: 'Italic CTRL + SHIFT + I', value: 'italic' },
					{ type: 'push', label: 'Underline CTRL + SHIFT + U', value: 'underline' }
                ]
            },
			{ type: 'separator' },
            { group: 'indentlist', label: 'Indenting and Lists',
                buttons: [
                    { type: 'push', label: 'Indent', value: 'indent',
disabled: true },
                    { type: 'push', label: 'Outdent', value: 'outdent',
disabled: true },
                    { type: 'push', label: 'Create a Bulleted List', value:
'insertunorderedlist' },
                    { type: 'push', label: 'Create a Numbered List', value:
'insertorderedlist' }
                ]
            },
            { type: 'separator' },
            { group: 'insertitem', label: 'Link',
                buttons: [
                    { type: 'push', label: 'HTML Link CTRL + SHIFT + L',
value: 'createlink', disabled: true }
                ]
            }
        ]
}
			}
			);
		editor._defaultToolbar.buttonType = 'advanced';
		editor.render();
</script>
{% endblock %}
 
{% block bodyclass %}{{ block.super }} yui-skin-sam{% endblock %}
 

Like I said, not rocket science. It adds some CSS & JavaScript includes (which are remotely-hosted, so you don't even have to worry about media roots or how it works locally vs. live) and then a bit to add a class to the body tag for the YUI skin.

4 Comments

My Name is Crew

I am posting this because I need to keep track of these things. Dreamt last night Michelle and I put on a community event centered around the retirement of some guy that had been a social worker all his life. After the dance crew came off the stage, there was a PowerPoint presentation of his life that I put together (each slide featured an allegorical photo of a raven) and a country music song. All I remember is:

My name is Crew
My name is Crew
Saving kids is kinda what I do
[a capella]Leading them away from a path of self-destruction . . .

And so on. The ravens were a result of watching a David Attenborough documentary last night and Michelle points out "kinda what I do" is a phrase that Bill Burr repeated in the stand-up show we watched again last night. So that explains a bit of it, but I still don't get where these dreams with original music come from. I must be choking off my creative brain during waking hours. Earlier this week I'd dreamt my friend had walked into a convenience store and declaimed a filthy sonnet in perfect ABAB rhyme scheme explaining why he needed to buy the New York Times Sunday Magazine and not the whole paper.

3 Comments

Expression Engine if Clauses

This is the kind of thing that's not worth a blog post except some day it might save one person hours of frustration. Expression Engine apparently doesn't like it when if statements either span multiple lines or when the trailing curly brace is pushed to a new line. I can't quite run down which it is, but it's not all that important: if your if clause isn't behaving as expected, make sure it's all on one line without any extraneous whitespace.

No Comments

Dreams They Complicate My Life

Had one of those constant dreams nights which I take as indicative of good sleep, though I was awoken by my iPod once. I've been listening to the over-my-head In Our Time podcast because, whether it's terribly interesting or terribly boring, it makes me terribly sleepy. It was off-putting to wake up hearing a stranger in a dark room speaking of the Fall of Carthage. The highlights:

  1. Falls into what I would call the "Tetris Dream" category, when you've become a little too interested in something: had a dream where I was in a field hospital somewhere in the jungle watching a TV report, hosted by @leolaporte about Canadian Twitterers, whom he referred to as "C-itters". I'd really hoped we were beyond that kind of prejudice in 2009.
  2. I was a amateur anti-mob sniper, recruited for the job by a rogue government agent who's ex-girlfriend I was dating (she was also recruited for the cause; for the record, I'm pretty sure it was this woman from Numb3rs). I was up in our hotel room[1] with my assignment in my sights when I noticed the Mob's snipers hanging out of the hotel window right next to me. Jumping back out of the window, I went to inventory the guns and ammunition I'd been left when the treachery became clear: the case had almost no bullets (but plenty AA batteries, the guns being electric). To heighten the stress of the moment, the cleaning crew started coming around the halls.
  3. To cap the evening, I got another go at my newest recurring dream. Since my Mom died, I've been having this strange cartographic dream where I try to map out the city of Newport[2] from a boat. It never works, the boat sinks and whatever I'm looking for goes unfound. I could probably save this dream-self a lot of time if he'd give me a whack at his map.

[1] We'd gotten to the point in our relationship where we were not only comfortable sharing a hotel room, we could interrupt a vacation to gun down mobsters without any negative effect on our relationship
[2] More accurately, the whole of Aquidneck Island, as I think last time I wound up in Portsmouth under the Mount Hope Bridge.

1 Comment

PHP Excel Exporter

A few times a year a client needs to export something from a database table to Excel. There's a simple hack to do it in most any language. There are actually a few, but having come up as a web developer, my preferred trick is to just build an HTML table and serve it as Excel by setting the mime type header. Having done this dozens of times, I finally formalized this into a simple PHP class tonight to save myself some time and figured I might as well share it.

The bad news: because I am lazy, it relies on an old data connection class I wrote years ago when I was even less bright than I am now. The thing's so ugly I posted it somewhere else because I am too ashamed to host it here. You can rip that out and use whatever you prefer by just changing the logic in _get_table() below. If you do choose to use my old data-class.php, be aware it expects 4 constants, DB_SERVER, DB_USER, DB_USER_PASS, DB_NAME to create a connection to the database.

Here's the exporter code itself Update: I moved the code to snipplr because this Wordpress plugin doesn't handle newline characters very well.

The simplest use is to instantiate an object, tell the exporter what you want to appear in the header row in the spreadsheet (by setting column_heads to an array of values) and then calling export(), passing it the SQL query that gets the data. If the number of fields in your query doesn't match the number of heads in column_heads, the resulting HTML will be a mess. You will understand if the code assumes you never make such mistakes. Here's a code example:

 
$e = new ExcelExporter();
$e->column_heads = array("First Name", "Last Name");
echo $e->export("SELECT first_name, last_name FROM table");
 

Quick notes:

  • Control the Excel filename in my example by setting $e->filename("something-else.xls")
  • Add a timestamp to every file (useful for making sure the filename is always unique) by setting $e->timestamp_file = true
  • When you're trying to implement this and it's not working and having to say yes to the popup and let the file open in Excel is driving you crazy, set $e->debug = true and it will skip the Excel headers, sending the output to the browser

The big gotcha that works well for me but might not for you: there's a hook in the code that passes every data column through _format_field(). In my current class, this looks for any field with "_date" in the column name, assumes that field is a Unix timestamp and transforms the value into a m/d/y date. If you live in the other 99% of the world where people format their dates un-Americanly, well, you can do that like this: $e->date_format("d/m/y") or whatever other crazy date/ time format you like.

If you think that behavior stinks, rip it out. Alternatively, you can modify it or subclass this code (like "client-xyz-exporter extends ExcelExporter" for every client who lives in Excel) and change _format_field() to do whatever you want in a one-off sort of way. This is not high art, it's just a faster way of making someone happy (if you can imagine the kind of person whose life is improved by additional spreadsheets).

No Comments