Categories: Zune Posted by Shawn Oster on 5/7/2008 1:53 PM | Comments

So "Meet Again" is a bit of a misnomer since I use my Zune everyday but each time an update comes out it always feels like I'm relearning the Zune all over again.  This time it's the Zune 2.5 Spring 2008 Update and like every previous update I have a love/hate relationship with it.

The Love

This is an interesting update because they've actually added a ton of new features but they're not all immediately obvious.  The feature that jumps out the most is the new video section in the marketplace which currently has TV episode purchases but I'm assuming will eventually expand to include movie rentals and purchases.  This helps bring the Zune in line with iTunes and the XBox's version of the Marketplace and really helps round out the media experience.

They've listened to the community because some of the most demanded features are there, namely auto-playlists, gapless playback and browsing by genre.  They've also really started taking the whole "Social" more seriously since you can finally view ZuneCards inside the software and get directly to your friend's (and their friends) play list.  I'd love to see these ideas explored even more, perhaps creating an API that allows you to import your play information from other players and the ability to create custom playlists that can be featured on your ZuneCard.

Another big area that has been improved that's not immediately obvious is metadata editing.  The amount of editing allowed before was so limited as to not exist whereas now they have a solid story in place that allows full editing as well as album info lookup with 800x800 album art.  Metadata is near and dear to me so I've used almost everything out there to edit with and I'd say the user experience is up there in the Top 5.

Of course there are still a few issues with it, for example I have Fischerspooner's 'Danse En France' maxi-single and while I can easily find it in the Marketplace the 'Find album info' command comes back with everything else but the right album and that happens more often then I'd like.  Also it's easy to get a 100+ result set back and there aren't any good tools to narrowing that down.

There are quite a few little UI adjustments as well; different font sizes, album art is now displayed next to progress bar, the 'Now playing' allows you to always hide the track listing, there is a nice "Save as playlist" option when viewing your now playing queue, and a ton of other great little additions.

The Hate

Perhaps 'Hate' is too strong a word but there are still some quirky things about the Zune that frustrate me.  My biggest one is that you can't use the device when it's connected to your computer.  There is a whole laundry list of frustrations on that front:

  • You can't play music directly off your Zune, you have to copy it off first.
  • You can't copy a playlist off the Zune.
  • You can't copy a podcast off the Zune.

What's ironic is that if the reason you can't play directly from the device is because of DRM concerns then having to copy it off before playing it only encourages piracy.

With 2.5 they've nicely reduced some of the UI element's font sizes yet they've made others HUGE, such as the track number.  The track number has all the visual focus while the more important information, the track title, is dwarfed and forgotten in the shadow of THE HUGE NUMBER.  People don't care about track numbers nearly as much these days yet somehow that gets all the focus?  I'm completely baffled.  Check it out:

Besides your eyes being assaulted by the huge numbers did you notice the bonus UI bug?  That's right, it says "11 songs by album".  Umm, no, sorry, this is actually being sorted by track number.

Besides the track number travesty they seem to have really cranked up the bold knob, everything is now very important.  If you look at the properties tab for a song it's like you just walked into a political debate, everything is really important and demands your attention, right now.  It about sets my brain on fire.  Also, it's very curious that you can't get to the metadata editing screen from the properties dialog.  It seems someone with very bad eyesight that hasn't been to the opthamologist in about a decade got put in charge of the UI team.

I saved the best for last... while I applaud the new metadata editing features there is a huge glaring problem with it, it doesn't actually edit the real metadata.  It may look lovely in your Zune but all your other applications, such as Winamp, Sonos, your mobile phone, iTunes, etc. will still see the same old busted metadata.  Instead of correctly updating the underlying ID3 information it just makes some tweaks to the Zune database.  Imagine when you get a new PC and you reinstall the Zune software, happily re-importing all your tracks only to discover all that painstaking metadata updating you did is gone.  Or you want to show off all the album art you've added to all your tracks on your Sonos or Roku Soundbridge, only to see empty little lonely squares.

For this reason alone I'd suggest that you don't use the Zune 2.5 metadata editing features.  Don't touch it, don't look at it, don't pass go.  Don't even think about it.  If you want your metadata to really be updated then follow my suggestions here.

UPDATE: I was corrected on this issue by Zach Johnson, the Zune Client Development Lead.  Seems the client uses a background thread to handle the actual writing of the ID3 tags.  Of course this isn't the most helpful if you want your changes to take place instantly but it's better than I had thought.  Also, while the ID3 data does eventually get updated the embedded album art doesn't, which poses an issue for all your non-Zune applications. 

The Rest

This is by and large a great update, bringing a lot of new features, fixing some old bugs and really polishing up the experience yet it seems for every bug or feature they fixed they managed to really bungle up some other ones.  Metadata editing is very pretty and has a nice user experience, it's just worthless.  The UI has been polished, except for the spots where they just punted.  Closer, you're getting closer Zune team.

Posted by Shawn Oster on 5/2/2008 8:05 AM | Comments

Usually I post my pet peeves and various net grumblings to Twitter but I've encountered too many in the last few days to fit inside a 140 character limit.  Also I think if you're going to complain about something you should also provide a solution so it doesn't seem like you're just a bitter, crazy, no-pants wearing old man that lives to kill the dreams of others.

Company Blogs That Go Dark

A few times a week I encounter some company blog that hasn't been updated in more than six months, thus leaving a very bad impression about exactly what the blog is for in the first place.  What's ironic is that I see this most often with self-styled Web 2.0 companies that start with a flurry of almost daily blog posts then suddenly it's as if the reality of running a company hits and the blog goes silent.

While a silent personal blog is no big deal a company blog is meant to give users a warm fuzzy that things are still moving right along and that their investment, whether it be with their time, data or attention, is still safe.  Given the frenetic pace of the Internet and how fast things change even going a month without a post can make users start to wonder if the chef is still in the kitchen.  The posts don't even have to be earth shattering, they can simply be, "Yes, we're still here and still working on things" or "We made these very minor changes recently that you probably don't care about but show we do care."

Year Old "New Features"

This is really an extension of the above.  While some may not care how often a company blog is updated (crazy people for sure) it's really annoying to go to a site day after day and see the same "Just Added!" call-out on a feature that's almost two years old.  Blinksale I'm looking at you with your "Just Added!" Basecamp integration.  It's now May 2008 and that just added feature came out in November of 2006. 

I completely understand getting busy and not updating a site due to time constraints but why not future-proof yourself and instead of always doing "Just Added" start with "Newest Feature!" instead, which is a timeless statement.

Cramped Lists

Aren't bulleted lists supposed to make reading easier?  Then why is it so many blog templates completely ignore the styling of ordered/unordered lists and instead create this clumped indented mass of text?  In fact poorly styled bulleted lists is one reason I migrated away from templates in the first place.  If you're creating a blog or site template please include well spaced li elements in your CSS.


For anyone on my gmail contact list I sincerely apologize by any spam you received from  I was fooled into thinking they had the same feature that Facebook does, point Reunion at your address book and it'll automatically link you with any of your friends that are also on  Instead it uses some slippery wording and a link from Facebook to mass spam everyone on your contact list.  I can't think of a single person that actually wants their entire contact list mailed carte blache so this lands squarely on the Spam Site list.

And Bob's Yer Uncle.

Posted by Shawn Oster on 4/24/2008 9:30 AM | Comments

One of my clients recently switched hosting providers which threw me for a loop because I was doing all their web site deployment using Subversion.  I'd make a change on my development box, commit it, ssh over to their host and issue a matching svn update.  It worked great and gave me a big warm fuzzy.

The new host sadly doesn't have svn installed and while I could probably bug them to install it for me I thought I'd see what others out there were doing when it came to shared hosting.  Seems svn+rsync is a popular choice along with variations on that theme but I wanted something simpler.  Enter Springloops.

Springloops is basically a hosted svn repository that will push your changes via FTP to a deployment server, but that doesn't truly convey just how smooth an experience it really is.  Getting set up is a snap, the interface is well thought out and has a great aesthetic.  You know there is a svn repository behind the interface but it's presented in a very non-threatening for the non-nerd way.

Once you've imported all your files, using whatever svn client you like, you setup a deployment server, giving it your FTP host, path and log in information and from that point on deployment is as simple as a button click.  All of this for free and if you step up to one of their paid plans you get automatic deployment, large storage, more deployment servers and more depending on the level you pick.

All in all I actually like this solution better than what I had before because it's easier for others to interact with your site as well as push deployments.  Anyone looking for a way to use version control (you are using version control, right?) with shared hosting should definitely give Springloops a try.

Posted by Shawn Oster on 4/24/2008 6:02 AM | Comments

At the end of last year I picked up HP's MediaSmart Server because while playing the three computer Monte at home I managed to lose 10 years worth of documents which really shook me up.  It's a small, energy-efficient, quiet little box running Windows Home Server and frankly it rocks.  It automatically backs up my laptop, my desktop and my wife's laptop fully every night and it's pants-wearing-monkey simple to get setup.

I bought the 500GB version but decided I also wanted to move my entire video and music collection over to WHS so last week I picked up another 500GB drive from Amazon (via Giveness) and it arrived yesterday so last night I set about installing the puppy and suffice to say I have never had such an amazing experience installing any piece of hardware other than say an USB flash drive.

Installing a new internal drive is as simple as swinging open the front cover, sliding out a tray, popping the new drive into it and sliding it back in, all while the computer is still running.  After closing the front cover I got a little prompt that new storage was available and asking if it should include it in it's "cloud" of storage.  It was that simple.  It took me longer to unpack the drive than to install it and I have every confidence that I could have easily walked my wife, mother or 2 year-old nephew through the same process.

On a site note, a lot of people give WHS a big "meh", saying you can easily duplicate all that functionality with free software and while that's entirely true I highly doubt it can be reproduced as easily or cheaply. 

By easy I mean that I have confidence that even households without a power geek could quickly setup it up out of the box and that my wife doesn't need me around to do a complete restore or to pick individual files out of an old backup. 

By cheap I mean that my time is money, every hour I spend fiddling with a backup server is an hour I'm not writing new and interesting code, spending with my wife or improving my XBox Live Gamerscore.  Once WHS is running I don't have to do anything, no maintenance or patching since Windows Update takes care of all that.  No monthly fee to a backup provider like Jungle Disk (though if you don't have a backup server I suggest you look at one of the S3-backed providers like Jungle Disk).  No time wasted as I try to pull down a 4 gig image via the wire.

I continue to be impressed by WHS and the ability to hot-swap a new drive just bumped it up even further in my opinion.  The fact that it's such a great product at 1.0 means it can only get better from here.  In the future I'd like to see better integration with Media Center and I'm seeing all kinds of options if you combined it with Live Mesh.

For any household with multiple computers with data you just don't want to lose I can't recommend WHS enough.

Posted by Shawn Oster on 4/22/2008 1:22 PM | Comments

I recently moved my blog from to GoDaddy with BlogEngine.NET as my blog engine and so far everything has been pretty smooth once I figured out how to move all my old posts from blogger into BlogEngine.NET.  Once I got a basic template up and most of the data over I considered it "good enough" but it's always bothered me that I have duplicate data hanging around out there so today I rolled up my sleeves.

I really hate broken links so didn't want to pull my old blog entirely incase anyone was linked to it but I did want them redirected to the new hotness and so after some searching I came across a great link, How To Redirect Blogger Beta To, and that got me about 90% of the way there.  I only ran into a few issues.

The first issue was that his script assumes a Wordpress permalink format (obviously, based on the post) so I had to adjust the regex to BlogEngine.NET style.  After some tweaking and having to once again remember regex I got that working which led me into my next issue.

The second problem was that blogger doesn't use the entire post title for the slug, it stops at a certain character limit whereas BlogEngine.NET uses the full Monty.  I didn't have a magic fix for this so instead I fired up Google Analytics, looked at my top 10 posts and manually adjusted the slug in BlogEngine to match what was coming through blogger and now the redirects come over like butta.

Another minor issue was that the auto-generated sitemap has a lastmod date of 0001-01-01, which really pisses web crawlers off.  At first I thought it was just a few posts and was manually updating them but then realized it was pretty much everything.  I'll probably spin through the posts and set the last modified to the post date but I was a little disappointed that BlogEngine.NET didn't have this logic already built in.

All in all I've been very happy with BlogEngine.NET and I like knowing I can start mucking up the code if I feel really creative.  For another perspective on switching check out Steve Trefethen's thoughts on BlogEngine.NET.

Posted by Shawn Oster on 4/13/2008 10:13 AM | Comments

A few weeks ago Rob Conery foolishly tapped me to help get migrations in SubSonic up to snuff and I've been working on them ever since trying to sneak them into the latest SubSonic beta.  I've changed the way they're implemented slightly from when Rob first talked about them so here's a quick re-introduction to migrations.

Migrations are a way to create and version your database schema using code rather than having to rely on SQL scripts or compare and sync tools.  They allow you to quickly rollback schema changes as well migrate schema changes from your development database to staging and then on to production.  In a nutshell they rock when it comes to database maintaince, versioning and deployment.

Migration Breakdown

A migration is a class that descends from SubSonic.Migration and overrides both the Up() and Down() methods.  Up() is used when going up a version and Down() is used to restore the database schema to the pre-Up() state.  Anything you do in the Up() should be undone in your Down(). 

By convention they are put in a Migrations folder off the root of your project folder.  While the actual name of the class isn't important the name of the file is critical because this is how SubSonic determines which version the migration represents.  The naming convention is 000_MigrationName.cs (or .vb) with the version number represented by leading three numerics, starting at '001' and working your way up.  Currently it's pretty particular about that naming convention so make sure it's exactly three numerics, padded with zeros if needed.  It's convention to name your migration file something descriptive and to also not repeat names, such as:


An Example

Let's start with a simple example and break it down:

using System;
using System.Collections.Generic;
using System.Text;
using SubSonic;
namespace SubSonic {
  public class Migration001:Migration {
    public override void Up() {
      TableSchema.Table t = CreateTable("Flights");
      t.AddColumn("Name", System.Data.DbType.String);
      t.AddColumn("FlightNumber", System.Data.DbType.String, 100);
      t.AddColumn("DateTraveling", System.Data.DbType.DateTime, 0, false, "getdate()"); 
    public override void Down() {

In the example the 'Flights' table is created, then three columns are added to it, followed by the standard SubSonic state columns.  If you don't specify a primary key one will be created for you with the pattern of 'TableNameID', so that's one less thing to worry about.  The Down() method undoes everything we did in the Up() by dropping the 'Flights' table.

Available Methods

Currently the methods available from inside your migration are:

  • CreateTable(string tableName) - This creates and returns a table schema to which you can add your columns, as seen in the example.
  • DropTable(string tableName) - Does exactly what it says.  If your Up() has a CreateTable() you'll need a corresponding DropTable().
  • AddColumn(string tableName, string columnName, ...) - Used to add a new column to an existing table.  It has all the same overloads as TableSchema.Table.AddColumn() except the first parameter is the name of the table you'll be adding columns to.
  • RemoveColumn(string tableName, string columnName) - You only get one guess that this does :)
  • AlterColumn(string tableName, string columnName, ...) - Used to alter an existing column, again, the same overloads as AddColumn.
  • AddSubSonicStateColumns(TableSchema.Table table) - Adds the conventional SubSonic state columns to your table.  I'll be adding another overload that just takes a tableName if you want to add those columns to an existing table.

Running your Migrations

To run your migrations you'll use SubCommander, the same tool used to generate your models but with the 'migrate' command.  The simplest usage is:

sonic migrate

That's it.  It'll use your default provider, look for your migrations in <project>\Migrations and run every migration Up() starting at your database's current migration up the last one found in the Migrations folder.  You can also specify the provider, migration directory and version at the command line like this:

sonic migrate /provider "Northwind" /migrationDirectory "D:\Testing\Migrations" /version 4

A few things to remember:

  • Migrations by convention are looked for in a \Migrations folder off the root of your project, though this can be changed via the command line. (/migrationDirectory "D:\Migrations")
  • You run a migration against a single provider at a time, there is no support for specifying the provider inside the migration.  The main reason is portability, often you'll be running this migrations against different databases and hardcoding the provider name in the migration destroys their usefulness.
  • Migrations will run against the default provider unless otherwise specified via the command line (/provider "Northwind")
  • By default migrations will try to go up to the latest version found in the migrations folder.   To go up or down to a specific version use /version X to indicate which version.
  • To enable migration support a new table 'SubSonicSchemaInfo' will be created in your database, so don't delete it and tell your DBA that it's OK :)


These are things you *should* see before the next beta drop, but don't hold me to it :)

  • Ability to generate your migration code skeleton using sonic.exe.
  • Add RenameTable()
  • Add RenameColumn()
  • Add ability to execute ad-hoc sql, for creating stored procs, views, creating roles, users, etc.
  • Add constraints
  • Add foreign keys
Posted by Shawn Oster on 4/3/2008 1:45 PM | Comments

I just had a friend at work ask that most innocuous of questions, "So, what should I learn if I want to be web developer?" which led us into a pretty good discussion about all things web related and to give him (Hi Nat!) a place to reference my ramblings I thought I'd jot down what I suggested.

Define "Web Developer"

Web developer can pretty much mean anything these days so I find it best to ask yourself what it is you really want to do.  I've been in shops where web developer meant just HTML/CSS while in others the dev does it all, from comps to HTML to database interaction.  In my friend's case it meant creating a dynamic database-driven website from nothing more than a designer's comps and the napkin the business leaders scribbled on in between rounds of golf.  Which was good because that's how I define it.

Stage 1 - Learn HTML/CSS

You've gotta learn the basic currency of the web before you can get fancy pants on it so getting a solid understanding of good, standards-based semantic HTML and CSS (vs. table tag soup) is key.  Regardless of which whiz-bang rocket framework you use in the end it all comes down to pushing HTML so you need to know how to craft good basic pages.

I also suggest forgetting about Dreamweaver, FrontPage or any other HTML editor, for now.  In fact I'd suggest using just a really solid text editor like TextPad, InType or E.  My current favorite is InType because it doesn't require the cygwin install like E yet it has better syntax highlighting and snippet expansion than TextPad.  When learning HTML you want to be as close to the metal as possible.

There are a ton of great books and websites out there teaching this stuff.  Two of my favorites are "Bulletproof Web Design" and "Web Standards Solutions", both by Dan Cederholm, who presents web design (as in the HTML, not Photoshop comp work) in a real-world, useful manner.  Good stuff.

Stage 2 - Learn JavaScript

I'm still iffy on this one since you could argue that JavaScript could come later but I feel it's best to at least get a rudimentary understanding of JavaScript to learn the basics like client-side validation, confirmation boxes and how to use one of the various JavaScript libraries out there like Prototype, jQuery, ExtJS.  Most server-side frameworks try to color the basic way you use JavaScript which I feel can dilute a person's understanding of just what client-side coding is all about.

Stage 3 - Pick Your Poison (Server-Side Framework)

Ahh, the golden ring, the big prize, what it's all about, at least for me, the server-side framework that makes all the magic happen when it comes to dynamic page generation.  This was probably the hardest thing to guide him on because I've worked with most of the major frameworks and they all have pros and cons.  The big three to me are ASP.NET, Rails and PHP.  They all have great support, vibrant communities and very active development.  There is also Java, but I was badly scarred when I learned Java's AWT and Swing frameworks so I'm going to completely ignore it since even thinking about it again makes me whimper :)

ASP.NET - I'm a little biased towards .NET because it offers a great springboard in terms further types of development.  Want to do create a desktop application?  No problem, you already know the IDE and C# (OK, or Visual Basic).  Feel like being more creative and want to do something Flashy?  .NET has you covered with Silverlight.  It's like a gateway drug of development, especially once you start factoring in things like IronPython, IronRuby and MVC.  And despite what some people say ASP.NET isn't just for corporate drones, there's no Web 2.0 site out there that can't be coded in .NET.  Downsides are that it's a little more complex to get started and that it'll warp your fragile little mind when it comes to the bastard child that is WebForms.

Rails - I think learning Ruby (the language of Rails) is a great addition to any developer's knowledge, regardless of what they code in by day.  If someone is interested strictly in single focus, highly dynamic web sites and really has an aversion to Microsoft this is where I'd steer them.  It's a much better abstraction of the web than .NET's WebForms and you can really get rocking quickly without having to understand much with Rails.  The downside is finding jobs in your area looking for entry-level Rails devs.

PHP - This is sort of the monkey in the middle.  There are a ton of great PHP jobs but it's lost a little of it's hipster sizzle, which isn't exactly a bad thing.  PHP is a great choice for the newbie consultant looking to work with small to medium-sized companies because there are a lot of CMS packages in PHP and you can get solid PHP hosting for a song.

In the end I suggested that he go through job descriptions he was interested in (shhh, don't tell his boss) and see what they were asking for in terms of knowledge.  This brings up another good point, why do you want to be a web developer?  If it's just for a better job then I stand by my suggestion.  On the other hand if it's because you want to do Website X or Project Y then that completely changes the game and makes it easier.  You pick the technology and learning curve that will get you quickest to your goal.  In the end users could care less if your site is in Rails, .NET or PHP.

Posted by Shawn Oster on 3/20/2008 7:07 PM | Comments

I decided to self-host my blog over on my own domain, I figured I've been paying for it I may as well put it to good use :) I decided to go with BlogEngine.NET, mostly because it was super simple to get setup and seemed to have pretty active development. I think I've ported most of the articles and comments over though a few stragglers may be around. I'll be posting all my pearls and nuggets over there so update to the new RSS address.

I know some of the layout may seem funky, I'm currently porting a free CSS template from a fixed-width layout to a fluid one instead and I haven't pushed everything yet. For the record I used Yahoo's grid builder to come up with the CSS layout and it's damn snazzy. Usually I build up my divs by hand or crib one of my prior fluid layouts but this time I tried something different and I'm impressed. Clean CSS/HTML, though I could use a little more verbose id and class selectors.

Posted by Shawn Oster on 2/28/2008 3:18 PM | Comments

The cool kids over on the other side of the fence always make these really cool "cheat sheets" for whatever bit of tech kit they're using and I fully expect someone with some good design skills to produce one for ASP.NET MVC.

You hear that Rob Conery?  Scott Hanselman?  How about you Phil Haack?  I fully expect Scott Guthrie, who is a Word among Bytes, to conscript some stylish hipster graphic designer to produce a masterful, stylish and yes, useful cheat sheet for the MVC masses at Mix '08, an event I sadly won't be attending because my company considers computers and those that make them work to be second class citizens.  I'm lucky if I get  to upgrade my IDE before the next one comes out much less attend an actual conference.  I've heard of conference swag but I've never actually received any of this mythical bounty.

Still, I desire, want and dare I say expect said cool cheat sheet.

Here are some examples for those that need some prompting and design ideas and to figure out just what in the hell I'm talking about:

Posted by Shawn Oster on 2/26/2008 12:45 PM | Comments

I ported the CopySourceAsHtml to work with Visual Studio 2008.  There are some workarounds to get the existing addin to work with Visual Studio 2008 but they all assume you have 2005 installed, which I don't.  I recompiled from source, built against .NET 3.0, removed some crufty code thanks to FxCop and removed a call into olepro32.dll that wasn't needed.  I'll provide the updated source if anyone cares, this is just a quick posting as I'm flying out the door :)

To Install

  1. Download the CopySourceAsHtml AddIn zip.
  2. Unzip to \My Documents\Visual Studio 2008\Addins, if the Addins folder doesn't exist just create it.
  3. Restart Visual Studio (you did close it first right?)
  4. Right-click some selected code and you'll have a new Copy As HTML... menu item, that's the gold, click it. 
  5. Check the boxes in the dialog that comes up to your delight and then paste into your blog software or forum post.
  6. IMPORTANT: This Addin generates HTML code, so remember to switch into the HTML view in your blog software or forum edit box. 
  7. Bob's yer uncle


This is how a chuck of code looks when pasted (you'll notice it uses your exact color and font settings):

public void Select_ColumnList_Specified()
    SqlQuery qry = new Select("productid", "productname").From(Northwind.Product.Schema);
    ANSISqlGenerator gen = new ANSISqlGenerator(qry);
    string selectList = gen.GenerateCommandLine();
    Assert.IsTrue(selectList == "SELECT [dbo].[Products].[ProductID], [dbo].[Products].[ProductName]\r\n");

The Source

UPDATE: I've finally zipped up the source and uploaded it by request.  Remember, I'm not the original author so all the good credit goes to someone else, I'm just the monkey that made it work on Visual Studio 2008.  Here it is for your enjoyment: