The Daily Parker

Politics, Weather, Photography, and the Dog

Moments in travel derpitude; or, check your phone first

We live in a wondrous age of travel. The mobile phone has revolutionized it: You can get travel alerts, boarding passes, taxis, delay notifications—everything you need.

Against that you have the state of the human brain at 5 in the morning.

According to my mobile phone, I actually woke up at 6. But I'm not in my home time zone. Nor have I exactly gotten enough sleep this week. So when I woke up at 6, I started executing the Leave Louisville Plan, which did not, unfortunately, include checking my mobile phone for flight delays.

It's only a one-hour delay. But it's an hour I could have stayed in bed.

Smart phone, dumb guy.

Cool part of my job

West Monroe Partners (my employer, who have no editorial control over this blog, nor do they endorse anything I write here) has a thriving mergers and acquisitions practice. In order to provide appropriate advice to our private equity clients, we perform "diligences," which are thorough investigations of a company's strengths and weaknesses. Almost always, the target companies have technology assets that we evaluate as part of the diligence. Which is why I'm up at the crack of dawn in a hotel outside Phoenix.

Obviously I can't disclose anything about a diligence effort, or what kind of transaction is contemplated, or even what industry the company is in. In fact, sometimes I won't even know who the target is until I get there, as is the case today. So I am able to say nothing more about today's work than I'm in Arizona.

Still, the work is really interesting. We get pretty deep into the target's processes, methodologies, even sometimes their actual code and infrastructure. As a technology professional, it gives me exposure to different ways of doing things, especially what works and what doesn't. And it gets me out of the house for a day or two.

Of course, this will slow down posting a bit this week...

Why is this Ctrl-F not like other Ctrl-Fs?

Microsoft veteran Raymond Chen explains why Ctrl-F doesn't "find" in Outlook, like it does in every other modern application across the universe:

It's a widespread convention that the Ctrl+F keyboard shortcut initiates a Find operation. Word does it, Excel does it, Wordpad does it, Notepad does it, Internet Explorer does it. But Outlook doesn't. Why doesn't Outlook get with the program?

Rewind to 1995.

The mail team was hard at work on their mail client, known as Exchange (code name Capone, in keeping with all the Chicago-related code names from that era). Back in those days, the Ctrl+F keyboard shortcut did indeed call up the Find dialog, in accordance with convention.

And then a bug report came in from a beta tester who wanted Ctrl+F to forward rather than find, because he had become accustomed to that keyboard shortcut from the email program he used before Exchange.

I'll let Chen give you the punchline.

Lucene coming to Weather Now

I have to dash off to a meeting in a few minutes, then to Wrigley. So this is more of a note to myself.

Lucene.NET will be coming to Weather Now, I hope in a few weeks. This will massively improve its piss-poor searching, and allow me to do a few other things as well given Lucene's amazing search capabilities.

Unfortunately, Weather Now ranks third in development priorities behind my employer and my long-suffering freelance client. At least it kind of runs itself these days.

Unexpected master class

Imagine you're sitting on your front stoop, strumming your guitar, and Eric Clapton comes out of nowhere to give you some pointers.

That's about what happened to me today. Earlier this week, Jon Skeet (described by Scott Hanselman as "the world's greatest living programmer) noticed something I posted on the IANA Time Zone list, and asked me about the Inner Drive Time Zone library.

So I sent him the package.

And this afternoon, he sent me a benchmark that he wrote for it. Just like that.

Of course, the benchmark showed that my stuff was about 10% as fast as the Noda Time library, an open-source project he curates. So, having a couple of hours for "personal development time" available, I optimized it.

The specific details of the optimization are not that interesting, but I managed to more than double the library's performance by changing about ten lines of code. (It's now 20% as fast as Noda.) Along the way I exchanged about 10 emails with Skeet, because he kept making really crack suggestions and giving me valuable feedback about both my design and his.

That was cool.

Yes, that's an improvement (Comcast win!)

A Comcast installer showed up this morning within the appointed time frame, and in about an hour had taken my apartment the Inner Drive Technology World Headquarters from this:

To this:

I almost want to dance around singing "A Whole New World" but that would be very disturbing to my self image.

Instead I'll head into the office, getting in a little earlier than I expected, and come home to real Internet speeds. In fact, I think right now I'll watch something on YouTube just because I can.

Goodbye, AT&T. Hello Comcast, you gorgeous thing.

Scary software deployment

Jez Humble, who wrote the book on continuous delivery, believes deployments should be boring. I totally agree; it's one of the biggest reasons I like working with Microsoft Azure.

Occasionally, however, deploying software is not at all boring. Today, for example.

Because Microsoft has ended support for Windows Server 2008 as of next week, I've upgraded an old application that I first released to Azure in August 2012. Well, actually, I updated it back in March, so I could get ahead of the game, and the boring deployment turned horrifying when half of my client's customers couldn't use the application because the OS upgrade broke their Windows XP/IE8 user experience. Seriously.

All of my client's customers have now upgraded to Chrome, IE11, or Firefox, and I've tested the app on all three browsers. Everything works. But now I have to redeploy the upgrade, and I've got a real feeling of being once-bitten.

The hard part, the part that makes this a one-way upgrade, is a significant change to the database schema. All the application's lookup lists, event logging, auditing, and a few other data structures, are incompatible with the current Production version. Even if there weren't an OS upgrade involved, the database changes are overdue, so there is no going back after this.

Here are the steps that I will take for this deployment:

  1. Copy current Production database to new MigrationTest database
  2. Upgrade MigrationTest database
  3. Verify Test settings, connection strings, and storage keys
  4. Deploy Web project to Test instance (production slot)
  5. Validate Test instance
  6. Deploy Worker project to Test instance (production slot)
  7. Validate Worker instance
  8. Shut down Production instance
  9. Back up Production database to bacpac
  10. Copy Production database within SQL instance
  11. Upgrade Production database
  12. Verify Production settings, connection strings, and storage keys
  13. Deploy solution to Production instance (staging slot)
  14. Validate Production Web instance
  15. Validate Production Worker instance
  16. VIP swap to Production

Step 1 is already complete. Step 2 will be delayed for a moment while I apply a patch to Visual Studio over my painfully-slow internet connection (thanks, AT&T!). And I expect to be done with all of this in time for Game of Thrones.

How to look up Azure table data by ID

Short answer: You can't. So don't try.

Back in 2007, when I wrote a scheduling application for a (still ongoing!) client, Azure was a frustrating research project at Microsoft. Every bit of data the application stored went into SQL Server tables including field-level auditing and event logs.

The application migrated to Azure in August 2012, still logging every audit record and event to SQL tables, which are something like 10x more expensive per byte than Azure Table Storage. Recently, I completed an upgrade to the Inner Drive Extensible Architecture™ so it can now use Azure table storage for both.

The old application knew nothing about this. So upgrading the application with the new IDEA bits worked fine for writing to the audit and event logs, but completely broke reading from them.

Here's the code the app uses displaying a specific audit record so an administrator can see the field-level details:

// Get the repository from Castle IoC:
var repo = ActiveContainer.Instance.Container.Resolve<IAuditRepository>();

// Get the individual audit record by ID:
var audit = repo.Find(id);

That's great if the audit record uses a database identity key. Unfortunately it does not; it uses an Azure partition and row key combination.

I agonized for a couple of days how to fake database identities in Azure, or how to write a mapping table, or do some other code- or data-intensive thing or another. Then this afternoon, epiphany!

The user viewing an audit record is doing it in the context of reviewing a short list of audit headers. They click on one of these headers to pop up the detail box. The detail box uses the audit ID like this: https://scheduler.myclient.com/Auditing/AuditDetailViewer/12345.

It turns out, the only time a user cares about audit details is when she has the audit list right in front of her. So the audit ID is irrelevant. It only has to be unique within the context of the user's experience.

Here's the solution. In the Auditing class, which generates the audit list, I do this:

foreach (var item in orderedAudits)
{
	// Temporal cohesion: Add identity to Audit before using
	AddIdentity(item);
	Cache(item);
	CreateAuditRow(placeHolder, isObjectSpecified, item, timeZone);
	// End temporal cohesion
}

The cache uses least-frequently-used scavenging with a capacity of 512 items. (If the one user who cares about auditing ever needs to see more than 512 audit items in one list, I'll coach him not to do that.) Items live in the cache until it gets full, at which time the least-used ones are removed. This lets me do this in the audit detail view's control code:

var audit = Auditing.Find(id);

The Auditing.Find method simply plucks the item from the cache. If it returns null, oops, the audit details are missing or have expired from the cache, sorry. Just rerun the list of audits that you just clicked on.

I'm going to use a similar approach to the event log.

Waiting for software to deploy...

I'm uploading a couple of fixes to Inner-Drive.com right now, so I have a few minutes to read things people have sent me. It takes a while to deploy the site fully, because the Inner Drive Extensible Architecture™ documentation (reg.req.) is quite large—about 3,000 HTML pages. I'd like to web-deploy the changes, but the way Azure cloud services work, any changes deployed that way get overwritten as soon as the instance reboots.

All of the changes to Inner-Drive.com are under the hood. In fact, I didn't change anything at all in the website. But I made a bunch of changes to the Azure support classes, including a much better approach to logging inspired by a conversation I had with my colleague Igor Popirov a couple of weeks ago. I'll go into more details later, but suffice it to say, there are some people who can give you more ideas in one sentence than you can get in a year of reading blogs, and he's one of them.

So, while sitting here at my remote office waiting for bits to upload, I encountered these things:

  • The bartender's iPod played "Bette Davis Eyes" which immediately sent me back to this.
  • Andrew Sullivan pointed me (and everyone else who reads his blog) towards the ultimate Boomer fantasy, the live-foreverists. (At some point in the near future I'm going to write about how much X-ers hate picking up after both Boomers and Millennials, and how this fits right in. Just, not right now.)
  • Slate's Jamelle Bouie belives Wisconsin's voter rights decision is a win for our cause. ("Our" in this case includes those who believe retail voter fraud is so rare as to be a laughable excuse for denying a sizable portion of the population their voting rights, especially when the people denied voting rights tend to be the exact people who Republicans would prefer not to vote.)

OK, the software is deployed, and I need to walk Parker now. Maybe I'll read all these things after Game of Thrones.

Clbuttic software mistake

Apparently OCR software sometimes still has trouble interpreting older books:

[A]s Sarah Wendell, editor of the Romance blog  Smart Bitches, Trashy Books noticed recently, something has gone awry. Because, in many old texts the scanner is reading the word ‘arms’ as ‘anus’ and replacing it as such in the digital edition. As you can imagine, you don’t want to be getting those two things mixed up.

The resulting sentences are hilarious, turning tender scenes of passionate embrace into something much darker, and in some cases, nearly physically impossible. The Guardian’s Alison Flood quotes some of the best:

From the title Matisse on the Loose: “When she spotted me, she flung her anus high in the air and kept them up until she reached me. ‘Matisse. Oh boy!’ she said. She grabbed my anus and positioned my body in the direction of the east gallery and we started walking.”

And ‘”Bertie, dear Bertie, will you not say good night to me” pleaded the sweet, voice of Minnie Hamilton, as she wound her anus affectionately around her brother’s neck. “No,” he replied angrily, pushing her away from him.”‘ Well, wouldn’t you?

As Flood notes, a quick search in Google Books reveals that the problem is widespread. Parents should keep their children away from the ebook edition of the 1882 children’s book Sunday Reading From the Young. It all seems perfectly innocent until… “Little Milly wound her anus lovingly around Mrs Green’s neck and begged her to make her home with them. At first Mrs Green hesitated.” And who can really blame her?

Clbuttic.