This document provides best practices for developing apps using Titanium Appcelerator. It discusses software quality characteristics from both the user and developer perspectives. Key aspects of a good software project are stability, performance, rapid development, and readability. Specific practices covered include avoiding global scope, nulling object references, using namespaces, lazy script loading, avoiding memory leaks with event listeners, optimizing images, and best practices for databases.
Hot Sexy call girls in Panjabi Bagh 🔝 9953056974 🔝 Delhi escort Service
Best Practices in apps development with Titanium Appcelerator
1. BEST PRACTICES
in apps development using
TITANIUM APPCELERATOR
Alessio Ricco
@alessioricco
!1
2. Software Quality characteristics
By the user point of view
Adaptability: is the app able to run in different
environments ?
Accuracy: how well your app does the job ?
Correctness: your app does the job ?
Efficiency: minimizing system resources
Integrity: your app is secure ?
Reliability: does it crash ?
Robustness: your app handle invalid inputs ?
Usability: it's easy to learn how to use it ?
USERS notice STABILITY and PERFORMANCE
!2
3. Software Quality characteristics
By the developer point of view
Flexibility: can you adapt the app for other uses ?
Maintanability: debug, improve, modify the app
Portability: adapting the app for other platforms
Readability: source code is easy to understand
Reusability: using parts of your code in other apps
Testability: the degree to which you can test the app
Understandability: can you understand what the app does
and how it does it ?
DEVELOPERS needs RAPIDITY and READABILITY
!3
4. A good software project must be
User side:
STABLE
(applications must have a predictive behaviour)
PERFORMANT (speed must approach the speed of native
code applications)
Developer side:
RAPID
(development must be fast)
READABLE
(code must be easy to understand)
!4
5. Stability
PREDICTIVE BEHAVIOUR
The software works in a reliable way, and the output is
deterministic
ERROR HANDLING
The software runs consistently without a crash
RELIABLE PLATFORM
If the platform is stable, writing stable software is easier.
(also our libraries are part of the platform)
!5
6. Performance
RESPONSIVENESS
The app must complete the assigned task within a given
(short) time. User must receive feedback.
OPTIMIZATION IN SPEED
Apps must be approaching the native platform speed
OPTIMIZATION IN MEMORY
Apps must avoid memory leaks and release the resources
ASAP
!6
7. Rapid development
REUSABILITY
Don't design twice the same piece of software.
Don't write twice the same routine.
USE CODE SNIPPETS / PATTERNS
Known problems always have known solutions.
Google them!
SAVE DEBUG TIME WITH DEFENSIVE CODE
Writing good, correct, tested and smart code is faster than
writing quick and dirty spaghetti code to debug later
!7
8. Readability
MEANINGFUL COMMENTS
Comment your code. Comments are tools for saving time
SELF-DOCUMENTING CODE
Write code you can read and understand at different level
of granularity (from 'big picture' to 'statement' level)
CHOOSING GOOD NAMES
Use meaningful names for your variables and functions.
!8
10. Avoid the global scope
NO GARBAGE COLLECTION
In the global scope not null objects cannot be collected
SCOPE IS NOT ACCESSIBLE FROM MODULES
app.js is not accessible within CommonJS modules
app.js is not accessible within other contexts (windows)
- Always declare variables
- Always declare variables inside modules or functions
- Assign global objects to null after the use
!10
11. Nulling out object references
// create ui objects
var window = Ti.UI.createWindow();
var myView = myLibrary.createMyView();
win.add(myView);
win.open();
// remove objects and release memory
win.remove(myView);
myView = null;
// the view could be removed by the GC
!11
12. Keep local your temp vars
// immediate functions help us to avoid
// global scope pollution
var sum = (function() {
var tmpValue = 0; // local scope
for (var i = 0; i < 100; i++) {
tmpValue += i;
}
return tmpValue;
})();
// i, tmpValue are ready for GC !
!12
13. use self-calling functions
// self calling function
(
function()
{
var priv = 'I'm local!';
}
)();
//undefined in the global scope
alert(priv);
!13
14. Don't Re-use your temp vars
Javascript is loosely typed.
You can repurpose objects any time via assignment
don't do it!
var i = 5;
i+=2;
i = “let me change my type”; // BAD!
!14
15. Use namespaces
Enclose your application's API functions and properties into
a single variable (namespace).
- this prevent the global scope pollution
- this protect your code from colliding with other code or
libraries
// declare it in the global scope
var mynamespace = {};
mynamespace.myvar = “hello”;
mynamespace.myfunction = function(param) {}
!15
16. Namespaces are extendable
// extend and encapsulate by using self-calling functions
(function() {
function helper() {
// this is a private function not directly accessible
// from the global scope
}
mynamespace.info = function(msg) {
// added to the app's namespace, so a public function
helper(msg);
Ti.API.info(msg)
};
})();
// you could then call your function with
mynamespace.info('Hello World');
DON'T EXTEND TITANIUM NAMESPACES !!!!!
!16
17. Understanding the closures
A closure is a function together with a referencing
environment for the non local variables of that function
// Return a function that approximates the derivative of f
// using an interval of dx, which should be appropriately small.
function derivative(f, dx) {
return function (x) {
return (f(x + dx) - f(x)) / dx;
};
}
the variable f, dx lives after the function derivative returns.
Variables must continue to exist as long as any existing
closures have references to them
!17
18. Avoid memory leaks in global event listeners
function badLocal() {
// local variables
var table = Ti.UI.createTableView();
var view = Ti.UI.createView();
// global event listener
Ti.App.addEventListener('myevent', function(e) {
// table is local but not locally scoped
table.setData(e.data);
});
view.add(table);
return view;
};
- consider to use callback functions instead of custom
global events
- place global event handlers in app.js
rule : global events handle global objects
!18
19. Lazy script loading
LOAD SCRIPTS ONLY WHEN THEY ARE NEEDED
JavaScript evaluation is slow.
Avoid loading scripts if they are not necessary
// load immediately
var _window1 = require('lib/window1').getWindow;
var win1 = new _window1();
win1.open()
win1.addEventListener('click', function(){
// load when needed
var _window2 = require('lib/window2').getWindow;
var win2 = new _window2();
win2.open()
})
BE AWARE: Some bugs could not be discovered until you load the script...
!19
20. D.R.Y. (don't repeat yourself)
Don't repeat the same code
code repeated N times could be buggy in N different places
Reuse your code
if your code was correct until now, probably it will be correct in future
Instantiate your code using the factory pattern
hiding the class details to make future improvements easier
Create libraries
functions called in N different places could be improved in just one
place
!20
21. Test your code and Reuse it
Coding is about Testing and Trusting
“I test my code and I trust several other things:
- the platform correctness
- the compiler correctness
- the 3th party libraries
- the samples I copied from forums
… etc...”
but
if you write correct code you can trust YOUR code
and re-use it !!!!
!21
22. Test your code and Reuse it
function foo (param)
{
...statement #1
...statement #2
...statement #3
myfunctioncall(); // 3 years old function tested several times
}
foo() is correct when statements are correct
plus
myfunctioncall() is correct
short code and high level of trust in tested libraries make coding and
debugging easier
!22
23. Meaningful Wrapping
Wrap your general-pourpose library functions and make them
specialized.
exports.getLeaderBoard = function(callbackSuccess, callbackError)
{
var headers = null;
exports.beintooREST('GET','https://api.beintoo.com/api/rest/app/leaderboard?
kind=STANDARD',headers,callbackSuccess, callbackError);
}
exports.submitScore = function(playerGuid, score, contest, callbackSuccess,
callbackError)
{
var headers = [
{key : 'guid', value : exports.getPlayer().guid},
{key : 'codeID', value : contest}
];
exports.beintooREST('GET','https://api.beintoo.com/api/rest/player/submitscore/?
lastScore=' + score,headers,callbackSuccess, callbackError);
}
exports.beintooREST is a specialized REST query function
if they change something i should change just one function
!23
24. Multiplatform programming
BRANCHING
useful when your code is mostly the same across platforms
but vary in some points
// Query the platform just once
var osname = Ti.Platform.osname;
var isAndroid = (osname == 'android') ? true : false;
var isIPhone = (osname == 'iphone') ? true : false;
// branch the code
if (isAndroid) {
// do Android code
...
} else {
// do code for other platforms (iOS not guaranteed)
...
};
// branch the values
var myValue = (isAndroid) ? 100 : 150;
!24
25. Multiplatform programming
BRANCHING
Slower but elegant method
// Query the platform just once
var osname = (Ti.Platform.osname == 'ipod') ? 'iphone' : Ti.Platform.osname;
os = function(/*Object*/ map) {
var def = map.def||null; //default function or value
if (map[osname]) {
if (typeof map[osname] == 'function') { return map[osname](); }
else { return map[osname]; }
}
else {
if (typeof def == 'function') { return def(); }
else { return def; }
}
};
// better than if statement and ternary operator. easily support more platforms
var myValue = os({ android: 100, ipad: 90, iphone: 50 });
!25
26. Multiplatform programming
PLATFORM-SPECIFIC JS STYLE SHEETS (JSS)
JSS separate presentation and code.
module.js
var myLabel = Ti.UI.createLabel({
text:'this is the text',
id:'myLabel'
});
module.jss
#myLabel {
width:149;
text-align:'right';
color:'#909';
}
for platform specific stylesheets you can use module.android.jss and module.iphone.jss,
but module.jss have the precedence.
!26
27. Using CommonJS
Titanium Appcelerator adopted the CommonJS module
specification as the way in which end users of the platform
structure their JS code
sample usage:
// load the module “Resources/myModule.js” and return a Javascript object
var myModule = require('myModule');
// good practice: always test if objects are null
if (myModule != null)
{
myModule.myMethod(“twinsmatcher”);
}
!27
28. Using CommonJS: exports
the exports variable exposes public methods and variables
exports.myProperty = 123;
exports.myMethod = function (message) {
Ti.API.info (message );
};
!28
29. Using CommonJS: module.exports
the module.exports object could be used for functions
which act as object constructors
Employee.js
function Employee(name, surname, title)
{
this.name = name;
this.surname = surname;
this.title = title;
}
Employee.prototype.fullName()
{
Ti.API.info(this.title + ' ' + this.name + ' ' + this.surname);
}
module.exports = Employee;
usage:
var Employee = require('Employee');
var myEmployee = new Employee('john','doe');
myEmployee.fullName();
!29
30. Using Images
Minimize memory footprint
Image files are decompressed in memory to be converted
in bitmap when they are displayed.
No matter the .png or .JPG original file size
WIDTH HEIGHT COLORS FOOTPRINT
(bit) (KB)
320 480 24 450
640 960 24 1800
1024 768 24 2304
2048 1536 24 9216
!30
31. Image Optimization
- use JPG for displaying photos
- use PNG for displaying icons, line-art, text
- use remove() when the image is not visible on screen
- set image views to null once no longer need those objs
- resize and crops images to the dimensions you need
- resize images to minimize file storage and network usage
- cache remote images (https://gist.github.com/1901680)
!31
32. Database
Release the resultsets as soon as you can
exports.getScore = function (level) {
var rows = null;
var score= 0;
try {
rows = db.execute( "select max(score) as maxscore from score where level=?",
level );
if( rows.isValidRow( )) {
Ti.API.info( "SCORE: (score,level) " + rows.field( 0 ) + ' ' + level );
score= rows.field( 0 )
} else {
Ti.API.info( "SCORE: error retrieving score [1]" );
}
}
catch (e) {
Ti.API.info( "SCORE: error retrieving score [2]" );
}
finally {
rows.close( );
}
return score;
}
!32
33. Database best practices
Close the database connection after insert and update
var db = Ti.Database.open('myDatabase');
try{
db.execute('BEGIN'); // begin the transaction
for(var i=0, var j=playlist.length; i < j; i++) {
var item = playlist[i];
db.execute('INSERT INTO albums (disc, artist, rating) VALUES (?, ?, ?)',
item.disc, item.artist, item.comment);
}
db.execute('COMMIT');
}
catch (e){
Ti.API.info( "SCORE: error retrieving score [2]" );
}
finally {
db.close();
}
!33
34. Database best practices
Minimize your database size
- Big Databases increases your app package file size
- The database is duplicated on your device because is
copied to the ApplicationDataDirectory
- On some Android releases the installer cannot
uncompress assets over 1MB (if you have a 2MB database
you need some workarounds)
Keep your db small and populate it on the 1st run !
!34
35. Style and conventions
Learn and follow language rules, styles and paradigms
javascript isn't c# or java or php
titanium appcelerator is not just javascript
Follow coding style best practices
Naming Conventions
Indentation
Comments Style
Follow language related communities and forums
don't reinvent the wheel
learn community best practices
!35
36. Language Rules
Always declare the variables
When you fail to specify var, the variable gets placed in the
global context, potentially clobbering existing values. Also,
if there's no declaration, it's hard to tell in what scope a
variable lives.
So always declare with var.
!36
37. Language Rules
Always use semicolons to terminate statements
you can cause hard to debug problems in your code....
var THINGS_TO_EAT = [apples, oysters, sprayOnCheese] // ;
// conditional execution a la bash
-1 == resultOfOperation() || die();
!37
38. Language Best Practices: === operator
Use the Exactly Equal operator (===)
comparing two operands of the same type is, most of the
time, what we need
!38
39. Language Best Practices : === operator
Use === instead of == , use !== instead of !=
var testme = '1';
if(testme == 1) // '1' is converted to 1
{
// this will be executed
}
var testme = '1';
if(testme === 1) {
// this will not be executed
}
!39
40. Language Best Practices : optimizing loops
Make your loops more efficient
var names = ['Jeff','Nolan','Marshall','Don'];
for(var i=0;i<names.length;i++){
process(names[i]);
}
// I can check the array length only once
var names = ['Jeff','Nolan','Marshall','Don'];
for(var i=0,j=names.length;i<j;i++){
process(names[i]);
}
!40
41. Language Best Practices : parenthesis
Is better wrap self functions with parenthesis
var myValue = function() {
//do stuff
return someValue;
}();
// the same code, but it's clear that myValue is not a function
var myValue = (function() {
//do stuff
return someValue;
})();
!41
42. Language Best Practices : a better if
How to avoid assignment bugs in your if statements
var test = 1;
// classic boolean expression style (left side is a variable)
if (test == 1)
{
test++;
Ti.API.info('test = ' + test); // test = 2
}
// classic boolean expression bug (is not a test, is an assignment)
if (test=1)
{
Ti.API.info('test = ' + test); // test = 1
}
// safe boolean expression style (left side is a constant)
if (1 == test)
{
Ti.API.info('test = ' + test); // test = 1
}
// compiler or interpreter will raise an exception: good !
if (1 = test) // error: Left side of assignment is not a reference
{
Ti.API.info('test = ' + test); // test = 1
}
!42
43. Coding Style
Variable names start with a category noun (lowercase)
Examples:
personName
personNameLast
personPhone
employeeId
companyAddress
!43
44. Coding Style
Function names start with a category verb (lowercase) and
(if possible) are followed by an associated variable name
Examples:
getPersonName
setPersonNameLast
callPersonPhone
saveEmployee
showCompanyAddress
!44
45. Coding Style
Major Objects and constructors follow a capitalized words
pattern
Examples:
Person
Employee
Company
GarbageCollector
Same rule is applied for namespaces
Examples:
App.UI.Widget
App.Network.Request
!45
48. Coding Style: Comments
// Single line comments are required
// for code documentation
var personAge = calculatePersonAge(person); //-10; avoid this!
/*
// this line of code is disabled using block comment
var personAge = calculatePersonAge(person)-10;
*/
/**
* @param {String} customerName Customer's full Name
**/
function getCustomer(customerName) {}
comments could be a great code/debug/documentation tool
!48
49. References
Titanium Appcelerator online documentation
http://docs.appcelerator.com/
Code Complete 2nd Edition – Steven C. McConnell - Microsoft Press
http://www.cc2e.com/Default.aspx
SQLite Optimization FAQ
http://web.utk.edu/~jplyon/sqlite/SQLite_optimization_FAQ.html
Douglas Crockford
http://javascript.crockford.com/
Google Javascript Style Guide
http://google-styleguide.googlecode.com/svn/trunk/javascriptguide.xml
TwinsMatcher
http://itunes.apple.com/app/twinsmatcher/id429890747?mt=8
@alessioricco
http://www.linkedin.com/in/alessioricco
!49