Posts Tagged ‘software design’

Conceptual coherence in software design

There’s no doubt about it, a good design is hard to find.   But design is critical in software engineering, just as in hardware engineering – bridges, skyscrapers, iPads, anything in the physical world.  Design affects almost every aspect of product development and its costs – and in software, the most costly one is maintenance. 

I always try to take extra time in the design phase to ensure that I’ve got it right, since I find that with a good design, everything is easier – from the start.

clip_image002How do you know if you have a “good” design?   After all, no one in the world can sum up the essentials of good design in a meaningful way for everyone.  And rather than empty academic prescriptions — “flexible, layered, blah blah blah” — I tend to use a series of acid tests whenever I’m coming up with a software design.  For instance:

  • Does the design meet the needs of the project?
  • Is it flexible and extensible enough to meet the likely needs of the business moving forward?
  • Can the development team pull it off easily to meet committed deadlines?
  • Is it conceptually coherent?  Would someone easily understand it, or would it be an effort to explain? 

There are others, too; but in this post what I want to talk about is near and dear to my heart: whether a design is conceptually coherent, and whether it affords easy use. 

Conceptual coherence

Sounds fancy, but what this really means is: “does it make sense?”  Do the concepts “stick together?”  (From the Latin, co-, together, + haere, to stick.)   If you’ve factored your design into classes and entities, do they make sense at a high level?  Can the classes, components, and services in your design be easily understood and used by other developers?  Or do developers have to understand and master details that should really be hidden from their sphere of concern?

A good design will make it easy to create robust, working software:

  • Classes and components map directly to real-world entities
  • Object model is easy to use and supports real-world scenarios (containment, iteration, etc.)

Let’s look at each one of these aspects in turn.

Classes and components map to real-world entities

The classes and entities you create in your design should map almost 1:1 to real-world entities.  Name your classes and entities in terms that end-users understand; use vocabulary familiar in the solution domain.  We programmers are generally such a smart lot that we tend to invent alternate realities, populated with their fantastic devices and widgets. Sometimes we lose sight of the real one, and that eventually have to explain ours to someone else in order for them to use it.  Avoid this like the plague!  Keep it simple: classes and components should model “things” in the real world.

An astute reader pointed out that this is very similar to the concepts of domain-driven design, which is true:  see additional links at the end.

clip_image004Say you’re developing the My Golf Genius application, which will allow golfers to track their play on courses across the world, and will use massively parallel service-oriented clustered computing architectures in the cloud to apply brilliant heuristic analyses to captured golf rounds, bettering the game of the average Joe by over 8 strokes! 

Your classes, objects, and entities should model real-world things like golfers, clubs, courses, holes, tees, strokes, handicaps, and so on.   Even if the implementation seems trivial, create and keep entities separate if that’s the way we think about them in the real world.   In code, classes and objects are super-cheap to create and manage these days in all aspects, from compilation to memory footprint to runtime.  The benefits of conceptual clarity far outweigh the shortcuts. 

For example, our My Golf Genius application architect needs to keep track of the number of strokes per hole during play;  he could reasonably store the number of strokes as an integer StrokeCount in a MyGolfApp.Hole class.  After all, it is a “count” – and counts are integers or longs, right?  It’s design overkill to create a whole object to represent each stroke, right??

clip_image006

Not so fast.  What happens when you need to extend your successful My Golf Genius application to provide stats on how your success in sand saves correlates with the time of day, the weather, and the stock market trends that day?  You don’t have this info:  you only have “StrokeCount” for each hole.   The problem is that "StrokeCount” is really a rollup of the real data. The solution is, of course, to have a list of Stroke objects, each of which can be any legal type of stroke, such as a PenaltyStroke or a SandStroke.  You can even add Drives and Putts – which of course, derive from MyGolfGenius.Stroke.  

If the architect of My Golf Genius had started out simple, he would have captured the reasonably relevant details of what really happens on the golf course: a series of strokes are taken on each hole by a golfer.  Extending the application to capture stroke detail – which of course enables enhanced analytics for Joe the Golfer –  would then be a straightforward task. 

clip_image008

An exception to this rule might naturally be  an “extreme” design, such as a high-performance computing system or any system where memory, storage, or performance requirements might require a tailored approach.  Few systems are like this.

The model supports real-world scenarios

It’s important beyond all that the models and classes and entities you come up with are usable.   They should work together easily and make it difficult for developers to screw up.   A lot of this happens naturally if you have composed your entities according the “looks like the real world” directive above.   Developers can interact with your model in a straightforward way to access and use entities in the system. 

For instance, we’d certainly be happy to see a clear model like this, which every developer is sure to understand:

clip_image010

Avoid creating leaky abstractions,” where the user must understand underlying implementation details or “gotchas”  in order to use your object model correctly.   The developer’s mental image of what’s happening must match what the objects are doing in software;  if there’s a disparity, the developer doesn’t really understand what’s going on.

Conclusion

Model your designs after the real world, and your solutions will be easy to create, easy to use, and easy to test.  By not inventing an alternate world in software, the team will have a ready common language of objects between them, with an existing understanding of how they interrelate and function.  In addition, other stakeholders such as business analysts and testers will find it easier to relate to the system.

***

More reading

  • Joel on Software: The Law of Leaky Abstractions
    Abstractions “leak” when you have to understand the underlying implementation details in order to use them.
  • Domain-Driven Design,” Eric Evans (Amazon.com)
    The book that started it all: four stars, well-loved by its readers. 
    “Readers learn how to use a domain model to make a complex development effort more focused and dynamic. A core of best practices and standard patterns provides a common language for the development team.”
  • Domain-driven design (Wikipedia.com)
    ”Domain-driven design (DDD) is an approach to developing software for complex needs by deeply connecting the implementation to an evolving model of the core business concepts”
  • The Secret to Designing an Intuitive UX: Match the Mental Model to the Conceptual Model (UXMag.com)
    An analog in user interface design – again, the paradigm of matching existing mental models. 
    “The secret to designing an intuitive user experience is making sure that the conceptual model of your product matches, as much as possible, the mental models of your users”

The metaphor in software design

[tweetmeme source=”KeithBluestone” only_single=false]One major problem with software today is usability: user interfaces are difficult to use, obscure, confusing, and frustrating.   Why?   Because they do not present consistent metaphors to the users, who don’t understand what the software is doing.

Metaphor, metaphor, on the wall

Quicken check formAn interface metaphor represents the user’s conception of what is going on.  UI coherence is achieved if the user’s mental model mirrors what’s going on in the software.

As in life, software interface metaphors should be simple, common, and relevant.

An early example was Intuit’s Quicken bill payment software:  Quicken presented check-writing and bill payment functionality using the metaphor of an ordinary checkbook.

How radical!  Making software in the model of real-world things!  If only more software was made as easy to use as Quicken…

The checkbook and its checks are familiar to all of us — well, most of us.  As a result, we immediately understand what the application is doing and find it highly user-friendly.

Poor design strips context

An impaired metaphor – a poor design — for check-writing might present fields in a table-like layout, labelled “number”, “payee” and “amount” and “date.”  Think spreadsheet.  (Trust me, it has been done.)

Tabular design-inappropriate metaphor

In this interface design, almost all the aspects of normal, real-world bill payment  have been stripped out.  The process has been reduced to a simple task of data input.  Bland and tasteless, isn’t it?

So what, you might say.  When writing a check, everyone has to enter the check amount and payee anyway — it’s just a few fields of data.  What’s the big deal about the "check" form and all these fancy “metaphors?”  Seems like a big waste of time to me.

Well… no.   Check-writing is just one aspect of managing finances on a computer.   There are a whole host of other activities that need to be addressed, including managing the register, searching for items, reconciling the “checkbook,” and reports.   We already have a conceptual framework for doing most of these things in the physical world.

What are you, the developer, going to do?  Re-invent the wheel for each concept and activity by providing new, “de-natured” modern-age mechanisms for each — a form, a field, a listbox, a grid?   Or will you create familiar models for your users?

Encapsulating familiar metaphors in self-contained packages – user interface controls, for instance – promotes re-use across the codebase (lowering SDLC costs) and a better, more consistent UI (looking and behaving the same everywhere).

Affordances

Affordance is another key usability concept mentioned by Don Norman in his excellent Design of Everyday Things. An affordance suggests or directs the appropriate action.

A good example of a design with a prominent affordance is the lowly doorknob.  It’s shaped and sized for the hand to grab comfortably, and it’s placed at a height which makes for easy access to the hand.

Affordance ensures effective use.  The best designs are ones that can’t be misunderstood, and which don’t cause frustration.  The same applies to software design as to user interface design.

Doorknob

Is your design as good as this? 
(Don’t gold-plate it unless you’re asked to…)

Poor design is very expensive

Defining usable metaphors takes time and dedication to the task.  It takes time to model the entities in the application domain – entities the user will already be familiar with, and a requirement for creating a coherent model.  Often, the designers or engineers cave to schedule pressure and use an assortment of loosely coupled, functional designs:  the fields and listboxes and grids mentioned above.  These get the job done, but often at a high cost to UX, code clarity, extensibility, scalability, and maintainability.  

Individually and for certain tasks, these metaphors may be usable and may make sense.   But no system is an island any more, and complexity and other issues may pop up at system boundaries, interactions, and special cases.

As users, we have high expectations for software, and it’s the unexpected failures, the crashes, the lost documents, that lead us to silently loathe software.   Tell me:  who loves Microsoft Word?   Many use it, many respect it, but very few actually love it.

Conclusion

When designing software, ask what metaphors you’re offering to the user.  The key to usability is modeling your user interface after concepts the user understands fully.  As an added benefit, these concepts generally map one-to-one to objects or entities in your software designs and models, so you’re killing at least two birds with one stone.  There are many other benefits, all of which lead to better software in less time.  

Whatever it is you’re building, develop your metaphors fully, then make the software behave consistently with them.  Your users will thank you – and your clients will re-hire you.

Some great examples include:

  • Quicken’s check metaphor. As mentioned above.  More or less everybody could figure out how to use Quicken in 15 minutes.
  • Control panels. A good control panel or dashboard metaphor enables a user to understand what’s happening at a glance.  Everybody understands gauges, warning lights, and switches;  and almost everybody understands the basic semantics of red (problem/critical), yellow (warning), and green (ok).  
  • Print layout view.  Shows documents on the screen as they would look in printed form;  most modern word processors have this feature.
  • The Macintosh trash can icon.   Trash canContinues the metaphor of a real desktop; understood and loved by all.  (Yet to be understood:  why Apple’s OS designers violated this metaphor most rudely by requiring users to drag their disks into the trash can to eject them.  Tell me you didn’t think long and hard before you did that the first time.)

***

References / more reading

  • The Secret to Designing an Intuitive UX: Match the Mental Model to the Conceptual Model (UXMag.com, April 2010)
    This is what a metaphor enables…  Excerpt:
    “The secret to designing an intuitive user experience is making sure that the conceptual model of your product matches, as much as possible, the mental models of your users.”
  • The Design of Everyday Things (Donald Norman).   Excellent, fun-to-read treatment by one of the world’s foremost design authorities.  Learn about “affordance” and other tenets of good design, illustrated in everyday objects in the world around you.
  • useit.com (Jakob Nielsen).  A partner of Donald Norman (above) in the Nielsen-Norman Group and also a leading design expert.  Great articles and perspectives on usability.
  • Interface metaphor (Wikipedia).  Actually uses the example of files and folders, too. (I wrote this article before I read the Wiki entry.)
  • Tom Proulx (Wikipedia).  CO-founder of Intuit and passionate user interface designer who pioneered software usability testing.
  • Web Design Trends 2010: Real-Life Metaphors and CSS3 Adaptation(Smashing Magazine).