Coding Horror

programming and human factors

Not All LCD Panels Are Created Equal

When I purchased my last set of LCD monitors, I didn't fully understand that not all LCD panels are created equal. There are three distinct families of LCD display technology, each with their own tradeoffs and peculiarities. Before you buy a new LCD display, you should take note of what kind of panel technology you're investing in.

Color Reproduction Viewing Angle Response Time Price Quirks
*-IPS
In Plane Switching
Excellent Excellent Good Expensive Slight color tinges may be visible at an angle.
*VA
Vertical Alignment
Good Good Average Reasonable Colors shift when viewed at an angle.
TN
Twisted Nematic
Average Average Excellent Inexpensive Limited to 6-bit color; restricted vertical viewing angles.

Most panels these days are TN, which isn't much of a surprise; if a consumer has the choice between a 22" or 24" display at the same price, they're naturally going to go with the larger one. Although TN displays can be quite good, they all suffer to some degree from the genetic defects of their TN family lineage.

Right now, one of my monitors is PVA, and the other two are TN. The color reproduction is slightly more pleasing on the PVA monitor, but the TN is in the ballpark. I'm only able to tell because the monitors are literally right next to each other. What I do notice in regular use on my TN displays, however, is their incredibly limited vertical view angle. I'm no graphics designer, but even I can see that colors vary quite noticeably in intensity from top-to-bottom on my TN display. You have to keep your head perfectly aligned in the tiny "sweet spot" to see consistent vertical color on these displays. Horizontally, it's fine, but vertically, it is far too sensitive.

Unfortunately, the vast majority of LCDs on the market now are TN. You can opt to pay a little bit more for one of the few models with *VA -- if there are any available in the size you want. *-IPS is widely considered the best all around LCD display technology, but it is rapidly being pushed into the vertical "pro" graphics designer market due to the big jump in price. It's usually not an option, unless you're willing to pay more than twice as much for a monitor.

But even within the TN and *VA families, there are new improvements and variants being introduced all the time. For example, LED backlighting, which is just now catching on for laptops, should eventually trickle down to the humble TN display. That one upgrade will allow it to reproduce all 100% of the NTSC color gamut for the first time. There's a more detailed chart at LCD Resource that illustrates how the various LCD display technologies have evolved over time. I've adapted it here in simple HTML:

Bright Black Level Resp Time Color
Depth
Gamma Sat View Angle (H) View Angle (V) Input Lag Cost
TN                    
20/22" TN                    
P-MVA                    
20"+ P-MVA                    
PVA                    
20"+ PVA                    
S-PVA                    
S-IPS                    
20" S-IPS                    
AS-IPS                    
A-TW-IPS                    

Don't get discouraged, though. Modern, inexpensive TN based LCDs can still perform quite well, as you can see in this review of the Samsung 245BW. The main downside is-- you guessed it-- the severely limited vertical viewing angles.

The next time you set out to buy a LCD, be informed about the underlying display technology you're getting. If you're in the market, I recommend paging through the excellent LCD Monitor Buying guide at X-bit Labs, which covers that crucial aspect, and much more.

Discussion

The F5 Key Is Not a Build Process

Hacknot's If They Come, How Will They Build It? is a harrowing series of 29 emails sent over a two week period.

To: Mike Cooper
From: Ed Johnson

Mike,

I finally got CVS access today from Arnold. So I've checked out the AccountView module OK, but it won't compile. The Eclipse project has dependencies on about five other projects. I tried checking those dependent projects out as well, but a few of them won't build at all? How are you managing to develop this thing when the dependent projects don't build?

Ed

From: Mike Cooper To: Ed Johnson

Oh yeah - I forgot to tell you about the dependent projects. I always forget about them. I'm not so surprised some of them don't build for you. I've got versions on my machine that build OK but I haven't checked them in for a while. Gimme about 15 minutes and I'll check them in, then you should be right to go.

M.

It's a cautionary tale about a serious software project pathology: the pain of getting a new developer up and running on an existing software project. It's startlingly common.

This points us to one of the most important health metrics on a software development project. How long does it take for you to get a new team member working productively on your project? If the answer is more than one day, you have a problem. Specifically, you don't have a proper build process in place.

I've talked before about the importance of a build server as the heartbeat for your project. A sane software development project has automatic daily builds, performed on a neutral build server. If your team is in the habit of producing those kind of daily builds, it's difficult to accumulate the deep technical debt enumerated in all those emails. If the build server can do it, so can your newly hired coworkers.

But based on the development practices I've often seen on site with customers, I think setting up a build server might be an unrealistic goal, at least initially. It might not get done. We should shoot for a more modest goal to start with.

visual-studio-debug-menu

Here's how most clients I work with build a project:

  1. Open the IDE
  2. Load the solution
  3. Get latest
  4. Press F5 (or CTRL+SHIFT+B)

If your "build process" is the F5 key, you have a problem. If you think this sounds ridiculous-- who would possibly use their IDE as a substitute for a proper build process? -- then I humbly suggest that you haven't worked much in the mainstream corporate development world. The very idea of a build script outside the IDE is alien to most of these teams.

Get your build process out of the IDE and into a build script. That's the first step on the road to build enlightenment.

The value of a build script is manifold. Once you have a build script together, you've created a form of living documentation: here's how you build this crazy thing. And naturally this artifact is checked into source control, right alongside the files necessary to build it (and even the database necessary to run it, too). From there, you can begin to think about having that script run on a neutral build server to avoid the "Works On My Machine" syndrome. You can also consider all the nifty ways you could enhance the script with stuff like BATs, BVTs, and Functional Tests. Your build server can become the heartbeat of your project. There's no upper limit on how clever you can be, and how many different build scripts you can come up with. Build scripts can be incredibly powerful-- but you'll never know until you start using them.

The F5 key is not a build process. It's a quick and dirty substitute. If that's how you build your software, I regret that I have to be the one to tell you this, but your project is not based on solid software engineering practices.

So, if you don't have a build script on your project, what are you waiting for?

Discussion

Embracing Languages Inside Languages

Martin Fowler loosely defines a fluent interface thusly: "The more the use of the API has that language like flow, the more fluent it is." If you detect a whiff of skepticism here, you're right: I've never seen this work. Computer languages aren't human languages.

Let's look at a concrete example from Joshua Flanagan. Here's how we define a regular expression in the standard way:

<divs*class="game"s*id="(?<gameID>d+)-game"(?<content>.*?)
<!--gameStatuss*=s*(?<gameState>d+)-->

Here's how we'd define that same regular expression in Joshua's fluent interface.

Pattern findGamesPattern = Pattern.With.Literal(@"<div")
.WhiteSpace.Repeat.ZeroOrMore
.Literal(@"class=""game""").WhiteSpace.Repeat.ZeroOrMore.Literal(@"id=""")
.NamedGroup("gameId", Pattern.With.Digit.Repeat.OneOrMore)
.Literal(@"-game""")
.NamedGroup("content", Pattern.With.Anything.Repeat.Lazy.ZeroOrMore)
.Literal(@"<!--gameStatus")
.WhiteSpace.Repeat.ZeroOrMore.Literal("=").WhiteSpace.Repeat.ZeroOrMore
.NamedGroup("gameState", Pattern.With.Digit.Repeat.OneOrMore)
.Literal("-->");

So we're replacing a nice, succinct one line regular expression with ten lines of objects, methods, and named enumerations. This is progress?

I'll grant you that I am probably unusually familiar with regular expressions, even by developer standards. There's a reason they have a reputation for being dense and inscrutable. I've definitely seen some incredibly bad regular expressions in my day. But in my professional opinion, that regex was a well written one. I had no problem reading it. Adding a ton of hyper-dense object wrappers to that regex makes it harder for me to understand what it does.

The new syntax Joshua invented is great, but it's specific to his implementation. Although it may seem like a good idea to use these kinds of training wheels to "learn" regular expressions, I'd argue that you aren't learning them at all. And that's a shame, because regular expression syntax is a mini-language of its own. Once you learn it, you can use it anywhere; it works (almost) the same in every environment.

The Subsonic project attempts to do something similar for SQL. Consider this SQL query:

SELECT * from Customers WHERE Country = "USA"
ORDER BY CompanyName

Here's how we would express that same SQL query in SubSonic's fluent interface:

CustomerCollection c = new CustomerCollection();
c.Where(Customer.Columns.Country, "USA");
c.OrderByAsc(Customer.Columns.CompanyName);
c.Load();

I've mentioned before that I'm no fan of object-oriented rendering when a simple string will suffice. That's exactly the reaction I had here; why in the world would I want to use four lines of code instead of one? This seems like a particularly egregious example. The SQL is harder to write and more difficult to understand when it's wrapped in all that proprietary SubSonic object noise. Furthermore, if you don't learn the underlying SQL-- and how databases work-- you're in serious trouble as a software developer.

But I can see the rationale behind these types of database code generation tools:

  1. They "solve" the object-relational mapping problem for you (and if you believe that, I have a bridge you might be interested in)
  2. you get intellisense
  3. your database is strongly typed
  4. the compiler now "understands" the database, or at least the generated classes that represent the database.

I definitely sympathize with the desire to produce less code, and that's the whole point of database code generation tools. Personally, I would argue that most of these benefits could be realized with smarter IDEs that actually understood native SQL strings (or regular expressions), rather than relying on a slew of generated code and complicated, proprietary object syntax.

But let's take a step back and think about what's really happening here. In both cases, we are embedding one language inside another. SQL is a language. Regular expressions are a language. Wrapping those languages inside a bunch of mega-verbose fluent interface ObjectJunk-- just so we can pretend we're writing code in our primary language-- is a total cop-out. Fluent interface object wrappers feel like a nasty hack to me.

Why can't we embrace the language-inside-a-language paradigm, rather than running and hiding from it? These domain specific languages exist because they are optimized for processing strings and data efficiently. Avoiding them is counterproductive.

Perhaps the ultimate solution is to redefine the underlying language to incorporate the features of another language.

Consider how Perl integrates the regular expression language:

while (my $line = <IN>) {
while ( $line =~ /(Romeo|Juliet|Mercutio|Tybalt|Friar w+)/g ) {
my $character = $1;
++$counts{ $character };
}
}

Here's how C# 3.0, with LINQ, integrates the SQL language:

var c = from Customer in Customers
where Customer.Country == "USA"
orderby Customer.CompanyName
select Customer;

Note the conspicuous lack of ObjectJunk. No explosion at the parens and periods factory. No MassivelyLongTextEnumerations to deal with. There's nothing but code that looks like exactly what it does. And that's a beautiful thing.

Embrace the idea of languages inside languages. In The Land of Strings, we speak regular expressions. In The Land of Data, we speak SQL. Oh sure, you can pretend those languages don't exist, and hide out in the Kingdom of Nouns-- but you're only cheating yourself out of a deeper understanding of how things really work in those other places. Fluent interface object wrappers may seem like a helpful convenience, but they're actually an ugly hack, and a terrible substitute for true language integration.

Discussion

Your Desktop Is Not a Destination

I'm of two minds on the desktop.

If you're really using your computer, your desktop should almost never be visible. Your screen should be covered with information, with whatever data you're working on. I can't imagine why you'd willingly stare at a static background image-- or even a background image covered with a sea of icons. Unless you consider your computer a really expensive digital picture frame, I suppose.

The desktop background, as I see it, is completely superfluous. My desktop "background" right now is plain black. And that doesn't bother me in the least, because none of it is visible. I have browser windows and programs-- the things I'm actually doing -- covering all three monitors. When I'm using a computer, I make it my goal to never see the desktop background. Every time the desktop background is visible, that means I'm making poor use of my monitor pixels. Whenever the desktop background peeks through, I treat it like a reprimand.

I won't lie to you. I don't always achieve my goal. The desktop is sometimes visible when I'm working. But I do try my darndest to cover all my monitors with something useful, and a static desktop background just isn't useful.

Ubuntu 7.10 'Gutsy Gibbon' desktop

OSX 10.5 'Jaguar' desktop

That said, it is fun to have a unique desktop background. Even if you rarely see it. In the above official screenshots from Apple and Canonical, the desktop background images were picked quite intentionally. I've done this myself; when I put together those pictures of the monitor arms, I specifically chose an interesting desktop background to show it off.

Ergotron monitor arms in action

Sometimes you just want to show off, even if it's only for yourself. When I graduated to my first triple monitor configuration, back in 2004, I used this 3200 x 1200 image of the entire first level of Super Mario brothers as my desktop background.

But I felt very, very dirty afterwards. I worry that if we spend too much time obsessing over our desktop backgrounds, we'll start treating our computers like fashion accessories instead of tools. We should be filling our screens with information, not distracting ourselves with pretty frippery.

However, if we do it responsibly, if we keep reminding ourselves that our desktop is not a destination, it's OK to obsess over our desktop backgrounds a little bit. The desktop is like an aesthetically pleasing airport we must occasionally pass through before arriving at our real destinations: a web browser, a word processor, an IDE, a graphics editor, etcetera. You know, the places we really want to go. A good-looking airport gives every traveller a positive feeling about where they're going, so feel free to spruce it up. Just don't go so far that you become one of those weird people who hangs out in airports.

In my original research, I ran across a lot of sites with great wallpaper resources. There's a heavy emphasis on extra-wide wallpapers here, as I run triple monitor configurations at home and at work. If you, too, rock a multi-mon setup under Windows, you'll need a utility to get different background images on each monitor, or to span a single image across all your monitors. I use Ultramon which does this and much more; Display Fusion does less, but it works for this, and it's free.

Personally, I don't care for photographs on my desktop. I prefer abstract backgrounds. This must be an unusual preference, because most desktop background websites are completely dominated by photographs. Still, I found a few sites with good abstract backgrounds, even though I had to sift through a lot of photographs to get to them.

For abstract backgrounds, I had the best luck with Flickr and InterfaceLIFT.

If you spend the next hour searching for the perfect desktop background, don't blame me. I tried to warn you. I'm hoping you don't see that special desktop background of yours too often.

Discussion

How To Achieve Ultimate Blog Success In One Easy Step

Always Be Jabbing. Always Be Shipping. Always Be Firing. It's the same advice, stated in different ways for different audiences.

My theory is that lead generation derives from Google rank and that the best way to increase Google rank is to be like a professional fighter: neither jabs nor haymakers are enough. You must be always jabbing and you must regularly throw haymakers. Blog continuously to keep your hit-rate and link-traffic high and write longer pieces, containing the high-value words associated with your niche, occasionally.

When people ask me for advice on blogging, I always respond with yet another form of the same advice: pick a schedule you can live with, and stick to it. Until you do that, none of the other advice I could give you will matter. I don't care if you suck at writing. I don't care if nobody reads your blog. I don't care if you have nothing interesting to say. If you can demonstrate a willingness to write, and a desire to keep continually improving your writing, you will eventually be successful.

rocky marciano postcard

But success takes time – a lot of time. I'd say a year at minimum. That's the element that weeds out so many impatient people. I wrote this blog for a year in utter obscurity, but I kept at it because I enjoyed it. I made a commitment to myself, under the banner of personal development, and I planned to meet that goal. My schedule was six posts per week, and I kept jabbing, kept shipping, kept firing. Not every post was that great, but I invested a reasonable effort in each one. Every time I wrote, I got a little better at writing. Every time I wrote, I learned a little more about the topic, how to research topics effectively, where the best sources of information were. Every time I wrote, I was slightly more plugged in to the rich software development community all around me. Every time I wrote, I'd get a morsel of feedback or comments that I kept rolling up into future posts. Every time I wrote, I tried to write something just the tiniest bit better than I did last time.

The changes, to me, were almost imperceptible. But from a very modest start – a 2004 new year's resolution for professional development – I'd say writing this blog is now, without a doubt, the most important thing I've ever done in my entire career.

I won't say I got my job here at Vertigo back in 2005 because of this blog, but it was definitely a factor. I was interviewed on .NET rocks, and I've been interviewed online not once but twice. I've been invited to speak at conferences. I am approached for book deals every few months. I exchange email regularly with Steve McConnell, one of my programming idols as a young adult, and he once asked me for advice on blogging. Joel Spolsky actually recognized me and invited conversation when I attended the Emeryville leg of his world tour. Charles Petzold sent me, completely unprompted, a signed copy of his latest book. People offer to send me incredibly cool free swag on a regular basis.

As near as I can tell, between RSS stats and log stats, around 100,000 people read this blog every day. Ad revenues that I've only reluctantly taken are significant enough now that I've actually entertained the idea, in my weaker moments, of becoming a full-time blogger. That is how crazy it's gotten. I would never have predicted this outcome in a million years, and writing it all down like this actually freaks me out a little bit.

I mention these things not because I'm a big fat showoff (or at least that's not the only reason), but because I achieved all this without being particularly talented. It was done one small post at a time, with no real planning or strategy whatsoever, beyond the simple incremental suck less every year kind. I am continually amazed and completely humbled by the success of this blog. All it took was a basic commitment to keep jabbing, keep shipping, keep firing.

If anything, what I've learned is this: if I can achieve this kind of success with my blog, so can you. So if you're wondering why the first thing I ask you when I meet you is "do you have a blog?" or "why don't you post to your blog more regularly?", or "could you turn that into a blog post?", now you know why. It's not just because I'm that annoying blog guy; it's because I'd like to wish the kind of amazing success I've had on everyone I meet.

blog comic 255548 full

I'm just trying to share my easy one step plan to achieve Ultimate Blog Success: find a posting schedule you can live with, and stick to it for a year. Probably several years. Okay, so maybe that one step is really not quite so easy as I made it out to be. But everyone has to start somewhere, and the sooner the better.

So when was the last time you wrote a blog post?

Discussion