Design, Programming

Simplicity via Redundancy

Typically when we do a time versus space tradeoff analysis for solving a computational problem, we have to give up one for the sake of the other. By definition, you trade reduced memory usage for slower execution or vice versa, faster execution for increased memory usage. Caching responses from a web server is a good example of space traded for time efficiency. You can store the response of a web request in a cache store hoping that you could reuse it, if the same request needs to be served again. On the other hand, if you wanted to be space efficient, you would not cache anything and perform the necessary computations on every request.

When I am having a discussion with my colleagues, this time versus space tradeoff analysis comes up quite frequently ending in a time efficient solution or a space efficient solution based on the problem requirements. Recently I got into a discussion which gave me a new way of thinking about the problem. How about if we also include simplicity of the solution as another dimension which directly contributes to development efficiency. In an industrial setting, simplicity is just as important or the lack thereof costs money just as time or space inefficient solutions would.

So the recent discussion I had was about a problem that involved some serious computation at the end of a workflow that spanned multiple web requests in a web application. This computation would have been considerably simpler, if we stored some extra state on a model in the middle of the workflow. It started to turn into a classic time versus space efficiency debate. Time was not an issue in this case and hence giving up that extra space was considered unnecessary. But I was arguing for the sake of simplicity. Quite understandably, there was some resistance to this approach. The main argument was “We dont have to store that intermediate result, then why are we storing it”. I can understand that. If there is no need, then why do it. But if it makes the solution simple, why not?

I admit there might be certain pitfalls in storing redundant information in the database, because it is not classic normalized data. Also, there could be inconsistencies in the data, if one piece changes and the other piece is not updated along with it. Also it might be a little weird storing random pieces of information on a domain. Luckily in my favor, none of these were true. The data made sense on the model and could be made immutable as it had no reason to change once set and hence guaranteeing data consistency.

Extending this principle to code, I sometimes prefer redundancy over DRYness (Don’t Repeat Yourself), if it buys me simplicity. Some developers obsess over DRYness and in the process make the code harder to read. They would put unrelated code in some shared location just to avoid duplication of code. Trying to reduce the lines of code, by generating methods on the fly that are similar to each other, using meta-programming can take it to a whole new level. It might certainly be justified in some cases but I am not sure how many developers think about the added complexity brought on by this approach.

A good way to think about reusability is thinking about common reason for change. If two classes have a similar looking method, and you want to create a reusable method and have it share between the two, then you should also think about if those two classes have a common reason for that method to change. If yes, then very clearly that method should be shared, if not, may be not so much, especially if it makes the code hard to understand.

I feel redundancy has value sometimes and simplicity should get precedence over eliminating redundancy. Thank you for reading. Comments welcome.

Standard
Design, User Experience

Design Studio

My dream job would be a place where I get to play with, interact with, and build physical objects. It is incredibly satisfying to hold something in your hand and say I built this. It gives you that instant connection with the fruit of your labor. Now given the business that I am in, of building software (which I love by the way), there are no physical objects in a software system. The closest we get, is drawing some diagrams to represent the components in a software system or show how data flows between those components. Physical objects are great not only from a gratification point of view, but they also provide valuable feedback on the design and usability of the system.

Enter the idea of design studio for software. The idea is to have entities in a software system represented by physical objects, that you can touch and feel. When you interact with this physical world of software, you would get a much better feel for the system you are building and it would accelerate your learning about the system under construction. Also it levels the playing field between the designer of the software system and the innocent user. Let me explain how.

Lets say you are building a website that comprises of multiple screens. In this design studio, these screens would be represented by wooden blocks that would be placed on the floor, large enough for a person to stand on it. A user navigating these screens in a real world would be represented by a person jumping from one wooden block to the other. In addition to moving around on these blocks, the person would have to carry weights on her/him. These weights would be representative of the “effort” that the user has to put in, to use the website. Example of such “effort” would be the presence of too many UI (User Interface) elements on the screen, like buttons, drop-downs, et al (more UI elements, more effort required on part of the user to understand what they do), waiting time spent on the screen, information user has to hold across screens (did I click that checkbox 2 screens ago or am I shipping this to the right address on the checkout page with no shipping address on it), etc. All these things negatively affect the user experience on the website and hence, in a physical world, weights would be added as and when the user is subjected to such “effort”, when jumping from block to block.

So the first justification for building such a design studio would be to reduce the user interface complexity of a system. When professionals design a website, they often do not realize what a user really goes through when navigating a website. This is partly because websites are built by professionals for people who have little or no experience in working with a website. Imagine if you were to click a couple of extra links to get somewhere on a website, you might not think of it as a big deal. But if you were to hop around a few extra blocks carrying all those weights, then it seems a bit too much. When the designer is feeling the pain (literally) the user goes through on a real website, in a sense we are leveling the playing field between the designer and the user.

For usability testing, you could bring in some real users and have them walk through this physical world of the software system. You could introduce them to this “game”, hand them a task and see how they perform. You could have the person, leave a breadcrumb, when she/he jumps over the wooden blocks. This way you could study the paths they take through the system. With the help of the physical trace, you might notice that people, when performing apparently simple tasks, jump through a lot of “hoops” (in our case blocks), when it should have been rather obvious to begin with. This could be because of bad layout or just incorrect assumptions about user behavior. The solution could be as simple as placing related blocks adjacent to each other or providing appropriate directions to the user on the blocks. This would translate to providing a better workflow to the user in the software system and placing related screens closer to each other and linking them in a easy-to-find way.

The other justification for the design studio would be to get feedback on the system architecture. Same situation, you were building a website with some screens. Lets say each screen was backed by a combination of databases and services. Now as per the previous analogy, each screen would be represented by a wooden block and each external service/database would be represented by a physical box. There would be ropes connected from a screen to all the external systems that it talks to. What do I get out of this?

First of all you get the system view of things. You can easily tell if a screen is backed by too many external connections and infer that the screen might be slow to respond to user input. May be you should think of consolidating the external system end points or move some of the functionality to a different screen. Going back to the earlier example, you would add additional weights proportional to the connections the screen makes, to account for the latency introduced by the system integration, when you jumped on the wooden block representing that screen. Typically this kind of system integration information is left out of initial prototyping and becomes cumbersome to incorporate later into the user experience. User experience is not just about how the software looks but also how it behaves. Integration points can have a huge bearing on the design of the user experience and it is better to identify them sooner than later.

One other thing that I would like to throw in there is that the lengths of the ropes connecting the screens to the external systems should be proportional to the integration effort. Say a database is quick and easy to work with, so it gets a shorter rope, whereas an external uncontrolled service gets a relatively longer rope. A crazy idea would be, just by measuring the lengths of these ropes, you should be able to put some estimates around the actual integration effort. Yaa, how about putting some science into estimation!

All in all, it feels that this experiment might be worthwhile to give it a shot. I hope I can try this out soon enough on a real project. Thanks for reading and let me know how you feel about this idea.

Standard
Design

Design Thinking

I just finished reading Donald Norman’s ‘The Design Of Everyday Things’ and here are my thoughts on it. The author talks about a lot of enlightening concepts and I will summarize them as I understand them. There is plenty of other interesting stuff in the book that I have not covered here, including great pictures, and I would strongly urge you to read the book.

Natural mapping: The author says that when designing systems, you should make use of natural mapping. What does it mean? For example, lets say you were designing the switch board for electrical appliances in a room. One way and the common way to do it would be, to place all switches in one straight line. Now, this means, that the user has to remember, which switch does what. If you use natural mapping, you would design the switch board in such a way that the switch position on the board mirrors or maps the physical location of the appliance it operates in the room. This way it is very intuitive, which switch goes to which appliance in the room. Another great example is the gas burner switches, that I struggle with almost every day. I can never remember, which switch is for which burner. The author suggests some beautiful designs to map the actual burner position to its switch. Doors are a source of constant pain when operating. Wouldn’t it be nice to have a flat plate on the side of the door that needs to be pushed to be opened and a vertical bar for ones that need to be pulled. Why is it so hard? Any way, another nice example of natural mapping, that I have encountered on a Mac is, you see the Caps lock light located on the button itself. Sweet, no more searching!

Knowledge in the head versus knowledge in the world: This concept is complementary to the natural mapping one. If you make use of natural mapping, like having a switch board that mirrors the physical layout of the room, it reduces the burden on the person to hold the knowledge in the head of what switch does what. On the contrary, you are putting that information out in the world! A great benefit of this is reduced learning curve for everybody, when dealing with new switches.

Visibility: When designing systems, sometimes people get too caught with aesthetics and don’t care much about usability. You might have come across numerous faucets or doors that look awesome but are not very friendly to operate. Every time I see one of these new faucets, I spend at least a minute or two trying to figure out how to make it work. I once rented a car for which I could not figure out for a long time how to lower the windows. I approached a toll booth and I actually had to get off of the car to pay the toll. Funny! Later I figured out there was a small knob above the radio to lower the windows. Who thought it would be a good idea to put the window opener on the dashboard. Another funny incident that happened to me on the British Rail train, which I think the author mentions too in the book. The train stopped at my destination station and I was waiting patiently for the doors to open automatically, as there was no handle on the door to open it. Somebody walked from behind me, lowered the window on the door, put his hand out and turned the handle on the outside to open the door. Holy cow! Had I not known about that, I would have easily missed my stop. Coming to the point of visibility, the author argues it is extremely important to provide visual clues, to help the user, to operate the system. A long hanging chain with a handle at the bottom provides a visual clue that the device can be operated by pulling it. Sure aesthetics are important, but usability comes foremost. And by the way, I don’t think the British Rail train door was designed that way for aesthetic purpose. 😉

While I was reading this book, I had my own moment of slight ingenuity. I was thinking about how I have had a hard time opening cabinet doors that have a flat plate on the corner that needs to be pushed and then some spring is released and the door pops out. I always try to put my finger in the small gap between the door and the cabinet and pull it out. I thought it might be nice if you could make a small depression on the plate, big enough the size of a finger, to indicate that the plate needs to be pushed to open the door. 🙂

Feedback: The author talks about how important it is for the system to give the user feedback, for the action they have performed, to assure that they have completed the task successfully. You do not want people sitting there thinking the machine is doing something when it is doing nothing or even vice versa. Feedback can be provided by sound (buzz when the microwave door opens), lights (caps lock is on), tactile (pressing a button on a telephone), et al. These are examples of feedback provided after an action has been performed. One of the examples that the author gives, is for providing feedback, even before an action is performed. This is about designing aircraft switches for landing gear and wing control, which I thought was ingenious given the risk involved in flying an airplane. He suggests that we create the landing gear switch shaped like a tire, whereas the switch that operates the wings shaped like a flat plate. When the pilot is working with these switches, the tactile feedback of touching a flat plate versus a round knob would have a much bigger chance of reducing error as opposed to having both the switches feel the same, especially in pressure situations.

Constraints and forcing functions: Constraints can be used very effectively to better design products. For example, keys for locks are designed in such a way that it goes in only one way, which is a constraint that is built into the system to avoid making errors. Computer programs do this well these days with disabling certain options on the screen when they are not applicable to the user. Washing machines do not let you open the door when the system is running to avoid possible mishap. The author talks about other types of constraints like cultural constraints. An example of this would be when creating a LEGO model of motorcycle driver, the user knows to build the model with the motorcycle driver facing forward because it is the only possible way the driver can drive safely. The author issues a word of caution in using constraints because sometimes they can be a source of annoyance. You would know what I am talking about, if you have been in a situation where you are carrying stuff in your car and you place a heavy bag on the passengers seat and the seat belt buzzer goes off when you start driving the car. It would be dangerous if the driver permanently disabled the passenger seat belt warning. What I have seen happen is that the seat belt warning beeps for a while and then displays a warning on the dashboard to indicate the non-compliance, which is not so annoying.

So what do I think of the book? I think it is great. It is very insightful. I got a little lost in the middle where it starts to talk a lot about psychology but there was always something that piqued my interest. The other thing I liked about the book is the book itself. Its nice and concise with 200 odd pages. I think books with about that size are perfect. They are easy to carry around, not too long yet enough to give a good understanding of about anything in the universe.

When I first started reading the book, I thought all these issues were minor, trivial or first-world problems1. Then as I started thinking more about it, I realized how important the problem is of fixing the usability of everyday things like train doors, aircraft switches, car windows, gas burner switches, et al. The problem only gets worse when you think of operating these devices in a panic situation. We have been producing fantastic devices until now but not paying a lot of attention to usability and I think that should be one of our top priorities going forward.

[1] First-world problem

Standard