Titanium Mobile – CommonJS Fundamentals

For many developers, a Titanium mobile project might be their first exposure to serious object-oriented programming in Javascript. They may have even used a framework like jquery or mootools (or if they’re really lucky, qooxdoo — check it out sometime). But most of the time, even if you’re using those frameworks, you don’t have to do a lot of your own class definitions.

It’s critical in Titanium Mobile that you follow best practices in your application design. There are three different methods that have been used by Titanium Mobile developers during its relatively short lifetime. There is really only one you should use at this point; I will cover the others so that you can recognize them when you encounter them online (there are still people using these techniques).

  • multi-context: open a window with the "url" property set to a Javascript file; this results in a new Javascript context being created for the file to run in. DON’T DO THIS!
  • namespacing: create a global variable and add properties to that global variable via modules that you include() into your code. DON’T DO THIS!
  • CommonJS: build modules that are each isolated from the global namespace and explicitly define the interface for that module. DO THIS!

More information on these strategies is found here: http://docs.appcelerator.com/titanium/2.0/index.html#!/guide/Coding_Strategies

All guidance from Appcelerator points to using CommonJS modules. It is the best way to build a robust single-context application that is free from nasty memory management issues.

So how do you structure your modules? I will illustrate a number of different techniques here.

exports, module.exports

There are two ways to expose the interface of your module. You can either add properties and methods to the exports variable, or you can define a replacement for the module.exports object.

Which you use depends on how you want your module to function:

  • a generic module object with its own set of properties and methods (add properties and methods to "exports")
  • a class definition that is used to instantiate objects (replace the "module.exports" object)

Generic module objects

Generic module objects can be a convenient way to wrap up a set of related functions without defining an explicit object class. I typically use these when I have utility functions that don’t share much (or any) state among themselves.

To use these functions from outside the module:

Note that the functions *can* share state if they need to:

_someStateVar is private to the module: it does not pollute the global namespace, and it is not accessible to users of the module.

Class Definitions

More commonly, I like to use OOD principles and define reusable classes of objects using CommonJS.

Note: I realize that Appcelerator discourages the use of classical inheritance techniques like this, but I find it straightforward, and Appcelerator’s arguments seem to center around philosophical issues rather than specific performance/stability issues.

The function serves as a constructor of sorts for the class. When you use the new operator with the function, the function will be called and the "this" keyword will be set to a new object.

to use this class, you do this:

Note that this class doesn’t do anything interesting; we’ll get to that.

Declaring Members and Methods

To make the class do useful things, we need to define member variables and methods to act upon those variables. We can do a pretty good job mimicing the access level modifiers and static/instance members found in languages like Java.

Private instance members

Private instance variables are defined inside the MyClass () constructor:

Code inside the MyClass () function (including code within private and public methods defined within the MyClass () function) can access _privateInstanceMember, but it is not accessible anywhere else. All instances of MyClass have their own _privateInstanceMember.

Private instance Methods

Private methods are defined inside the MyClass () constructor:

Code inside the MyClass () function (including code within functions defined within the MyClass () function) can access _privateInstanceMethod, but it is not accessible anywhere else.

The method’s access to other members and methods looks like this:

  • private instance members/methods: yes
  • private static members/methods: yes
  • public instance members/methods: yes, using this.foo or this.foo()
  • public static members/methods: yes, using MyClass.foo or MyClass.foo()

Private static members

Private static member variables are defined inside the module, but outside the MyClass () constructor:

All code in the module has access to this variable, but it is not accessible outside the module. All instances of the MyClass object share _privateStaticMember.

Private static methods

Private static methods are defined inside the module, but outside the MyClass () constructor:

All code in the module can call this method, but it is not accessible outside the module.

The method’s access to other members and methods looks like this:

  • private instance members/methods: no
  • private static members/methods: yes
  • public instance members/methods: no
  • public static members/methods: yes, using MyClass.foo or MyClass.foo()

Public instance members

Public instance members are defined inside the MyClass () constructor:

All code inside the constructor has access to this variable, and it is accessible outside the module. All instances of MyClass have their own publicInstanceMember.

To use the publicInstanceMember from outside the module:

Public instance methods

Public Instance Methods are defined inside the MyClass () constructor:

All code inside the constructor has access to this method, and it is accessible outside the module.

The method’s access to other members and methods looks like this:

  • private instance members/methods: yes
  • private static members/methods: yes
  • public instance members/methods: yes, using this.foo or this.foo()
  • public static members/methods: yes, using MyClass.foo or MyClass.foo()

To use the publicInstanceMethod from outside the module:

Public static members

Public static members are defined outside the MyClass () constructor:

All code in the module has access to this variable, and it is accessible outside the module. All instances of MyClass share publicStaticMember.

To use the publicInstanceMember from outside the module:

Public static methods

Public static methods are defined outside the MyClass () constructor:

All code in the module has access to this method, and it is accessible outside the module.

To use the publicInstanceMethod from outside the module:

The method’s access to other members and methods looks like this:

  • private instance members/methods: no
  • private static members/methods: yes
  • public instance members/methods: no
  • public static members/methods: yes, using MyClass.foo or MyClass.foo()

Pulling it all together

The following code example shows all eight types of members and methods in one class; it also demonstrates

which members are available to the different types of methods, and how they’re accessed.

Code conventions

I have a number of conventions that I follow in my coding that make the classes a bit easier to read:

  • prefix all private member and method names with ‘_’
  • put private static members at the top of the module
  • put the constructor immediately after the private static members
  • declare the private instance members at the top of the constructor

I recommend that you stick to these principles as well:

  • don’t use public instance members — make them private instead and use public instance methods if you need to access them outside the module
  • for some reason, I’m not quite as averse to public static members; maybe that’s because there’s a lot more danger in multiple instances running around "naked" with public members 😛
  • keep your public interfaces simple; whenever possible, keep your members and methods private

Considerations

Code execution

Some of this may be obvious, but it’s worth noting. The require() function call has some magic of its own in Titanium. When you call

the MyClass.js file is parsed, and any code in the "global" space of the module is executed, but only if it has not been required previously. Code that is inside the constructor function is executed every time you instantiate an object of MyClass.

Adding methods to prototype

You will often see Javascript classes defined with methods added to the prototype, like this:

The advantage of this technique is that the function is only defined once, when the module is first required. This saves time, and it also saves memory (if the function is defined inside the constructor, every instance of the object has a copy of that function; adding the function to the prototype means that all instances share a single copy of the function).

The big downside is that these functions cannot access private instance members and methods.

Many javascript developers would suggest that the solution is to abandon the concept of private/public and make everything public. I’m not quite ready to do that, but I’m seeing the logic of it. Not only does trying to enforce private/public lead to inefficiencies like defining your functions inside the constructor, but it causes problems with inheritance (see below for more).

inheritance

Inheritance with this model is difficult to impossible. There are a number of big problems introduced by using the class design outlined here.

  • private members and methods are truly private, not protected; code in your derived class won’t see those private members, period
  • class members and methods don’t get inherited with the standard inheritance techniques

Here’s how to inherit from MyClass:

This technique was inspired by this blog post: https://go-left.com/blog/2011/08/js-inheritance/

I think that if you really want to build sophisticated object models, you may have to consider dropping the concept of private/public and just make everything public. That would give you two advantages:

  • inherited classes would have full access to all methods and members of the parent class
  • you can define your functions in the class prototype rather than in the constructor; this can save memory and execution time

More reading:

Common pitfalls

global temptation

Don’t be tempted to use any globals in your application, especially if you have the brilliant inspiration to access them from within your CommonJS modules. The problem is that this will work — sometimes. Titanium’s iOS implementation has a deficiency which allows Javascript inside of CommonJS modules to see variables defined in the global namespace. Android won’t let you do that, so if you’re like a lot of Titanium developers, you will be happily coding along and testing in the iOS simulator, only to watch your app fail miserably when you load it on your Android device.

require paths

Make sure to put a leading "/" on the paths to your CommonJS modules. It may work without the leading "/" on some platforms, but not others. This is one of the many cases where Titanium is too forgiving on some platforms, leading you to sloppy behavior, only to find that stuff mysteriously doesn’t work on other platforms.

forgotten require() call

If you forget to make the

call before trying to instantiate an object of MyClass, your app will crash with the RSOD (red screen of death), saying something like "Application Error – Can’t find variable: MyClass at app.js (line 5)"; the console will say something like "Script Error = Can’t find variable: MyClass at app.js (line 5)." Note that for android, the RSOD looks different; it will say something like "Runtime Error", "Location: [5,9] app.js", "Message: Uncaught TypeError: object is not a function", "Source: var o = new MyClass ();". Very informative, but you don’t want your end users seeing it.

Note that if the module has been required elsewhere in the application, you can get away with this in iOS, only to have it fail on Android. (I believe this is related to the issue where iOS can see global variables).

forgotten "module.exports"

If you omit the

from the module, your app will crash with the RSOD, saying something like "Application Error – ‘[object Object]’ is not a constructor (evaluating ‘new MyClass ()’) at app.js (line 5)"; the console will say something like "Script Error = ‘[object Object]’ is not a constructor (evaluating ‘new MyClass ()’) at app.js (line 5).

Back to Titanium Mobile: Beyond the prototype

One thought on “Titanium Mobile – CommonJS Fundamentals

  1. Very nice tutorial to understand CommonJS design. In this document you have covered all the required details. Thanks a lot.

Leave a Reply

Your email address will not be published. Required fields are marked *