Monday, October 17, 2011

A tribute to Steve Jobs

For some inexplicable reason, the death of Steve Jobs has deeply touched me. I felt as if I had personally lost someone dear. It wouldn't be a big exaggeration to say that this death was probably the first death of a public figure that influenced me so deep. So this post is an attempt to understand why.

I bought my first Apple product in 2006. It was a 30GB iPod (for those who forgot, back then it only played music :) ). I use it up until now and don't see myself changing it in a near future. I was fortunate enough to buy it in an Apple store, and as it is always with Apple, the excitement started there. I remember to this very day that it was like entering a museum of modern art. Everyone who has ever experienced this would understand what I'm talking about. The design in its best - in every little detail. The message that by buying at this place you join a circle of chosen people. The desire to linger there despite the fact that I knew exactly what it is I want to buy. To act as if I'm still not sure - just to breath the atmosphere of this place. Then, the package. Several years passed until I have disposed of the bag the iPod was sold in. The fabric, the logo, the "unlike-anything-else"-ness of this made me want to repeat the moment of opening the package. And finally, the iPod itself. As few buttons as possible - just like in the first Macintosh mouse. Actually, the first impression is that it doesn't have buttons at all! A case that looks as a single body, as if it was molded as a whole, without any trace of assembly. Several years later I discovered that it is possible to open it - it was in a desperate attempt to save it after it has fallen in a stream (together with myself). I remember it continuing to play music for some 30 seconds, being immersed in the water completely.

If I need to summarize what attracts me the most, it is the proof that perfection can actually work. My whole professional life tries to teach me the opposite - that it doesn't pay off to strive for perfection. That perfection is nice only in the theoretical computer science. That we are in the industry and shipping product on time with reasonable (or sometimes not) amount of bugs is more important than the internal architecture, the beauty of the interfaces, the robustness of the infrastructure. Well, I'm glad that there is at least one example that shows that it is not true. That it is important to make your product perfect. Because then your end-users will really love it! Not just use it because it's not as bad as competitors' but because it's really good. Because it's a pleasure to use it. I once listened to Joel Spolsky joking that the front of an IBM laptop is uglier than the back of a Mac. Well, he is right. I'm sure the reason Mac doesn't have the standard VGA connector is that the VGA connector simply looks ugly! No way this thing could have found a way into the beautiful Mac!

I'm typing this on my iPad which I own for less than two months. Perhaps this explains my passion. I must admit that there's something in this iPad which is so compelling that I'm using it for typing despite the fact that a keyboard would surely be more convenient and the editing would probably be easier on a normal screen. The reason probably is that it resembles a toy much more than a computer. We all prefer to have fun than to work. Or at least make sure our work looks like we are having fun. I have recently read in a newspaper article that Apple products don't require their users to learn to use them. It was used as an argument that Apple products promote stupidity. Well, for me, I think it's brilliant! No one comes up with an argument that a fridge is a bad product because it doesn't require one to learn it, right? When learning to drive a car the most difficult part is to learn to cope with the other drivers, not mastering the wheel. Thank goodness we don't have to "learn" how to use different models of elevators. It's about time computers turn into a commodity as well. Apple has done just this. Ever since I have an Internet connection at home, I'm wondering how people who are not programmers manage to keep it working. Well, my mother has me. What the rest of the people do? A friend of mine has told me that they plan to buy an iPad for her 90-year old grandmother. Doesn't it speak for itself?

And this is the second reason I love Apple products. Simplicity! Don't get me wrong, inside it's a state-of-the-art electronics. But for the user "the mouse should have only one button, to prevent confusion". In order to connect to my Exchange account, my iPad only asked me for my e-mail address and my password. My calendar and e-mail are now synchronized. I still didn't figure out how to do it properly on Ubuntu, so I'm using iPad to read and write my business e-mails.

And the overall process of buying and installing the applications? Isn't it brilliant? Both the simplicity of the process and the prices of the software! Meanwhile the most "expensive" application I bought costed $5, but I'm sure that at the moment I find myself writing documents on iPad, I will gladly pay $10 for the relevant application. I sometimes find it difficult restraining myself from actually buying it "just for the fun of it".

Do I know all the above sounds one-sided? I do. Do I realize I have been "charmed" by the cleverly  organized marketing strategy? Yes I do. Don't I realized I'm being used for the benefit of a single company? I do and I gladly submit myself. But! As long as I truly enjoy every time I take their product(s) in my hands. I once used to be a big fan of Nokia phones. Their idea of a single big button that "does the job" every time you need it was brilliant. But as years passed and models replaced one another, buttons multiplied. The "magic" button became just the "left button". Before I finally gave up and bought an iPhone, the last model I owned made me regret the moment I bought it every time I took it out of my pocket. I hear the next ones will have Windows inside. I'm glad I won't have to endure that.

Why am I saying this? Because there's no guarantee Apple will remain Apple after Steve Jobs has left this world. Especially in the case of Apple. I really hope I'm wrong, but I don't think there are too many people in this world who can do wonders that Steve Jobs has done. May his memory inspire the young entrepreneurs to come and prevent them from turning into regular "businessmen".

Friday, March 25, 2011

The pains of upgrade and how to alleviate them

User customizations! The same thing that many times makes the product successful, turns into a nightmare for its developers. Anyone who faced the challenges of deploying an upgrade over an existing installation knows what I'm talking about. If only things could be as simple as scraping the old installation and unpacking a new set of files! Alas! The cunning user has made changes in our precious files! He loves our product because of that! Everything is stored in readable, textual files! He reverse-engineered them and discovered that he could turn our great product into a fantastic one by tweaking these two little parameters! And now we're overriding everything! Oh, no!

My experience taught me that although the problem happens again and again, there is a set of rules which if followed judiciously, helps if not to avoid the problem altogether, then to minimize it at least. I'll state the rules and explain them with a set of examples.

Rule #1
Draw a clear line between the things you allow your users to customize and the things you don't. For instance, if the configuration is stored in files, put the customizable files in one dedicated folder. Name the folder appropriately. When the structure is organized this way, even if it is not documented, it conveys a message to your user - this is the area where you can make customizations and only here!

Rule #2
Separate the factory (out-of-the-box) settings from the user settings. For example, if you have a configuration file with default settings you allow your user to change, try to split it in two - "your" file that contains the default (hidden deep inside your files structure) and "user" file, which contains comments guiding him what and how he can customize.

Rule #3
Do not expose the factory defaults in a form that provokes changing them. For instance, instead of placing them in a file, place them in a resource packed inside a JAR and read it as an InputStream.

Sometimes the reality is tough and you find yourself being led by your users. I mean that sometimes a majority of them starts customizing things you didn't intend them to customize but you have to support it because you value your users. Even in this case, try to fix the situation post-factum by organizing things differently and implementing a clever upgrade tool that would transform the existing situation to a new format.

Why is it important to follow these rules? The first is rather simple - it is unpleasant to find yourself in a situation where you have overridden user changes in a certain place just because you didn't have a clue anyone besides yourself would want to change it. As I have just said, it can still happen even if you follow the rule #1. But in this case you'd at least have an excuse - this specific file does not reside in the "customizable" area, we didn't intend to support customizations done there. Again, if the user has a justified case, it's a subject for negotiations and support, but deep inside the user will know you're right.

The second rule is less obvious and one has to make a mental effort to follow it. Many times the format of a configuration file is predefined by some third-party tool or library we use and it's very easy to miss the point of decision. It wants a settings file - let's create this file and use it. The problem is that you'll never see any problem with it until the next release where you come with an upgrade. Then several bad things can happen.
  • You may upgrade the third-party library and see that it needs an additional parameter. If you override the configuration file, you override your user's possible modifications and make him angry.
  • You may reach the conclusion that you want to change the default value of one of the parameters. If you change it blindly, you may break the behavior for those users who customized it. If you don't change, you save them but the rest of the users don't get the benefit of the improved default.
  • The third-party library provider may decide to change the format of the configuration file. It rarely happens (everyone is in the same game) but if it does, you're in a deep sh*t.
However, if we consider these scenarios in advance, we may save a lot of headache in the future. This is the time to be creative. If the format supports the "include" directive, use it to split the file into the "factory" and the "user" portion (placing them in different directories as per Rule #1). If not, perhaps you may simulate it yourself by first parsing the two portions and combining them into a single temporary file to be fed to your third-party. The format is not friendly for a split? Perhaps it's worth to invent your own and again, convert it on the fly to something the third-party expects. If the third-party supports configuration by API this might be the best option. The same rule holds if you store the configuration in the database - do not mix the defaults and the user settings in one table because of the same problems outlined above. In short - think forward and try to save yourself from a complicated upgrade in the future. 

The meaning of the last rule is - if you don't want your user to customize something, don't provoke him. For instance, if you have (for any reason) a file that lists the names of your classes implementing a certain interface, do not store it in the filesystem. Turn it into a resource and hide it inside a JAR file. In general, avoid files because they are much harder to keep track of, to redistribute, to overwrite etc. When something is a resource, you can be 100% sure it is available, up-to-date and matches the corresponding code. So resources should always be your first choice. Resort to files only when it is absolutely inevitable.

To summarize - I believe that the absolute majority of upgrade problems can be prevented if the features are written with the upgrade in mind. The complexity of upgrade is not inherent, it is mainly caused by our own design mistakes. Design for upgrade!