The Sean Code

Programming is a wonderful mix of art and science; source code is both a poem and a math problem. It should be as simple and elegant as it is functional and fast. This blog is about that (along with whatever else I feel like writing about).

Thursday, November 06, 2008

The Entire Problem with Microsoft

Steve Ballmer has always had the uncanny ability to take something complicated and sum it up in a nice, simple phrase that explains it so everyone can understand. In dismissing Android as a competitor, he's done it again:
"Google doesn't exactly bubble to the top of the list of the top competitors we've got going in mobile. They might someday. But right now..." he said.
In other words, Microsoft doesn't bother trying to compete with someone until they're already beaten. It worked when they created Windows after they'd been beaten by the MacOS, but since then it's been far less successful (IE, Vista, search, Zune, etc).

Perhaps they should try competing with something while it's still new and weak? Maybe they could finally win again? Like when the 360 beat the PS3 by attacking it before it was ready?

Just a thought.

Sunday, October 26, 2008

Breadcrumb History in Django

This afternoon I wanted to add a breadcrumb-like feature to an application I've been writing in Django. I figured the best way to do this is with sessions, so the first step is to turn those on.

The way I wanted it to work is like a rolling history of pages visited. So there's no implied hierarchy of pages, it just shows you the pages you've visited most recently. I figured limiting it to four pages was reasonable, but I can certainly see myself increasing that number in the future.

The first thing to do is to create a helper function that adds the current page to the history. You want to create the default empty history if there's nothing for it in the session, and you want to make sure it doesn't get too long. Also, you access the session and the address of the current page through the HttpRequest object that's available to every view in Django, so we just pass that in.

Here's my function:
# the breadcrumb history is a list of the last pages the user has visited
# the newest page is at the end of the list
# the length of the list is limited; currently it is at four pages
def add_breadcrumb_history(request):
    history = request.session.get('breadcrumb_history', [])

    # if the last item in the history is the current page, we don't want to add this page to the history
    # if it's not the last item in the history, we do add it
    if len(history) == 0 or history[len(history)-1] != request.path:
        history.append(request.path)

    # if there are more than four items in the history, pop the first one
    if len(history) > 4:
        history.pop(0)

    # save the history to the session
    request.session['breadcrumb_history'] = history

    # return the current breadcrumb
    return history

And in your views, its usage is simple enough. You call:
breadcrumb = add_breadcrumb_history(request)

in your view, preferably after you verify the user's permission to view that page. Then you want to add it to the list of variables exposed to your template, usually in your call to render_to_response().

Then you have to add the breadcrumb handler to the template. I put mine in my base.html, so it's available on every page.
{% if breadcrumb %}
<p class="breadcrumb">
{% for page in breadcrumb %}
<a href="{{ page }}">{{ page }}</a>
{% endfor %}
</p>
{% endif %}

Very simple; if there's no breadcrumb history, it doesn't display anything. If there is, it displays the links in order.

I like this feature; while I recognize it's close to useless in some situations (namely those where the data actually adheres to a strict hierarchy), in others it can be really useful. It means I have to do a lot less state checking on my pages to try to "calculate where the user came from" to get to that page, and can trust that users can easily navigate back to recent pages even if they POSTed information in between. (While I like that "You POSTed information on this page, do you really want to hit the back button?" feature, it can be really annoying in practice.)

Just thought I'd toss this up there in case anyone found it useful -- or is aware of similar functionality elsewhere.

Thursday, October 02, 2008

Asus 1000H vs Acer Aspire One ... A Pack of Lies

I just saw this "brilliant" visual comparison of the Eee 1000H vs the Acer Aspire One, and I can't just let it pass. I mean, I understand that the netbook marketplace has become absurdly overcrowded, and the main differentiators between the machines are 1) price, 2) software, 3) packaging. Asus is clearly annoyed that despite virtually inventing the category, they are left as the overpriced competitor much maligned for their confusing marketing and unpredictable product cycle.

Meanwhile, Acer has pumped out exactly one netbook, priced it competitively, and just let people buy it and enjoy it. And here comes Asus to rain on Acer's parade in the most immature way possible. (They couldn't even bring themselves to spell out Aspire, instead spelling it "A*****" -- um, lame?)

As the owner of an Asus laptop and an Acer Aspire One, I find myself compelled to take on the comparison point by point.

1) Battery life

Asus: 6 cells, 7 hours
Acer: 3 cells, 2.25 hours

I haven't used the Eee 1000H, but my Aspire One gets 3.5-4 hours of battery life when I use it normally (ie, wifi 100% of the time, internet browsing, typing). And that's with the default 3 cell battery, not the add-on 6 cell. If the Eee really gets 7 hours of battery I'd be impressed, but I wouldn't be at all surprised if they're lying about their own battery life to the same extent they're lying about the Acer's.

2) Hard drive

Asus: 160 GB
Acer: 120 GB

Firstly, big f'ing deal. It's a netbook. If you're storing a bunch of media locally, you're doing it wrong. Secondly, the Acer defaults to a nice little SSD that more than gets the job done and allows me to 1) not worry at all about the fact that I keep dropping it, and 2) boot/sleep really quickly. 40 GB is meaningless on a laptop, moreso on a netbook.

3) RAM

Asus: 1024 MB
Acer: 512 MB

Yes, I could go for more RAM. It's not like I've been dying without it, but this is a pretty clear win for the Asus.

4) Size

Asus: Large touchpad, large screen, large keyboard (92% standard), wider palm rest
Acer: Tiny touchpad, small screen, small keyboard (80% standard -- although it's actually 85%), tiny palm rest

Every single point here is true ... and made possible by the fact that the Asus is a 10.2" netbook while the Acer is an 8.9" netbook. I wonder how Asus feels about its own 7" netbooks. Also, more lying ... the keyboard is bigger than Asus claims it is. And Acer's sub-9" netbook is certainly more portable than the over-10" Asus. Which, I think, is the point of netbooks.

5) Um, miscellaneous networking, I guess

Asus: Bluetooth & 802.11n, 1.3 megapixel webcam, "Digital Array Mic"
Acer: No Bluetooth & 802.11n, 0.3 megapixel webcam

Frankly I wish my Acer had Bluetooth, but I can't say I miss it all that much -- I don't even use it on my full-size Asus. And 802.11n isn't that meaningful to me, since I don't have an 802.11n router (and neither does anyone else). Oh, and the webcam? My full-size Asus has a 1.3 MP webcam, and it looks awful compared to the 0.3 MP on the Acer, when both are using Skype on Linux. Seriously, Acer's 0.3MP webcam is surprisingly awesome. And what the hell is the "Digital Array Mic?" Is it something that solves the horrible feedback problem my full-size Asus has? Because if it is, that's nice, but the Aspire One doesn't have any feedback problems with its mic.

6) Location of touchpad buttons

Apparently the familiar position of the Asus' touchbad buttons allows easy usage, while the odd location of the buttons on the Aspire One leads to "unsmooth usage." I've heard other people complain about this too, and I just don't get it. It seems to me that it's an innovative use of space given the obvious size constraints, and it's not exactly counterintuitive -- the "right click" button is "on the right side" of the touchpad. Holy crap, I'd never find it!

7) Temperature

Asus: Gives off no heat at all -- the whole thing is green!!
Acer: It's on fire! Look at all the red!

In reality ... I can't speak to the Asus, but the Aspire One doesn't give off any heat. I've used it for 10 hours straight, plugged in for 4, then 3 hours on battery, then plugged in for another 4, and the temperature remained constant the entire time. And it remained constantly the same temperature as it was when it was off. Both on the top and bottom, it's comfortably cool the entire time. I don't know how they came up with this test, but the only way it could be true is if the Asus has The Al Gore Anti-Global-Warming Super-Prius Hybrid Engine built into it, or something, and actively sucks heat and carbon emissions into it and converts them into sunshine and virgins. I call bullshit.

8) "Work Efficiently"

Asus: Boots in 30 seconds, ready in 38 seconds, ready to launch "AP" in 41 seconds, shuts down in 15 seconds
Acer: Boots in 45 seconds, ready in 62 seconds, ready to launch "AP" in 74 seconds, shuts down in 30 seconds

Apparently time goes faster in my apartment, because the Aspire One actually boots in about 10 seconds. And shuts down in about 5. And goes from "off" to "browsing the web" in 12-15. I don't know what "AP" is, so I'll go ahead and skip it. I guess I don't use it. Hopefully Asus' users really like it, because it seems to take a really long time. The only computers I've seen get going faster than the Aspire One are Macbooks. And, um, those are in a slightly different market segment, and I don't think I'd compare them.

9) "Quiet Computing"

Asus: Idle, 25.1 dB; Media Player, 28.8 dB
Acer: Idle, 30.7 dB; Media Player, 31.5 dB

I guess the 2.7-5.6 dB difference is simply massive, the difference between "silent" and "a fucking jet engine." But I have two things to say: 1) I haven't heard the Aspire One since I've owned it; I wasn't even aware it had a fan in it. 2) If you're using the media player and not wearing headphones, you're doing it wrong; it's not like these things come with great speakers. Also, 2.7 dB? Did you know that normal humans can't tell the difference?

Finally, the major differences as I see them:

1) Size

The Acer is a 9" netbook, and is smaller, thinner, and lighter (2.2 lbs vs 3.2 lbs) than Asus' 10" entry. Really, Asus? That extra 1" of screen space weighs an entire pound? Are you sure you're not just bad at this?

2) Price

I bought my Aspire One for $400 a couple months ago, and it's down to $330 from Amazon. On the other hand, the Eee costs $530 and is available for pre-order. Raise your hand if you can tell which is better.

3) Linux

The Aspire One runs Linux, and runs it well. The Eee 1000H runs Windows XP, and I'm sure it runs it worse than computer with 2-5x its specs that can barely keep themselves on their feet. Acer wins.

In conclusion, the choice of a netbook really comes down to personal taste and how much you want to pay for it -- you might prefer a 10" Windows machine to a 9" Linux machine, and you might not. But this kind of childish lying about yourself and your competitor is the stuff of Microsoft and Republicans. Is that really who Asus wants to model themselves after? Oh yeah, and I thought false advertising was illegal?

Sunday, August 31, 2008

The Contractor Experiment Ends, Plus My First Wordpress Plugin

It's been a while since I've posted anything, but I figured I should mention this: The Contractor Experiment is over, after just one contract. I found myself in a place I liked, with a good working environment and good co-workers ... and I became a full time employee last week. I plan on working exactly the same way as an employee as I did when I was a contractor -- why else would they have hired me? -- and it should remain a lot of fun.

Meanwhile, I think I should also mention a little side project I've been working on, and have just released. It's a Wordpress plugin that downloads baseball player's stats and displays them on your blog.

It can be seen in action at my baseball blog, Fire Gardy. To learn more about the program, you can visit the Fire Gardy Stat Grabber home page. Or just jump straight to the project page at Github. (It's GPL software.)

When I wrote it, the first step was to write a Baseball-Reference.com parser, which grabs the requested player's page (via PHP's CURL), and runs through it line by line to get the player's batting statistics (pitching stats will have to be added later).

Once that was there, it was time to turn it into a Wordpress plugin. It was actually a lot easier than I thought it'd be.

First you go to your blog's wp-content/plugins directory. Create a new directory inside it for your plugin (mine was called "fire-gardy-stat-grabber"). Inside that new directory, create a PHP file with the same name as the plugin directory ("fire-gardy-stat-grabber.php").

Open it up and put a comment inside it that will tell Wordpress the details of your program. Mine looks like this:
/*
Plugin Name: FireGardy Stat Grabber
Plugin URI: http://stat-grabber.firegardy.com
Description: Download a player's stats from Baseball-Reference.com and display them on the page.
Version: 0.1a
Author: Sean Schulte
Author URI: http://seancode.blogspot.com
*/
Really, only the "Plugin Name" line is required.

You need to define a function that will display what you want -- because for this plugin we'll be using a "Template Tag" (which allows us to put it anywhere on the page by editing the theme's template files).

It's a simple PHP function, that can take any parameters you want. It doesn't return anything, and needs to echo your desired HTML output to the screen. Mine has the following signature:
function fire_gardy_stat_grabber($playerName, $playerId, $year)
I'm not going to print all the code for it here -- you can go check it out at Github.

You can use the Wordpress database in this function -- which is useful for caching the results you get back from Baseball-Reference. There are two options for using the database. One is to create your own tables and use actual SQL queries; that'd be useful for more complicated plugins. The other is to use the Wordpress options table which stores anything -- accessible as part of a simple name-value pair.
get_option($key);
delete_option($key);
update_option($key, $value);
The plugin also uses a Wordpress Plugin hook to load some CSS. A function like this writes the CSS:
function fg_baseball_reference_css()
And this line makes it load:
add_action('wp_footer', 'fg_baseball_reference_css');
Once you've got that in place, just toss it into your sidebar.php in your theme's template:
<?php fire_gardy_stat_grabber('Nick Punto', 'puntoni01', 2008); ?>
And that's that! Now that I've finally written a Wordpress plugin I expect to do it significantly more often. I expected there'd be a lot more BS involved in hooking extensions into the Wordpress system, and realistically anyone who can write even the simplest PHP functions can do this.

Friday, July 04, 2008

Flex Injection: Passing a Function to a Component

Sometimes, in Flex, I find myself in the situation of using a ViewStack to define different screens of my application. And I want to be able to navigate between those views easily, in addition to using components to make development simpler.

I've found that having a "Back" button inside a component can be useful, but if the back button is hidden inside the component, it can't access the ViewStack (since it's in the parent).

I thought it would be useful to be able to pass a little bit of ActionScript to the component that would jump back to the previous view. It would effectively inject functionality from the parent to the child. Here's what my component looks like:
<?xml version="1.0" encoding="utf-8" ?>
<mx:VBox xmlns:mx="http://www.adobe.com/2006/mxml" width="100%" height="100%">
<mx:Script>
<![CDATA[

[Bindable] private var _labelText:String;
[Bindable] private var _buttonClick:Function;

public function set labelText(str:String):void {
_labelText = str;
}

public function set buttonClick(func:Function):void {
_buttonClick = func;
}

]]>
</mx:Script>

<mx:Label text="{_labelText}" />
<mx:Button label="Back" click="{_buttonClick()}" />
</mx:VBox>
As you can see, this component allows you to define some text to display and the back button's click handler. The click handler has to be a Function object.

Note that when you call this Function object, you have to put () at the end. It thinks this is actually a method that it can call, so you have to call it like any other method.

But when you instantiate this component, you can't just do something simple like buttonClick="viewStack.selectedChild=anotherView" ... while that may be the ActionScript code you want to execute, and it may work when you're defining the actual click event, the component will interpret this as a String instead of a Function, and it won't work. So you actually have to create a Function object in the parent.
<?xml version="1.0" encoding="utf-8" ?>
<mx:Application
xmlns:mx="http://www.adobe.com/2006/mxml"
xmlns:components="components.*"
width="100%"
height="100%">
<mx:Script>
<![CDATA[
[Bindable] private var backToViewZero:Function =
function():void { viewStack.selectedChild = viewZero };
]]>
</mx:Script>

<mx:ViewStack id="viewStack" width="100%" height="100%">
<mx:VBox id="viewZero" width="100%" height="100%">
<mx:Label text="Start here!" />
<mx:Button label="One" click="viewStack.selectedChild=viewOne" />
<mx:Button label="Two" click="viewStack.selectedChild=viewTwo" />
</mx:VBox>
<components:MyBox id="viewOne" labelText="One" buttonClick="{backToViewZero}" />
<components:MyBox id="viewTwo" labelText="Two" buttonClick="{backToViewZero}" />
</mx:ViewStack>

</mx:Application>
Here, we create an anonymous method and assign it to the Function object, and then we can pass it to the component when we instantiate it.

This works splendidly, and is a pretty cool way to inject functionality down into your components that wouldn't otherwise be possible. (The component doesn't have to reach up to the parent somehow, which means your component doesn't need to know what the ViewStack is called, or about any of the other views; instead, it just needs to know that it's going to do something, and the parent is responsible for knowing what.)

It leaves me wondering, though, if there's a way to get around the problem of passing in code and having it interpreted as a String rather than the preferred Function. Perhaps by having the buttonClick setter take a String and create the Function object at that point, using something like eval(). Unfortunately, ActionScript 3.0 doesn't have eval(), so I don't know if this is possible. Maybe I'll figure something out later. In the mean time, I'll be creating Function objects in the parent.

Tuesday, February 26, 2008

The Freedom Framework Bends to Your Will

On Sunday, I came up with the concept for the Freedom Framework, which consists of PHP Object Generator, EpiCode, and Smarty. I'd like to take some time and go into what I feel are some of its actual advantages, over other frameworks and over not using a framework at all.

First, you define your data model from the perspective of the database, rather than from the code. While you don't actually have to write any SQL, you're defining the fields and their types as if you're just creating a table. It adds to this with the Parent/Child/Sibling concept, but doesn't go as far as other frameworks which give you the impression that you're just creating and working with objects, and then try to generate the database from that (or make you write both the database and the models).

When you've done this, you edit the config file with your database's login information and run setup. It tests your database connectivity, creates the tables, and then runs some unit tests to make sure everything's working. At this point you have a set of classes that give you CRUD functionality for the tables you've defined.

And now, EpiCode comes in to define your controllers. This is the best part of the "framework." Since you define the controller classes yourself (rather than having them generated), you have a little extra freedom there. And since you actually define the routes table (rather than generating it or being stuck with a convention), you gain more control over the URLs that'll be used by your application. If it's a small application, you can use just one controller class, even if you have a bunch of differently named URLs pointing to its methods.

That freedom allows for excellent refactoring support. As I was feeling my way around the new "framework," I had only one controller class. After my methods started growing, I decided it would be best to separate them into multiple classes. This was the work of a few seconds (made easier since these are static methods); then I just had to update the routes table to point the URLs to the new classes and methods ... and voila! The project graduates from being a simple proof of concept to being a maintanable MVC application.

Even Smarty allows this sort of flexibility for the view. When I was putting together my proof of concept, I just threw the .html files into the root templates/ directory. As it grew, and I decided that this was more than just a tiny project, I created subdirectories underneath the templates/ directory and moved the .html files into them. (It's probably simplest to name these subdirectories in such a way that they match the URLs, but you don't HAVE to.)

The goal of the Freedom Framework is to minimize the things you're forced to do to work with it. There's no generated filesystem structure or controller classes; you can name them and structure them however you please. The framework grows with each project, starting out as just a little bit of glue and expanding into a well defined structure for your code (and since it's YOUR code, you get to define that structure). You don't have to know (or be told) the final structure before you start working on it.

The more I think about this "framework," the more I like it. The more I use it, the more I like it. It's the first I've found that doesn't inherently limit the way I want to work. The tool bends to my will. That's what makes it a good tool.

Sunday, February 24, 2008

POG + EpiCode + Smarty == The Freedom Framework

I generally have a problem with web frameworks, like Rails, CakePHP, Symfony, and the millions of others that have sprung up lately (moreso in PHP than in Ruby, as Ruby hadn't really been used for web development until Rails came along). As a rule, they force you to do things a certain way, and -- more importantly -- to think in a certain way. In most cases, this "way" is mimicry of Rails, but in all cases, this "correct way of thinking" is the way the framework developers think. That's the aspect of frameworks that I take issue with, while at the same time acknowledging the productivity gains that are possible with these frameworks.

Since everybody likes productivity gains ... I decided to go out and see if there was some way to get the same increase in productivity without using a framework. I want to use tools in such a way that makes sense to me, not to the tool.

The place I started was with the model; I needed to find a good ORM tool for PHP. I hadn't found one that I like yet, so this search took me a while. I still haven't found a real ORM library that I like, but I have come across an interesting tool. The PHP Object Generator allows you to define a database table (with an interface similar to phpMyAdmin, which I don't care for, but at least it's a familiar concept), and from that it generates not only the SQL to create the table, but also a PHP class with the standard CRUD methods. It handles relationships between tables with a parent/child concept (a parent can have multiple children, but a child may only have one parent). At first, it didn't support has_and_belongs_to_many relationships, but added that in with the concept of "siblings." I think that terminology is a bit of a stretch, and the documentation on it isn't the best, but it works well enough.

For the controller, I wanted something really light. I considered just making my own, and that probably would have worked. But by chance, I discovered EpiCode, which is just about exactly what I would have wanted to create on my own. It uses a .htaccess file to direct all HTTP access to the index.php file, which contains an array called $routes, which in turn wires paths to functions (or static methods, which works even better). It doesn't touch the query string parameters, so you get to process those however you like.

For the view, I stuck with the old Smarty standby, and it works like a charm for this. You have to define which variables to open up to the template, as well as which template file to use; despite having to type a couple of extra lines of code, I prefer this to being forced into a particular directory structure and naming convention that is common among the true frameworks.

In my first foray into the POG+EpiCode+Smarty "framework," I made an IMDB clone in about an hour and a half, and I didn't have to write a single line of SQL (table creation or queries). In fact, I didn't even have to log into the database (as the POG setup process creates the tables and verifies that everything's working). I'd say that's a fairly significant increase in productivity over my previous methods, and I still got to define my workflow for myself, rather than kneeling before some anonymous framework creator.

I know a lot of people like frameworks, and a lot of people use them. Because of this, my opinion on the matter probably isn't very popular. But I think this freedom is really valuable. And I find it difficult to believe that my opinion is unique.