Archives for category: design

Sort of a Maslovian hierarchy. I.e. don’t attempt a subsequent step until you get the previous step right.

  1. Load fast
  2. Don’t break the browser or the web (e.g. bookmark-ability, back/foward, searchability, etc.)
  3. Align with core web UI conventions (e.g. use hyperlinks for navigation, use forms for data entry)
  4. Be consistent with other web apps in your product family if you have one (e.g. all Google apps, all IBM apps)
  5. Make it pretty and do cool stuff if if it helps your users be more productive and/or have a more pleasant user experience

Between early 2006 and early this year, my team at IBM Rational and I built a framework for component-based Ajax development for use in the Rational Jazz platform. The framework’s capabilities aren’t the focus of this entry, so I’ll just list some of them briefly:

  • A nice component model based on OSGi bundles and the Dojo module system
  • Request-time “building” of many fine-grained JavaScript files into monolithic files for faster download based on the introspected relationships between the files – i.e. no developer effort required for fast code loading other than writing good application code
  • Making a subset of the Eclipse extension registry available in the web page and queryable via JavaScript APIs modeled off of the org.eclipse.core.runtime extension registry Java APIs, allowing for open-ended extensibility using the Eclipse extensibility model
  • A simple framework for demarcating UI states that made the back button, history, and page titles work seamlessly within the Ajax page, even when a user gesture resulted in crossing a component boundary (e.g. loading and displaying a new virtual “page” from a different component) [1]
  • Dynamic, transparent loading of missing code in response to a user gesture that required it

We did a fairly good job of keeping our Ajax framework decoupled from the rest of the Jazz Platform both for the purpose of design cohesiveness but also to allow for possible future use by teams who weren’t building full-blown application lifecycle management applications like Jazz SCM or Iteration Planning.

Over time, other IBM teams heard about some of our capabilities and saw the positive results in our Rational Team Concert web UIs [2] and contacted us to explore whether they could make use of our code in their products. Each conversation went like this:

  1. We gave a demo and talk about the capabilities and architecture of the framework
  2. The other team said “that’s really nice, that’s really useful, that would be great to have”
  3. The other team said “we’re not sure we want to live within your framework, we’ll get back to you”
  4. The other team didn’t get back to us

Initially this didn’t really bother me – after all my job was to deliver the foundation for our Jazz web user interfaces, not to create a general purpose Ajax framework for IBM, but as I’ve thought about it more over time and seen this anti-pattern from other teams and other frameworks, I’ve decided that we should make a conscious effort to make our useful functionality available as simple building blocks (in the form of libraries) and then provide frameworks that layer on top of these building blocks.

Let me take a step back and explain what I mean.

A library is a set of reusable functionality where your application uses parts of the library as necessary. For instance, most programming languages have a library for creating and manipulating dates. Frameworks also provide functionality to the application programmer, but instead of the application programmer making simple function calls, the framework runs the show and calls into the application at well defined hook points. For example, GUI frameworks provide ways to wire up code to run in response to users clicking on buttons.

Both the library and the framework provide useful functionality intended to make the application developer more productive. Though it’s dangerous to make a general statement, it feels to me that the big difference between the two is that frameworks generally provide more power, but require you to make a bigger commitment to the framework’s way of working, while libraries provide generally less power, but make few (if any) demands about how you structure your application.

What’s unfortunate is when you’ve got some useful bit of functionality that could be made available as a simple library but it’s only available in the context of a framework. This is where we were with our Ajax framework. This stuff is too abstract, so here’s an analogy: Imagine that you heard about a new refrigerator which provided every feature and characteristic you ever dreamed about having in a refrigerator. The catch however was that you couldn’t just buy the refrigerator – you had to move into a house on the other side of town that included the new refrigerator. After about 10 seconds of thought you realize that even though it’s the fridge of your dreams, you’re sure as hell not going to move into a new house across town in order to get it. This situation (switching back to software from refrigerators) is shown in the diagram below.

Useful building blocks locked inside a framework

Useful building blocks locked inside a framework

My recent realization (which seems obvious in hindsight) is that the useful functionality provided by frameworks and libraries need not be mutually exclusive. For instance, in our Ajax framework’s dynamic build system, rather than requiring applications to run within our framework to enjoy this capability, we could have created a simple callable library to perform dynamic optimization on a set of files, and then created a framework that simply used this same library. This approach is shown in the diagram below:

Useful building blocks used by a framework but also available independently of the framework

Useful building blocks used by a framework but also available independently of the framework

Over the past month or so we’ve been refactoring our Ajax framework to extract the useful building blocks into simple callable libraries and making the framework proper smaller by delegating to these libraries. We’ve done this in the hopes that our code will be useful to other IBM teams but as a result of the exercise, we’ve gained a deeper knowledge of our software and the software’s quality has improved as we’ve decoupled the framework aspects from the building blocks aspects.

Going forward, it’s my intention that our team will generally start with building blocks first and then consider if we should provide some higher-level framework that uses these building blocks. I only wish we had taken this approach from the beginning but you know, live and learn.

Footnotes

  1. This UI state management framework evolved into dojo.hash
  2. You can see our Jazz web UIs built on top of this framework in the development section of Jazz.net if you register.

Updates

Changed “other than writing good code” to “other than writing good application code”

Last Friday I did an RIA weekly podcast (mp3) with Michael Coté of Redmonk and Ryan Stewart of Adobe. This was a fun and interesting experience. Fun because I like Coté and Ryan a great deal and enjoy talking to them and interesting because of the subject matter and also because it was the first podcast I’ve ever done.

There were a few things I said in the podcast for which I’d like to provide a bit of extra context, because it’s difficult in the podcast format to provide a great deal of context.

Network Transparency and Latency

At one point in the podcast, I talk about Jazz‘s early RPC-style web services and say something along the lines of “This is great for the Java client developers because they essentially get network transparency, which is awesome except for the latency.” This is sort of like saying “Not paying income tax is great, except for the eventual fines and imprisonment.” RPC-style interfaces that strive to provide network transparency have the unusual problem that they make remote connectivity too easy for developers. The result, which is almost a cliché, is that developers design applications which are way too chatty and which work fine on local area networks (the environment in which they are developed) but fall apart in wide area networks (the environments in which they are deployed). Later, in the clichéd scenario, the developers learn about explicitly designing the “stuff” that travels over the wire to provide a good balance between the needs of the application and the realities of the network.

Sometimes you just shouldn’t make things too easy. Like you shouldn’t put the car’s ejector seat button where the toddlers can reach it 🙂

Why We Didn’t Consider Flash as the Basis for the Jazz Web UI Infrastructure

At another point, Ryan asked me if we ever considered Flash and I said something along the lines of “Well we didn’t select Flash because it wasn’t as ubiquitous as the standalone browser” but after saying this I remember Pat Mueller telling me recently that Flash is the most widely deployed web client technology when you compare it against particular browsers (i.e. browsers in general are more widely deployed than Flash, but Flash is more widely deployed than any particular browser like Internet Explorer or Firefox). So though my memory is a little fuzzy, I believe the reason was that just as a general principle, we didn’t want any core Web UI application functionality depedning on a particular plug-in; for instance, the user shouldn’t require Flash to create a bug report. Another factor was that this was early 2006 so Flash was probably not as ubiquitous as it is today. Yet another factor was our later principle that “look like a normal web page” and some examples of Flash violate this (i.e. the big box of Flash in the middle of the page, or overly ambitious site welcome screens). But I have to say, my thoughts on Flash have really changed over the past two years, because I’ve seen some incredibly useful, subtle applications of it. I can’t think of a particular example, but I know a couple of times some page on Amazon.com had a really cool little visual effect and sure enough when I right-clicked it turned out to be a little Flash app seamlessly embedded in the page. So using Flash in tactical ways where it can provide a powerful but non-jarring user experience is something I would like to explore in the future.

Meeting with the WebSphere Application Server Folks

At one point early in the interview Coté mentions that we hung out and got drinks in Austin one night and I mentioned that I was down for a meeting with some WebSphere Application Server folks and it was also a good opportunity to meet with Coté which is why I accepted the meeting. Listening to the podcast, I feel bad about how this came out because in reality the WebSphere App Server folks were doing us a favor by taking a day off to review the security architecture of Jazz.net and indeed they pointed out both important security and scalability issues. The missing context is that I hate work travel (I repeat hate) because I have two toddlers and they just grow too much and we miss each other too much when I travel without them. So the only time I travel for work is if I really need to be there in person (like if I’m speaking at a conference) or if I can accomplish more than one goal with a single trip. If not for the chance to both do the Jazz.net review and meet Coté, who in my opinion (don’t blush Coté) is both a cool guy and important industry analyst, I would have probably called in.

Innovation vs. Standardization

At another point in the podcast, I mention a blog post by Alex Russell of Dojo where he talks about standards not saving us and encourages browser vendors to provide non-standard innovative features. I think in the podcast I may have come across as “standards don’t matter”. In fact I think standardization is important to build the applications of today but agree with Alex and that the future won’t be invented by standards bodies.

Finally…

Otherwise I agree with everything I said 🙂

I had an insight a few weeks ago that I thought was worth sharing. First some context.

On the Jazz project, one of my jobs is leading the software development for our platform-level web UI stuff [1]. Erich Gamma is the overall Jazz technology lead. Twice a month we have a sync up meeting where we discuss platform-level web UI progress.

In our last chat in mid-December, one of the things we chatted about was the status of the Jazz Server’s Admin Web UI. We began bootstrapping the Admin Web UI in September and I thought we’d made good progress in such a short amount of time. Erich didn’t seem so impressed with what he saw. I was a bit frustrated by this because I thought Erich was being unreasonable – we’d made good progress for the short amount of time we’d been working on it. But after a few more minutes of chatting, I realized that there was simply a mismatch in what we were evaluating. I was evaluating the state of the Admin Web UI vs. the resources (time and people) we’d had to work on it; Erich was evaluating the state of the Admin Web UI vs. his vision of what an awesome Admin Web UI should look like. Put more tersely, I was measuring “current vs. previous” while Erich was measuring “current vs. ideal”.

I found this difference in approach fascinating and insightful. I’m a very methodical person; when someone gives me a job I very methodically list its goals and measures of success, then I work backwards given the time and people I have to reach the goals and then over the course of weeks or month work towards the goals. But during my conversation with Erich I realized that a risk of my methodical approach is that I can become too bogged-down on the blocking and tackling of day-to-day software development and become overly focused on incremental progress and lose sight of the big vision of what you’re trying to build. I found that when I adopted Erich’s point of view and thought about the current state of the Admin Web UI vs. what it could become in the very long-term, I became very dissatisfied with its current state and highly motivated to be more ambitious with the next iteration plan.

It’s ironic because most of the iterative software development literature talks about the converse problem – you’re too focused on the big picture that you don’t make day-to-day progress. Indeed it’s become a cliché over the past several years to make fun of architects who are too far removed from day-to-day coding, testing, and building.

So the insight I gained was that I need to think in terms of both “current vs. previous” and “current vs. ideal”. Fortunately our iterative development process supports finding this balance. At the beginning of iterations it’s fine to dream big dreams about what you’re trying to achieve but then to become very pragmatic about how to make incremental progress towards realizing those dreams in the course of a four week iteration. Then over the four weeks you can be extremely methodical about making progress. Then at the end of the iteration you can reflect on what you’ve accomplished and feel some short satisfaction that the software is significantly better now than it was four weeks ago. Then you can reflect that the software’s not nearly as good as you ideally want it to be which provides the motivation to start the cycle again.

[1] By “platform-level” I simply mean more of the infrastructure. That is, frameworks and APIs rather than tangible applications.

There’s a theory called ‘The Uncanny Valley’ regarding humans’ emotional response to human-like robots. From The Wikipedia entry:

The Uncanny Valley is a hypothesis about robotics concerning the emotional response of humans to robots and other non-human entities. It was introduced by Japanese roboticist Masahiro Mori in 1970 […]

Mori’s hypothesis states that as a robot is made more humanlike in its appearance and motion, the emotional response from a human being to the robot will become increasingly positive and empathic, until a point is reached beyond which the response quickly becomes strongly repulsive. However, as the appearance and motion continue to become less distinguishable from a human being’s, the emotional response becomes positive once more and approaches human-human empathy levels.

This area of repulsive response aroused by a robot with appearance and motion between a “barely-human” and “fully human” entity is called the Uncanny Valley. The name captures the idea that a robot which is “almost human” will seem overly “strange” to a human being and thus will fail to evoke the requisite empathetic response required for productive human-robot interaction.

While most of us don’t interact with human-like robots frequently enough to accept or reject this theory, many of us have seen a movie like The Polar Express or Final Fantasy: The Spirit Within, which use realistic – as opposed to cartoonish – computer-generated human characters. Although the filmmakers take great care to make the characters’ expressions and movements replicate those of real human actors, many viewers find these almost-but-not-quite-human characters to be unsettling or even creepy.

The problem is that our minds have a model of how humans should behave and the pseudo-humans, whether robotic or computer-generated images, don’t quite fit this model, producing a sense of unease – in other words, we know that something’s not right – even if we can’t precisely articulate what’s wrong.

Why don’t we feel a similar sense of unease when we watch a cartoon like The Simpsons, where the characters are even further away from our concept of humanness? Because in the cartoon environment, we accept that the characters are not really human at all – they’re cartoon characters and are self-consistent within their animated environment. Conversely, it would be jarring if a real human entered the frame and interacted with the Simpsons, because eighteen years of Simspons cartoons and eighty years of cartoons in general have conditioned us not to expect this [Footnote 1].

There’s a lesson here for software designers, and one that I’ve talked about recently – we must ensure that we design our applications to remain consistent with the environment in which our software runs. In more concrete terms: a Windows application should look and feel like a Windows application, a Mac application should look and feel like a Mac application, and a web application should look and feel like a web application.

Obvious, you say? I’d agree that software designers and developers generally observe this rule except in the midst of a technological paradigm shift. During periods of rapid innovation and exploration, it’s tempting and more acceptable to violate the expectations of a particular environment. I know this is a sweeping and abstract claim, so let me back it up with a few examples.

Does anyone remember Active Desktop? When Bill Gates realized that the web was a big deal, he directed all of Microsoft to web-enable all Microsoft software products. Active Desktop was a feature that made the Windows desktop look like a web page and allowed users to initiate the default action on a file or folder via a hyperlink-like single-click rather than the traditional double-click. One of the problems with Active Desktop was that it broke all of users expectations about interacting with files and folders. Changing from the double-click to single-click model subtley changed other interactions, like drag and drop, select, and rename. The only reason I remember this feature is because so many non-technical friends at Penn State asked me to help them turn it off.

Another game-changing technology of the 1990s was the Java platform. Java’s attraction was that the language’s syntax looked and felt a lot like C and C++ (which many programmers knew) but it was (in theory) ‘write once, run anywhere’ – in other words, multiplatform. Although Java took hold on the server-side, it never took off on the desktop as many predicted it would. Why didn’t it take off on the desktop? My own experience with using Java GUI apps of the late 1990s was that they were slow and they looked and behaved weirdly vs. standard Windows (or Mac or Linux) applications. That’s because they weren’t true Windows/Mac/Linux apps. They were Java Swing apps which emulated Windows/Mac/Linux apps. Despite the herculean efforts of the Swing designers and implementers, they couldn’t escape the Uncanny Valley of emulated user interfaces.

Eclipse and SWT took a different approach to Java-based desktop apps [Footnote 2]. Rather than emulating native desktop widgets, SWT favor direct delegation to native desktop widgets [Footnote 3], resulting in applications that look like Windows/Mac/Linux applications rather than Java Swing applications. The downside of this design decision is that SWT widget developers must manually port a new widget to each supported desktop environment. This development-time and maintenance pain point only serves to emphasize how important the Eclipse/SWT designers judged native look and feel to be.

Just like Windows/Mac/Linux apps have a native look and feel, so too do browser-based applications. The native widgets of the web are the standard HTML elements – hyperlinks, tables, buttons, text inputs, select boxes, and colored spans and divs. We’ve had the tools to create richer web applications ever since pre-standards DOMs and Javascript 1.0, but it’s only been the combination of DOM (semi-)standardization, XHR de-facto standardization, emerging libraries, and exemplary next-gen apps like Google Suggest and Gmail that have led to a non-trivial segment of the software community to attempt richer web UIs which I believe we’re now lumping under the banner of ‘Ajax’ (or is it ‘RIA’?). Like the web and Java before it, the availability of Ajax technology is causing some developers to diverge from the native look and feel of the web in favor of a user interface style I call “desktop app in a web browser”. For an example of this style of Ajax app, take a few minutes and view this Flash demo of the Zimbra collaboration suite.

To me, Zimbra doesn’t in any way resemble my mental model of a web application; it resembles Microsoft Outlook [Footnote 4]. On the other hand Gmail, which is also an Ajax-based email application, almost exactly matches my mental model of how a web application should look and feel (screenshots). Do I prefer the Gmail look and feel over the Zimbra look and feel? Yes. Why? Because over the past twelve years, my mind has developed a very specific model of how a web application should look and feel, and because Gmail aligns to this model, I can immediately use it and it feels natural to me. Gmail uses Ajax to accelerate common operations (e.g. email address auto-complete) and to enable data transfer sans jarring page refresh (e.g. refresh Inbox contents) but its core look and feel remains very similar to that of a traditional web page. In my view, this is not a shortcoming; it’s a smart design decision.

So I’d recommend that if you’re considering or actively building Ajax/RIA applications, you should consider the Uncanny Valley of user interface design and recognize that when you build a “desktop in the web browser”-style application, you’re violating users’ unwritten expectations of how a web application should look and behave. This choice may have significant negative impact on learnability, pleasantness of use, and adoption. The fact that you can create web applications that resemble desktop applications does not imply that you should; it only means that you have one more option and subsequent set of trade-offs to consider when making design decisions.

[Footnote 1] Who Framed Roger Rabbit is a notable exception.

[Footnote 2] I work for the IBM group (Eclipse/Jazz) that created SWT, so I may be biased.

[Footnote 3] Though SWT favors delegation to native platform widgets, it sometimes uses emulated widgets if the particular platform doesn’t provide an acceptable native widget. This helps it get around the ‘least-common denominator’ problem of AWT.

[Footnote 4] I’m being a bit unfair to Zimbra here because there’s a scenario where its Outlook-like L&F really shines. If I were a CIO looking to migrate off of Exchange/Outlook to a cheaper multiplatform alternative, Zimbra would be very attractive because since Zimbra is functionally consistent with Outlook, I’d expect that Outlook users could transition to Zimbra fairly quickly.

Andrew Shebanow of Adobe recently wrote an interesting blog entry with the unfortunate title of “The Death of UI Consistency“. A few excerpts:

What I’m really talking about here is how the goal of complete UI consistency is a quest for the grail, a quest for a goal that can never be reached.

The reason I think [that RIAs bringing web conventions to the desktop is a good thing] is that it lets us move the conversation away from the discussion of conformance with a mythical ideal and towards a discussion of what a usable UI should be.

I’ve been thinking about UI consistency quite a bit recently. Although Andrew’s on the right track, I think he clouds the issue by arguing that the “the goal of complete UI consistency is a quest for the grail”. I personally don’t know anyone who has argued for complete UI consistency; indeed my recent experience, especially with Ajax-style web applications, has been that many designers don’t consider UI consistency enough. But before going further, I think it’s important to consider what it means to provide UI consistency.

First it’s important to remember that consistency is relative. While we can measure certain UI characteristics, like background color or width, in absolute terms (e.g. ‘white’ or ‘1400 pixels’), we can only measure consistency relative to established visual and behavioral conventions. These conventions vary by platform – for example in a Windows application you expect to see a closing ‘x’ in the upper right hand corner of each application; on a web site you expect clicking on a hyperlink to take you to a new page. So because there are no universal UI conventions, there’s no such thing as absolute consistency; there is only consistency vis-à-vis platform conventions.

I believe Andrew is observing that as rich client and web technologies converge, so too do their UI conventions, and sometimes these conventions conflict with one another. John Gruber complained that the Adobe CS3 close box didn’t follow the Mac convention; Andrew posits that this is because CS3 does not try to follow Mac conventions nor Windows conventions – it follows the conventions of the Adobe platform.

It’s all well and good to say that you’re creating a new platform and that your new platform introduces new UI conventions, but the fact is that users do have certain expectations about how UIs should look and behave, and when you violate these expectations by not following conventions, you’d better be confident that the benefits outweigh the potential pain you’ll cause users.

So how should we decide whether to follow established UI conventions or to attempt something new and different? To answer this question, it’s important to first understand the value of following conventions as well as the costs and benefits of violating conventions.

Observing established UI conventions has two main benefits:

  • You reduce your application’s learning curve because the user can (subconsciously) leverage previous experience within your application. For example, when you see blue underlined text on a web page, no one needs to explain that you can click it.
  • Your app is more pleasant to use or, more accurately, your app is less unpleasant to use; observe Gruber’s comment “God, that just looks so wrong” – have you ever felt that way when you used a Swing application that was trying to emulate a native Windows or Macintosh look and feel but not quite succeeding?

To quote my former colleague Don Ferguson, “different is hard”. Different can also feel awkward. As you interact with a class of apps over time, your mind builds up subconscious expectations about how apps of that class should look and behave. When an app violates its platform conventions, it often becomes harder to use and sometimes just plain annoying. For instance, have you ever used a web site that decided its hyperlinks shouldn’t be underlined and shouldn’t be blue? Not pleasant. All this being said, it seems like we should always observe UI conventions, but this is not the case either.

UI conventions are not the laws of physics. They represent previous human design decisions that became the norm either because they were very useful (the hyperlink) or just because they became entrenched (the ‘File’ menu). Either way it is possible that a smart or lucky designer can invent a new mechanism that violates existing conventions yet overcomes the barriers to entry because of its usefulness. But it’s a high bar. A new UI mechanism must not simply be better than a UI convention; it must be significantly better such that its value negates the added learning curve and strangeness. A good example of a UI innovation that succeeded is the ‘web text box auto-complete dropdown’ pattern that we see in web applications like Google Suggest, del.icio.us, and Google Maps. Many smart people considered this behavior strange and novel when they first discovered it; these days we don’t really notice it though we certainly appreciate its usefulness. In other words it’s on its way to becoming a new convention.

So I believe that designers should observe established UI conventions except when they decide that violating said conventions provides enough value to obviate the costs. In practice, many designers don’t really think about observing or breaking conventions; they just do what feels right. And you know what? Sometimes they succeed and their arbitrary design choices become new conventions. But a design that violates conventions without understanding the trade-offs runs the risk of feeling just plain arbitrary.

In the last week of the most recent Jazz milestone, I realized that I was running out of time to give one of the web features a UI overhaul. Jen Hayes, the primary web UI designer, had sent me a spec more than a month before but I hadn’t implemented it because I was overwhelmed by the many lines, measurements, and notes specifying the changes I was to make. So I moved on to other stuff and forgot about the UI work until the UI designers brought up my procrastination on a UI design review call with Erich. Doh!

Jen pointed out the most pressing problem (font style in form elements, if memory serves) and I said “Oh, I can change that” and one line of CSS later, the major problem was fixed. Hey, this was pretty easy! Jen mentioned a few other things and I realized that they were easy as well. Erich and the other folks dropped off the call and we decided to start a NetMeeting and try to knock out as many UI polish items we could. Two hours later we were completely done – not only had we fulfilled the spirit of the spec, we’d rethought a few spec’d decisions and tweaked a few additional items in the process of our extremely rapid iterations.

A few days later, I reflected on this and wondered why the heck we had the UI designers sending us super-detailed specs in the first place. If someone were to send me a highly-detailed technical spec on how I should code a particular feature, I’d ask them if I were being Punk’d. Yet with regards to UI design, this is standard practice. Not anymore, at least for me. The UI designers are welcome to draw up whatever specs they like, but I’m only going to do major UI work via pair programming with a UI designer.

Pair programming with a UI designer has the same benefits as pair programming something in [fill in your programming language of choice]. You can experiment, discuss, learn, and refine very quickly, and the real-time verbal and visual communication is much higher bandwidth than email and documents. This is especially true in a web environment, where you can hack CSS literally in real-time via EditCss and a screen sharing program.

This experience and another recent email conversation with James Governor on my reticence to publish a new Ajax article “before it is completely ready” has made me decide to reflect on how I can apply the principles of experiment/discuss/learn/refine to everything I do.

The other day, I thought of a clever solution to speed up an important Jazz function by perhaps 20-40% (depending on a set of environmental factors). I eagerly documented the solution in a bug report and CC’d several teammates. Several times over the past week, I almost went ahead and just coded the solution, because I was so happy with its cleverness.

But I haven’t done this.

Fortunately for users but unfortunately for my idea, the function in question already runs as fast (1-4 seconds) as users expect it to run, given the nature of the function.  So although the 20-40% improvement is certainly relatively significant, it isn’t of any practical significance to users.  After all, who cares if something that currently runs in a ‘speedy’ 2 seconds were reduced to 1.5 seconds?

So it’s been with great discipline (and a bit of angst) that I’ve abstained from writing this clever code, basically because of the YAGNI principle, which the team as a whole rigorously observes.  The benefits (0.2 – 1.6 second reduced response time) simply don’t justify these costs:

  • time to implement
  • time to test
  • potential defects (the current implementation has been stable for six months)
  • increased complexity (it’s clever, you know)
  • opportunity cost of not doing other work which is of practical use to users (backlogged enhancement requests, UI/UX improvements, bug fixes)

The reason I bring this up is because it demonstrates the powerful temptation to implement a clever or elegant solution despite the fact that it lacks a compelling problem.  I consider YAGNI to be a fundamental principle of my personal development philosophy, yet I still found myself tempted to implement the solution once I had fallen in love with its cleverness and efficiency.

So … I’ll be patient for now and my solution will remain unimplemented, but documented in a bug report.  If, over time, other system factors cause the response time to degrade, perhaps the solution’s value may increase enough to justify its costs.

Or not.

Some excerpts below.  Click on the person’s name for the full content.

Grady:

There’s a phrase from systems engineering that applies here, the principal of least astonishment. When an abstraction fails, a well-designed one will (hopefully) fail in predictable ways. It’s when an abstraction fails and it fails in an unexpected way that we have evidence of a leaky abstraction. Unfortunately, I don’t think this kind of behavior is avoidable, although it is the case that tracing down the roots of such failures and then refactoring the stuff at those roots will generally lead to a better separation of concerns. The problem is, in software, we generally never take the time to do that refactoring, and so we occasionally continue to be astonished at the most inopportune times.

Josh:

I’ve struggled with this issue too.

I haven’t come to any concrete conclusions either other than to emphasize that abstraction *costs*.

And not only does it cost, but it usually costs *more* than we think it does – because the person designing the abstraction is not the same person who has to invest the effort to learn how the abstraction works later on.

Abhijit:

According to Joel all abstractions are leaky. When this happens transparency helps. Both are required, because I believe people who need to know about abstraction and transparency are different. Abstraction is for users, transparency is for problem solvers.

After finishing Brand‘s How Buildings Learn a few weeks ago, I picked up another Brand book: The Clock of the Long Now which discusses (among other things) how one would design a clock intended to keep accurate time for 10,000 years. Chapter 11 lists the key design principles that the clock’s principal designer decided were most important to the clock’s success or failure. The principle that caught my eye was transparency.

(segue from discussion of clock design to software design)

Transparency is the quality of how easy (or hard) it is to understand how a mechanism works. Upon reflection, one of the reasons that I favor the pure Ajax/REST web architecture I described earlier is because it’s easy to mentally separate into three parts (browser, wire, server) and it’s easy to understand how these parts interact (HTTP requests from browser to server via wire; HTTP responses from server to browser via wire). Why is this ability to compartmentalize subsystems desirable? Because it’s easy to debug when something inevitably goes wrong.

But there’s a tension here; abstraction in software is supposed to be a good thing. The pace at which we can develop software has increased substantially for those of us who don’t have to worry about (for instance) pointers, packets, and concurrent access to persistent storage. Yet anyone who’s tried to debug a problem within an überframework will tell you that it’s hard to figure out where the error’s occurring (their code or your code), let alone fix it. This tension was described in Joel Spolsky’s the Law of Leaky Abstractions article. Net: all abstractions are imperfect, and when a mechanism underlying an abstraction fails, it’s difficult to understand and remediate the problem since the abstraction previously allowed you to remain blissfully ignorant of the underlying mechanism.

So from a design point of view, both abstraction and transparency have merit. Abstraction reduces the amount of detail one needs to master in order to accomplish a task or apply a concept. Transparency makes it easy for new team members to understand the flow of the system and allows developers and administrators to quickly track down and resolve problems. So how to find a balance between these two qualities?

I have some not-fully-formed thoughts on this question, so I’ll save them for a later entry, but I’d be happy to hear others’ thoughts in the meantime.