Friday, August 19, 2011

A simple guide to effective logging

One of my coding pet peeves is lack of useful log messages. While logging is the simplest, yet effective tool in a developer's arsenal, it is often the most neglected one. We developers do not take the time to think through what and where we should add log messages in our codes.

We tend to use only "error" and "debug" level log messages. We use "debug" messages to help test our codes during development stage. But we add these debug messages on an ad hoc basis. And, our applications usually do not have debug level turned on in production (and we don't want to). The only other time we log messages is when there is an error or exception. This is partly because traditionally developers are not required to provide operational support for the software they write. They are usually removed from production support by 1 or 2 levels- a support team in the client's organization and then another in their own organization. With SaaS model, this separation is going away to some extent, but the issue persists. Well thought out log messages can save a lot of time & frustration with debuging production issues.

Here is a set of rules I use when I write codes,
  1. Use a good mix of 4 levels of log messages- error, warn, info, and debug.
  2. Usually "info" to "debug" ratio is 30%.
  3. "Info" is the most important log level from operations perspective, yet the most neglected and misunderstood one. Systems should run at info level. I see it as the "system's heart beat." At any point in time, anyone should be able to say how the system is doing by reviewing info messages. The trick is to achieve that using the minimum number of messages with just enough useful information.
  4. Use "info" message to trace high level application flow.
  5. Use "debug" message to trace detailed level application flow. Never use "system.out" messages.
  6. Use "warn" level messages when system can recover from a failure. Also use warn when a user is doing anything unusual, i.e. multiple attempt to login, or trying to access functions that they are not supposed to etc. This is specifically useful in the SaaS systems. "Warn" messages can serve as an early warning signal.
  7. Send email when an "error" message is logged. Do not use "error" level if you do not want to receive an email about it.
  8. Be vigilant about what data you write out in a log message. Only enough data to help track activities, but never any security sensitive data (in the context of the domain).
  9. Add context to the log messages. For example, date & time, line#, class name, method name, session id, user id etc. Logging frameworks available in most languages now-a-days are designed after "log4j," one of the most well-designed framework by Ceki Gülcü. Log4j and similar frameworks make it easy to automatically add this context to all messages. 
  10. Format log messages in a way so that it is easy to plop them into a tool like Excel for easier analysis. Here is an example of a good formatted log message,
[ DEBUG] | 110817 21:28:58 | pid-609 | user 2 | session 12345 | controller | effective_logging.rb:17:in `descope_multiple' | wi 12 descoped
Here is an example code showing a good mix of log messages used:



What guideline do you follow for logging?

Wednesday, August 10, 2011

7 usability guidelines for developers

Over last year, as we worked on improving the usability of ScrumPad, we learned a few things that are not so obvious to us "Developers." The conventional wisdom is that usability is something developers don't understand, or should defer to interaction designers. Some aspects of interaction design probably require specialist skills. But, here are seven things that we developers could easily do to improve usability by an order of magnitude.
1) Choose an appropriate default behavior.
Most applications have a default use case. This is usually implemented through some parameters with some default values. But, we do not take time to carefully analyze and understand this default use case. It is an after-thought or an ad hoc decision most of the times. Worse, we defer this to users by making them go through an elaborate setup process to pick the default values. We feel that users would feel empowered if we make them explicitly set these values themselves. As it turns out, most users want to get up and running right away and expect the application to just work. Customization, if necessary, should be "as and when" needed, and should be presented to the users in the context of their actions (and not as a separate action). We call it "on-demand incremental context-sensitive customization." For example, in ScrumPad, users can create a project with 2 weeks sprint as a default (they don't have to do anything extra). When they define sprints, the system would set the end date 2 weeks apart from a given start date. We even help pick the start date based on the last sprint / current date. We also pick the name of the sprint as "Sprint#count." However, users can change the length of a particular sprint by changing the pre-populated dates, or they can change the name of the sprint, if they want to, when creating the sprint. It may seem trivial, and it is, but this little thought about default behavior can greatly enhances the user experience.

2) Minimize required information.
Most applications have forms to collect different data. Some of the elements on these forms are required and some are not. We tend to make more data required than we ought to. What we found is that most of the time we over think what we should make mandatory when we collect data from users. We should really question our assumptions about what we think are really necessary. We need to allow users to move forward with the minimum information and let them provide rest of the information "as and when" necessary.  We call it "on-demand incremental context-sensitive data collection." Amazon does it really well. You can start shopping without needing to login. You are prompted for login at the last possible moment. We see this also in signup process for most of the new breed of Web applications. In ScrumPad, we used to force users to pick tags when adding stories. We thought we were helping the users by forcing them to think about themes / grouping for their stories at the time of creation. Our users did not see it that way, instead they found it annoying / limiting. We changed our mind and now it is an optional element, and the users are happy!

3) Trust users, not constrain them.
We tend to design our applications around the idea that our users, if allowed, would do things that they are not supposed to. If somehow we prevent them from doing "not allowed" things through different roles, we would help them. This Also gives us a false sense of satisfaction that our applications would become more secured. This was the case with ScrumPad when we initially designed it. Scrum promotes three roles- Scrum Master, Product Owner, and the team members. As any purist would do, we segregated these roles very strictly. As a result, we were forcing our users to fit into these straight jackets and made their lives difficult. As we faced with different real world situations, we started to relax some of these constraints by allowing users to be in multiple roles. Still with that, it felt like it was a work-around rather than natural. We started to question our assumption that we need to prevent one role from doing things that usually is expected of from another role. We came up with two reasons why we do this. One, we are afraid that we won't be able to track who did what. We could easily address this concern by implementing tracking "change history." Second, we are afraid that people will be confused about what a role entails. If this is the case, then we have a bigger issue than what a tool allows us to do. However, we are certainly not suggesting that we should allow everyone to do everything. Of course, we need to draw some lines among different roles, but we should minimize them to improve user experience with our system.

4) Mange the context.
All user actions have contexts. The context depends on what action was taken just before, what role a user is in, the location a user is coming from, what time of the day it is now, etc. etc. among many other things. Most applications don't do a good job of taking all these into account and making it easier for users to perform the action. For example, if you go to "Groupon" site for the first time, it forces you to choose a city or login/signup before you can see the current deals, whereas if you go to "Livingsocial" site, it recognizes your location, and allows you to go the current deals page for that location. Which one do you think is more user-friendly? Manging the context is becoming easier and richer (with location and other contextual inputs from other connected apps- i.e. social networks) now-a-days. It is in fact expected of applications to manage the context more intelligently.

5) Personalize interactions.
Personalization has become popular among applications now-a-days. We see this commonly implemented as "My page/data/tasks," popularized by "iGoogle" type personal Web portal sites. However, it is more static in nature, and requires the users to set it up. We can harness the power of personalization even more by making this more dynamic in nature. For example, what it means in ScrumPad is keeping track of report / search queries recently run, or the projects/stories recently viewed, or discussions recently participated in, or even better, organizing menus based on the usage pattern.

6) Don't interrupt, allow "undo".
Traditionally we have designed applications with many little interruptions in the form our pop-up prompts. This form of interaction design has been popularized by Microsoft. Here is a good illustration of this by Joel Spolsky in his Business of Software conference talk. The most common and popular of such interruptions is a "delete prompt"- asking user to confirm their intent to delete something. The thought behind it is users might accidentally clicked "delete," when he did not mean to. We know these situations are rare. We are interrupting all users most of the time for those rare occasions. Google has shown how we could avoid these type of interruptions by implementing "undo." We don't have to implement/support "undo" for all users actions. Given the context and domain of the applications, we could pick and choose actions that could benefit from "undo."

7) Learn and accommodate.
We are just starting to see more and more applications are designed to learn user behaviors and adjust accordingly. An example of this is Gmail. Gmail recently introduced tracking important emails. It tries to determine whether an email is important based on the context and the past actions by the users- whether the user opens an email from a certain user or with certain subject line for example. Also the users can explicitly tell Gmail which emails are important. Overtime, Gmail gets better at isolating important emails from regular. Recommendation engine (i.e., friend recommendation, content recommendation etc.) is another example where "learning" is applied. I'll use Zynga as an example to illustrate where an application could implement "learning mechanics." We all played Zynga's one of many popular games. One thing they encourage is to post status messages from time to time to Facebook. While I understand the motivation behind this, but it provides poor experiences to users who always choose to skip posting such messages. A better thing to do would be to learn the behavior of individual users and stop prompting for posting messages for the users that always/most of the time skip such actions. Instead, Zynga could provide a visible action button to post a message, just in case these users do feel to brag once in a while.

We can summarize these 7 usability rules into just one as Jared Spool would put it- "increase goal time, reduce tool time." In other words, we should do everything we could to not require users spend time in learning & using the tool (tool time) so that they can have more time doing things that they actually want to do (goal time).

The ultimate test of usability lies in how much training users need (in-person training, or help screen casts, or help FAQs) to start using a product. "A perfectly usable product" would not need any user manual, or training, or FAQs.

Do you have any insights for improving user experience?