Monday, September 15, 2008

Some Android (and Java) Lessons Learned

In my spare time over the previous 3 weeks I developed a small application for Google's Android platform. I did this to learn about it in more detail than is possible by only reading general descriptions. The utility for me is to better inform my future decisions for commercial ventures.

A secondary objective was to have a bit of fun. I have not programmed in a very long time and I wanted to challenge myself to see if I could do it. Not only have I never programmed in Java, I have never programmed in any OO language, so I needed to endure some painful re-education. Add to that my unfamiliarity with modern development tools (Eclipse in my case), mobile devices, and of course the entire Android OS with its APIs and emulator. Looking back, perhaps I should be surprised that I accomplished anything at all in just 3 weeks!

As the title says I want to relate what I learned during this process. This article will most likely be of no interest to non-programmers. To programmers it will at best perhaps be of no more than cursory interest. Nevertheless I find it instructive to document these points if for no one's benefit other than my own.

My first attempt to start coding in Java was to use the monkey-see, monkey-do method. This entails liberally cutting and pasting structure and code snippets from sample programs and usage examples shown in the documentation, then modifying these segments in accord with a general sense of how things ought to work. I've done this in the past and it can be quite successful. However in this case I failed miserably. The structural paradigms underlying object-oriented languages are too different from my experience with the earlier generation of 'linear' languages. An analogy to my difficulty would be when a speaker of English, French, Spanish and German decides to learn a new language by leveraging knowledge of sentence structure and common linguistic roots. This can work well when tackling another European or Indo-European language, but not for, say, Japanese. Its historical roots are entirely different.

Sadly this meant I had to hit the books (web sites) to learn the basics of OO and Java. I tried the various introductory material on Sun's and other sites, but found that tutorial material primarily targets beginning programmers, so the material was too elementary for my needs. I settled on the Java language reference manual as my primary guide. While this would be a terrible way for a beginner to learn, I was able to skip around and learn the elements of OO fundamentals, Java structure, and the particulars quite quickly - about 8 hours spread over 3 days. Though still a neophyte I now grasp the principles well-enough to understand what I see and write code that works, without simply aping what others have written.

With that introduction to my quest I will list some curiosities that popped out at me as I went along. If you already know all this stuff well, you might not find this of interest, though perhaps for others who find themselves in my particular situation (there must be some out there) it may be useful.
  • Java is a police state language. Back in graduate school (a long time ago), a visiting professor (forget the name now but he was well-known in formal language theory circles) liked to characterize computer languages by two general attributes: easy to write good programs, and hard to write bad programs. The latter he called a police state language. Java seems to fit the latter attribute pretty well. Something you must do when faced with a police state language is to learn all the things you must do and those things you cannot do. This can be tedious unless you are very experienced with the language since it requires lots at reference material at hand to write any code at all. With a language like C, to pick a random example, you can get going much quicker, with the attendant danger that it is easy to create bugs that are hard to pin down.
  • Java has strong typing that is very flexible, but which I found hard to navigate. Perhaps my biggest difficulty was type conversion. Java, along with reams of imported classes, has several ways to do this, and it is never very clear which to use in each case. Let me give an example. I needed to do lots of conversions among String, CharSequence and Float. Depending on the classes and their methods, I had to determine if I could do a cast or use a suitable method (and the class that defined it). It can be tedious finding the one to use in each case. Then there was a case I ran into where I needed to convert a String into a CharSequence but a cast wouldn't work and I couldn't find a method that fit. In frustration I placed the String object into the parameter that required a CharSequence and ... it worked.
  • Strong typing can let you down at run time. While the Eclipse IDE is good at finding compile-time typing errors, there are many cases where this can't be done, about which the Java reference manual gives ample warning. When a type error occurs at run time it can be time-consuming to find, understand and correct. Then there was an oddity I discovered (at least I found it odd) where methods of a particular type, say boolean or float, that when used were indifferent as to whether the result was used. For example, say there's a method declared as 'public float fred (int v)'. The method can be used in the statement 'fred(x);'. The result of the method isn't referred to in its use, and Java is indifferent about it. This seems bizarre seeing how strict Java is about usage of types. There may be a good reason for allowing this in the language, but I cannot guess what.
  • Logic flow is easy to subvert into something resembling spaghetti. You can, for example, place a return statement pretty much anywhere to end execution of a method. Similarly, you can insert a finish() anywhere to terminate an Activity. This violates all I learned about good program structure; I learned, and came to believe, that logic flow should be logically nested with no ability to jump into or out of a code block except at the beginning and end, respectively. It's almost as bad as the old go to statement. Related to this is the ability Java permits to dynamically assign a type to an object. Considering what a type can be, including a large swath of code, while being nicely fungible it also allows the creation of unfathomable code. Sure, lots of languages like C allow this, but, again, this seems like an inconsistency with Java's rigidly-enforced type rules in other circumstances.
  • Locating and structuring nested objects, packages and inheritance can be important. For my first program I had a lot of difficulty deciding how to arrange classes of objects and methods. There are many ways to do so and it is up to the programmer's judgement to decide how to do this. With everything else on my plate I simply gave up and put the entire application in one package with one class, with all the primitives and other objects available to all the many methods I defined. I did keep some primitives local to a method, but that was an exception to the rule. I know I'll have to do better in future if I want to keep applications easy to work on, and also when I need to launch multiple activities.
  • A large effort is required for designing UI and persistent data storage. Applications for mobile devices have to pay close attention to interactions with the user. Time is profitably spent designing screen layouts and informative feedback. Interaction requires buttons, menus, forms and information displays of many types. That means laying out screens, usually in XML, in great detail and provide support in the code for all the user activity events as they click and type away. Of course all the data entered and generated often needs to be stored for later retrieval, which requires good schema design and database interrogation techniques. After doing all this I found that the core application code can be a small part of the actual effort!
Apart from Java, I also had a lot to learn about the Android APIs to write even the simplest program. I won't mention all of that here except to note that the documentation, while extensive, is in many cases difficult to navigate to the information I specifically need. There are also errors sprinkled throughout, though documentation quality is gradually improving. In some cases the material still reflects the older SDK and not the most recent one (0.9).

Now that I have gotten as far as developing a working application I may stop. I am mostly interested in understanding enough about Android to make better choices in application design, and not to necessarily do the development myself. Despite the difficulties I encountered due to my rusty skills I did enjoy myself. I now have some dim remembrance about why I originally got into the software field so many years ago.

No comments: