Tuesday, September 30, 2008

Writing Large-Scale iPhone Applications using Jiggy

Developing for the iPhone is the hype nowadays. However, one big obstacle that faces anyone who wish to write iPhone applications is learning Objective-C. After all, it is a high-level Object Oriented language. However, in my point of view, and for many people as well, the C family of languages is not suitable for application development. It is perfectly suited for writing system libraries and frameworks. This is because one should always take care of memory management, types and low level system calls.

Thats why we are here, quoted from the Jiggy official website:


What is Jiggy?


Simply put, Jiggy is the easiest way to create applications for the iPhone (or iPod Touch). With just Jiggy and a browser, you'll be able to write an awesome iPhone application in a matter of minutes. JiggyApps run natively on the iPhone, so there is no messing around with HTML and the limitations of Mobile Safari. At the same time, you don't need a compiler or even a Mac, because JiggyApps are written in JavaScript.


When you start writing an application with Jiggy you will find it very simple. However, as your application grows it will be so hard to maintain. Thats why I am writing the following guidelines, which if followed, will help you write large-scale, neat and maintainable Jiggy applications:




  1. Don't use the Jiggy IDE, prepare your development environment around ssh.
    If you already installed Jiggy on your iPhone, you will probably have noticed that there are 2 packages your are installing. First one is called Jiggy runtime. This is a set of dynamic-link libraries that encapsulate all native functionality. These are installed in the library path of the system (/usr/lib) and start with the prefix jiggy, as an example: jiggy.UIKit and jiggy.sqlite. The other package is called just Jiggy. This is the Jiggy IDE I am talking about. It is just an application server built on an HTTP server. You run it from SpringBoard, open a browser on your PC and point it to the iPhone IP to get the IDE working inside the browser. This is the simplest way to develop Jiggy applications. You only need a browser. Running into big applications, you will soon find that the browser is never meant to be a reliable IDE. It WILL crash more frequent than you expect. It will leak memory to the ground. It will freeze for seconds as you save and run the application. Moreover, to work on multiple files simultaneously, you have to open several tabs/windows. You can use this IDE as a fast boot but when you eventually develop seriously you need a more reliable environment. Install OpenSSH on the iPhone (but be careful if you need to change the root password). Next, mount the iPhone filesystem using sshfs:

    sshfs root@IPHONE_IP /mount/point -o allow_other

    You can download sshfs from its official site or if you are using Debian/Ubuntu by:

    sudo apt-get install sshfs

    or if you are using Gnome use the menu Places/Connect to Server... and select server type as SSH. Write the iPhone IP and root as the username. A shortcut will be placed in Places and on the desktop. Either way, you can browse through /Applicatoins/ and point to your application folder then double click on any Javascript file to edit using your favorite editor. I personally use gedit or vim. Just a note, be sure the iPhone is mounted before editing the files or the editor may get confused and hangs.

  2. Distribute required runtime libraries along with your applications, don't assume Jiggy runtime.
    These can be found in /usr/lib as discussed earlier. During the installation process, don't copy the libraries in the system /usr/lib in order not to conflict versions. It is safer to leave them in the application directory. By the way, I didn't try leaving them in the application directory yet :) On the contrary, you may prefer to distribute the libraries through Jiggy runtime. However, be very clear in the installation steps.

  3. For a more stable and collaborative environment, use a code repository and deploy on device as needed.
    When your code-base grows over time, you will discover that it is safer to use a code repostiory (Subversion of CVS). This will also enable you to share the application with other developers. Now you don't have to mount the iPhone filesystem using ssh as you will not be editing files in-place. You will have a working copy on your PC which is linked against some repository. Each time you need to run the application you will have to copy files over the iPhone, you can write a small shell script to do the copy commands. Till the time of writing this line, Jiggy is only available for the iPhone OS 1.x which has no official SDK or emulator from Apple. If Jiggy is ported to iPhone OS 2.x it would be easier to run applications on the emulator without the need of copying files on each run.

  4. Avoid using off-the-shelf libraries (prototype for example), you don't need larger useless interpretation times.
    Usually you won't need fancy mechanisms or drag-and-drop and alike functionality. If you need to use AJAX, write your own prototype-alike around the XMLHttpRequest object. If you are too lazy to write it, see mine.

  5. Don't start the application from SpringBoard (if you don't have to). Start it from an ssh terminal instead.
    Some functionality won't work if you don't start the application from SpringBoard (like the accelerometer). If you don' have to, ssh to your iPhone and change to the applications directory then launch the jiggy binary:

    ssh root@IPHONE_IP
    cd /Applications/MyApp.app
    ./jiggy

    This is a must if you need to see useful log messages from Jiggy native implementation. You can also write your own logs straight from Javascript using the global function log(). See my other post for a discussion on logging in Javascript platforms.

  6. Optionally generate a public/private ssh key-pair so that you don't have to enter ssh password every time you login to your iPhone.
    See the OpenSSH page or this good tutorial.

  7. Keep your main.js as small as 10 lines or less.
    This is always a rule-of-thumb for all programming paradigms. The general flow of the program should be readable by anybody. Throw away your implementations inside classes and throw these classes inside files other than your main.js. Even more, I do NOT write any flow in my main, its just a logic switch, or program selector:


  8. // main.js
    try {
    //include("test1.js")
    //include("test2.js")
    include("myprog1.js")
    }
    catch(e) {
    log(e)
    terminate()
    }

    Whenever I need to test any code or run any sample code, I just throw it in a file and switch to it in my main. When I am finished I uncomment back the original program.
    The try/catch is there to bust silly alerts that appears on-screen which if not dismissed normally by user, will freeze the SpringBoard.

  9. Create a test-harness because you will need to try various things first.
    You may create a new application for the sole purpose of testing code. Create any testing code in new files and switch between them in main.js. This way you don't need new applications each time you try any code. See the code of main.js in previous point as an example.

  10. Make your files self-contained, don't assume any implicit dependency.
    In Jiggy, there are 2 types of code dependency. First is Plugin dependency where you depend on a native plugin (Jigglin). Second type is Javascript dependency where you depend on other Javascript files. As an example for the first type, if you use the package Images don't assume that the UIKit plugin is loaded. In the beginning of the file check if it is not loaded and load it accordingly:

    if (typeof Images == 'undefined')
    Plugins.load('UIKit')

    Current Jiggy implementation does not check for loading same plugins more than once, and hence the check above.
    As an example for the second dependency type consider this:

    include('another.js')

    And in another.js put the inclusion guard which I borrow from C/C++!

    if (typeof __ANOTHER_JS == 'undefined') {
    __ANOTHER_JS = 0
    // write all your Javascript code here
    ...
    }

  11. This inclusion guard is recommended although not mandatory because re-interpretation of code may cause undesired logical errors.

  12. Use a central include path because you are going to make/use reusable components.
    Sticking to the Object Oriented design will render many parts of your code reusable. The straightforward way to reuse the components is to copy them over through different applications. However, you will be changing them frequently and you need a central place for them. You may place them in a separate directory and create symbolic links inside your application folder. I wish I could have time to patch Jiggy source so that it looks in a central include path if it does not find the file in the application directory. Did I hear someone offering help?

  13. Always remember the restricted memory resources, cache on disk if necessary.
    Don't write code that aggressively allocates memory. Don't let your arrays grow indefinitely. If you need large data-structures let them write their data on disk if they exceeded some limit, using sqlite if needed. If it is all about memory cache, let older values drop altogether.

  14. Don't forget your friend, the garbage collector (GC), you may know when to call it better than the engine does.
    Let the code be smart and invoke it in places where you are sure many objects have been released. Each time you release an object, or return from a function, increment released objects count and invoke the GC if it reached some limit. The AutoReleaseCache and ImageLoader are perfect examples for restricted memory management and garbage collection. There should be a global GC function when using them. Here it is:

    var GC_TRIGGER = 40
    var releasedObjectsCount = 0
    GC = function(force)
    {
    if (force || releasedObjectsCount++ > GC_TRIGGER) {
    releasedObjectsCount = 0
    log("-----------------------------------------------")
    log("running gc")
    log("-----------------------------------------------")
    gc(1)
    }
    }



Read more...

Your Guide to Writing Large-Scale Javascript Applications

What is peculiar in Javascript is that it is designed for many types of applications. Noobs can learn it in minutes. They can just go write little validation code insided web pages. Advanced web applications also rely heavily on Javascript. It is even taken beyond the web paradigm. Now you can find Javascript running on servers, inside desktop applications, and even on hand-held devices.

This explains the ongoing war between Javascript interpreters, V8, SquirrelFish (and SquirrelFish Extreme) and TraceMonkey. Each engine fights to dominate the market. Actually this is so important as web applications are becoming a lot more complex and old-style Javascript engines are dying out of performance. Embedded devices also need performant Javascript engines due to their limited resources.

When your Javascript application grows in size, you will find it very difficult to maintain because the language is designed to be written in a simple way, no enforcements or conventions of any type. Actually, you will most probably end up with a very bad code. To avoid this and to write neat, maintainble and scalable Javascript applications, I have brainstormed with myself and wrote down the following guidelines. Some of them are general and can be applied to any programming language, not necessarily Javascript. I will be constantly adding to these guidelines as I forumalate them.



  1. Use classes instead of separate global functions.
    One may simply write an old C-style program around functions. The good, although old, news is that Javascript can be written in an object-oriented (OO) style. Although there are no explicit class definitions or inheritance, you still can work around this and define your own classes with both public and private access to data members and member functions. As implied by the OO design, your application will neatly grow as it goes. I will not discuss how to write classes but you can see the these examples and see these useful links (1 and 2 or google it).
  2. Don't pollute the global context, always use namespaces/singletons.
    If you strictly followed the previous point of the OO design, you will end up with a lot of class names. These class names are nothing but global variables, we approach the start point again. You can create namespaces to hold class definitions inside. For example:
  3. var MyPackage = {
    MyClassA: function() {...},
    MyClassB: function() {...}
    }

    This way, we have just hidden MyClassA and MyClassB inside MyPackage namespace. To instanciate objects we write:

    x = new MyPackage.MyClassA().

    Note also that similarly we can write a singleton class:

    var MySingleton = {
    method1: function() {...},
    method2: function() {...},
    variable1: 10,
    variable2: "hello"
    }

    You access singleton members as:

    MySingleton.method1()
    MySingleton.variable1

    and so on.
  4. Make your functions anonymous and give them variable names.
  5. Functions in Javascript may be anonymous as well as named. For example you can define a function like this:

    function myfunc() {...}

    You can also write:

    function() {...}

    The latter form can be used as a closure or as an inline function. See this, this and that for more information about closures.
    Being an inline function you can set it to a variable:

    var myfunc = function() {...}

    This form may seem equivalent to the named form example above. However, they are not always equivalent. It is interpreter-specific. In IE JScript (I think it was IE6), named functions are always given their name regardless of their scope. This has the side effect of defining the function name as a global variable name. Take this example for more clarification:

    if (a > 1)
    function foo() {...}

    In bad interpreters (Micro$oft JScript for example) foo is always a global variable of type function. It can be called in all cases not only if a > 1!
    Need a dangerous scenario? Take this example:

    if (typeof foo == 'undefined')
    function foo() {...}

    Suppose you need to check whether a function is defined or not, and if not define it your own way. This could happen inside a large application where you test if some sources are included and act accordingly. This will not work as expected due to the missbehavior of such interpreter. I faced this problem when writing some code that checks if prototype was included or not. So I wrote:

    if (typeof $ == 'undefined')
    function $(element) {return document.getElementById(element)}

    The result was my $ always overriding prototype's $!
    The solution is easy, just use:

    if (typeof $ == 'undefined')
    var $ = function (element) {return document.getElementById(element)}

    This way, $ will not be defined unless it is already defined before.

  6. Keep your files small, don't worry about number of files.
  7. As a general practice, don't place more than 1 class definition in a file. Consider Java public classes where you cannot define more than 1 public class in a file and file name should be the same as that public class. If this has changed in current specification, please tell me as I am not an active Java developer. This will add to modularity and will make your classes more liable to reusability.

  8. Never use alerts for debugging.
  9. Debugging Javascript code using alerts always proves to be not practical. It pauses execution until the user dismisses the alert. You cannot just put 10 alerts and have them displayed each run waiting for you to dismiss them! Sometimes it is invalid to log through alerts. Suppose you need to simulate real time performance while you are having multiple threads, for AJAX requests as an example. Alerts will ruin the synchronization of threads because they pause their owning threads. Its worth noting that text inside alerts are limited to the display area.

  10. Always use log messages for debugging.
  11. A better solution for debugging, still not the best, is using log messages rather than alerts. Logging debug information has many benifits of not blocking the running thread, playing the 10 messages with no code interruption and simulating the real time performance of threads. If you are inside a web page, you can log to some text area by modifying its value property. In Jiggy, you can use the global function log() to throw away any message to the console. It is important to note that logging is not only for debugging. You have to log your application activity for inspection afterwards. This may help you enhance its performance or monitor user activity.

  12. Consider using dynamic log-levels when your logs become bloated.
  13. Following the logging paradigm will render your log stream unreadable. When you add a new log line it will not be noticed among tens and hundreds of other log lines. Thinking of disabling older log lines is not the best solution, you may need to come back and debug something old. By enabling/disabling log lines you will be uncommenting/commenting some code. As a general practice code inside comments is highly discouraged. Actually you will need to debug several aspects continuously, like requests sent/received on network. Thats why log levels are for. However, I don't mean here the basic 4 levels that are widely used: Error, Warning, Info and Debug. These levels are placed according to severity of log. What I mean here is dynamically creating log levels according to different aspects of your application logic. For example, you may have aspects called "Network", "Database", "Rendering", "Flow" and such. Lets call them log aspects as opposed to log levels. When you log any message you define its aspect from these aspects. You may also combine an aspect with one of the 4 basic log levels mentioned above. When you wish to debug warnings from the network aspects you enable Warning level and Network aspect from a central configuration file. Such file may turn on and off all aspects and levels for your application. For example:

    var ENABLE_LOGS = true
    var DEBUG_ASPECT_NETWORK = true
    var DEBUG_ASPECT_DATABASE = false
    ...
    var DEBUG_LEVEL_ERROR = false
    var DEBUG_LEVEL_WARN = true
    ...

    and in your log lines:

    LOG("message here", DEBUG_ASPECT_NETWORK && DEBUG_LEVEL_WARN)

    where LOG is simply defined as:

    var LOG = function(message, enabled)
    {
    if (ENABLE_LOGS && enabled) log(message)
    }

    You can add debug aspects and levels dynamically as your application grows. You can enable/disable aspects and levels as required without commenting/uncommenting your code.

  14. If you are working inside a web browser, consider a Javascript debugger. For Firefox there is Venkman and Firebug. If your log mechanism didn't help you, you may consider a real debugger which steps you into your code and helps you inspecting variables.
Thats all for now, stay tuned for a more focused post about writing large-scale Jiggy applications!




Read more...