The Daily Parker

Politics, Weather, Photography, and the Dog

Two on technology

The first, from the Poynter Institute, concerns how Michigan Governor Jennifer Granholm's staff made Twitter into journalism:

I tuned in an Internet broadcast of ... Granholm's annual state of the state speech because it was expected to be laden with energy and environment issues. On impulse I logged into Twitter and asked my followers if there had been a hashtag established for the speech. There was: MiSOTS (Mich. State of the State).

To my amazement, the hashtag had been established by the governor's staff—who were tweeting major points of Granholm's speech as she made them.

Meanwhile, many, many, many other people used this hashtag to challenge points, support points, do some partisan sniping, question assumptions, add perspective, speculate about what was going on, and provide links to supporting information—including a transcript of the speech and the opposite (Republican) party's response.

(Emphasis in original.)

The second, Mark Morford musing about technology in general:

To paraphrase a renowned philosopher, we just keep making the pie higher. This is the nature of us. It is, in turns, both wonderful and terrifying.

It seems there are only two real options, two end results of our civilization's grand experiment. Either the stack becomes so high -- with our sense of wonder and integrity rising right along with it -- that it finally lifts us off the ground and transports us to some new realm of understanding and evolution, or it ultimately topples over, crashes and mauls everything that came before, because we just didn't care enough to stop and smell the astonishment.

You have but to remember: How many ancient, advanced civilizations have collapsed under the weight of their own unchecked growth, their own technological advances, their own inability to stay nimble and attuned to the crushing marvel of it all? Answer: all of them.

Both are worth reading in full.

Annoying software design (professional edition)

Developers generally don't like third-party UI controls because they're generally frustrating to use. Case in point: in the Infragistics Windows Forms controls package, the UltraGridColumn has sucked a substantial portion of my day away.

If you don't write software, you still appreciate it when it works simply and intuitively. You want to search for something, you go to Google and type in a search term. Brilliant. When you go to some company's website because you want to call the company, you look for something called "contact us" and click it. If you don't get the address and phone number of the company after clicking that link, you get irritated: the simple, intuitive thing didn't work. Jakob Nielsen is all over that stuff.

So. I have a simple problem, which is how to make a column in a grid grey out so my users don't inadvertently edit something they shouldn't. What I expect to write is something like this—or I would, if the member existed:

theReadOnlyColumn.Enabled = false;

Sadly, there is no "Enabled" member. So how about using a member that actually does exist?

theReadOnlyColumn.IsReadOnly = true;

Interesting. That member doesn't allow you to change its value. In fairness, the particle "Is" suggested it was a read-only member (ironic, that), but still, it looked like the right thing to do.

But no, here's the intuitive, simple, gosh-how-didn't-I-see-that-right-away thing to do:

theReadOnlyColumn.CellActivation = Activation.Disabled;

<rant>

This sort of thing happens when developers create software based on how it works, rather than what it does. It's sloppy, it reflects an inability to think like the person using the product, and it's compounded by a criminal lack of clear "how-to" documentation. (The Infragistics documentation site appears to have no way to search for concepts, requiring you to figure out how Infragistics developers organize things on your own.) This really, really annoys me, and is why I avoid using their products.

</rant>

Unbelievable cold in Alaska

The weather has cooled off a bit in the interior of Alaska:

Friday marked day six of the worst cold snap to hit Fairbanks in several years and there is no relief in sight for residents who live in Alaska’s second-largest city — or the business owners they call to bail them out when their cars, pipes and septic tanks freeze.

The temperature in North Pole dipped to 55 degrees below zero on Wednesday night, the lowest temperature recorded in the greater Fairbanks area during what has been six days of severe cold. It was “only” 46 below at 4 p.m. Friday in North Pole, but the temperature was “dropping by the hour,” meteorologist Austin Cross at the National Weather Service in Fairbanks said.

Friday marked the fifth day in the last six the temperature at Fairbanks International Airport hit 40 below or colder; it was only 38 below at the airport on New Year’s Day.

Forecasters expect temperatures in Fairbanks this weekend will likely touch 50 below and there is no indication the cold wave will dissipate anytime soon.

Since I don't read Alaskan newspapers often, and I'm used to seeing cold Alaskan temperatures on the Weather Now extremes page, I actually first heard this when ten people emailed me to complain about a bug in Weather Now. It turns out, the news story above linked to Weather Now and drove 2,400 unique visitors to the site in six hours.

I should know better. Fortunately my servers easily handle 10,000 page views per hour, but still, seeing a traffic spike like that caught me a little off-guard.

Turning Japanese

I've given up for the evening attempting to configure a recalcitrant firewall. To cheer up, I turn to Paul Krugman, who reminds us that a 0% Fed rate means we're in trouble:

ZIRP!

That's zero interest rate policy. And it has arrived. America has turned Japanese.

This is the thing I’ve been afraid of ever since I realized that Japan really was in the dreaded, possibly mythical liquidity trap. ...

Seriously, we are in very deep trouble. Getting out of this will require a lot of creativity, and maybe some luck too.

At least I think I've figured out where I mis-configured the firewall....

LINQ to FogBugz fun

Most Daily Parker readers can skip this (long) post about software. But if you're interested in C# 3.0, LINQ, or FogBugz, read on.

I use FogBugz's time tracking tool to provide tracability in my billing. If I bill a client 2.75 hours for work on a bug, I want the client to see the exact times and dates I worked on the bug along with all the other details. And because I track non-billable time as well, and I often work in coffee shops or places like the Duke of Perth, I wind up with lots of tiny time intervals that I have to aggregate to produce a bill.

My time sheet today, for example, looks like this:

Start End Case Title
7:11 AM 7:23 AM 901 Walking the dog (November)
8:18 AM 9:32 AM 950 FogBugz to LINQ project
9:32 AM Stop Work 902 Blogging (November)

But what I need for QuickBooks looks like this:

Case Hours
901: Walking the dog (November) 0.20
950: FogBugz to LINQ project 1.23
902: Blogging (November)  

(The last bit has no time because I'm still working on it.)

This is the perfect kind of thing to waste a few hours on while learning some new programming tricks. (Code here.)

First: the entity

To use LINQ to SQL in its pure form, you first have to create entity classes that pretty much exactly mirror the tables you're interested in. My target, the FogBugz timeintervals table, yields an entity that looks like this:

[Table(Name="timeinterval")]
class TimeInterval
{
	[Column(Name="ixInterval",IsPrimaryKey=true)]
	public int Identity;

	[Column(Name = "ixPerson")]
	public int PersonId;

	[Column(Name = "ixBug")]
	public int CaseId;

	[Column(Name = "dtStart")]
	public DateTime StartDate;

	[Column(Name = "dtEnd")]
	public DateTime EndDate;
}

Because I'm interested in the aggregate time spent on each case, I also created a simple structure to hold that info:

struct AggregateInterval
{
	public int CaseId;
	public double TotalHours;
}

Second: the console app

To use LINQ to SQL, you need to include a reference to the System.Data.Linq assembly, and import the appropriate namespaces:

#region Copyright ©2008 Inner Drive Technology

using System;
using System.Collections.Generic;
using System.Data.Linq;
using System.Data.Linq.Mapping;
using System.Linq;

#endregion

namespace InnerDrive.Research.FogBugz
{
	class Program
	{
		static void Main(string[] args)
		{

Next, set up the data context:

DataContext context = new DataContext(" (your connection string) ");
context.ObjectTrackingEnabled = false;
Table<TimeInterval> table = context.GetTable<TimeInterval>();

(I turned off object tracking because this is a read-only application. Setting ObjectTrackingEnabled to false improves performance, but the data context will throw an exception if you call DataContext.SubmitChanges().)

I actually need two queries, one to get the table rows and another to aggregate them. The reason for this is that my aggregation depends on getting the total hours each interval represents; LINQ to SQL won't do that. Here's the first query:

// FogBugz stores time as UTC; I want the time for today in Chicago, not London
DateTime startDate = DateTime.Today.ToUniversalTime();

var intervals =
	from interval in table
	where interval.EndDate <= startDate.AddDays(1) &
		interval.StartDate >= startDate
	group interval by interval.CaseId
	into grouping
	select grouping;

The second query does the aggregation, transforming the first query into an IEnumerable<T> and returning AggregateInterval structs:

IEnumerable<AggregateInterval> aggregation =
	from grouping in intervals.AsEnumerable()
	select new AggregateInterval
	{
		CaseId = grouping.First().CaseId,
		TotalHours = grouping.Sum(t => t.EndDate.Subtract(t.StartDate).TotalHours)
	};

Neither query has fired yet, by the way. That's another cool thing about LINQ. Both queries fire when I output the data, which is trivially simple:

foreach(var item in aggregation)
{
	Console.WriteLine(string.Format("Case {0} = {1:0.00}", item.CaseId, item.TotalHours));
}
Console.ReadLine();

That's it. Share and enjoy.

Down the memory hole

Every so often, one must wipe and reinstall his main computer. This is not fun. Even Parker finds it boring, and he sleeps all day.

Still, my main box (a Dell D620) now runs so much faster it's making me cry. So, several hours of boring work will save me several dozen hours waiting for the damn computer.

Heading home

Ah, family. I'm glad I got a chance to unwind with the Ps after my conference. But I do miss my dog.

Tomorrow: or, rather, tonight after 7pm CDT: check out Weather Now for, well, something appropriate to the season.

About this Blog

I'm David Braverman, this is my blog, and Parker is my 8-month-old mutt.

Here are the main topics on the Daily Parker:

  • Parker, my dog, whom I adopted on September 1st.
  • Biking. I ride my bikes a lot. Last year I prepared for two Century rides but, alas, my gallbladder decided to explode a week before the first one. I might not have a lot to say until later in the spring, but I have big plans in 2007.
  • Jokes. All right, I admit: when I'm strapped for ideas, sometimes I just post a dumb joke.
  • Politics. I'm a moderate-leftie by International standards, which makes me a radical left-winger in today's United States. Less than 701 days remain in the worst presidential administration in history, so I have plenty to write about.
  • Software. I own a small software company in Evanston, Illinois, and I have some experience writing software. I see a lot of code, and since I often get called in to projects in crisis, I see a lot of bad code. Posts in this blog about software will likely be cross-posted from the blog I'm about to start, Inner Drive Software.
  • The weather. I've operated a weather website for more than seven years. That site deals with raw data and objective observations. Many weather posts also touch politics, given the political implications of addressing climate change under a President who's beholden to the oil industry.

This is public writing, too, so I hope to continue a standard of literacy (i.e., spelling, grammar, and diction) and fluidity of prose that makes you want to keep reading.

So thanks for reading, and I hope you continue to enjoy the blog.