Thanks for the help

If you're hypothetically considering changing the interface of your application so completely that users can't find the stuff they need in the places where they're used to finding it (Office, I'm looking at you...), you might be expected to have your users need to use "help" a bit more than normal.

And if you expect your users to need to use your help system, and if you choose to make that help system an internet experience, and if that internet experience is going to use a browser that's had so many restrictions placed upon it in the name of security that you can't sneeze without seeing some sort of exception (IE, I'm looking at you....), you should probably consider the likelihood that your users (already frustrated because they can no longer accomplish something that they used to be able to accomplish on their own) are going to encounter a help system that looks something like this:

Thanks a lot, Microsoft.

Don’t get hosed by “Someday”

For the last couple days, I've been helping another project team track down a memory leak in their app. Memory leaks always seem to show up at the most inopportune moments, of course, and this one was no exception.

This memory leak, however, was self-inflicted.  The source of the memory leak appears to be rooted in an open-source project the team was using to manage detached POCO's.  The detached POCO's, it turns out, weren't needed by the project when they were built into the architecture, but were built to support a yet-to-be-built offline client.  The project team met the anticipated requirement with a clever project that met a widely-recognized need in Entity Framework 3.5.  For those shops that absolutely needed this functionality, there weren't too many choices, and this one was right at the top of the list.  The extra functionality, though, added code and complexity, and in this case, a memory leak.

As a final insult, it now looks like this offline client won't be needing the detached POCO's, after all, and on top of everything else, the POCO support project is now essentially deprecated in favor of native support for POCO's in EF 4.0.   The lesson is repeated every day in development shops around the world: someday never comes (you had no idea CCR was singing about software development, did you?).

Everyone who designs software has done this, but if you're designing software, think about these points to avoid this all-too-common pitfall:

  • Beware the temptation to build for future requirements.  I'll be the first to admit that it's pretty tempting to put in that hook or extra layer when you just know you're going to need it, but consider the risk when you do this.  Requirements change all the time after they're real, and the ones that aren't real yet are even more tenuous.
  • If you're using  a third-party tool or library, open-source or not, be sure to assess the present and future stability of the software.  On Scott Guthrie's blog today, he announced a new View engine called "Razor".  Buried in the article was a little gem of a quote:  "Razor will be one of the view engine options we ship built-into ASP.NET MVC."  If you don't have a quote like that for your library, you have to factor in the risk that the software you're counting on will go away (perhaps with little notice).
  • Be especially vigilant about architecture decisions that permeate your software deeply or create extra complexity in your design.  These decisions are critical and difficult to correct later.

When you build for the future and guess right, you might wind up looking like a genius, but be careful, because far more often, "someday" will bite you.

Automated patterns considered harmful

A couple years ago, if you read some of the "best practices" stuff coming out of Redmond, you'd have thought that software factories were going to transform software development.  Thankfully, this turns out not to have been the case.  I never met a software factory I didn't detest almost immediately, and I'm glad the idea hasn't really caught on any more than it did.

Software factories generally consist of some tools to assist software development, but a central theme of these tools is that they generate code for you.  I've always felt that automation in software development is a very good thing, but it's vitally important that you understand what you're left with when you're done.  If automation results in code that you never have to touch or see, then you're probably more productive as a result, but if you're generating code that you're going to have to maintain, there's a very good chance that you're taking one step forward and two steps back.

Most developers are familiar with "Don't Repeat Yourself" (DRY).  The objective of DRY, of course, is not just reduction in code (and thus, effort) when developing new software, but a centralization of logic that pays dividends as you maintain software.  Code generation often accomplishes a deceptively attractive initial productivity for new development, but the generated code is typically littered with repetitive code.  This code is "free" when generated, but it's an anchor around your neck every time you have to maintain the code, or even when you step through it while debugging.  It clutters your project, reduces readability, and inhibits your capacity to maintain, revise, and refactor your software.  There's a reason why repetitive code is usually right at the top of Code Smells lists.

Given my strong preference for software craftsmanship, it shouldn't be surprising that I consider software factories that barf out projects and classes that you're supposed to maintain an absolute blight upon the landscape of software development, but there are any number of other automation tools available to us.  Here are some thoughts on a few of these:

  • Designers.  These remain the best example of code generation done right, in my opinion.  Designers, when properly executed, produce wholly-standalone code files that we can largely ignore.  Classes are declared as "partial" so that if you need to modify them, you can do so without touching the generated code.  Some designers will add [DebuggerStepThrough] attributes so you don't see this code when debugging.  All of these things help the generated code disappear unless we're specifically looking for something, and that's a very good thing.
  • Snippets.  I remain mixed on these little gems.  When used correctly, they can be a big help, but in practice, they're almost always a sign that you should be doing things differently.  Whether or not you're using a snippet to generate code, you don't want to end up with code that violates DRY, and this means that the opportunities to use snippets effectively are few and far between.
  • T4.  The best usage I've seen of this generation tool (built into Visual Studio, by the way), is Rob Conery's SubSonic data access project.  T4 creates code from templates written in an ASP-like syntax, and is great for iterating over a database or other object structure to crank out code in for...each loops.  Like designers, this code is intended to be read-only (you shouldn't modify the generated code), and it can be marked with [DebuggerStepThrough].
  • Reflection.  Yes, it's a little bit of a stretch to call reflection an automation tool, but creative use of reflection can help you achieve some Ruby on Rails-like productivity by adding behavior dynamically.  Reflection is commonly maligned as a performance-killer, but Rocky Lhotka has been doing great things with reflection in CSLA for years with minimal impact on performance.
  • Copy-paste coding.  If you're not even using a tool to help you with your unnecessary code duplication, you're definitely doing it wrong.  'Nuff said, I think.

In addition to these "automation" tools, there are language features and frameworks available to us today that can serve the same productivity objectives without resulting in tons of repeated code:

  • Attributes.  Typically used with reflection to act on classes at run-time, attributes can make your code much more expressive by declaring behavior rather than implementing it over and over.
  • MVC.  Since MVC is a framework, it doesn't really do anything at all to enforce DRY (or any other coding practice), but it encourages a declarative style of Model development that's very consistent with the ideas I've been discussing here, and most MVC examples use a very expressive, compact Model syntax.
  • Model-driven development.  Microsoft's data modeling bits (known at various times as "Oslo") consist of tools, modeling syntax, and extensions that create a very dynamic metadata-driven application environment.  We're still looking at the early stages of these tools, but the broad objective is to make object behavior completely declarative and dynamic.  There's a danger that we could trade unmaintainable code for unmaintainable configuration data, but I think that as this technology matures, it's going to move us in the right direction.

In addition to the options available to us today, we'll continue to see innovations in the future.  When you're reviewing and evaluating these options, though, remember to always add lightness, because less code is better.

Enhanced by Zemanta

Have we really fallen this far?

I am a grammar zealot.

It's entirely my Mother's fault; she drilled proper grammar into my skull from an early age, and I now cannot help but notice the absolutely atrocious spelling, grammar, and punctuation that permeates our culture.

Have you ever watched a history documentary where they read some crusty, tattered old manuscript that some Civil War soldier left behind?  Not ol' Honest Abe, or even Grant or Sherman -- just some guy who wrote to his folks or his girl.  These everyday soldiers invariably sound like Shakespeare compared to the IM-speaking crackberry addicts we meet today.

But surely, even if the everyday American has given up on proper grammar, our journalists are still upholding these standards.  Surely, they manage to set a positive example for all of us: showing us the error of our ways and offering their own writing as a shining sample of excellence, and surely among all of these highly-trained journalists, the writers for the Wall Street Journal would be right at the top.

Surely, this must be true.  Right?

Sadly, no.  Here's an excerpt from an article I saw from the WSJ a while back (preserved with spelling, capitalization, etc., exactly as found in the article online):

"A lot of traders are getting carried out of there seats. There are lots of liquidations including hedge funds out of riskier assets," Michael Franzese, head of Treasury trading at Wunderlich Securities in New York. "No one was expecting this sell off in stocks and the euro and a flight to quality trade is in full effect and it not yields levels it just capital preservation."

Read it again.  Sorry - yes, I know it hurts.  This time, just try to figure out what it's supposed to say.  I'll bet you can't do it.  It's like swimming a 100 IM in a pool full of Jello.

People, if you're going to commit anything to writing, please make a passing attempt to make it readable.  If you supposedly make your living as a writer, don't ever, ever do anything like this.

Thanks.

Nothing short of world domination will do

A good friend of mine sent me an email commenting on the changes in Apple's Developer Program license for the 4.0 iPhone OS, and I decided to share my thoughts here, as my email grew to become the tome you see here.

Steve Jobs at the WWDC 07
Image via Wikipedia

Apple has, as you've probably heard, indicated that it will allow apps on the iPhone and iPad only if they're written with Apple-native languages and tools, and it's widely-believed that this has been done as a form of anti-Flash "nuclear weapon", as my friend commented.

I'm not convinced that this move is directed only at Flash, though.  Any third-party tool (MonoTouch, for example) will be impacted by this move.   Some people have even speculated that this move is intended to help iPhone multitasking ("BS", I say -- write a damned API).  While all of these things might be factors in this move, I believe that the fundamental driver here is a maniacal need for Steve Jobs to control the entire digital experience for his users; nothing short of this will be enough.

Apple isn't perceived among consumers to be monopolistic simply because they don't have a majority market share yet.  The thing that just kills me about Apple right now, though, is that within their customer base, they're monopolistic to an extent that would have gotten Microsoft run out of town on a rail, even in its heyday.

Apple is a cult.  They mandate congruent behavior and thinking with an iron fist, and won't let trivia such as fairness or consistency cloud their vision (witness the iPhone app approval process).
Go ahead and float up to 50,000 feet and look at the whole "app" strategy on the iPhone.  Here's what I see:
  • All functionality on these devices is approved by Apple.
  • When rejecting an app or content, "because we said so" is sufficient reason.
  • "We changed our minds" is enough to get an app pulled after approval -- including yanking it off any devices upon which it's installed.
  • To get an app on your device, you have to go through iTunes.
  • To build an app, you have to use Apple development products (for all intents and purposes).
  • To use Apple development products, you have to be running a Mac.

That's a lot of kool-aide, folks, but if you think that's bad, it's going to get worse.[callout title=A benevolent monopoly?] Despite my ranting here,  I can appreciate the benefits of a technology monopoly.  The incredible growth of the PC platform was made possible mainly because of Wintel's near-monopoly -- it created a huge ecosystem for hardware companies, software companies, and consumers.  But as much as that partnership was effectively a monopoly, they still let mice scurry around and fight over table scraps, and the table scraps were enough to keep a lot of mice fed.[/callout]

I got a new phone last week.  Although I've experienced some teething pains, one of the most pleasant parts of the experience was spinning up my contact list and calendar.  I pointed a new Exchange account at Nuevasync (which connects to my Google account), and sucked down all my contacts and appoinments at 3G speed.  Easily the most painless phone transition I've ever experienced.  This is what cloud computing looks like for the consumer.

Apple is building a gigantic data center in North Carolina.  Care to take a guess why?

Data centers this size are being built today for cloud computing, almost exclusively.  Apple is going to suck your entire digital identity into their brand-new data center, and you'll never see it alive again unless you keep paying your monthly ransom.  As long as you play along, life will be wonderful, in a fuzzy, heavily-sedated way, but if you engage in nonconformist behavior (trying to get your data back, for instance), you should expect to be punished as you'd expect to punish any troublemaker.

Another friend of mine asked me the other day how he could get his DRM-protected music (bought on iTunes) off an old PC and onto his new one.  This is a smart man, by the way - a successful businessman, and he'd tried to figure this out and was stumped.  If you've ever tried this, I'm sure you can understand.

Take a good whiff, folks, because that's the experience we could be signing up for with all of your data.

I'll pass.  How about you?

Related articles by Zemanta

Reblog this post [with Zemanta]

Meet the new phone, same as the old phone

I've been soldiering on for a couple of years on a T-Mobile Wing.  That old phone did some pretty great things for my personal organization, but I always seemed to struggle with connection issues.

Last weekend, I finally bit the bullet and picked up a new HTC HD2.  Make no mistake, this is a spectacular piece of hardware, but sadly, I still find myself chasing connection issues.  I'll share some thoughts on the rest of the phone later if I end up keeping it, but right now, I want to detail my signal strength problems.  I'll continue to update this post as the fun and games ensues, so if I (or T-Mobile) manage to fix the problem, this post will show the resolution, and if not, you'll be able to see why I left.  All of the observations here, unless otherwise indicated, occured in exactly the same spot in Columbus, Ohio, near the OSU campus (ie, not while moving around).

Sunday, 3/28

  • Bought the phone, took it home, charged it, and powered on.  No data connection.  It turns out that the upgrade to 3G takes a while to provision.

Monday, 3/29

  • Signal bounces around all day.  Full-strength Edge, then nothing, then 3G, then nothing, then no connection at all.  This goes on most of the day, with almost all day spent on Edge only (no 3G).
  • In the evening, I got a good 3G signal, and the phone worked great.

Tuesday, 3/30

  • Slightly better luck with 3G, but not by much.
  • I talked to a couple people who said they tried to call me several times -- the phone never rang, and didn't show any missed calls.

Wednesday, 3/31

  • Noticed the same problems.  Signal really bouncing in the morning.
  • Called T-Mobile customer care at around 11:45.  Rep advised me to power off and back on a couple minutes later, and asked if I could call from another line (I can't).
  • Immediately upon powering up, here's what I saw:
  • 11:57 - 3G w/ 2 bars.
  • 11:58 - Edge w/ 3 bars.
  • 12:00 - no service (I was trying to dial voice mail).
  • 12:00 - Edge w/ 4 bars (after I stopped trying to dial VM).
  • 12:01 - no service (as soon as I dialed VM).
  • 12:20 - 3G w/ 3 bars.
  • 12:20 - Call to VM fails.
  • 12:22 - 3G w/ 2 bars.
  • 12:22 - Call to VM fails.
  • 12:24 - Call to VM fails.  "Phone operation failed" message.  Immediately saw Edge w/ 4 bars, then no signal.
  • 12:26 - Finally completed a call to VM.
  • 12:27 - no service.
  • 12:28 - no service - unable to place call.
  • 12:30 - placed call - it worked!
  • 12:39 - Edge w/ 4 bars.  As a side-effect of the connection-hunting, my battery is down to 57% - I noticed this sort of decreased battery life when my Wing was connection-hunting, too.  Done troubleshooting for now - my lunch is over.

(watch below for more updates) Continue reading "Meet the new phone, same as the old phone"

A feature greater than the sum of its bugs

Douglas Adams, muse to software developers everywhere, had this to say about bugs:

"Just as a slow series of clicks when speeded up will lose the definition of each individual click and gradually take on the quality of a sustained and rising tone, so a series of individual impressions here took on the quality of a sustained emotion[.]"

Ok, yeah - the quote is really from "Life, the Universe, and Everything", and he wasn't talking about bugs, but he could have been.

Big Bug III…!!!
Image by Denis Collette...!!! via Flickr

If you look at bugs one at a time, you can miss some important "big picture" stuff.  It's possible to spot product design issues, usability issues, architecture issues, and more by looking at patterns across multiple bugs.  Instead of just taking the bug at face value, consider whether there are other factors that caused this bug (and others like it) to show up.  Unless you're writing mission support modules for NASA, it doesn't make sense to do a full five-why's breakdown on each bug, but keep your eyes open for signs like this:

  • You find yourself going back to the same area of code over and over.
  • User complaints cluster around a few screens (or functions) in your application.
  • You recognize a similar pattern in source code that keeps popping up.

When you see patterns like this, you can certainly keep on fixing the bugs one at a time, but it's pretty hard to make progress this way.  Instead, consider a larger bug fix, or even an actual feature (there's really no difference, IMO) that cuts across individual bugs and fixes the foundational problem that's spawning them.

  • Maybe you need to redesign a screen.  If users are having a hard time figuring out part of your application, you're not going to be able to fix your users.  Bite the bullet and figure out what you need to change in your application so that it makes sense.
  • Refactor ugly code.  This should be a no-brainer.  Spaghetti code can hide a multitude of sins, and the bugs are just going to keep coming until you deal with the problem.
  • Address architectural issues.  Sometimes, your problems run really deep, and big changes are needed to fix them.  This can be a tough sell, but if you can show a pattern of costly bug fixes over time, all of which share an architectural root cause, you've got the ammunition to push for a fix that will make them go away.

If you eliminate the sources of these clustered bugs, you not only get rid of the current bugs, you wipe out a whole swarm of future bugs before they've had a chance to show their ugly little faces.  Don't believe for a second that you can do this one bug at a time.

Enhanced by Zemanta

Almost a great idea

Here's an example of a good idea gone wrong.  I saw a link for a web site that exists solely to advance openness in government.  How cool is that?

U.S.
Image via Wikipedia

I clicked around for a bit, eventually reaching a place where I was supposed to be able to submit an idea for government, where it would (presumably) be viewed and discussed among my peers.  When I clicked the button to enter my idea, I was prompted to log in with OpenID (again, very cool).  I logged in and clicked the button again, and was rewarded with the following barfage:

500 Servlet Exception

[show] java.lang.NullPointerException

java.lang.NullPointerException
	at _jsp._jsp._includes._build_0header__jsp._jspService(jsp/includes/build_header.jsp:37)
	at com.caucho.jsp.JavaPage.service(JavaPage.java:61)
	at com.caucho.jsp.Page.pageservice(Page.java:578)
	at com.caucho.server.dispatch.PageFilterChain.doFilter(PageFilterChain.java:195)
	at com.caucho.server.webapp.DispatchFilterChain.doFilter(DispatchFilterChain.java:97)
	at com.caucho.server.dispatch.ServletInvocation.service(ServletInvocation.java:266)
	at com.caucho.server.webapp.RequestDispatcherImpl.include(RequestDispatcherImpl.java:494)
	at com.caucho.server.webapp.RequestDispatcherImpl.include(RequestDispatcherImpl.java:358)
	at com.caucho.jsp.PageContextImpl.include(PageContextImpl.java:1008)
	at _jsp._jsp._includes._autoselect_0header__jsp._jspService(jsp/includes/autoselect_header.jsp:23)
	at com.caucho.jsp.JavaPage.service(JavaPage.java:61)....

Close, guys. Very close!

Please don't do this to your customers, okay?

Reblog this post [with Zemanta]