[Coding] Setting Up a Dynamic Namespacing Architecture
Posted by Khatharsis on August 12, 2013
One of the exciting things with coding smaller apps is when they start having a life of their own and demand new, sibling apps to be created. What makes it even sweeter is when the apps also have the potential for learning in quick bursts that can be easily loaded up throughout the day. Sort of hammering home the concept that memorizing is better done in small bits of time sprinkled over a larger amount of time vs. cramming in a short amount of time.
In my previous coding post, I had a brief interlude in which I explained how I set up my JavaScript game files. I decided to put my game project on hold in favor of developing additional apps for my Thai Apps suite (see Thai Sorting (Alphabetical), Thai Sorting (Classes), and Maanii Sentences) and realized it was the perfect testing ground for my dynamic namespacing idea. I’ll briefly summarize again how I divided up my files and some of the theory behind it, then I’ll go into a little more detail in how it all works together.
To quickly re-explain the division of files, the Thai Apps suite [currently] consists of four JavaScript files that are shared among the three apps I have written so far. These four files are the following:
- app.setup.js: declaration of the global
APPvar and also initialization of namespaces withinAPP. These namespaces correspond to the additional files that belong withinAPP(i.e.,APP.dataObjectsmaps to app.dataObjects.js). - app.dataObjects.js: data object wrappers for easy retrieval of data; an example is posted below.
- app.data.js: raw data objects presented in arrays; an example is posted below.
- app.utilities.js: common, reusable functions among the individual apps.
Within the files, with the exception of the first one, the following template is used:
(function() {
// Preserve "this" (APP) to use with callback and inner functions
var that = this;
this.aFunction = function() {
// Code
}
}).call(APP.namespace);
call() can be replaced by apply(), but since I am not passing in any parameters in this example, it is faster to use call().
To give a more concrete example of a function within the namespace, consider one of the data objects is consonant, which is currently used by both Sorting apps, Alphabetical and Classes. It looks like the following:
this.consonant = function(fChar, order, type) {
return {
fChar: fChar,
order: order,
type: type
};
};
The way consonant gets used in the data namespace looks like a longer version of:
this.thaiConsonants = [
consonant('ก', 1, 'mid'),
consonant('ข', 2, 'high'),
consonant('ฃ', 3, 'high'),
consonant('ค', 4, 'low')
];
So, the app.data.js file is really a collection of array objects rather than holding functions. It literally is just data.
From my previous post on this topic, I mentioned a game.js file (or the equivalent here would be app.js) that would map the more “back-end” JavaScript to HTML/UI functionality. I did away with that file in these apps as I explain in the next section.
—
I won’t go into the details of why I chose dynamic namespacing over other patterns as I’ve already covered that. Instead, I’ll try and do a little bit of reflection on how I ended up with this architecture.
Since each of my apps are fairly small in terms of functionality, I opted to keep the JavaScript code on the individual HTML pages rather than abstract them to another JavaScript file. This removed the need of the awkward calling structure and order I had before: game.preload.js then game.js then game.utilities.js. I may be a little OCD in the whole alphabetical-slash-logic loading of files and felt that game.js seemed like the black sheep being stuck in the middle when it “should” be the first one loaded. Now, the calling structure makes a little more sense, including the change of the namespace name from preload to setup: app.setup.js then app.dataObjects.js then app.data.js and finally app.utilities.js.
Each individual app then follows this same sequence of loading the JS files. Following that, in the HTML 5, I have a script tag using the same template from above to set up the interface between HTML and JS interaction. The namespace that I call() to is the base APP var itself, thus keeping the specific interactions of each app from potentially polluting the shared namespaces. If my understanding of JS is correct, since the apps all exist on different pages, they will each have their own copy of the JS code files, but just in case and to keep things in neat packages, it made more sense to put app-specific functionality in the APP var. Again, maybe it’s my OCD with desiring elegant code.
The nice thing about having a “raw” app.data.js file is then each app can handle the data differently. The flexibility of the data objects (e.g., consonant) themselves lend to an easier use in the APP functions. For example, in Maanii Sentences, I end up sorting maaniiVocab and maaniiSentence differently. With maaniiVocab, I create a hashtable with a key according to the Thai word of each maaniiVocab object whereas with maaniiSentence, I create another hashtable but use the lesson variable as its key. See the following code:
// Construct a hash table of vocab words (key: Thai word)
for (var i = 0; i < data.maaniiVocab.length; i++) {
if (!vocabHash[data.maaniiVocab[i].fWord]) {
vocabHash[data.maaniiVocab[i].fWord] = data.maaniiVocab[i];
}
}
// Construct a hash table of sentences (key: lesson)
for (var i = 0; i < data.maaniiSentences.length; i++) {
if (!sentenceHash[data.maaniiSentences[i].lesson]) {
sentenceHash[data.maaniiSentences[i].lesson] = [];
}
sentenceHash[data.maaniiSentences[i].lesson].push(data.maaniiSentences[i]);
}
The value for the maaniiVocab hashtable is simply the maaniiVocab object itself. The value for the maaniiSentence hashtable is an array consisting of all of the maaniiSentence objects and requires a little bit of extra code to manage.
--
The only issue I foresee with this app is specifically with app.data.js. As I add more apps, and I know Maanii Sentences is far from complete in terms of its data, this file will grow to be quite large and may hinder loading times. It would make more sense to have an AJAX call that calls a PHP file that can serve up the data required for the specific app calling it. However, what is the threshold of the data file in terms of loading time to the time it takes to make the AJAX call and return data? I have toyed with the idea of the proxy pattern or some variant of it, but I am thinking of delaying the solution until it becomes a real problem. It may be the case that having a decent-sized app.data.js file may be viable for a while to come.
A related issue is the way I construct two data structures for the Maanii Sentences app. For a small data set, this is viable and isn't too time-consuming, but I can expect for a larger data set, it will be more demanding. Again, a way to populate those data structures on-the-fly would be ideal, but then I run into a user-experience problem. Currently, users can select from a list of lessons which sentences they would like to practice from. Since the data structures are already populated, there is no downtime when a user switches from one lesson to another. If I implement a data population on-the-fly, there would be a slight bit of delay involved to iterate down the raw maaniiSentences array to locate the sentences that are within the selected lesson and then populate the data structure. I could speed up the iteration using binary search since the data will be ordered according to lesson. I may be making a mountain out of a molehill, especially since I can use caching/memoization with the data structure to save repeated look ups, but again this is something I'm putting off until a later time.
--
So, I'm quite happy with the architecture that I have and since it is working well so far, in terms of integration and adding new apps using the existing JS files, I feel more comfortable using it with my game app. I actually feel like I should go back and recode my canvas apps, but I feel they better serve as an example of my growth? Eh. I am still on the fence on refactoring Thai Typing and bringing it over to the Thai Apps suite, however. It is more of a desktop game than a mobile app, but it is still a good resource to become more familiar with the Thai language.
I have a couple of housekeeping tasks left with the Thai Apps suite, but three fully functional apps (so far) that have served me quite well in the past couple of months makes me very happy. The things I have learned from books and articles and being able to implement them in these apps has been very exciting. I am wondering what else I will be able to learn and apply. I also want to add in that grain of salt in that I'm aware this namespacing architecture may not be the "best" idea. There's even the chance I may not be using it correctly. Or, perhaps there is a purple monster with abnormally long arms and crazy hair that will pop up leading to me needing to create a concoction remedy to turn it back into functional yellow cylindrical creatures (a Despicable Me 2 reference). Who knows. I just thought I'd document my latest code.