Developing Mobile Apps ? You may want to read this…

If you are developing Mobile Apps, ask these 3 basic questions

  1.  Why users will download your mobile apps ?  (why one will use it?)
  2.  How they come to know there is such an apps ? (App discovery !)
  3.  Why users will NOT un-install your mobile app ? (User retention !)

1. Why users will download your mobile apps ?

  • They believe app will help in someway or the other, and not having similar app. (b2c app)
  • Or existing similar app sucks a lot !
  • Employer/boss  force to use the app ! (enterprise app)
  • (here users are not in control, they dont have choice !)
  • just doing timepass to check the app
  • To impress others !
  • <More idea ? Put it in the comment !!!!>

2.  How they come to know there is such an apps ? (App discovery !)

  • friend/family/colleague
  • blog ! Yeah, when your app got featured, sudden hike in installation
  • facebook/twitter
  • Telco and other Appstores !
  • newspaper/tv/radio
  • Already users of other non-mobile app service (Ex : Justdial,Naukri, Bharatmatrimony, News etc)
  • <More idea ? Put it in the comment !!!!>

3. Why user will un-install your mobile apps ?

  • No value addition as described in marketing.
  • Not solve real problem.
  • Tooo much information, most of them irrelavant or not of my interest.
  • Used the apps heavily, now getting bored with this. <——————
  • Same feature sets.
  • Great sexy UI but battery draining
  • Sexy UI but failed for UX
  • Sexy UI/UX, but failed for giving accurate/expected results/basic functionality.
  • Poor UI.
  • Apps are crashing a lot, and no new updates for fixing.
  • When shooting mail to developer, developer don’t care to reply the mail.
  • Back button not working (or i expect something else when i press back button on my android)(Android App !)
  • <More idea ? Put it in the comment !!!!>

Raxit Sheth

BarcampMumbai7 #bcm7

If you are reading this and it is yet not Oct 2. Come and join us @ Barcamp Mumbai.

If you are hacker, mobile, android, j2me, python, nltk,  Come and hack with us.

I know couple of cool folks,  featured in techcrunch and others are coming, to show some hack of android <non-phone, non-tablet !>

No more words, just come and experience,

Here is the details

http://barcampmumbai.org/index.php/BCM7

Thanks to @sengupta @mehulnved for wonderful leadership to bring this up again !

 

Load Testing – Node.js vs Single Threaded Python Web Server vs PHP5+Apache2.2

Load testing is generally used to test performance of any product by putting it under extreme conditions and one can know about expected performance in worst scenario. In case of web applications, this is acheived by with writing a bot script or using some automated tools like Seleneium.

So, I got curious about testing the relative performace of a webserver written in Node.js, a single threaded Python web server and one application written in PHP and hosted on Apache 2.2 web server. Task of web application was to get exactly 5 key-value pairs via GET request and insert it into MongoDB database. For example – if one url like http://127.0.0.1:8000/?key_1=value1&key_2=value2&key_3=value_3&key_4=value_4&key_5=value_5 is called, then one document like {key_1:value_1, key_2:value_2, key_3:value_3, key_4:value_4, key_5:value_5} will be inserted in the existing collection of some MongoDB database.

For this testing I wrote a Python script which works something like this -

  1. A set of urls arerequested parallely to web server inside the python test script.
  2. It waits for response for each url until time out limit is reached.
  3. If there is any URLError like “connection timed out” or any HTTPError, we count all of them
  4. Above 3 steps are repeated in a for loop say for a given no. of times.
  5. Above 4 steps are repeated by varying count of urls in the set for parallel request.

Results
Click here to see the image in new window.

Screenshot

Analysis
As you can see in the screenshot that

  • node.js is vey quick in handling requests even if only instance of node is running. This is because of intelligent architecture of node and event based handling.
  • PHP5+Apache 2.2 is not as fast as node but performance is acceptable. In apache, many child processes are created under one parent process which leads to good performance.
  • In case of single threaded Python server, requests are handled after one another. Due to this as no. of parallel requests increases we get very bad performance and lot of requests face “Conncetion timed out” error.

This means, web applications written in node.js can handle very large no. of requests at a time (as they one node instance can handle as many as 10000 requests at a time), PHP5+Apache can be a good option if you are not expecting very high traffic on you website. On the other hand, single threaded Python servers should never be used in production systems but they help a lot in while developing any web application using Python based frameworks like Django, Web2py or Pylons.

Thanks for reading till last line, please leave a comment.

Contributors for this post - 

Nisha – <nisha at m4mum dot com> and Pankaj – <psjinx at m4mum dot com>


Here is the code -

run.py

 

#! /usr/bin/env python
import random
import urllib
import urllib2
import string
import datetime
import time
from threading import Thread, enumerate

URIS_COUNT = 500 #total no. of urls to be accessed in parallel
FORLOOP_COUNT = 100 #total no. of loops in which prallel request will be sent
TIME_OUT = 5.0 #timeout in seconds
UPDATE_INTERVAL = 0.01 #update interval for checking threads
BASE_URL = 'http://127.0.0.1:8000/' #base url of server, remember trailing slash is required

errors = {} #this dictionary is used to store count of all sort of HTTPError and URLError

def rand():
    return ''.join(random.choice(string.ascii_letters + string.digits) for x in range(20))

def dict_to_query_string(d):
    return '&'.join([k+'='+urllib.quote(str(v)) for (k,v) in d.items()])

class URLThread(Thread):
    def __init__(self,url):
        super(URLThread, self).__init__()
        self.url = url
        self.response = None

    def run(self):
        req = urllib2.Request(self.url)
        try:
            self.request = urllib2.urlopen(req)
            #self.response = self.request.read()
        except urllib2.HTTPError, e:
            try:
                errors['HTTPError Code - '+str(e.code)] += 1
            except KeyError:
                errors['HTTPError Code - '+str(e.code)] = 1
        except urllib2.URLError, e:
            try:
                errors['URLError Reason - '+str(e.reason)] += 1
            except KeyError:
                errors['URLError Reason - '+str(e.reason)] = 1
        else:
            pass

uris = []
for k in range(URIS_COUNT):
    values = {}
    for j in range(5):
        values[rand()]= rand()
    uris.append(BASE_URL+'?'+dict_to_query_string(values))

def multi_get(uris,timeout=TIME_OUT):
    def alive_count(lst):
        alive = map(lambda x : 1 if x.isAlive() else 0, lst)
        return reduce(lambda a,b : a + b, alive)
    threads = [ URLThread(url) for url in uris ]
    for thread in threads:
        thread.start()
    while alive_count(threads) > 0 and timeout > 0.0:
        timeout = timeout - UPDATE_INTERVAL
        time.sleep(UPDATE_INTERVAL)
    return
    #return [ (x.url, x.response) for x in threads ]

start_time = datetime.datetime.now()
for i in range(FORLOOP_COUNT):
    print 'Step no. - %d'%(i+1)
    multi_get(uris,timeout=100.0)
end_time = datetime.datetime.now()

td = end_time - start_time
seconds = td.days*24*3600 + td.seconds + float(td.microseconds/10**6)

print '**********************Finished********************'
print 'Total time taken = %f seconds'%seconds
print errors
print '**************************************************'


example.py

 

#! /usr/bin/env python
import datetime
import sys
import BaseHTTPServer
from urlparse import urlparse
from pymongo import Connection

connection = Connection('localhost', 27017)
db = connection.mydb
collection = db.mycollection

class MyHandler(BaseHTTPServer.BaseHTTPRequestHandler):
    def do_HEAD(s):
        s.send_response(200)
        s.send_header('Content-type', 'text/plain')
        s.end_headers()
    def do_GET(s):
        s.do_HEAD()
        qs = urlparse(s.path).query
        params = dict([part.split('=') for part in qs.split('&')])

        if not len(params)==5:
            print 'Query string should have exactly 5 key value pairs.'
            s.wfile.write('Failure')
        else:
            print 'Query String has been saved successfully'
            collection.insert(params)
            s.wfile.write('Success')

server_class = BaseHTTPServer.HTTPServer
handler_class = MyHandler
server_address = ('', 8000)

httpd = server_class(server_address, handler_class)

print 'Server Starts'
try:
    httpd.serve_forever()
except KeyboardInterrupt:
    pass
print 'Server Stops'


example.js

 

var http = require('http');
var url = require('url');
var mongo = require('mongodb')
db = new mongo.Db('mydb', new mongo.Server('localhost', 27017, {}), {});

db.open(function() {
    db.collection('mycollection', function(err, collection){
        http.createServer(function (request, response) {
            var query = url.parse(request.url, true)['query']
            var count = 0;
        for (var key in query){
            count += 1;
        }

        response.writeHead(200, {'Content-Type': 'text/plain'});

        if (count>5 || count<5){
            console.log('Query string should have exactly 5 key value pairs.')
            response.end('Failure');
        }else {
            collection.insert(query, function(){
                console.log('Query String has been saved successfully.');
            });
            response.end('Success');
        };
        }).listen(8000);
    });

});

console.log('Server running at http://127.0.0.1:8000/');


example.php

 

<?php
try {
    $m = new Mongo('localhost:27017', array('persist'=>'x')); //creating new mongo connection.
    $db = $m->selectDB('mydb');
} catch (MongoConnectionException $e) {
    echo '<p>Couldn\'t connect to mongodb, is the "mongod" process running?</p>';
    exit();
}

$collection = $db->selectCollection('mycollection');

$query = $_GET;

if (count($query)==5){
    $collection->insert($query);
    echo 'Success';
} else {
    echo 'Failure - Query string should have exactly 5 key-value pairs.';
    exit();
}
?>