49
BEST PRACTICES in apps development using TITANIUM APPCELERATOR Alessio Ricco @alessioricco 1

Best Practices in apps development with Titanium Appcelerator

Embed Size (px)

Citation preview

Page 1: Best Practices in apps development with Titanium Appcelerator

BEST PRACTICES in apps development using

TITANIUM APPCELERATOR

Alessio Ricco @alessioricco

!1

Page 2: Best Practices in apps development with Titanium Appcelerator

Software Quality characteristicsBy the user point of viewAdaptability: 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 resourcesIntegrity: 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

Page 3: Best Practices in apps development with Titanium Appcelerator

Software Quality characteristicsBy the developer point of viewFlexibility: can you adapt the app for other uses ? Maintanability: debug, improve, modify the app Portability: adapting the app for other platformsReadability: source code is easy to understand Reusability: using parts of your code in other appsTestability: 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

Page 4: Best Practices in apps development with Titanium Appcelerator

A good software project must beUser 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

Page 5: Best Practices in apps development with Titanium Appcelerator

StabilityPREDICTIVE BEHAVIOUR The software works in a reliable way, and the output is deterministicERROR HANDLINGThe software runs consistently without a crash RELIABLE PLATFORMIf the platform is stable, writing stable software is easier.(also our libraries are part of the platform)

!5

Page 6: Best Practices in apps development with Titanium Appcelerator

PerformanceRESPONSIVENESSThe 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 MEMORYApps must avoid memory leaks and release the resources ASAP

!6

Page 7: Best Practices in apps development with Titanium Appcelerator

Rapid developmentREUSABILITYDon'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 CODEWriting good, correct, tested and smart code is faster than writing quick and dirty spaghetti code to debug later

!7

Page 8: Best Practices in apps development with Titanium Appcelerator

ReadabilityMEANINGFUL COMMENTSComment 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 NAMESUse meaningful names for your variables and functions.

!8

Page 9: Best Practices in apps development with Titanium Appcelerator

Appcelerator Best Practices

!9

Page 10: Best Practices in apps development with Titanium Appcelerator

Avoid the global scopeNO GARBAGE COLLECTION In the global scope not null objects cannot be collected SCOPE IS NOT ACCESSIBLE FROM MODULESapp.js is not accessible within CommonJS modulesapp.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

Page 11: Best Practices in apps development with Titanium Appcelerator

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

Page 12: Best Practices in apps development with Titanium Appcelerator

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

Page 13: Best Practices in apps development with Titanium Appcelerator

use self-calling functions // self calling function ( function() { var priv = 'I\'m local!'; } )(); //undefined in the global scope alert(priv);

!13

Page 14: Best Practices in apps development with Titanium Appcelerator

Don't Re-use your temp vars

Javascript is loosely typed.You can repurpose objects any time via assignmentdon't do it!var i = 5; i+=2; i = “let me change my type”; // BAD!

!14

Page 15: Best Practices in apps development with Titanium Appcelerator

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

Page 16: Best Practices in apps development with Titanium Appcelerator

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

Page 17: Best Practices in apps development with Titanium Appcelerator

Understanding the closuresA 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

Page 18: Best Practices in apps development with Titanium Appcelerator

Avoid memory leaks in global event listenersfunction 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

Page 19: Best Practices in apps development with Titanium Appcelerator

Lazy script loadingLOAD 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

Page 20: Best Practices in apps development with Titanium Appcelerator

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 librariesfunctions called in N different places could be improved in just one place

!20

Page 21: Best Practices in apps development with Titanium Appcelerator

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

Page 22: Best Practices in apps development with Titanium Appcelerator

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 plusmyfunctioncall() is correctshort code and high level of trust in tested libraries make coding and debugging easier

!22

Page 23: Best Practices in apps development with Titanium Appcelerator

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

Page 24: Best Practices in apps development with Titanium Appcelerator

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

Page 25: Best Practices in apps development with Titanium Appcelerator

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

Page 26: Best Practices in apps development with Titanium Appcelerator

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

Page 27: Best Practices in apps development with Titanium Appcelerator

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

Page 28: Best Practices in apps development with Titanium Appcelerator

Using CommonJS: exports

the exports variable exposes public methods and variables exports.myProperty = 123; exports.myMethod = function (message) { Ti.API.info (message ); };

!28

Page 29: Best Practices in apps development with Titanium Appcelerator

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

Page 30: Best Practices in apps development with Titanium Appcelerator

Using ImagesMinimize memory footprintImage 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 (bit)

FOOTPRINT (KB)

320 480 24 450

640 960 24 1800

1024 768 24 2304

2048 1536 24 9216

!30

Page 31: Best Practices in apps development with Titanium Appcelerator

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

Page 32: Best Practices in apps development with Titanium Appcelerator

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

Page 33: Best Practices in apps development with Titanium Appcelerator

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

Page 34: Best Practices in apps development with Titanium Appcelerator

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

Page 35: Best Practices in apps development with Titanium Appcelerator

Style and conventionsLearn 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

Page 36: Best Practices in apps development with Titanium Appcelerator

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

Page 37: Best Practices in apps development with Titanium Appcelerator

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

Page 38: Best Practices in apps development with Titanium Appcelerator

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

Page 39: Best Practices in apps development with Titanium Appcelerator

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

Page 40: Best Practices in apps development with Titanium Appcelerator

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

Page 41: Best Practices in apps development with Titanium Appcelerator

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

Page 42: Best Practices in apps development with Titanium Appcelerator

Language Best Practices : a better ifHow 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

Page 43: Best Practices in apps development with Titanium Appcelerator

Coding Style

Variable names start with a category noun (lowercase) Examples: personName personNameLast personPhone employeeId companyAddress

!43

Page 44: Best Practices in apps development with Titanium Appcelerator

Coding StyleFunction names start with a category verb (lowercase) and (if possible) are followed by an associated variable name Examples: getPersonName setPersonNameLast callPersonPhone saveEmployee showCompanyAddress

!44

Page 45: Best Practices in apps development with Titanium Appcelerator

Coding StyleMajor Objects and constructors follow a capitalized words pattern Examples: Person Employee Company GarbageCollector Same rule is applied for namespacesExamples:App.UI.Widget App.Network.Request

!45

Page 46: Best Practices in apps development with Titanium Appcelerator

Coding Style: Indentation

K&R Style Example if (x < 10) { if (y > 10) { // do this } } else { // do this }

!46

Page 47: Best Practices in apps development with Titanium Appcelerator

Coding Style: IndentationAllman Style Example if (x < 10) { if (y > 10) { // do this } } else { // do this } !47

Page 48: Best Practices in apps development with Titanium Appcelerator

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

Page 49: Best Practices in apps development with Titanium Appcelerator

ReferencesTitanium 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