Sort of a continuation of the ongoing maintainability series, it's time to look at some of the benefits. And rant because that's just what I do.
After publishing My Programming Manifesto (about the things *I* was thinking about at the time) post, Scott Watermasysk quite correctly stated that usability was very important and completely missing from the manifesto. The first thing that popped into my mind upon reading Scott's post was "…it was NOT the perfect country and western song because he hadn't said anything about Momma, or trains, or trucks, or prison, or gettin' drunk" (if you understand that reference, you are *definitely* a redneck, and I, of course, proudly had the CD in college).
So, back to the title, what about Usability? Personally, I'm not very good with usability or GUI design in general, but what I do know from experience is that good usability and happy end users generally result from lots of user and BA feedback early and often throughout the project. Getting feedback is the first step, but it's worthless unless you can actually act upon that feedback. What I do know is how to write software that is maintainable and apply development practices that further enhance maintainability. In bullet point form, here's how I think good code and good development practices facilitate good user experiences through the successful application of user feedback.
- Slice the development work vertically instead of horizontally. This was one of the hardest lessons I had to learn when I was new to Extreme Programming. One of the constraints in defining a user story is that it must be a unit of work that provides observable value to the end users. Don't build the data layer or only infrastructure first. Write features from end to end and get these features in front of users as quickly as possible for early feedback. The feedback from users on the very usefulness of the project is probably more important than understanding whether or not an architectural choice is technically viable. In the former, you may need to cancel or reconstitute the entire project. In the latter you merely need to find a different technical strategy. Okay, in the latter you may need to cancel the project too. It's disappointing sometimes that black and white rules just don't seem to exist.
- You need to be able to push incremental changes of the system for demonstrations to the users, analysts, and designers quickly, reliably, and repeatedly. A solid Continuous Integration infrastructure and strategy is the best way I know of to make rapid deployment of development builds possible. You need a maintainable software ecosystem. Invest in this infrastructure early, because it'll get harder the longer you wait.
- From Scott's post:
"You need to think early and often about how users will use your software and make sure the code can accommodate that experience and not the other way around. It is definitely possible to write killer code and then apply it to a killer UI and then refine both as necessary. However, real world schedules and business practices make this a utopia."
Actually, to answer Scott's quote here, look back at bullet number one again about building complete features first. Simply don't allow any divergence in schedule between the user interface and the rest of the system if you can possibly help it.
I'm going to partially disagree with Scott about the code though, or maybe just specifically define "killer" code to mean code that is easy to understand and change. Say you've just finished a batch of features and successfully demonstrated these features to the users or user representative. After using the early version of the UI, the users ask for some changes to the user interface — even though these same people might have quite happily "signed off" on the UI design in some sort of specification or even a mock up. You do want to make your users happy after all, so you have to break open that existing code and change the user interface without breaking the user interface. A meticulous attention to separation of concerns (some flavor of Model View Controller) in your user interface code can isolate those changes, and make the code changes much smaller than they would be if you jumble display, behavior, navigation, validation, and business logic all in one massive file. I really do believe that writing orthogonal code will help you create more usable code by giving you much more ability to safely adjust your user interface without breaking its behavior.
- From Scott again: "If people love your software they will ask for more…which is when having unit tests/etc becomes that much more important." Ditto, and loudly. Automated tests, and preferably multiple layers of automated tests from the unit level to acceptance testing, do a great deal to enable change. Not just changes after your first release either. Automated tests will enable you to more safely change code to accomodate the usability feedback you get from the user representatives during the project.
- There's a persistent, and false, rumour that you cannot write automated tests for the user interface. You can automate testing for the user interface, but the conventional wisdom and my own experiences say that the best way is to remove as much of the user interface functionality away from the actual view machinery. It's worth your time to go learn about, and apply, design patterns like Model View Controller and Model View Presenter to separate the concerns (validation, behavior, flow control & navigation, security, etc.) within your user interface layer. The secret to testability in the user interface layer is to isolate as much as possible into "Plain Old Object" classes that are easy to test while keeping your View classes as thin as possible. You can apply tools like NUnitForms, NUnitASP, Selenium, and Watir to test the actual UI, but again, you're probably better off if you have sliced the View code thinly so you can write granular tests against a user control at a time. End to end testing through the client is an order of magnitude harder than writing unit tests.
- Go read up, or listen to, any paper, book, or podcast from 37signals. My short list of most admired software companies, besides Finetix of course, goes something like 37Signals, ObjectMentor, Google, and JetBrains. One of my former employers is an obvious omission to that list, but I'm subscribing to the Groucho Marx theory on them.
A mini-rant here. Don't treat the structure and design of the user interface code as less important than the server side. UI's will need to change the same way that business logic does, and need the same qualities of orthogonal code and infrastructural support from build and test automation. Moreover, user interface code, especially when it's heavily event driven, can easily be more complicated than the server side. UI code is very frequently the largest source of bugs because it has to interact with extremely unpredictable modules (humans). Don't put the very most junior developers on "mere" GUI coding. You'll need just as much architecture work on the client to achieve a good separation of concerns as you do in the rest of the system. I'm eagerly awaiting Martin Fowler's sequel to the PEAA book that deals with patterns for user interface clients.
Mini rant #2: Don't fool yourself into believing that you know anything just because it's in a specification document. All a specification document is is a snapshot of what somebody thought at the time it was written, and it's very likely you'll learn something as you go along that invalidates or illuminates part of that document. By no means does the existence of a "spec" give you a license as a team to turn your brain off. I'm very rapidly coming around to the increasingly common opinion that functional specification documents do more harm than good. More on this later someday.
Mini rant #3: Code behind's in the .Net world are View code, not controllers or presenters, period. Treat them accordingly.
Wait, there's more! I'm not sure about the timing or order, but the next two maintainability posts are going to be about tradeoffs between maintainability and performance optimization and a timely for me post on the "Don't Repeat Yourself" principle and the closely related Wormhole Anti-pattern.