Is that topic too wide for a single blog post? It certainly is, but I'm going to focus on some of the big pieces, and ignore lots of rabbit holes.
First things first, I'm talking about the kind of software that I spend my 8-5 working on. Namely, business type software with lots of data to capture, a fair amount of process, and a number of different "classifications" of user. This process will not apply to Operating System development, or multi-media application development, or sales websites, etc.
With that out of the way, here are my steps:
- Investigate the process this software is intended to solve
- Find out what data needs to be captured
- Design the UI
- Design the data queries and updates
- Design the database
- Design the code structure
I believe this fits firmly in the "UI First" category. Of course, on my list UI is #3, but #1 and #2 are really just reminding you to do good analysis of the problem before you start designing.
UI First is a pretty widely accepted approach. Here's some evidence:
- Rick Schaut: UI Design
- Jeff Atwood: UI-First Software Design
- Jeff Atwood: The User Interface Is The Application
- Matz on Craftmanship
- 37 Signals: Getting Real, Step 1: No Functional Spec
- Joel on Software: Painless Functional Specifications
BDD
I'm not too up on today's newest fad: BDD. But, I think my steps align fairly well with the goals of BDD, though they certainly aren't the same. BDD supporters will probably complain that I put "design the database" before "design the code structure". I would argue these are more or less interchangeable, but that database before code makes more practical sense for a number of reasons. For one thing, doing the db first allows you to use the Active Record pattern instead of the Repository pattern, if that makes more sense for your app. It also allows you to use a wider array of tools (Linq to SQL, Entity Framework, Ruby on Rails (scaffold!), etc).
Data First
Not database first, data first. There is a difference!
Its easy to take all the "entities" you know you will need and lay them all out into database tables, normalizing as you go. But databases can represent the same thing in a surprising number of different ways. So if you're just looking at the entities and data elements and laying out a database from that you're shooting in the dark.
You need to figure out how you're going to be using (querying, updating) this data first. For example, what searches will you be doing on what data elements?
This may lead you to discover that you will always return data from two entities together. If you'd blindly created two tables which contain many of the same columns, you'd constantly be unioning them. This will not only be a coding problem but could even become a performance issue, depending on how complicated things get. Maybe it would be better to de-normalized a bit and put both entities in the same table.
De-normalizing is not the only change you may make when you think about queries and updates first. As a real example, I once had a situation where I decided to add a bunch of bit columns to a table. These columns would represent if certain attributes where present or not. I was going to need to return entities that had some of those attributes on or off based on the person who was logged in. With bit columns my query would require mapping from the person's attributes to parameters on a stored procedure to the bit columns on the entity. It would also require lots of chained "where ( @bit1 is null or @bit1 = tbl.bit1 )" statements. This would all be a real pain to update when a new bit arrived, not to mention its a lot of repetitive code.
But since I thought about the query first, I realized I could represent the bits as rows in a child table of the entity. If the bit was on, there was a record for it in the child table, if not there was no record. Then the query simply became an inner join dramatically reducing the amount of code needed and making the whole thing more maintainable.
Don't take this too far. I'm not suggesting you prematurely optimize everything. But the database is there to support your application, not dictate how it should behave. So it should be designed to support the application as best it can.
How to design the UI
I suspect the reason why UI design isn't done first more often is simply because its a real pain. The simplest things can be ridiculously difficult. Sometimes you struggle with screen real estate. Other times you struggle with representing relationships (ex: parent, child).
But coming up with a UI concept is not nearly as hard as prototyping your UI. Laying out a UI, in Visual Studio lets say, can be a real challenge. Sure, for simple UIs its a breeze, but in my experience most UIs don't stay simple for long. Because the UIs are so hard to layout, there is real pressure not to change them. Please just find the first thing that looks like its probably passable and lets call it a day!
This simply comes down to a tooling problem. Visual Studio is not a great UI prototyping tool. Even if you avoid the slippery slope to perfectionville and remember your working on a prototype there's a problem. The problem is, it looks too good! When you show it to people it looks so similar to what the final product will look like, they wont be able to get past the fact that it's not perfect. They'll constantly be on you about "Why is that not lined up right?", "Why doesn't this look better", "Couldn't you have made this not suck so bad?"
What about whiteboards? Its easy and fast to sketch up some UI on a whiteboard. But, there are two problems here.
- Scale. Its much too easy to cheat on a whiteboard. You can make things fit that will never fit or make things look good that really wont. And you wont find out until you actually go to put together the UI...
- Unprofessional. If you want to share this with a client, or do a "screen demo" you'll be showing a bunch of digital photos of chickenscratch on a whiteboard. I know Peopleware says unprofessional is a word used by weak frightened managers, but in this case the truth is no one is going to be impressed by your whiteboard pictures. They might even think you're just lazy.
But, to me this seems like a lot of work. I want to prototype a UI, not enjoy craft time with my scissors and straight edge and glue sticks and note cards and post its and different sizes of paper and digital camera...
That's why I like Balsamiq Mockups. Its kind of like Flash meets Visio, so its flexible and very easy to use. I've been using it for only a week or so but I'm really enjoying it. It solves the "too perfect" problem by using images that look hand drawn. So when you show it to people, they can focus on what matters: how the user will inteact with the interface. And unlike my white board sketches, I find the look to be quite appealing.
To see what it looks like, check out their samples. This is a best of both worlds type of situation. Its easier to build and change than paper, faster to save snapshots, AND it comes out looking surprisingly professional, without looking so similar people can't focus.
And now you code
Of course, coding is the easy part... Ha! But, its easier when you have a good design. And hopefully because you have a good design, you'll encounter less re-work and fewer surprises.
You hit the nail on the head regarding Balsamiq! Fantastic tool that keeps focus on functionality instead of pixels.
ReplyDeleteYour approach to software development makes sense. Have you checked out NHibernate (or Active Record) in the past? It enables you to develop your database as you build your entities. Making it easier to create a top-down slice for an entire feature very quickly, instead of focusing on one layer at a time. The big benefit with this approach is that you can get iterative feedback from your clients as the project progresses, allowing you to react earlier to changes they might (will) need. Obviously this type of approach is possible without NHibernate\Active Records, it just makes it easier because you can automatically generate your db from entity mappings\attributes.
Overall fantastic writeup again Kevin!