Wednesday, March 28, 2007

Posting to Blogger via Ruby

TextMate has what seems to be a very nice blogging bundle for programmatically sending posts to your blogging engine of choice. Except that it doesn't work for the new Blogger API. Or at least it didn't the last time I checked. Mostly I just wanted to see if I could write my own script to send to Blogger.

This is a Ruby script based on the Python script located at http://djcraven.blogspot.com/2006/10/success-posting-to-blogger-beta-using.html -- the author of that script did the heavy lifting in terms of the GData API calls, what I did was translate it into Ruby in a somewhat more flexible structure. At least I hope so. I also hope this will look like decent, idiomatic Ruby and not like a horrific hack. And I'd like a pony. If you're asking.

Let's do this in pieces. The first piece of the puzzle is using the Google ClientLogin API to get an authentication token. The token is then passed as a parameter to later calls when we actually want to post something. Google says that the lifespan of the token is dependent on the application being used, but I don't see where they specify how long Blogger keeps them.

Here's the start of our class. We're in a module called Blogger and a class called Blog. I've got an external dependency here on BlueCloth because I'm also going to automatically translate Markdown later, but that's not something you need to do...


module Blogger

require 'net/https'
require 'net/http'
require "uri"
require "bluecloth"

class Blog

attr_accessor :account, :password, :blogid

@@auth_url = "www.google.com"
@@auth_path = URI.parse('/accounts/ClientLogin')

def http
http = Net::HTTP.new(@@auth_url, 443)
http.use_ssl = true
http
end

def request_data
["Email=#{account}",
"Passwd=#{password}",
"service=blogger",
"service=TestCompany-TestApp-0.0"].join("&amp")
end

def auth_headers
{'Content-Type' =>
'application/x-www-form-urlencoded'}
end

def auth_token
response, data = http.post(@@auth_path,
request_data, auth_headers)
return nil unless response.code == '200'
data.match(/Auth=(\S*)/)[1]
end


After the setup lines, we've got three methods here. The first two define the data objects. The first one creates a Ruby HTTP object, set up for an HTTPS connection to the Google ClientLogin URL. The second builds the request data string, tying together the four pieces of data into a single string. They are both used in the auth_token method -- I'm taking advantage of one of my favorite features of Ruby, which is the lack of distinction between local variables, no-argument methods, and data field getters.

So, http, request_data, and auth_headers are just dropped into the auth_token code as if they were local, even though they are separate methods. To me, that makes the code read cleanly, and encourages moving small bits out to separate methods where they can be separately tested and documented.

The auth_token itself takes the path, the request_data, and the headers, and uses the HTTP object to make a secure post call. Request data, by the way, has account and password information that I'm assuming would be defined in an abstract subclass of this Blog class. If the response code is 200, we're good to go, and we do a little regular expression magic to extract and return the authentication token.

We use the authentication token in our actual post call, the one that contains the blog post itself. We need to build up the XML Atom document to send to the Blogger server. Step one is to get the data. Since I'm going to be doing this from TextMate, I'm going to assume we're going to start with the file name that will eventually be provided by the TextMate command. First, we'll convert it to an array of lines.


def read_data(filename)
text = open(filename) { |f| f.readlines }
end


In case it's not already clear, this method and the ones that follow are all parts of the
Blog
class. We're splitting this into lines to facilitate some processing of the text. I'm assuming that the first line of my file will be the title of the post, the second line will be a comma-delimted list of category labels, and the remainder of the file will be the body, written in Markdown. Obviously, that specific format is a weird quirk of the particular blog I'm posting to, which is set up to take XML and not to preserve blank lines. In your case, do whatever you need to do. Building that data structure
is quite simple in Ruby.


def build_data(lines)
categories = lines[1].split(",").map {|c| c.strip}
body = BlueCloth.new(lines[2..-1].join(" ")).to_html
data_xml(lines[0], categories, body)
end


The last line of build_data calls the data_xml method that builds up the XML document:


def data_xml(title, categories, body)
result = []
result << "<entry xmlns='http://www.w3.org/2005/Atom'>"
result << " <title type='text'>#{title}</title>"
for cat in categories
result << " <category scheme='http://www.blogger.com/atom/ns#' "
result << " term='#{cat.strip}'/>"
end
result << " <content type='xhtml'>"
result << body.to_s
result << " </content>"
result << "</entry>"
result.join("\n")
end


I was going to use the REXML library for this -- normally I'm a big fan of building XML programatically. However, REXML really, really didn't like it when the included content contained HTML tags. So I decided it'd be much less aggravating to build the XML from scratch. Details on the syndication format can be found in the GData and Atom online docs.

Once we can create the data, we can finally make our post:


def post_headers
{'Content-Type' => 'application/atom+xml',
'Authorization' =>"GoogleLogin auth=#{auth_token}"}
end

def uri
"http://www.blogger.com/feeds/#{blogid}/posts/full"
end

def post(lines)
response, content = http.post(uri, build_data(lines), post_headers)
while response.code == '302'
response, content = http.request(response.location, entry.headers)
end
return response.code == '201'
end

def post_file(filename)
post(read_data(filename))
end
end
end # of module


Couple things to point out here. First, we call auth_token directly when we're building up our header in preparation for the call -- so that's when we perform the HTTPS login shown above. The while loop takes care of following along if Blogger decides to redirect the post. Finally, we return true if Blogger sends us an OK response code 201, meaning the post has been successfully added.

To use this, you need to set up your own subclass of Blog with the expected information, for example.


class MyBlog < Blog
def initialize
@account = "YOUR_GMAIL_HERE"
@password = "YOUR_PASSWORD_HERE"
@blogid = "YOUR_BLOG_ID"
end
end


As written, that would be included in the Blogger module, otherwise, you'd need to qualify the name Blog. The invocation of the whole thing looks like this. This assumes that the filename with the post is in ARGV[0], placed there by TextMate.


p Blogger::MyBlog.new.post_file(ARGV[0])


One problem, though. We're making an HTTPS connection for authentication to keep our password secure, but including the password in plain text in the script file. Good point. There's a cool way around that in TextMate, and probably

Wednesday, March 21, 2007

Rubies in My Coffee

Now two of the big Java IDE's are promoting Ruby language tools as a big thing. IntelliJ has a plugin in early beta, and NetBeans is also making a big deal of their new early beta support. Eclipse has had a Ruby/Rails plugin for about a year or so.

This is weird, weird, weird, that suddenly all the Java tools would feel the need to grow into somewhat ill-fitting Ruby IDE's (Eclipse has always styled itself as more of a meta-IDE, so that's a little less strange). But do we really need all these Windows Ruby IDE's to be attached to big, memory hogging, Java tools. (And in IntelliJ's case, I say that with love...)

I've played with all three now -- I've used Eclipse for Windows-side Ruby editing for a while, and for the last few days I've been going back and forth between IntelliJ and NetBeans checking them out on an existing Rails project. None of the three are going to make me ditch TextMate yet (although I'd say the big tools all have somewhat more developed project support that TextMate).

IntelliJ's plugin really strikes me as Not Ready Yet. For one thing, there's no syntax checking on .rhtml files, which is a big problem. Also, there's a cool Rails project view, that associates the .rhtml files with the appropriate controller method, but there didn't seem to be an obvious way to get to partial .rhtml files. Another minor frustration is that the Ruby syntax layout is not customizable yet, the way the Java one is. It's even hard to keep a separate setup so that Ruby files only have a two character indent. (And there's a good sociology of programmers paper, on why Ruby is canonically a two character indent, not four).

This seems like a good place to point out that I still haven't spent all that much time with any of the new tools, so it's entirely possible I just missed something. For instance, even though the IntelliJ docs say there are Live Templates for Ruby, my installation didn't seem to have them.

There's some nice stuff in the IntelliJ tool -- all the ctrl-N navigation works on Ruby classes and methods. It's very easy to run arbitrary Rake tasks from the UI (although they seem to run kind of slowly) I don't think syntax completion is there yet, but it does syntax check .rb files on the fly I'd like to see this one a few revs down the line.

The NetBeans tool is in their beta for version 6 (you have to download the tool, then grab Ruby support via the update center). I was kind of amazed to be liking this because I fled NetBeans in a huff around version 3 and haven't had any success in trying it since. The syntax coloring and layout seems to be a bit stronger. It appears to be using JRuby not just for internal parsing, but also as the default external engine for running, say, WEBrick. Which makes everything feel a little slow. There is some syntax-completion -- I found it a little hit-and-miss in terms of getting useful alternatives. The project view is nice -- it flattens out all the /app subdirectories, but I couldn't see an obvious way to run arbitrary rake tasks or the test suite. Although there is a keyboard shortcut to run an individual file, and if you try it in a view page, it attempts to open that action in a browser. My app has a slightly nonstandard route configuration, though, so it didn't quite work for me.

I also had some stability problems, mostly with trying to run the server from NetBeans, it either hung or took a really long time to load. Development on this seems to be progressing rapidly -- they are releasing new versions much more quickly than IntelliJ, so all these things could be fixed by Thursday.

Right now, NetBeans would be my pick of the three if I couldn't use TextMate. I'm as surprised as anybody by that conclusion, but it felt pretty good as I was using it. Adding easy test hooks would help. All three tools are still under development (RDT for Eclipse just released a new version, and RadRails just passed to a new owner with new development promised). So, watch this space, I guess.

Update: Looks like NetBeans has a bug in reformatting code -- it kind of messed up some of my source files. Nothing permanent, just kept indenting and not noting the end to outdent so the file kept creeping to the right.

Sunday, March 18, 2007

Wow, There Are Comments

It's true -- the way to get comments on your blog is to mention Apple... I do something like one substantive post in three months, and then two apple posts in 48 hours, and bang! Four comments within a day. I'm surprised, not least because I really wasn't sure anybody was out there.

Anyway, interesting points have been made, and I thought I'd pull them up to either agree, or whine defensively.

On the Win 95 post, Massive writes:


My observation at the time was that the 'competitve analysis' of the OS features and capabiltiies was basically bogus and totally irrelevant. I felt that Apple wasn't whistling past the graveyard so much as completely lying to itself.


You say "tomato", I say "tomahtoe". There was a lot of denial in the air, that's for sure.

Still Massive, about the impact of Win95 on end users:


You could already, with Windows 3.1, show demos rigged to look identical between Mac and the Windows apps. And people were sufficiently ignorant about computers at the time that they would actually buy Windows 3.1 and tell people that it was 'just like the Mac'.


I can't really disagree with that, but I still think the general point that Windows 95 brought the two platforms much, much closer together holds. I certainly remember that to be the theme of much of the Win95 press coverage. I also remember Apple's slogan "Windows 95 = Macintosh 89". Y'know, Apple's marketing also kind of stunk in that period...

Massive also mentions that Apple had a poor relation with the dealer channel and that didn't help. Also true. As far as I can tell, still kind of true.

On to the internet posting, a couple of people comment on some other facets of how Microsoft eventually took over after they decided to start competing in browsers. Right, but there was a time when it was not yet clear that they were going to be willing and able to do that.

One anonymous poster did bring up a long-buried memory:


Nonesense. Apple's initial 'internet strategy' was CyberDog, which was a fantastic set of tools (web browser, mail client, etc ) unfortunately chained to the technological boat anchor that was OpenDoc.


Mike, is that you? Mike Pinkerton, who went on to create Camino, was the only person I knew who used CyberDog. I remember him as being very enthusiastic about it, but it was about 10 years ago, so I could easily be wrong. It did indeed look cool, but I recall the setup as being kind of daunting, and OpenDoc was kind of a pain in the neck. Also, CyberDog came out in 1996, and by then Microsoft had already moved in.

Thanks to the commenters -- I like responding, and it's a good way to get a post, so by all means, keep writing.

Saturday, March 17, 2007

Apple Dot Net

What is it about us tech fanboys and Apple... I've always found them interesting, even when I wasn't a regular Mac user. Infuriating, sometimes. But interesting.

So here's another thing about Apple, circa 1995... That was right about the end of something like a two-year period where Apple was way ahead on internet integration and didn't really make anything out of it. By the time the internet really started to escape out of academia, the Windows world was well on it's way to catching up, and by the time it all really went mainstream, Macs would be a fading memory. (I remember as late as 1995 impressing non-techy visitors to my grad school office with demos of a web browser. But a year later, the cat was largely out of the bag.)

But in 1994/1995 it was all Macish. Just accessing the internet was much easier (although it was a separate software purchase initially). And all the best software was on Macs (well, some of it was Unix, too) Eudora was the standard email client, and it was still Mac-only, for some reason the Windows version remained ugly forever. The Mac version of Netscape (and before that Mosaic) were much prettier than the Windows versions. (In my memory, the Mac versions came out sooner, particularly for early Netscape, but I can't find a source that backs that up).

On top of which, Microsoft was in the middle of a totally clueless stage. Win 95 did not, by default, ship with a web browser, and the big Microsoft internet initiative of 1995 was something called Blackbird, which was going to be a proprietary replacement for HTML. That worked out about as well as you'd expect, evidenced by the fact that Blackbird doesn't even have a Wikipedia article. Making it less important than even the most minor anime character...

Putting that all together, in the months before the Win95 launch, Mac had about a 12-18 month lead in Internet apps and Microsoft was distracted by an attempt to privatize the nascent WWW. There's clearly some room there for Apple to have maneuvered themselves into a better position than they wound up in. Being the best internet platform around would have been an interesting counterweight to the Win 95 launch, and while I doubt they could have stopped the upcoming onslaught, they probably could have mitigated it somewhat.

Instead, Apple didn't really do anything in the space, except release an email client (Claris Emailer -- which does have a Wikipedia article, which charitably refers to it as "popular"). Microsoft, on the other hand, turned on a dime, and gave up the futile attempt to take over the internet by co-opting the authoring tools. They switched instead to the more lucrative method of taking over the internet by co-opting the client tools. Apple wandered around in a fog for a few years, until they attacked the opportunity to go after digital media. But you probably know that part...

Apple Summer of 95

As I may have mentioned here, back in 1995 I spent three months as a summer intern at Apple HQ in Cupertino.

I was buried deep in the educational technology research group so, trust me, I didn't work on anything you've heard of. It was a fun summer, though. They stuffed about 15 of us, a mix of grad students and contractors, in a room that was really long and narrow. They tried to make up for the cramped office space by supplying us with Nerf toys (the admin assistant for our group would sometimes come in and announce a Toys R' Us run, and did anybody want anything). I got about a dozen free T-shirts in three months. I also experienced my first earthquake, which went like this:

A slow rumble, like a truck going down a slowdown strip

All the non-California people: What was that?

All the California people: What was what?

None of which is why I brought this up. 1995 was near a low point for Apple, but even at that there were three or four good-sized company parties during the few months I was there. I'm talking about food, music, drinks, some entertainment, all in the inner courtyard of the Infinite Loop campus. I may be slightly exaggerating in memory, and I was assured that it was small-scale by later Valley standards, but it sure seemed elaborate to me.

In August 1995, Apple held what you'd have to describe as an anti-Windows 95 launch party. More of a morale booster, I guess. The thing I remember most is a screen projecting Windows 95, while some Apple guy pointed out it's flaws. As in, "Windows 95 will only let you have 256 characters in a path name, but if you have more than 15 directory levels, you can cause it to give you a really weird error message." Thin stuff, but enthusiastically received by a lot of people who wanted to whistle in the dark together.

Everybody there, I think, knew that Apple lost something big that day. Prior to Win95, the visual differences between Mac and PC were so clear that you could see the difference in a store just by looking at the two. Afterwards, you actually had to use them both for a while to learn the difference. This was a big change in the Mac/PC dynamic, and it took Apple about five years of flailing before they would come up with a decent response.

Sunday, February 25, 2007

GWT part 3 and 4

Sorry for not mentioning this earlier, but part three of the GWT series is now up on the IBM site at:

http://www-128.ibm.com/developerworks/opensource/library/os-ad-gwt3/

This one is about remote procedure calls, and I'm pleased with how it turned out.

I just got the proofs for the fourth and final article in this series, about deployment. I expect it to be online Tuesday, Feb 27th at:

http://www-128.ibm.com/developerworks/opensource/library/os-ad-gwt4/

Friday, February 02, 2007

Clearing The Decks

A collection of small things, half-finished posts, and pure whatnot that hopefully will lead to more posts in the future:

  • Got my first Amazon affiliate statement with no less than $1.55 heading my way. Thanks to the person who clicked through...

  • There's a new sidebar, for small links, via del.icio.us. The sidebar has it's own RSS feed, on the off chance somebody is interested. UPDATE: It doesn't appear to work on Safari, which is a problem... Weird, because I did the preview using Safari, and it showed up fine, but not in the actual blog. Until I figure that out, Safari users can still click on the RSS icon and see the items.

  • I had a half-finished post on the iPhone that got buried by the trillions of electrons poured on this story. So, I'll distill it to this: that was one cool demo.

  • I also had a half-finished post on using XML as a scripting language, as in Ant scripts. Distilled: Don't do it. It's hard to read and nigh impossible to maintain. The thing I most like about Groovy is that it lets you actually script an Ant target. Although I think the JRuby/Rake combo is going to be pretty powerful here.

  • Hey, another half-finished post. This one was about the lack of list or hash literals in Java. Which bothers me just about every day that I work with Java.

Decks now cleared. Hoping to get some new content here soon.

Thursday, January 25, 2007

GWT Article Now Online, Part Two

The second part of my IBM Developerworks series on Google Web Toolkit is now online at http://www-128.ibm.com/developerworks/library/os-ad-gwt2/. This one focuses mostly on the Derby database, and features a really quick and dirty database-to-Java conversion tool.

Enjoy.

Wednesday, December 13, 2006

Playing in the Sandbox

This message showed up in the Manning Sandbox forum for wxPython In Action.  After saying some nice things about the book, the poster has some suggestions:

I would love to see an advanced volume covering topics such as XRC, using XML to define a screen layout; creating custom widgets...  internationalization, and a full chapter or more expanding on chapter 5 "Creating your blueprint." I find that... program organization is most important yet little seems to be written about it, for any programming language.... A book that illustrates solutions to design problems using patterns, Python, and wxPython will help many people...
Thanks for the kind words.  I'm thrilled that you found the book helpful.

There are about three or four things that I regret not being able to include in the book.  XRC is definitely on that list -- I think that XML or other GUI description languages are going to be increasingly important.  (Also on the list: multimedia and how to distribute your finished program).

These all got pushed out of the book over space considerations.  We were something like 75 pages over budget as it was.  Owing to some communication issues, nobody realized that we were that far over our page count until the pages were already written, and while it wasn't a problem to get them approved, it did mean that we didn't push forward into other topics.

There are no current plans for a second book, although it's not out of the question that we'd fill a gap or two with an article on line somewhere.  (To be clear, there are no current plans for that, either).  Frankly, sales are not high enough for a publisher to seek us out for a second book at this point, especially since an advanced book would, almost by definition, sell fewer copies than the original.  That's not a knock on the sales, which seem to be roughly in line with publisher expectations, just a comment on the size of the potential market.

As for a patterns/program organization book for Python, I'd love to write one.  For one thing, it'd give me a chance to rant at length about the finer points of architecture and class structure.  I've been known to have an opinion or two on the topic.  The main problem would be selling it.  My sense is that it's rather hard to sell a general-topic programming book compared to one that's tied to a specific tool or product.  This would especially be true for a relatively small market like Python. 

Still, that's what blogs are for, so hopefully I'll be able to get some interesting thoughts on those lines here.

Friday, December 08, 2006

GWT Article Now Online

I'm happy to announce that Part One of my four part series on using Google Web Toolkit is now available at: http://www-128.ibm.com/developerworks/opensource/library/os-ad-gwt1/



This part focuses on creating a GUI front-end using GWT. In case you wonder about the lead time on these things, it was originally written in August, and slightly updated right before it was published.



I think that the future part of the series will appear monthly. The next one is about using the Derby database as your back-end.



I'm pleased with how the article turned out, although I sort of wish I had taken the time to polish the look of the sample a bit -- that's one ugly Web 2.0 application. On the other hand, there's only a limited number of space available in this article (2000 words, and I was already over), and any graphical enhancement needs to be put in code and explained. So it's a tradeoff.



Hope you like it.

Saturday, December 02, 2006

Don't Ask Questions, It Only Encourages Him

Let me promote this from the comment section -- it's not hard to find, it's the only comment on the previous post.



What is your favorite Python IDE? Your editor choices are interesting and valid but I wondered if you have a preffered IDE for Python and wxPython work?

I may have covered this somewhere, either on this site, or in the Python 411 podcast interview. If so, I'm sorry.



When I'm on a Windows machine, my Python editor of choice is JEdit, and has been for quite a while. I should say that I only rarely use the Python debugger and Jython interpreter add-ons that are available for it. I do have a couple of custom scripts that execute the script I'm working on and so on, but it's not a very elaborate set-up. What I like about JEdit is that it has a clean interface, had familiar Windows keyboard shortcuts and menus, and had a lot of plugin and macro power. The main downside is that it's kind of a memory hog for a text editor.



When I jumped Mac-side for my personal stuff, I tried just about every free programmer's editor I could find (JEdit, like a lot of Java/Swing programs, behaves a bit oddly on a Mac). Finally, I somewhat reluctantly decided to pay for TextMate. Although Python-mode on TextMate hasn't quite gotten the love and attention that Ruby has, there's still a lot of power there. It's really easy to script and customize, and it's about the only editor I've seen that has dynamic mode. So that if you are writing, say, a Django template, TextMate knows the the HTML portion gets colored and edited under HTML scope, and inside the Django tags, you use Django/Python mode.



My main issue with the various IDE's is that I haven't seen a Python one where the gain in the IDE functionality makes up for the editor itself not being as powerful as my normal editor. Some of this is my personal workflow -- using Python and test-first programming, it's very rare for me to feel that I need a step-through debugger. I'm also not very fond of code-generating GUI builders, for reasons that are probably worth another post.



That said, one thing I do like when I'm in and IDE for whatever reason is the ability to specify a project and do useful things across project scope. (Both JEdit and TextMate have this ability, but not fully formed.) I've done some Ruby work using Eclipse with Ruby plugins, and it's nice to, say, have one-button access to running all your unit tests.



That's what works for me, but I'm always looking for new tools and finding out how other people work.

Friday, November 24, 2006

Editors I Like

Two tools I use all the time. Neither is free, and since my strong bias is to use free tools where possible, these are some really impressive editors.

IntelliJ IDEA For all my Java needs. It's got more features and is more usable than any other Java IDE out there. The only downsides are that it's not free, and there are about a half-dozen keyboard shortcuts you have to get down before you achieve anything like full Zen mastery (well, and it could be nicer about the way it arranges tabs in the editor). I converted one of my teams to IntelliJ largely by just using it in team programming session. (Sample comment: "You don't seem to be typing very much"). IntelliJ is so good at using the class and type information that it single-handedly makes it useful to have static typing.

There are a couple of killer features that I miss horribly when using another tool, like the control-n series of shortcuts to browse classes, files, or symbols in the project. Even better, in the search box, the search is camel-case aware. So if you type MBGC, it'll match the class MyBigGoofyClass, or the symbol makeBeveragesGreeenCoffee. It's brilliant, completely intuitive and makes searches through the code very quick. Ten seconds after you try it once, you're hooked.

Another cool feature -- a help menu item that lists cool features along with a count of how often you use them, so you can see what neat stuff you are missing out on.

TextMate My Mac-based editor of choice for everything other than Java. The Mac editor wars (BBEdit vs. Everybody Else) do sometimes reach a fever pitch normally associated only with critical topics like Emacs vs Vi. So I don't want this to be a bash on other Mac editors -- if I want to do that, I'll do another post. Besides, if what you are doing works for you, more power to you. What I like about TextMate is that it really was built from the bottom up to be scriptable, which gives it a tremendous amount of flexibility and power to handle different file modes, integrate shortcuts, run scripts from TextMate, just easy as could be to use that stuff, and even pretty easy to create new commands. Biggest quibbles are the single-keystroke only Undo, which I understand as a design choice even as I find it kind of frustrating, and the project mode, which is useless to me, at least partially because it will only display like five tabs across before going to the overflow menu, and that's just not enough.

Killer feature: select a chunk of text, type the left half of an enclosing pair, like a left paren or bracket. Rather than replace the selected text with the keypress, which is almost never what you want to do, TextMate will surround the selected text with the enclosing pair, which is so useful that I try and fail to use this in all my other editors now. And yes, the list of enclosing pairs is adjustable for each file mode.

Sunday, November 19, 2006

Less Frequently Asked Questions

Hi. Miss me? Thought not. Well, I've been feeling increasingly guilty about not posting something here, especially as the comments continue to trickle in -- we're up to eight now that I've cleared off some comment spam!

I'm going to boldly ignore the three partially written posts and do another round of publishing questions.

How's the wxPython book selling? Not bad. Got my first-ever royalty check a couple of weeks ago (actually, a royalty direct deposit). Went well into the low three figures, which is relevant to the older question about how much money you can make at this thing. (To be fair, that's artificially lowered a little bit because some of the royalties still were going to finish paying off the advance. I was hoping that the book would substantially outsell the Jython book, which hasn't happened yet. A little surprising given both the relative health of the mailing lists for the two tools and also the fact that the wx book had a substantially better rating on Amazon. And oh yes, I know what the Amazon rank is. Also the current total of reviews -- thanks to all ten people who have gone to Amazon and side nice things.

The implication of the Amazon numbers would seem to be that either a) Amazon is selling fewer books than four years ago or b) Manning doesn't have the distribution within bookstores that O'Reilly did. I suspect the latter, especially since the Jython book seems to have had more foreign sales.

What tools do you use to write the books? I'm actually pretty interested in this one with respect to how other authors do it. It seems to me that there isn't a fully satisfying tool for authoring technical books. In both cases, the main tool decisions were made before I came on board. For the Jython book, we used Word. There was exactly one positive of this -- it was nice to use the change-tracking system to do comments back and forth. Word, though, seems to be optimized for a two page office memo, and is really a pain for anything more complex. Especially when you are changing font styles frequently for things like code literals, or inserting code blocks, or numbered lists (which can be nightmarish). Most of my demo code was written in jEdit. O'Reilly provided a Word template with predefined paragraph and character styles for things like lists, headers, and literals, and they then automatically converted that for production.

Manning had something similar, but we only used it directly. For the wx book, we used ReStructured Text and a CVS server to do change tracking. This enabled us to do the writing in an ordinary text editor -- I used jEdit again (Robin used Emacs, I think). The CVS server was a great idea. Using ReST had some benefits -- for one thing, it was much easier to integrate figures and code snippets with include statements. The biggest downside from just a typing standpoint was tables, which were a pain. However, Manning would only accept submissions in Word at that time, so we had a kind of convoluted system where we would auto-convert the ReST to OpenOffice, then hand save it as a Word file. Once we turned the books in, we were stuck doing final proofreading and edits in Word. (Although Robin and I used Writely, now Google Docs, to do our change lists from the proofreading -- that worked really nicely). One significant difference between the publishers was that O'Reilly did the indexing in-house, whereas Manning asked us to do it. It's actually more difficult than it looks to do well -- I'm under no illusion that we did the index as well as somebody with more experience would have.

One more question along these lines upcoming, but it's longer and it's late. I'll try not to wait six weeks.

Sunday, October 01, 2006

Now with sound

Robin Dunn and I were interviewed for Ron Stevens' excellent Python 411 podcast -- you can download and listen to the .mp3 file here. It's about 45 minutes long, which should mean that Ron used nearly all of the interview. Hope you like it. It was a lot of fun to do. Thanks again to Ron for having us on, and also for the very nice review of the book he wrote on Slashdot. Haven't listened to the podcast myself yet, so I hope I don't sound like a gibbering idiot.

Saturday, September 30, 2006

wxWorld

I'm pleased to be able to link to a new article: Build cross-platform GUIs using wxWidgets available on the IBM developerWorks site. The original title was "wxWorld", and it's a quick look at wxPython, the wxWidgets toolkit, and some of the other wxWidgets language bindings. I had some fun digging through the different language tools trying to create short wx programs in each. Hope you like it.

Friday, September 22, 2006

Tips-First for Test-First

Of all the exciting ideas and revelations that came from Kent Beck's original XP book, Test-First Programming has been the one that most significantly affected the way I work on a day-to-day basis.

I love programming test-first. It's a great way to take a large, amorphous task and solve it piece by piece. It's also a nice morale boost -- "Hey, I know that my code does nine things. Let's go for ten..."

Here are a bunch of things I wish somebody had told me about test-first programming.

Unit Testing is not All Testing

So, after I started doing test-first, I walked around for about six months all, "my code is perfect because I wrote tests". My smugness came crashing down when testers found some bugs. My code was better because I wrote tests, but turns out I had made some dicey assumptions about the inputs, and so my tests passed, but were still incorrect. Test-first is not a complete test suite. You still need to do acceptance testing, you still need to do GUI testing where appropriate.

However, you can still automate a very large percentage of acceptance tests. The more you can automate the tests, the more they'll be run, and the happier you'll be.

Test-First is a structure for writing good code at least as much as it's a means for verifying code

Code that has been written in a test-first style tends to have certain qualities. Small methods, loosely coupled. Small objects, loosely coupled. Code that causes side effects (such as output) tends to be separated from code that doesn't. These are all side effects of what's easy to test -- it's easy to write small methods in a tight test-first loop. And dependencies between methods or objects make tests harder to write.

As it happens, those exact qualities -- tight cohesion and loose coupling -- are exactly what characterizes the best software architectures. My test-first experience is that I wind up with much better code architectures from test-first then I do when I try to guess the design before I start. (Which is not to say that a little bit of pre-design can't be helpful, just that it can be overdone).

Test-first is better suited for some things than others

That doesn't mean that you shouldn't try, of course. Test-first is vital in cases where you know the input and output, but not the process. It's also critical in cases where your program can be incorrect in subtle ways. It's somewhat less important for things that will visibly or loudly break. GUI's are a challenge because GUI layouts tend to change in ways that can break unit tests. GUI behaviors are more stable and easier to test. Again, though, you should try and have automated coverage of even those areas that weren't developed test-first.

Trust the process. Look ahead on tests, not implementation.

It works. The tight process is: Write a test. Run the test so that it fails. Make the simplest fix that will pass the test. Run the test so that it passes. Refactor. Keep to that tight loop. Resist the temptation to guess about what you'll need to pass the next test. What I usually do is put a list of the tests I'm going to write in comments in my test class -- that's my lookahead plan, and keeps me from forgetting something. But the design I do in my actual code comes during the refactor step, which is where I see duplication and abstraction.

The earlier you start the better off you are.

It gets increasingly hard to convert a code base to test-first the longer you wait. I've even had 20 line classes that needed significant refactoring to unit test (mostly because output was intertwined with functionality -- the code was better after the refactoring). Test-first is a good place to start, anyway -- pick something to test, and go.

Treat your tests like code and refactor them

Pretty much every test-first guide gives sort of a perfunctory nod to, "oh yeah, keep your test code clean." But I think this could stand a little more attention. For one thing, your unit tests are critically important to your ability to deliver quality code -- and they have no tests of their own. The cleaner your tests are, the better you'll be able to see issues with the tests themselves.

One thing that has worked nicely for me is extracting sets of assertions into custom assert methods. If you are continually making the same five assertions to check validity of your objects, throw them into an assert_instance method of some kind. Another common case is making the same assertion over a range of values -- move the for loop to your custom assertion and pass the range endpoints in.

There are two big advantages to doing this consistently. The first is that it's easier to see what's going on from one line of assert_person(expected_name, expected_addr) then from five lines of assert_equals. The second is that it ensures that you actually do make all the assertions every time. Hey, everybody slacks, and test-first is about making the test setups as quickly as possible. If you can trigger all umpteen tests on your class with one method call, you're more likely to do the whole set every time, rather than just picking one or two at random each time.

Don't reuse instance variables

This is another refactoring issue. It's tempting as you add new unit test cases to do something like this:
Person p = new Person("noel", "david", "rappin");
assertEquals(15, p.nameLength());
p.setLastName("flintstone");
assertEquals(19, p.nameLength());
p.setFirstName("pebbles")
assertEquals(22, p.nameLength());
p.setFirstName("betty");
assertEquals(22, p.nameLength());

The last test fails -- quick, what's it testing? Okay, now we have to trace the life of that instance variable all the way back up. It's hard to read, and prone to dangerous errors. You should never reuse an instance variable like this in a unit test -- every assertion should, where its at all feasible, be completely distinct:

assertNameLength(int expected, String first, String middle, String last) {
Person p = new Person(first, middle, last);
assertEquals(expected, p.nameLength())
};

testNameLength() {
assertNameLength(15, "noel", "david", "rappin");
assertNameLength(19, "noel", "david", "flintstone);
assertNameLength(22, "pebbles", "david", "flintstone");
assertNameLength(22, "betty", "david", "flintstone");
}
Now when the last test fails, you can actually see what's going on.

Avoid tautologies

The scariest issue you can have with tests is a test that passes when it should fail, allowing you to continue blithely along, ignorant of a bug you should have already caught. There will come a day, for instance, when you will forget to put any assertions in a test. There are a couple of things you can do to make tautologies less likely.
  1. Follow the process. The process says each test has to fail before you add code. Adding tests that you already know will pass can easily lead to writing a test that will never fail.

  2. If you have constants for text or numerical values in your code, don't reuse those in the tests -- use the literal or create a separate constant in the test.

  3. Be careful with Mock Objects. Try not to test the things that you are explicitly inserting in the Mock when it's created.

Mock Objects Rule

Mock Objects are the missing link in helping you test all the things that are traditionally hard to unit test, like databases, GUI, web server... anything where your code is dependent on an external system or person, the Mock can get in the way and pretend to be that third-party and allow you to send and receive data in a testable way. Mock Object packages exist for a variety of languages, and using a package will save you time and effort on your tests.

Hope that helps -- go out and test something.

Friday, September 15, 2006

Why, Johnny, Why?

We interrupt Python week to bring you the following alternative programming rant. I know, Python week has sort of gone up in smoke. But one of our mottoes here is "Whenever a Hugo Award winning SF novelist writes a hyperbolic screed about BASIC in the public schools, 10 Print Hello will be there". As a motto, it's not very catchy. We're working on it.

As soon as I mentioned "Hugo Award winner", "BASIC" and "hyperbolic screed" many of you were probably able to quickly deduce that the author is David Brin, here on Salon wondering what happened to BASIC (you'll have to watch an ad to view the article):

Only, quietly and without fanfare, or even any comment or notice by software pundits, we have drifted into a situation where almost none of the millions of personal computers in America offers a line-programming language simple enough for kids to pick up fast. Not even the one that was a software lingua franca on nearly all machines, only a decade or so ago. And that is not only a problem for Ben and me; it is a problem for our nation and civilization.
Does he have your attention yet? He'll equate the loss of BASIC to an act of war later in the essay. Brin seems to be making three separate points:
  • BASIC used to be available on all computers that kids touch, and that is no longer the case.
This is obviously true, but a bit less dramatic than Brin implies.

Brin implies that BASIC was available for kids for a long time, and only recently disappeared. Actually, that's close to backwards. BASIC was generally available for less than a decade, and has been fading ever since. Even though Brin says a couple of times that "20 years ago" millions of kids could have used BASIC, the fact is that by 1986 BASIC was on its way out as a standard part of home computers.

Although it was invented in the early 60's, BASIC is associated most strongly with the late '70s and early 80s generation of computers. This market would eventually be dominated by the Apple ][ line, but earlier included things like the TRS/80, and Texas Instruments. (I even remember the Bally TV based game system having a BASIC module circa 1981 or so.). In any case, neither the Mac (introduced in 1984) or the IBM PC and clones featured BASIC to that same degree. By 1985, the idea that all computers would have BASIC was much less strong, although Apple ][ and BASIC instruction lingered in schools for a few years after that Which is why Brin's son is still seeing it in math textbooks, although that says more about the textbook industry than anything else. Data point -- my middle school had an Apple ][ computer lab in 1984 or 5. In my high school, a couple of years later, the computers were already Mac & PC's without basic -- we learned Pascal.
  • There is much less of an sense that kids should be taught programming (particularly in BASIC) than there may have been in the mid 80's.
Largely true. Another data point -- my younger relatives about ten years later were no longer taught BASIC, nor were the kids at elementary schools I studied about the same time. By now, computers had migrated into the actual classroom and were being used as reference and also for what I guess you'd have to call multimedia authoring. I do think this is a loss. But at the same time, I've always kind of suspected that the reason why elementary school kids were taught BASIC in the early 80s was because the schools were kind of floundering around for what to do with the shiny new computers. My read of the educational literature during the time I was studying educational technology was that eventually this petered out because it was not clear that teaching programming was helping students become better general learners. To be fair, that's not exactly the point Brin is arguing, but it does suggest that, perhaps, losing BASIC is not the end of civilization.
  • BASIC has some magical set of properties (Brin calls it "line-programming") that makes it uniquely suitable for introducing programming concepts. Because of this, we're losing an entire generation of tinkerers. This, I don't get at all.
So, Brin goes on at some length about how the computer people he's talked to don't seem to feel that it's a problem that BASIC isn't around anymore, while he, Brin, knows better. (Anybody familiar with Brin's essay entitled "The Dogma of Otherness" should catch at least a hint of irony.) Anyway, while Brin does acknowledge that BASIC has a lot of limitations, he goes on at length about line-programming and how important it is.

I'm not completely sure what Brin means by line-programming. Google didn't give me a relevant link. I'm going to assume that it has something to do with the fact that BASIC circa the Applesoft years was coded on a line-by-line basis. Brin suggests that this was an experience that modern languages can't give:
The "scripting" languages that serve as entry-level tools for today's aspiring programmers -- like Perl and Python -- don't make this experience accessible to students in the same way. BASIC was close enough to the algorithm that you could actually follow the reasoning of the machine as it made choices and followed logical pathways. Repeating this point for emphasis: You could even do it all yourself, following along on paper, for a few iterations, verifying that the dot on the screen was moving by the sheer power of mathematics, alone. Wow! (Indeed, I would love to sit with my son and write "Pong" from scratch. The rule set -- the math -- is so simple. And he would never see the world the same, no matter how many higher-level languages he then moves on to.)
I confess, I have no idea what he's saying here, though I do like the scare-quotes around "scripting". I'm kind of trying to get my head around the idea that you can't program a mathematical algorithm in Python and follow the reasoning of the machine. I mean, there are higher level constructs, but if we're talking about loops and conditionals for 5th grade math problems... I think Python would be pretty easy to follow and would look a lot like the logical structure of the algorithm. Python even has an interactive interpreter so you could type the code in line-by-line if you wanted. That actually could be pretty cool in a learning-math setting. And you could even track it with pencil and paper.

It is true, though, that it was much more conceptually simple to do simple graphics in Applesoft BASIC than in Pascal. That's not the language's fault, and it's not because you write Python in a full text editor. It's because modern programming languages sit on an operating system that mediates access to the drawing controls, and Applesoft BASIC didn't. It wouldn't be hard to come up with a Python package that emulated the draw controls of Applesoft basic (which were on the order of "Make that pixel blue. Now make that one red").

I think what I object to is the implication that this is somehow a difficult time to be learning to program, that it's harder now to get into programming. That's totally wrong -- it's a fabulous time to be learning to program. Brin says his son is now learning C++, so I'll assume he's interested and motivated. Twenty years ago, yeah, he would have had BASIC. And that's it. Unless you wanted to pay some money. As for seeing any examples of what a real program looked like, forget it.

These days... Well, a Mac OS X box ships with what, a half-dozen or so programming languages right out of the box, with who knows how many all available for free. Want to see basic algorithm code for free? It's there. All kind of code, complex and simple, is available online. There's a whole industry of programming books, something I would have devoured as a kid. We've traded The One True Teaching Language for many different languages. An elementary school teacher explaining "20 goto 10" is now a publishing empire, plus the internet. Coloring individual dots on a screen is now building a web page, or a web application, or a sprite animation. Even an elementary school child who is motivated can do more and understand more about computers than I would have dreamed in 1985. Have we lost something? Maybe. Have we gained something? Oh yes.

Wednesday, September 13, 2006

Obligatory Apple Post

Since what every tech blog reader needs is another round up of Apple's Showtime event...

Overall, nice incremental stuff, perhaps a little disappointing to those who were expecting a radical new mainline iPod.

  • New Shuffle: This is getting close to being jewelry, actually is starting to look like a cufflink to me.

  • New Nano: Smaller, bigger drive, better battery life, colors. Solid incremental upgrade.

  • New iPod: A very small incremental upgrade. It's very irritating that the new search function is not being backported to existing video iPods.

    Here's my bold prediction -- the widescreen, touch panel iPod will never be released as it is currently rumored. My guess is that there will be practical troubles either keeping the screen clean and scratch free when people are putting their grubby mitts right on it and/or having a touch screen wheel UI that is actually usable. More likely the former, but I think the latter might be a problem too. Just wait for me to be wrong!

  • iTunes UI Enhancements: Mostly quite nice. The album art view and the cover flow view are both very pretty. They don't really mesh with how I use iTunes, but I can see where they will be useful. Points to Apple for actually buying CoverFlow rather than just ripping it off. The library enhancements and the iPod view are nice (although the iPod prefs aren't that much nicer than they were in the Preferences screen). As usual, the UI is in a state of flux, it's a bit more subdued, but some elements (like the tabs in the iPod screen just look weird.

  • iTunes Movies: Best seen as the beginning of a long term strategy than a goal in itself. Although if I were the manufacturer of a portable DVD player, I'd start getting a little worried. Still, I can't imaging genuinely sitting through a full-length widescreen movie on an iPod screen unless I was trapped on an airplane.

  • iTunes Games: Kind of underplayed, but in some ways the most interesting potential. If, that is, Apple releases an SDK such that the open source hackers of the world can get their hand on it. That could be very, very interesting... UPDATE: Looks like Apple has "no plans to offer an SDK". Bummer. Developers should be agitating for this.

  • iTV: I get where they are going with this, and I really want to like it, but absent DVR capability (even if it was on the networked Mac) I really can't see this being a major player.
Python tie-in (what with it being Python Week and all...): nothing really. I do have a pretty cool and obsessive Python script that creates fancy random playlists for iTunes/iPod, including things like, randomly pick albums, randomly play multiple songs in a row from the same artist, play songs in specific genres more often, etc., etc. I'll post it here someday, but the code really needs a good sweep first.

Tuesday, September 12, 2006

Re-refactoring

Here's a little riff inspired by one of the examples in Martin Fowler's book Refactoring, which is another great programming book that deserves an appreciation post one of these days. This was actually also spawned by code that I've read, and later realized that Fowler did a similar example. Thing is, I don't think Fowler went far enough in this case.

Here's the example. (page 243 for those of you playing the home game). But, since it's Python Week here, I'll translate to Python.

if isSpecialDeal():
total = price * 0.95
send()
else:
total = price * 0.98
send()
Fowler correctly notices the duplicate call to send(), and refactors to:
if isSpecialDeal():
total = price * 0.95
else:
total = price * 0.98
send()
This is fine as far as it goes, but as I see it, there's a second duplication in this snippet -- the formula for calculating the total. I'd rather see something like this (using the new Python 2.5 ternary syntax:
multiplier = (0.95 if isSpecialDeal() else 0.98)
total = price * multipiler
send()
There are a couple of advantages to this last snippet. We've separated the calculation of the total from the act of gathering the data for that calculation. This makes the actual formula for the total clearer, and allows you to easily spawn the multiplier getter off to it's own method if it gets more complicated. Plus we've removed more duplication, and I think made the code structure match the logical structure of the calculation a little bit better.

This is a simple example, and you could quibble with it. The general idea of separating conditional logic from calculations is a solid way to clean up code and make it easier to maintain in the long run.

Before I leave... I'm not sold on the syntax for the Python ternary yet. I'm told that the syntax was chosen over the perhaps more consistent if cond then x else y end because it was felt that in most use cases you'd have a clear preferred choice and a clear alternate choice, and putting the preferred choice before the conditional emphasized that. I don't know if that matches how I'd use a ternary. Although I guess it's reminiscent of listcomp syntax. I need to use it in real programs to know for sure.

Monday, September 11, 2006

Some 411 of my own

Saturday, Robin and I had the pleasure of being interviewed by Ron Stephens for the excellent Python 411 podcast. I think this was the first time I've ever been interviewed for anything, and while it's always fun to talk about Python, the book, and me (not necessarily in that order), it does take some getting used to.

Anyway, I do mention this here blog during the interview, and while I don't want to talk about the actual interview in detail until I hear the edited version, it did occur to me that I might want to have some actual Python content on board in case anybody comes by to check the place out.

Python content all week, then, starting with today's Things I Love About Python:

  1. Whitespace. I know that I said just a few short days ago that I wasn't going to redefend Python's whitespace blocks. That was then, this is now. Now, I'm just going to gush over them. I love using whitespace to mark blocks. It enforces what I'd be doing anyway. It encourages consistent style, with the result that other people's Python code is actually intelligible. It encourages short methods and shallow nesting, both good habits, and it lets you get about 10-25% more code on a page. Nobody is ever going to have an Obfuscated Python contest (okay, I looked it up... somebody has, but they realize it's a joke.

  2. List Comprehensions. One of my favorite syntax features in any language. So concise and yet so clear... Try to describe the following any more clearly in any language, programming or not.

    [x.name for x in students if x.grade > 90]

    Okay, they do sometimes blow up if you make them too complicated.

  3. First Class Functions. It's easier to pass around named function objects in Python than in just about any language not named Lisp. This is a very good thing. It enables all kinds of elegant abstractions (especially since classes and instances can all be made callable). Over time, using Python has made all my coding move to a more functional style that's easier to test, verify, and maintain.
Of course, not everything in Python needs to be elegant and abstracted. Last night I had a problem. I wanted to download all episodes of a popular podcast that does not have an easily accessible archive page. Rather that walk through months of postings, I decided to write a script that would take advantage of the pages naming conventions, loop to find the shows for given days, find the downloadable URL and download, then add to iTunes. Final code, just under 60 lines. Elapsed time, under 45 minutes start to first download, including downloading, installing, and using a new library (Beautiful Soup, which is a nice HTML parser). The point is not that I'm particularly good at this (the script is a little sloppy and doesn't handle error conditions well), but that Python is particularly good at this. Plus, it was fun -- no fighting with compilers and interpreters, able to find support for the libraries when I needed it.

Saturday, September 09, 2006

Hybrids In Bloom

A couple of big stories in the wide world of scripting languages running on virtual machine platforms.

  • IronPython, the .NET implementation of Python created by Jython creator Jim Hugunin, released version 1.0.

  • The two primary developers of the JRuby project, implementing a Java-based Ruby interpreter, were hired by Sun with the mandate to bring JRuby to 1.0.
Unsurprisingly, I think this is all great. Programming hybrids are a beautiful thing. The more tools the merrier, and the more ways to combine the best parts of different tools, the merrier squared.

The amazing thing about IronPython is that it benchmarks as being faster than traditional CPython, which seems sort of counter-intuitive. (I'm assuming, based on nothing at all, that there's a higher memory load, but if I'm wrong, I'm sure somebody will point that out).

One of the interesting things about JRuby is a certain shift in momentum. When Jim Hugunin created JPython, the primary goal was to be able to use existing Java libraries with Python syntax. The JRuby team (and by extension, Sun), in contrast, seem to be comparatively more interested in using existing Ruby libraries (like Campfire and Rails) on a JVM backdrop than in using existing Java classes.

For instance, JRuby does not seem to have an analogue to the Jython shortcut of using converting attribute assignment in Jython (foo.bar = 3) to a Java bean setter (foo.setbar(3)), which makes Java classes feel more Pythonic. (Again, correct me if wrong, the existing tutorials don't touch on this point, and I'm basing this on a possibly out-of-date article). (UPDATE: Somebody did correct me -- JRuby does have this style. I wonder if it also works on constructors the way Jython does. So the point below is somewhat invalidated.)

And I don't mean this as a good/bad thing, either -- it's perfectly all right for the different tools to have different priorities. It's fascinating that Ruby is now seen as bringing a host of useful tools to the Java platform, in a way that I think we would have been laughed at a few years ago for suggesting that strongly about Jython.

Good luck and more power to everyone, I can't wait for Java on Rails...

Thursday, September 07, 2006

I/O, I/O, It's Off To Work I Go

Welcome to our program, Things I Agree With Totally And Wish I Had Said First. Our hero tonight is Tim Ottinger with his hit, "Frameworks are for the Impatient". It seems Ottinger is puzzled by a library he's trying to use..

Look, this framework is not the game Myst. I did not install this thing so that I could amuse myself for days by running around the file system trying to figure out what it is about...

In the Java world... [E]ven opening and reading a file is cause to go google the library one more time. Heaven forbid you have to manipulate dates or the like. These are small things, and should be very easy.... You shouldn't have to crack open a half-dozen US$50.00 books.

One point of "obvious" is probably worth one hundred points of "clever".
In the immortal words of Arnold Horshack, "Right you are, Mr. Kotter". Hmm. That sounds better if you imagine it in a Horshack voice. Doesn't look like much in print...

The Java io library is a particular nemesis of mine. I've been using it for what, just under a decade now, and the only way I was able to stop looking up the API every other week was to write a utility class that had an API that was actually useful (you know, obscure methods like copyFile, readlines, writeToFile...).

The io library may actually be the purest example of the Java school of OO design, marked by the principles like:
  1. Use an abstraction (streams) that looks interesting on paper, but that nobody ever uses. Ignore the abstraction (files) that is already established. When that doesn't work, add a completely new abstraction (readers/writers) that's completely non-interoperable with the first one.

  2. Make sure the user has to type a lot of words to get anything done.

  3. Make it just as easy to do obscure, complicated things as it is to do typical things, even if this means making it harder to do normal tasks. Doesn't everybody want to randomly access binary files just as often as write some text? (Actually, there are obscure things in the API that are much easier than say, iterating over the lines in a text file).

Don't even get me started on the nio package. Really, don't. I couldn't explain it on a bet.

Sigh. Java is too easy a target sometimes.

Wednesday, September 06, 2006

Fonts

I'm curious -- how do you set up your screen in your text editor when you are programming?

Based on people I've worked with, I seem to do two things in my setup that are unusual. I use fairly large fonts (16-18 point, if I can) and I'm aggressive about cutting off lines at 80 characters. The upshot is that I'm showing less text on the screen at a time than most programmers I know.

Good? Bad? Not sure. The 80 character habit came from I think a combination of Code Complete where it's recommended on the (outdated now) premise that that's as many characters as you could print on a line, plus doing the books, where you generally do have to cut the examples off at 72 or 80 characters, plus some nasty HTML bugs where somebody tried to do a whole table in one line, and there was a missing </td> in column 436 or something. I'll stretch beyond 80 characters, but I really don't like having code hang that I
have to scroll right to see.

The bigger font I think is more of a aesthetic choice (and not, say, a vision issue). I do like that it tends to focus me on one method at a time, and encourages me to keep methods shorter to stay on one screen.

A couple of years ago, I did a little internet search on fonts for programming. Among other things, I found there are people who really like programming with a 7 or 9 point font. Anyway, I picked Bitstream Vera Sans Mono (and also the open source twin Deja Vu Sans Mono) because it is a bit heavier weight than Courier, a lot prettier to look at, and it's specifically designed to differentiate between similar characters.

Monday, September 04, 2006

Web Apps and Language Wars

I wasn't planning on posting about either web apps or linking to Joel Spolsky again, but this language wars post is just too interesting to pass up. Besides, a jillion people have already commented on this, so what's a jillion and one?

Spolsky is riffing on what language or platform you should use for an enterprise web project. He makes a few points (note, I'm paraphrasing him here -- these are his points, not mine):

  1. There are 3 1/2 platforms that are proven to work in the enterprise web app space (Java, C#, PHP, and maybe Python.

  2. Within that group, there's no difference large enough to offset expertise, so pick the one that you know the best.

  3. Rails is not part of that group. Even though it's fun.
I suspect you know which one of those three points has gotten the most attention. Obviously the Rails people are ticked off, which I think is a combination of Spolsky taking his point too far, and Rails partisans taking his point even farther.

Look, I love Rails as much as a person can love a framework. I wish I had been smart enough to put all the pieces together myself (another post for another time...). My Rails experience has been uniformly positive. Nevertheless, if I wanted to pitch Rails for a mission-critical enterprise application, I would expect to have to justify the choice. Using Rails is still a risk, relative to the others, it's still newer, people are still trying to work out optimal deployment, it still doesn't have the library support the others have. Where I would differ from what Spolsky is saying is that I think it might be a justifiable risk even in a mission-critical enterprise application.

Scaling and library support is not the only source of risk. There's also the risk that your code will get bogged down in a huge ball of intertangled display and logic code (PHP). Or the risk that your developer time will be slowed down enough that it delays deployment (Java). Or the risk of deploying in a system that is owned by Microsoft (guess...). Choosing one of the "nobody ever got fired for choosing X" languages is a safer choice. Which doesn't always make it the best choice.

(And yes, I know that Spolsky ends his essay by mentioning that one of his apps is written in a custom in-house version of VBScript. Red herring. He's not saying that Java, C#, and PHP are the only languages to use ever, just that they are the only languages that currently have the ecological support to be guaranteed safe in a "death before failure" scenario.)

I'd argue the following corollary: I agree that, all else being equal, expertise trumps any difference between these platforms. That's a little circular, of course, because how will you get experience without using a tool? (I know about apprenticeship as a junior member on a larger project, but it's not always feasible.) Almost every project or team spins off low-level applications -- bug trackers, vacation trackers, internal chat rooms. Things that are not high-priority, but are still useful. So, when putting those together, I think it's a good idea to range far and wide and try new things that might pay off in a future project (I almost wrote that you "have the right, no, the duty" to do that, but I thought that might be a little over the top). Me, I'm going to try out Python/Django next chance I get...

Friday, September 01, 2006

Java Closures

Here's a nice item being proposed for Java 1.7: closures in Java. On behalf of all those people who actually do create entire classes just to be able to use map and other functional styles in Java, may I say, please, please, please put this in Java. (This seems a good place to link to Joel Spolsky's wonderful programming fable "Can Your Programming Language Do This").

The proposed syntax looks like this:

public static void main(String[] args) {
int plus2(int x) { return x+2; }
int(int) plus2b = plus2;
System.out.println(plus2b(2));
}
Line one of that syntax creates a closure object that takes and returns an int using what is basically Java method syntax. Line two assigns that closure to another variable using the syntax int(int) to specify the types of the signature. Line three shows that you can call the closure object as you'd expect, although notice that, unlike most Java calls, there's no receiver object specified, and it's not using an implicit this -- it's purely a function.

The proposal also specifies an alternate syntax for creating short closure objects -- I don't like this one as much:

int(int) plus2b = (int x) : x+2;

This is all nice, and I know I'd use it pretty much daily. Unfortunately, though, I wonder if the strict typing will wind up making the closures less useful than, say, Ruby blocks. I assume there'd be some way to tie this into the generics system so that methods that might take blocks with different type signatures would be able to convince the compiler that everything is okay. Let's see... if I wanted to do a new method of List collect, it would be something like this.
public List<V> collect(V(T) closure) {
List
<V> result = new ArrayList<V>();
for (T obj : iterator()) {
result.add(closure(obj))
}
return result;
}

int plus2(int x) { return x+2 };
List fred = list.collect(plus2);
Is that right? If so, that's certainly a lot better than we have now.

I have three quibbles and an enhancement.

Quibble 1: Like generics, what looks nice for int(int) is going to look a lot less pleasant when the signature is, say, OrderLineItem(Order, Product) or even better List<List<OrderLineItem>>(List<Order>, List<Customer>, List<Product>), which I could easily see as a real world case.

Quibble 2: Do do this right would require including support for closures up and down the standard library -- all through the util classes, all through SWING, JDBC -- there's all sorts of places in the library that would be cleaned up by being able to take closures. I suspect that's unlikely to happen quickly.

Quibble 3: The proposal says "We are also experimenting with generalizing this to support an invocation syntax that interleaves parts of the method name and its arguments, which would allow more general user-defined control structures that look like if, if-else, do-while, and so on." I'm thinking this is more of a Smalltalk or Objective-C style? That would look odd within Java.

What I really want, though is a method literal analogous to a class literal. Something like...

Integer(MyClass) closure = MyClass.someSillyThing.method;
MyClass obj = new MyClass();
Integer x = obj.closure(3);

or even better:

MyClass obj = new MyClass();
Integer(MyClass) closure = obj.someSillyThing.method;
Integer x = closure(3);

And yes, I realize that's basically Python bound and unbound methods. The tricky part in Java is that there might be more than one overloaded method called someSillyThing, and so I'm assuming that whatever closure object I'm creating would be able to get the right one based on the declared type (or, alternately, I suppose, dispatch properly when called). That should be doable, though. And then my Java code can look even more like Python...

Good stuff. I hope something like this gets in.