Saturday, September 18, 2010

Simple javascript DHTML optimizations

Let us see some of the most simple javascript scripts optimizations with respect to DHTML which can make big difference,

Caching the DOM element

DIV1 element
DIV2 element
DIV3 element
Slow:
function nodomcache()
{
    var count=1000;
    for(var i=0;i<count;i++)
    {
        var value1=document.getElementById("div1").innerHTML;
        var value2=document.getElementById("div2").innerHTML;
        var value3=document.getElementById("div3").innerHTML;
    }
}
Faster:
function domcache()
{
    var count=1000;
    var ele1=document.getElementById("div1");
    var ele2=document.getElementById("div2");
    var ele3=document.getElementById("div3");
    for(var i=0;i<count;i++)
    {
        var value1=ele1.innerHTML;
        var value2=ele2.innerHTML;
        var value3=ele3.innerHTML;
    }
}

Rule: Cache the element for better performance. This caching is applicable for all types or variables.

Creating dynamic HTML (appendChild vs innerHTML)

Slow:
function appendchildhtml()
{
    var count=100;
    var tblele=document.createElement("table");
    var tblbodyele=document.createElement("tbody");
    for(var i=0;i<count;i++)
    {
        var trele= document.createElement("tr");
        var tdele1= document.createElement("td");
        tdele1.appendChild(document.createTextNode(i))
        trele.appendChild(tdele1);
        var tdele2= document.createElement("td");
        tdele2.appendChild(document.createTextNode(i))
        trele.appendChild(tdele2);
        tblbodyele.appendChild(trele);

    }
    tblele.appendChild(tblbodyele);
    document.getElementById("result1").appendChild(tblele);
}
Faster:
function innerhtml()
{
    var count=100;
    var strHTML="";
    strHTML+="<table>";
    for(var i=0;i<count;i++)
    {
        strHTML+="<tr>";
        strHTML+="<td>";
        strHTML+=i;
        strHTML+="</td>";
        strHTML+="<td>";
        strHTML+=i;
        strHTML+="</td>";
        strHTML+="</tr>";

    }
    strHTML+="</table>";
    document.getElementById("result2").innerHTML=strHTML;
}

Rule: Use innerHTML for dynamically adding html content.

Friday, September 17, 2010

Javascript measurement tools

There are two important factor which has to be measured to identify the improvement in the code
  • Time taken to complete some operation
  • Memory usage of the application
Below is the example code for measuring the time.
<html>
    <head>
        <title>Time measurement tool</title>
        <script>
        function measureTimeElapsed()
        {
            var divlogoutput;
            var starttime;
            var endtime;
            var timeelapsed;
            starttime=(new Date()).getTime();
            for(var i=0;i<10000;i++)
            {
                var temp=parseInt("10");
            }
            endtime=(new Date()).getTime();
            timeelapsed=endtime-starttime;
            divlogoutput=document.getElementById("logoutput");
            //append the timeelapsed
            divlogoutput.innerHTML="<b>TimeElapsed:"+
                timeelapsed+"(milliseconds)</b><br/>";
        }
        </script>
    </head>
    <body onload="measureTimeElapsed()">
        <div id="logoutput">
        </div>
    </body>
</html>
Output:
Chrome 6.0:TimeElapsed:1(milliseconds)
Safari 3.2:TimeElapsed:10(milliseconds)
IE 7.0:TimeElapsed:27(milliseconds)
Mozilla Firefox:3.0.3:1(milliseconds)

Note: Profiling tools can be used for the measuring execution time and memory leak.

Note: If you are testing with Google Chrome or Mozilla Firefox then try console.time(name); and console.timeEnd(name);. Please refer Console API

Thursday, September 16, 2010

C# XmlWriter vs XmlDocument vs StreamWriter

Use XmlWriter for creating xml document.The below example uses the following classes
  • Contact class is used for storing name and address
  • AddressBook is the colleciton of Contact class
The c# code example in this article will generate xml document as below, but with 10000 contacts elements.
<AddressBook>
  <Contact>
    <Name>Person1</Name>
    <Address1><![CDATA[Number101]]></Address1>
    <Address2><![CDATA[Address501]]></Address2>
    <Zip>50001</Zip>
    <Phone><![CDATA[999991]]></Phone>
 </Contact>
</AddressBook>
The example first creates and populates an AddressBook class with 10000 Contact objects and measures time taken to generate the xml file with 10000 contacts using using XmlDocument, XmlWriter and StreamWriter (usign StringBuilder).
using System;
using System.Collections.Generic;
using System.Text;
using System.Xml;
using System.IO;
using System.Diagnostics;
using System.Xml.Linq;
namespace XmlWrite
{
    class Contact
    {
        public string Name { get; set; }
        public string Address1 { get; set; }
        public string Address2 { get; set; }
        public int Zip { get; set; }
        public string Phone { get; set; }
        public Contact(string strName, string strAddress1, string strAddress2,
            int iZip,
            string strPhone)
        {
            Name = strName;
            Address1 = strAddress1;
            Address2 = strAddress2;
            Zip = iZip;
            Phone = strPhone;
        }
    }
    class AddressBook
    {
        private List<Contact> InnerList = null;
        public List<Contact> GetContacts()
        {
            return InnerList;
        }
        public AddressBook()
        {
            InnerList = new List<Contact>();
        }
        public void Add(Contact objContact)
        {
            InnerList.Add(objContact);
        }
    }
    class Program
    {
        static void Main(string[] args)
        {
            Stopwatch objSW = null;
            XmlDocument objXmlDoc = null;
            XmlWriter objXmlWriter = null;
            XDocument objXDoc = null;
            StringBuilder objSB = null;
            StreamWriter objStreamWriter = null;
            AddressBook objAddrBook = null;
            int iCount = 10000;
            List<Contact> objContacts = null;

            //populate contacts in the addressbook object model
            objAddrBook = new AddressBook();
            objSW = new Stopwatch();
            for (int i = 0; i < iCount; i++)
            {
                Contact objContact = null;
                string strName = "Person" + (i + 1);
                string strAddress1 = "Number" + (i + 101);
                string strAddress2 = "Address" + (i + 501);
                int iZip = 50000 + (i + 1);
                string strPhone = "99999" + (i + 1);
                objContact = new Contact(strName, strAddress1, strAddress2, iZip,
                    strPhone);
                objAddrBook.Add(objContact);
            }
            //xml creation using XmlDocument
            objSW.Reset();
            objSW.Start();
            objXmlDoc = new XmlDocument();
            XmlElement objXmlAddrBook = objXmlDoc.CreateElement("AddressBook");
            objContacts = objAddrBook.GetContacts();
            for (int i = 0; i < objContacts.Count; i++)
            {
                XmlElement objXmlContact = objXmlDoc.CreateElement("Contact");
                XmlElement objXmlName = objXmlDoc.CreateElement("Name");
                objXmlName.InnerText = objContacts[i].Name;
                objXmlContact.AppendChild(objXmlName);
                XmlElement objXmlAddress1 = objXmlDoc.CreateElement("Address1");
                objXmlAddress1.AppendChild(
                    objXmlDoc.CreateCDataSection(objContacts[i].Address1));
                objXmlContact.AppendChild(objXmlAddress1);
                XmlElement objXmlAddress2 = objXmlDoc.CreateElement("Address2");
                objXmlAddress2.AppendChild(
                    objXmlDoc.CreateCDataSection(objContacts[i].Address2));
                objXmlContact.AppendChild(objXmlAddress2);
                XmlElement objXmlZip = objXmlDoc.CreateElement("Zip");
                objXmlZip.InnerText = objContacts[i].Zip.ToString();
                objXmlContact.AppendChild(objXmlZip);
                XmlElement objXmlPhone = objXmlDoc.CreateElement("Phone");
                objXmlPhone.AppendChild(
                    objXmlDoc.CreateCDataSection(objContacts[i].Phone));
                objXmlContact.AppendChild(objXmlPhone);
                objXmlAddrBook.AppendChild(objXmlContact);
            }
            objXmlDoc.AppendChild(objXmlAddrBook);
            objXmlDoc.Save("address_dom.xml");
            objSW.Stop();
            Console.WriteLine("XML file created using XmlDocument");
            Console.WriteLine("TimeElapsed (Stopwatch float):{0}ms",
                objSW.Elapsed.TotalMilliseconds);
            Console.WriteLine("TimeElapsed (Stopwatch rounded):{0}ms",
                objSW.ElapsedMilliseconds);

            //xml creation using XmlWriter
            objSW.Reset();
            objSW.Start();
            XmlWriterSettings objSettings = new XmlWriterSettings();
            objSettings.Indent = true;
            using (objXmlWriter = XmlWriter.Create("address_xw.xml", objSettings))
            {
                objXmlWriter.WriteStartElement("AddressBook");
                objContacts = objAddrBook.GetContacts();
                for (int i = 0; i < objContacts.Count; i++)
                {
                    objXmlWriter.WriteStartElement("Contact");

                    objXmlWriter.WriteStartElement("Name");
                    objXmlWriter.WriteString(objContacts[i].Name);
                    objXmlWriter.WriteEndElement();
                    objXmlWriter.WriteStartElement("Address1");
                    objXmlWriter.WriteCData(objContacts[i].Address1);
                    objXmlWriter.WriteEndElement();
                    objXmlWriter.WriteStartElement("Address2");
                    objXmlWriter.WriteCData(objContacts[i].Address2);
                    objXmlWriter.WriteEndElement();
                    objXmlWriter.WriteStartElement("Zip");
                    objXmlWriter.WriteString(objContacts[i].Zip.ToString());
                    objXmlWriter.WriteEndElement();
                    objXmlWriter.WriteStartElement("Phone");
                    objXmlWriter.WriteCData(objContacts[i].Phone);
                    objXmlWriter.WriteEndElement();

                    objXmlWriter.WriteEndElement();
                }
                objXmlWriter.WriteEndElement();
            }
            objSW.Stop();
            Console.WriteLine("XML file created using XmlWriter");
            Console.WriteLine("TimeElapsed (Stopwatch float):{0}ms",
                objSW.Elapsed.TotalMilliseconds);
            Console.WriteLine("TimeElapsed (Stopwatch rounded):{0}ms",
                objSW.ElapsedMilliseconds);
            //xml creation using StringBuilder
            objSW.Reset();
            objSW.Start();
            objSB = new StringBuilder();
            objSB.AppendLine("<AddressBook>");
            objContacts = objAddrBook.GetContacts();

            for (int i = 0; i < objContacts.Count; i++)
            {
                objSB.AppendLine("<Contact>");
                objSB.AppendLine("<Name>" + objContacts[i].Name + "</Name>");
                objSB.AppendLine(
                "<Address1><![CDATA[" + objContacts[i].Address1 + "]]></Address1>");
                objSB.AppendLine(
                "<Address2><![CDATA[" + objContacts[i].Address2 + "]]></Address2>");
                objSB.AppendLine("<Zip>" + objContacts[i].Zip + "</Zip>");
                objSB.AppendLine(
                "<Phone><![CDATA[" + objContacts[i].Phone + "]]></Phone>");
                objSB.AppendLine("</Contact>");
            }
            objSB.AppendLine("</AddressBook>");
            using (objStreamWriter = new StreamWriter("address_sb.xml", false))
            {
                objStreamWriter.Write(objSB.ToString());
            }
            objSW.Stop();
            Console.WriteLine("XML file created using StringBuilder");
            Console.WriteLine("TimeElapsed (Stopwatch float):{0}ms",
                objSW.Elapsed.TotalMilliseconds);
            Console.WriteLine("TimeElapsed (Stopwatch rounded):{0}ms",
                objSW.ElapsedMilliseconds);

            //xml creation using XDocument (LINQ)
            objSW.Reset();
            objSW.Start();
            objContacts = objAddrBook.GetContacts();
            XElement[] arrXElem = new XElement[objContacts.Count];
            for (int i = 0; i < objContacts.Count; i++)
            {
                arrXElem[i] = new XElement("Contact",
                    new XElement("Name", objContacts[i].Name),
                    new XElement("Address1",
                    new XCData(objContacts[i].Address1)),
                    new XElement("Address2",
                    new XCData(objContacts[i].Address2)),
                    new XElement("Zip", objContacts[i].Zip),
                    new XElement("Phone", new XCData(objContacts[i].Phone)));
            }
            objXDoc = new XDocument(new XElement("AddressBook",arrXElem));
            objXDoc.Save("address_xdocument.xml");
            objSW.Stop();
            Console.WriteLine("XML file created using XDocument");
            Console.WriteLine("TimeElapsed (Stopwatch float):{0}ms",
                objSW.Elapsed.TotalMilliseconds);
            Console.WriteLine("TimeElapsed (Stopwatch rounded):{0}ms",
                objSW.ElapsedMilliseconds);

            Console.ReadLine();

        }
    }
}
Output:
XML file created using XmlDocument
TimeElapsed (Stopwatch float):90.0323ms
TimeElapsed (Stopwatch rounded):90ms
XML file created using XmlWriter
TimeElapsed (Stopwatch float):36.2555ms
TimeElapsed (Stopwatch rounded):36ms
XML file created using StringBuilder
TimeElapsed (Stopwatch float):91.5911ms
TimeElapsed (Stopwatch rounded):91ms
XML file created using XDocument
TimeElapsed (Stopwatch float):71.3794ms
TimeElapsed (Stopwatch rounded):71ms

Note: The StringBuilder performance can be improved by specifying the required capacity when creating the StringBuilder object.

Note: XmlDocument can be considered, if forward and backward reference is unavoidable during the generation of xml document.

Rule: Use XmlWriter for generating or creating xml document.

C# Structure vs Class

Structure performs better than the reference type (Class) with respect to CPU usage and memory usage. Consider using structure over class,
  • If your application has to support data which does not require inheritance and interface
  • The data is in large number
  • The data is only of primitive data type like integer, byte, float, etc.
  • Probability a graphics application or application which deals with large data

Note: Structure with large number of members will degrade the performance when passed as parameter/argument to functions because the values of the entire structure is copied as parameter/argument to the function.

Below code measures the creation of 100000 objects of a class and also measures the time taken to search an object from the collection.
using System;
using System.Collections.Generic;
using System.Text;
using System.Diagnostics;
using System.Drawing;
namespace ClassTimeElapsed
{
    class Brick
    {
        public int Id;
        public float X;
        public float Y;
        public float Width;
        public float Height;
        public Color Color;
    }
    class Program
    {
        static void Main(string[] args)
        {
            Stopwatch objStopwatch;
            Brick[] arrBrick;
            int iCount;
            iCount = 100000;

            objStopwatch = new Stopwatch();
            objStopwatch.Reset();
            objStopwatch.Start();
            arrBrick = new Brick[iCount];

            for (int i = 0; i < iCount; i++)
            {
                arrBrick[i] = new Brick();
            }
            int iConst = 15;
            for (int i = 0; i < iCount; i++)
            {
                arrBrick[i].Id = i + 1;
                arrBrick[i].X = i * iConst;
                arrBrick[i].Y = 0;
                arrBrick[i].Width = 10;
                arrBrick[i].Height = 10;
                arrBrick[i].Color = Color.Teal;
            }
            objStopwatch.Stop();
            Console.WriteLine(
                "Class time elapsed for allocation and population");
            //timeelapsed
            Console.WriteLine("TimeElapsed (Stopwatch float):{0}ms",
                objStopwatch.Elapsed.TotalMilliseconds);
            Console.WriteLine("TimeElapsed (Stopwatch rounded):{0}ms",
                objStopwatch.ElapsedMilliseconds);
            int iSearchId = 99880;
            Brick objBrick = null;
            objStopwatch.Reset();
            objStopwatch.Start();
            for (int i = 0; i < arrBrick.Length; i++)
            {
                if (iSearchId == arrBrick[i].Id)
                {
                    objBrick = arrBrick[i];
                    break;
                }
            }
            objStopwatch.Stop();
            Console.WriteLine(
                "Class time elapsed for searching");
            //search result
            Console.WriteLine(
                "search result: Id:{0},X:{1},Y:{2},Width:{3},Height:{4},Color:{5}",
                objBrick.Id, objBrick.X, objBrick.Y, objBrick.Width, objBrick.Height,
                objBrick.Color);
            //timeelapsed
            Console.WriteLine("TimeElapsed (Stopwatch float):{0}ms",
                objStopwatch.Elapsed.TotalMilliseconds);
            Console.WriteLine("TimeElapsed (Stopwatch rounded):{0}ms",
                objStopwatch.ElapsedMilliseconds);
            Console.ReadLine();
        }
    }
}
Output:
Class time elapsed for allocation and population
TimeElapsed (Stopwatch float):13.7327ms
TimeElapsed (Stopwatch rounded):13ms
Class time elapsed for searching
search result: Id:99880,X:1498185,Y:0,Width:10,Height:10,Color:Color [Teal]
TimeElapsed (Stopwatch float):1.3015ms
TimeElapsed (Stopwatch rounded):1ms
Below code measures the creation of 100000 objects of a struct and also measures the time taken to search an object from the collection.
using System;
using System.Collections.Generic;
using System.Text;
using System.Diagnostics;
using System.Drawing;
namespace StructTimeElapsed
{
    struct Brick
    {
        public int Id;
        public float X;
        public float Y;
        public float Width;
        public float Height;
        public Color Color;
    }
    class Program
    {
        static void Main(string[] args)
        {
            Stopwatch objStopwatch;
            Brick[] arrBrick;
            int iCount;
            iCount = 100000;
            objStopwatch = new Stopwatch();
            objStopwatch.Reset();
            objStopwatch.Start();
            arrBrick = new Brick[iCount];
            int iConst = 15;
            for (int i = 0; i < iCount; i++)
            {
                arrBrick[i].Id = i + 1;
                arrBrick[i].X = i * iConst;
                arrBrick[i].Y = 0;
                arrBrick[i].Width = 10;
                arrBrick[i].Height = 10;
                arrBrick[i].Color = Color.Teal;

            }
            objStopwatch.Stop();
            Console.WriteLine(
                "Struct time elapsed for allocation and population");
            //timeelapsed
            Console.WriteLine("TimeElapsed (Stopwatch float):{0}ms",
                objStopwatch.Elapsed.TotalMilliseconds);
            Console.WriteLine("TimeElapsed (Stopwatch rounded):{0}ms",
                objStopwatch.ElapsedMilliseconds);
            int iSearchId = 99880;
            Brick objBrick;
            objBrick.Id = 0;
            objBrick.X = 0;
            objBrick.Y = 0;
            objBrick.Width = 0;
            objBrick.Height = 0;
            objBrick.Color = Color.Transparent;
            objStopwatch.Reset();
            objStopwatch.Start();
            for (int i = 0; i < arrBrick.Length; i++)
            {
                if (iSearchId == arrBrick[i].Id)
                {
                    objBrick = arrBrick[i];
                    break;
                }
            }
            objStopwatch.Stop();
            Console.WriteLine(
                "Struct time elapsed for searching");
            //search result
            Console.WriteLine(
                "search result: Id:{0},X:{1},Y:{2},Width:{3},Height:{4},Color:{5}",
                objBrick.Id, objBrick.X, objBrick.Y, objBrick.Width, objBrick.Height,
                objBrick.Color);
            //timeelapsed
            Console.WriteLine("TimeElapsed (Stopwatch float):{0}ms",
                objStopwatch.Elapsed.TotalMilliseconds);
            Console.WriteLine("TimeElapsed (Stopwatch rounded):{0}ms",
                objStopwatch.ElapsedMilliseconds);
            Console.ReadLine();
        }
    }
}
Output:
Struct time elapsed for allocation and population
TimeElapsed (Stopwatch float):3.0684ms
TimeElapsed (Stopwatch rounded):3ms
Struct time elapsed for searching
search result: Id:99880,X:1498185,Y:0,Width:10,Height:10,Color:Color [Teal]
TimeElapsed (Stopwatch float):1.0981ms
TimeElapsed (Stopwatch rounded):1ms
Below code measures the memory usage of creation of 100000 objects of a class.
using System;
using System.Collections.Generic;
using System.Text;
using System.Diagnostics;
using System.Drawing;
namespace ClassMemoryUsage
{
    class Brick
    {
        public int Id;
        public float X;
        public float Y;
        public float Width;
        public float Height;
        public Color Color;
    }
    class Program
    {
        static void Main(string[] args)
        {
            long lngGCMemStart = 0;
            long lngGCMemEnd = 0;
            long lngProcessMemStart = 0;
            long lngProcessMemEnd = 0;
            Brick[] arrBrick;
            int iCount;
            iCount = 100000;
            Process objProcess = Process.GetCurrentProcess();
            //Measure starting point memory
            lngGCMemStart = System.GC.GetTotalMemory(true);
            lngProcessMemStart = objProcess.PrivateMemorySize64;
            arrBrick = new Brick[iCount];
            for (int i = 0; i < iCount; i++)
            {
                arrBrick[i] = new Brick();
            }
            //Measure memory after allocating
            lngGCMemEnd = System.GC.GetTotalMemory(true);
            lngProcessMemEnd = objProcess.PrivateMemorySize64;
            int iConst = 15;
            for (int i = 0; i < iCount; i++)
            {
                arrBrick[i].Id = i+1;
                arrBrick[i].X = i*iConst;
                arrBrick[i].Y = 0;
                arrBrick[i].Width = 10;
                arrBrick[i].Height = 10;
                arrBrick[i].Color = Color.Teal;
            }
            Console.WriteLine("Class memory usage.");
            //memoryusage difference
            Console.WriteLine("GC Memory Use:{0} (bytes)",
                lngGCMemEnd - lngGCMemStart);
            Console.WriteLine("Process Memory Use:{0} (bytes)",
                lngProcessMemEnd - lngProcessMemStart);
            Console.WriteLine("GC Memory Start:{0} (bytes)",
                lngGCMemStart.ToString());
            Console.WriteLine("Process Memory Start:{0} (bytes)",
                lngProcessMemStart.ToString());
            Console.WriteLine("GC Memory End:{0} (bytes)",
                lngGCMemEnd.ToString());
            Console.WriteLine("Process Memory End:{0} (bytes)",
                lngProcessMemEnd.ToString());
            Console.ReadLine();
        }
    }
}
Output:
Class memory usage.
GC Memory Use:4802368 (bytes)
Process Memory Use:0 (bytes)
GC Memory Start:130648 (bytes)
Process Memory Start:9232384 (bytes)
GC Memory End:4933016 (bytes)
Process Memory End:9232384 (bytes)
Below code measures the memory usage of creation of 100000 objects of a struct.
using System;
using System.Collections.Generic;
using System.Text;
using System.Diagnostics;
using System.Drawing;

namespace StructMemoryUsage
{
    struct Brick
    {
        public int Id;
        public float X;
        public float Y;
        public float Width;
        public float Height;
        public Color Color;
    }

    class Program
    {
        static void Main(string[] args)
        {
            long lngGCMemStart = 0;
            long lngGCMemEnd = 0;
            long lngProcessMemStart = 0;
            long lngProcessMemEnd = 0;
            Brick[] arrBrick;
            int iCount;
            iCount = 100000;
            Process objProcess = Process.GetCurrentProcess();
            //Measure starting point memory
            lngGCMemStart = System.GC.GetTotalMemory(true);
            lngProcessMemStart = objProcess.PrivateMemorySize64;
            arrBrick = new Brick[iCount];
            //Measure memory after allocating
            lngGCMemEnd = System.GC.GetTotalMemory(true);
            lngProcessMemEnd = objProcess.PrivateMemorySize64;
            int iConst = 15;
            for (int i = 0; i < iCount; i++)
            {
                arrBrick[i].Id = i + 1;
                arrBrick[i].X = i * iConst;
                arrBrick[i].Y = 0;
                arrBrick[i].Width = 10;
                arrBrick[i].Height = 10;
                arrBrick[i].Color = Color.Teal;
            }
            Console.WriteLine("Struct memory usage.");
            //memoryusage difference
            Console.WriteLine("GC Memory Use:{0} (bytes)",
                lngGCMemEnd - lngGCMemStart);
            Console.WriteLine("Process Memory Use:{0} (bytes)",
                lngProcessMemEnd - lngProcessMemStart);
            Console.WriteLine("GC Memory Start:{0} (bytes)",
                lngGCMemStart.ToString());
            Console.WriteLine("Process Memory Start:{0} (bytes)",
                lngProcessMemStart.ToString());
            Console.WriteLine("GC Memory End:{0} (bytes)",
                lngGCMemEnd.ToString());
            Console.WriteLine("Process Memory End:{0} (bytes)",
                lngProcessMemEnd.ToString());
            Console.ReadLine();
        }
    }
}
Output:
Struct memory usage.
GC Memory Use:3602368 (bytes)
Process Memory Use:0 (bytes)
GC Memory Start:130656 (bytes)
Process Memory Start:9232384 (bytes)
GC Memory End:3733024 (bytes)
Process Memory End:9232384 (bytes)

Why? Structure is created in the stack.Structure is a value type.

Rule: Consider using structure for supporting large number of objects(data) in your application.

C# StringBuilder vs String Concatenation

Use StringBuilder for string concatenation. Concatenation of string using StringBuilder has better performance over string.
Below code measures the time taken to concatenate a string for 5000 iteration using “string” and “StringBuilder”.
using System;
using System.Collections.Generic;
using System.Text;
using System.Diagnostics;
namespace StringVsStringBuilder
{
    class Program
    {
        static void Main(string[] args)
        {
            Stopwatch objStopwatch = new Stopwatch();
            string strValue=string.Empty;
            StringBuilder objSBValue = new StringBuilder();
            int iCount = 5000;
            objStopwatch.Reset();
            objStopwatch.Start();
            for (int i = 0; i < iCount; i++)
            {
                strValue = strValue+"simpleValue"+i.ToString();
            }
            objStopwatch.Stop();
            Console.WriteLine("concatenation using String.");
            Console.WriteLine(
                "TimeElapsed (Stopwatch float):{0}ms",
                objStopwatch.Elapsed.TotalMilliseconds
                );
            Console.WriteLine(
                "TimeElapsed (Stopwatch rounded):{0}ms",
                objStopwatch.ElapsedMilliseconds
                );
            //Console.WriteLine(strValue);
            objStopwatch.Reset();
            objStopwatch.Start();
            for (int i = 0; i < iCount; i++)
            {
                objSBValue.Append("simpleValue" + i.ToString());
            }
            objStopwatch.Stop();
            Console.WriteLine(
                "concatenation using StringBuilder."
                );
            Console.WriteLine(
                "TimeElapsed (Stopwatch float):{0}ms",
                objStopwatch.Elapsed.TotalMilliseconds
                );
            Console.WriteLine(
                "TimeElapsed (Stopwatch rounded):{0}ms",
                objStopwatch.ElapsedMilliseconds
                );
            //Console.WriteLine(objSBValue);
            Console.ReadLine();
        }
    }
}
Output:
concatenation using String.
TimeElapsed (Stopwatch float):316.6526ms
TimeElapsed (Stopwatch rounded):316ms
concatenation using StringBuilder.
TimeElapsed (Stopwatch float):2.4933ms
TimeElapsed (Stopwatch rounded):2ms

Why? Any object stored in heap is immutable with respect to size allocation, and any change to the underlying size will require reallocation. If the string is modified (concatenating another string onto it, changing its value), then a new string is created and this can have negative performance implications. The StringBuilder gets around the reallocation problem by using internal buffers. But once the buffer fills up, the reallocation occurs. It is recommended to specify the initial capacity to minimize the reallocation problem.

Rule: Use StringBuilder instead of string for string concatenation operation.

C# XmlReader vs XDocument vs XmlDocument

Use Xmlreader for parse xml document.
Create an xml file as show below, but with 10000 contact elements called as “address_xw_n.xml” and make it available in D driver (d:\).
<AddressBook>
  <Contact>
    <Name>Person1</Name>
    <Address1><![CDATA[Number101]]></Address1>
    <Address2><![CDATA[Address501]]></Address2>
    <Zip>50001</Zip>
    <Phone><![CDATA[999991]]></Phone>
 </Contact>
</AddressBook>
The below code demonstrate the time take to parse the above created xml file using XmlDocument, XDocument and XmlReader.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Xml;
using System.Diagnostics;
using System.Xml.Linq;
namespace XmlParse
{
    class Program
    {
        static void Main(string[] args)
        {
            Stopwatch objSW = null;
            String strNormalFilePath;
            strNormalFilePath = @"d:\address_xw_n.xml";
            XmlDocument xmlNDoc;
            XmlReader xmlNReader = null;
            XDocument xNDoc=null;
            objSW = new Stopwatch();

            //xml parsing using XmlDocument - Normal format
            objSW.Reset();
            objSW.Start();
            xmlNDoc = new XmlDocument();
            xmlNDoc.Load(strNormalFilePath);
            XmlElement xmlDocNElem = xmlNDoc.DocumentElement;
            for (int i = 0; i < xmlDocNElem.ChildNodes.Count; i++)
            {
                XmlNode xmlNode = xmlDocNElem.ChildNodes[i];
                for (int j = 0; j < xmlNode.ChildNodes.Count; j++)
                {
                    string strName = xmlNode.ChildNodes[j].Name;
                    string strValue = xmlNode.ChildNodes[j].ChildNodes[0].Value;
                    //Console.WriteLine(strName + "-" + strValue);
                }
            }
            //xmlNDoc = null;
            objSW.Stop();
            Console.WriteLine("XML parsing using XmlDocument - Normal format");
            Console.WriteLine("TimeElapsed (Stopwatch float):{0}ms",
                objSW.Elapsed.TotalMilliseconds);
            Console.WriteLine("TimeElapsed (Stopwatch rounded):{0}ms",
                objSW.ElapsedMilliseconds);

            //xml parsing using XDocument - Normal format
            objSW.Reset();
            objSW.Start();
            xNDoc = XDocument.Parse(xmlNDoc.OuterXml);
            foreach (XElement e in xNDoc.Root.Elements())
            {
                foreach (XElement c in e.Elements())
                {
                    string strName = c.Name.ToString();
                    string strValue = c.Value;
                    //Console.WriteLine(strName+"-"+strValue);
                }
            }
            xNDoc = null;
            objSW.Stop();
            Console.WriteLine("XML parsing using XDocument - Normal format");
            Console.WriteLine("TimeElapsed (Stopwatch float):{0}ms",
                objSW.Elapsed.TotalMilliseconds);
            Console.WriteLine("TimeElapsed (Stopwatch rounded):{0}ms",
                objSW.ElapsedMilliseconds);

            //xml parsing using XmlReader - Normal format
            objSW.Reset();
            objSW.Start();
            using (xmlNReader = XmlReader.Create(strNormalFilePath))
            {
                while (xmlNReader.Read())
                {
                    switch (xmlNReader.NodeType)
                    {
                        case XmlNodeType.Element:
                            {
                                switch (xmlNReader.Name)
                                {
                                    case "Name":
                                    case "Zip":
                                        {
                                            string strName = xmlNReader.Name;
                                            xmlNReader.Read();
                                            string strValue = xmlNReader.Value;
                                            //Console.WriteLine(strName +
                                            //  "-" + strValue);
                                            break;
                                        }
                                    case "Address1":
                                    case "Address2":
                                    case "Phone":
                                        {
                                            string strName = xmlNReader.Name;
                                            xmlNReader.Read();
                                            string strValue = xmlNReader.Value;
                                            //Console.WriteLine(strName +
                                            //  "-" + strValue);
                                            break;
                                        }
                                }

                                break;
                            }
                    }
                }
            }

            objSW.Stop();
            Console.WriteLine("XML parsing using XmlReader - Normal format");
            Console.WriteLine("TimeElapsed (Stopwatch float):{0}ms",
                objSW.Elapsed.TotalMilliseconds);
            Console.WriteLine("TimeElapsed (Stopwatch rounded):{0}ms",
                objSW.ElapsedMilliseconds);
            Console.ReadLine();


        }
    }
}
Output:
XML parsing using XmlDocument - Normal format
TimeElapsed (Stopwatch float):5232.8249ms
TimeElapsed (Stopwatch rounded):5232ms
XML parsing using XDocument - Normal format
TimeElapsed (Stopwatch float):114.9677ms
TimeElapsed (Stopwatch rounded):114ms
XML parsing using XmlReader - Normal format
TimeElapsed (Stopwatch float):42.7921ms
TimeElapsed (Stopwatch rounded):42ms

Note: XmlDocument can be considered, if forward and backward reference is unavoidable during the parsing of xml document.

Rule: Use XmlReader for parsing xml document.

C# XPATH vs LINQ

Use Xmlreader for parsing xml document.
Create an xml file as show below, but with 10000 contact elements called as “address_xw_n.xml” and make it available in D driver (d:\).
<AddressBook>
  <Contact>
    <Name>Person1</Name>
    <Address1><![CDATA[Number101]]></Address1>
    <Address2><![CDATA[Address501]]></Address2>
    <Zip>50001</Zip>
    <Phone><![CDATA[999991]]></Phone>
 </Contact>
</AddressBook>
The below code demonstrate the time take to query the above created xml file using xpath and LINQ for the Phone element value “999999996“.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Xml;
using System.Diagnostics;
using System.Xml.Linq;
namespace QueryXML
{
    class Program
    {
        static void Main(string[] args)
        {
            Stopwatch objSW = null;
            String strNormalFilePath;
            strNormalFilePath = @"d:\address_xw_n.xml";
            XmlDocument xmlNDoc;
            xmlNDoc = new XmlDocument();
            XDocument xNDoc;
            objSW = new Stopwatch();

            objSW.Reset();
            objSW.Start();
            //load the xml
            xmlNDoc.Load(strNormalFilePath);
            //xml query using xpath - Normal format
            objSW.Reset();
            objSW.Start();
            XmlNode xmlQNNode = xmlNDoc.SelectSingleNode(
                "/AddressBook/Contact/Phone[contains(text(),'999999996')]");
            //Console.WriteLine(xmlQNNode.Name +
            //  "-" + xmlQNNode.ChildNodes[0].Value);
            objSW.Stop();
            Console.WriteLine("XML query using xpath - Normal format");
            Console.WriteLine("TimeElapsed (Stopwatch float):{0}ms",
                objSW.Elapsed.TotalMilliseconds);
            Console.WriteLine("TimeElapsed (Stopwatch rounded):{0}ms",
                objSW.ElapsedMilliseconds);

            //xml query using LINQ - Normal format
            //Let us not include the conversion of XmlDocument to XDocument
            xNDoc = XDocument.Parse(xmlNDoc.OuterXml);
            objSW.Reset();
            objSW.Start();
            var linqNQuery = from p in
                                 xNDoc.Root.Elements("Contact").Elements("Phone")
                             where p.Value.Contains("999999996") select p;
            /*foreach (XElement e in linqNQuery)
            {
                Console.WriteLine(e.Name+"-"+e.Value);
            }*/
            objSW.Stop();
            Console.WriteLine("XML query using LINQ - Normal format");
            Console.WriteLine("TimeElapsed (Stopwatch float):{0}ms",
                objSW.Elapsed.TotalMilliseconds);
            Console.WriteLine("TimeElapsed (Stopwatch rounded):{0}ms",
                objSW.ElapsedMilliseconds);

            Console.ReadLine();
        }
    }
}

Output:
XML query using xpath - Normal format
TimeElapsed (Stopwatch float):20.0936ms
TimeElapsed (Stopwatch rounded):20ms
XML query using LINQ - Normal format
TimeElapsed (Stopwatch float):0.5082ms
TimeElapsed (Stopwatch rounded):0ms

Rule: Use LINQ for querying xml content.

Wednesday, September 15, 2010

MySQL performance optimization

Let us see some of the most simplest mysql optimizations and best practices,

Rue: Use MEDIUMINT for storing user Id for intranet applications. You can store -8388608 to 8388607 signed values or 0 to 16777215 unsigned values.

Rue: You can consider using BIGINT UNSIGNED for storing user Id for internet based applications. You can store -9223372036854775808 to 9223372036854775807 signed values or 0 to 18446744073709551615 unsigned values.

Rue: Always use UNSIGNED numeric types unless you want to store negative numbers.

Rue: Always have an primary key id column which is one of the INT types and UNSIGNED.

Rue: Use ENUM type over VARCHAR for storing predefined string values, e.g. "inactive", "inactive", "male", "female" etc.

Rue: Use DATE type instead of DATETIME if you want to store only date.

Rue: Use VARCHAR for variable string values.

Rue: Use INT UNSIGNED for IP4 values.

Rue: Using NOT NULL saves 1 bit per column.

Rue: Use binary type to store md5 value with 16 bytes instead of 32 bytes of varchar type.

Rue: Consider fixed format table structure (no varchar, no blob or no text columns) for tables with more write operations.

Rue: Use LIMIT in your SELECT, UPDATE statements if you already know your are looking for only one match, e.g. while checking for username and password match.

Rue: Avoid SELECT * FROM and specify only the interested column names.

Rue: Use index only when needed, indexes are good for reading and bad for storing data quickly. Identify the proportion of read and write operation on every single table in your database.

Rue: Consider storing image data outside the database and store only the reference of the image in the database. You can reconsider this approach if you want to support replication of servers.

For more information please refer the following sites,
http://dev.mysql.com/doc/refman/5.1/en/storage-engines.html
http://dev.mysql.com/doc/refman/5.1/en/optimization.html
http://www.slideshare.net/ronaldbradford/top-20-design-tips-for-mysql-data-architects-presentation
http://net.tutsplus.com/tutorials/other/top-20-mysql-best-practices/

Thursday, September 2, 2010

Improving the performance of web page | web application

The first step in improving the performance of your web page is to measure the current performance of the web page.

If you are using Google Chrome then try Speed Tracer. If you are using Firefox then try
Page Speed.

You can also try online performance testing at webpagetest.

Let us see some simple rules to improve the performance of the web page,

Rule: Remove broken links (<a>).

Rule: Combine the external javascript links into 2 or three links to reduce the HTTP request.

Rule: Use inline javascript for fewer lines of script.

Rule: To make the home page load faster have only the scripts needed for the home page either as external link or inline.

You can also try to defer the loading of javascript.

Rule: Try to defer the loading of javascript if possible.

Refer Browserscope for knowing the we browsers parallel loading capabilities of javascripts and other resources.

Rule: Combine the external css into 2 or three files to reduce the HTTP request.

Rule: Use inline css for fewer lines of css.

Rule: To make the home page load faster have only the css needed for the home page either as external link or inline.

Rule: Compress and compact the html, css and javascript resources to reduce the number of bytes sent over the network.

Rule: Minimize DNS lookups to reduce the resolution requests. Use URL paths e.g. host your site on www.xyz.com/abc instead of abc.xyz.com. Serve the startup javascript and other resources from the same host.

Rule: Minimize redirection from one URL to another.

Rule: Use image compressor. This would reduce number of bytes sent over the network.

Rule: Make the styles (css) load before the scripts (javascript). This would enables better parallelization of downloads and speeds up browser rendering.

Refer Browserscope for knowing the we browsers parallel loading capabilities of javascripts and other resources.

Rule: Parallelize the loading of resources.

Rule: Have the inline style and external style sheets in the "head" section.

Rule: Remove the unused css, javascript and html. This would eliminate unwanted bytes sent over the network.

Rule: Specify the size (height and width) of the image in the img tag.

For more details please refer Web Performance Best Practices and Let's make the web faster
.
Now try applying the above rules to your web page and measure the performance.

Watch the below two videos for more on improving web page | web application performance.

Speed Tracer



Page Speed

Wednesday, August 25, 2010

Reading GPS data from Nokia phones

To read GPS data from your Nokia phone follow the below steps,

Make sure your Nokia phone supports inbuilt GPS receiver.

Install Aptana with Nokia WRT Plug-in for Aptana Studio.

Create a new project in Aptana with WRTKit.

1) Paste the below code in the index.html file.
2) Package the widget.
3) Download the package (yourprojectname.wgz) to your Nokia phone and install.
4) Run the application and wait the application to establish connection with the satellites.
5) Have fun!

Javascript example
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title>GPS Tracker</title>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />        
<script type="text/javascript" src="WRTKit/WRTKit.js"></script>        
<META NAME="Generator" CONTENT="Nokia WRT plug-in for Aptana Studio 2.3.0" />
<style>
body{background-color:#ffffff;font-size:15px;}
#btnGetLocation{width:100%;margin:5px;height:50px;width:100px;}
#latLabel{text-align:left;margin:5px;width:150px;}
#longLabel{text-align:left;margin:5px;width:150px;}
#statusLabel{text-align:left;margin:5px;width:150px;}
#gpsStatusLabel{padding:5px;text-align:left;margin:5px;height:20px;width:150px;}
.gpsStatusLabelA{background-color:lightgreen;}
.gpsStatusLabelIA{background-color:red;}
#gpsStrengthLabel{text-align:left;margin:5px;width:150px;}
</style>
<script>
var interval=1000;   
var TXT_ACTIVE = "Active";
var TXT_INACTIVE = "Inactive";  
var TXT_RUNNING="Running";
var TXT_GPSSTATUSLABEL="gpsStatusLabel";
var GPS_INACTIVE = 0;
var GPS_ACTIVE = 1;

var locDataTimer = null;
var serviceObj = null;
var distanceCriteria = null;
var trackCriteria = null;

function updateElement(name,value)
{
 document.getElementById(name).innerHTML=value;
 if(name == TXT_GPSSTATUSLABEL)
 {     
  if(value == TXT_ACTIVE)
  {  
   document.getElementById(name).setAttribute("class", "gpsStatusLabelA");  
  }
  else
  {  
   document.getElementById(name).setAttribute("class", "gpsStatusLabelIA");
  }
 }
}
function reset()
{
 updateElement("gpsStatusLabel",TXT_INACTIVE);
 updateElement("gpsStrengthLabel","");
 updateElement("statusLabel","");
 updateElement("latLabel","");
 updateElement("longLabel","");    
}
function initUI()
{
 reset();
}
function initSO()
{
 try
 {
  serviceObj = device.getServiceObject("Service.Location", "ILocation");
 }
 catch (ex) 
 {
  updateElement("statusLabel",ex);
  return;
 } 
 // The user cancelled the service object initialization
 if (serviceObj.ILocation == null) 
 {
  return; 
 }        
 // Specify that location information need not be guaranteed. This helps in
 // that the widget doesn't need to wait for that information possibly
 // indefinitely.
 var updateOptions = new Object();
 updateOptions.PartialUpdates = true;
 
 // Initialize the criteria for the GetLocation call
 trackCriteria = new Object();
 trackCriteria.LocationInformationClass = "GenericLocationInfo";
 trackCriteria.Updateoptions = updateOptions;
 // Set the timer to tick (update the location data) at one second intervals
 locDataTimer = setInterval("tick()", interval);
}
function init()
{
 initUI();    
 initSO();
}

// Called when the locDataTimer's interval elapses
function tick() 
{
 updateElement("statusLabel",TXT_RUNNING);
 try 
 {
  var result = serviceObj.ILocation.GetLocation(trackCriteria);
  displayData(result);    
 }
 catch (ex) 
 {
  updateElement("statusLabel",ex);  
 }
}
// Displays the location data
function displayData(result) 
{
 if (result.ReturnValue == undefined) 
 {
  return;
 }

 var latitude = result.ReturnValue.Latitude;
 if (!isNaN(latitude)) 
 {
  updateElement("latLabel", latitude.toFixed(4) + " \u00B0");
 }       
 var longitude = result.ReturnValue.Longitude;
 if (!isNaN(longitude)) 
 {
  updateElement("longLabel", longitude.toFixed(4) + " \u00B0");
 }   
 if (!isNaN(latitude) || !isNaN(longitude)) 
 {
  // Either latitude or longitude information is received, so we can be
  // sure that the GPS is active
  changeGPSStatus(GPS_ACTIVE);
 }
 else 
 {
  changeGPSStatus(GPS_INACTIVE);
 }
 
 var numOfSatellites = result.ReturnValue.SatelliteNumView;
 if (numOfSatellites == undefined) 
 {
  numOfSatellites = 0;
 }
 updateElement("gpsStrengthLabel",numOfSatellites);
}   
//Changes the GPS status on the status pane
function changeGPSStatus(newStatus) 
{       
 if (newStatus == GPS_ACTIVE) 
 {
  updateElement("gpsStatusLabel",TXT_ACTIVE);
 } 
 else 
 {
  updateElement("gpsStatusLabel",TXT_INACTIVE);
 }
}
</script>
</head>
<body onload="init()">
<h3>GPS Tracker</h3>
<table border="1px" width="100%">
<tr>
<td>
GPS:
</td> 
<td align="center">
<div id="gpsStatusLabel"></div>   
</td>
</tr>
<tr>
<td>
GPS Strength:
</td> 
<td align="center">
<div id="gpsStrengthLabel"></div>   
</td>
</tr>
<tr>
<td>
Lat:
</td> 
<td align="center">
<div id="latLabel"></div>   
</td>
</tr>
<tr>
<td>
Long:
</td> 
<td align="center">
<div id="longLabel"></div>   
</td>
</tr>   
<tr>
<td>
Status:
</td> 
<td align="center">
<div id="statusLabel"></div>   
</td>
</tr>
</table>       
</body>
</html>

Simple soap client

Below is a simple javascript soap client. The same code can be modified to work as an ajax client by removing the SOAPAction header. The below code accepts the service URL, soap envelope, SOAPAction header name (because it may be of different case in different technology), action and method.

Javascript example
<html>
<head>
<title>Soap Client</title>
<script>
var READY_STATE_UNINITIALIZED=0;
var READY_STATE_LOADING=1;
var READY_STATE_LOADED=2;
var READY_STATE_INTERACTIVE=3;
var READY_STATE_COMPLETE=4;
var xmlHttpRequest;
function getXmlHttpRequest()
{
 var xRequest=null;
 if (window.XMLHttpRequest)
 {
  xRequest=new XMLHttpRequest();
 }
 else if (typeof ActiveXObject != "undefined")
 {
  xRequest=new ActiveXObject("Microsoft.XMLHTTP");
 }
 return xRequest;
}
function handleEmptyString(value,userMessage)
{
    var status=false;
    if(value == "")
    {
        alert(userMessage);
    }
    else
    {
        status=true;
    }
    return status;
}
function sendRequest(url,soapActionHeaderName,
                        soapAction,params,httpMethod,contentType)
{
    var status=false;
    status=handleEmptyString(url,"Please enter the URL.");
    if(status == true)
    {
        status=handleEmptyString(soapActionHeaderName,"Please enter the Soap action header name.");
        if(status == true)
        {
            status=handleEmptyString(soapAction,"Please enter the Saop action.");
            if(status == true)
            {
                status=handleEmptyString(params,"Please enter the soap request.");
                if(status == true)
                {
                    status=handleEmptyString(contentType,"Please enter the content type.");
                }
            }
        }
    }
    if(status==true)
    {
        //Disable mozilla security restriction
        if(window.netscape &&
        window.netscape.security.PrivilegeManager.enablePrivilege)
        {
            var pm=netscape.security.PrivilegeManager;
            pm.enablePrivilege('UniversalBrowserRead');
        }
        // If method not set
        if (!httpMethod)
        {
            httpMethod="GET";
        }
        xmlHttpRequest=getXmlHttpRequest();
        if (xmlHttpRequest)
        {
            xmlHttpRequest.onreadystatechange=onReadyStateChange;
            xmlHttpRequest.open(httpMethod,url,true);
            xmlHttpRequest.setRequestHeader(
            "Content-Type",contentType);
            xmlHttpRequest.setRequestHeader(soapActionHeaderName,soapAction);
            xmlHttpRequest.send(params);
        }
    }
}
function onReadyStateChange()
{
    var ready=xmlHttpRequest.readyState;
    var data=null;
    if (ready==READY_STATE_COMPLETE)
    {
        data=xmlHttpRequest.responseText;
        //... do something with the data...
        document.getElementsByName("taResponse")[0].value=data;
    }
    else
    {
        data="Loading...["+ready+"]";
        document.getElementsByName("taResponse")[0].value=data;
    }
}
function sendData()
{
    var url=document.getElementsByName("txtURL")[0].value;
    var params=document.getElementsByName("taRequest")[0].value;
    var httpMethod=document.getElementsByName("txtMethod")[0].value;
    var soapActionHeaderName;
    soapActionHeaderName=document.getElementsByName("txtActionHeaderName")[0].value;
    var soapAction=document.getElementsByName("txtAction")[0].value;
    var contentType=document.getElementsByName("txtContentType")[0].value;
    sendRequest(url,soapActionHeaderName,soapAction,params,httpMethod,contentType);
}
function clearData()
{
    document.getElementsByName("taResponse")[0].value="";
}
</script>
</head>
<body>
<h1>Soap client</h1>
<table>
<tr>
<tr>
<td>URL: (e.g. http://xyz.com/service)</td>
<td><input type="text"
value="http://localhost:8080/CalculatorProj/services/Calculator"
name="txtURL" size="150"/></td>
</tr>
<td>Request:</td>
<td><textarea rows="12" cols="120" name="taRequest">
<soapenv:Envelope
xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/"
xmlns:q0="http://wtp" xmlns:xsd="http://www.w3.org/2001/XMLSchema"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
  <soapenv:Body>
    <q0:add>
      <q0:number1>5</q0:number1>
      <q0:number2>6</q0:number2>
    </q0:add>
  </soapenv:Body>
</soapenv:Envelope>
</textarea>
</td>
</tr>
<tr>
<td>Action header name:</td>
<td><input type="text" value="SOAPAction" name="txtActionHeaderName"/></td>
</tr>
<tr>
<td>Action:</td>
<td><input type="text" value="add" name="txtAction"/></td>
</tr>
<tr>
<td>Content type:</td>
<td><input type="text" value="text/xml; charset=utf-8" name="txtContentType" /></td>
</tr>
<tr>
<td>Method: (GET/POST)</td>
<td><input type="text" value="POST" name="txtMethod"/></td>
</tr>
<tr>
<td>Response:</td>
<td><textarea rows="8" cols="120" name="taResponse"></textarea></td>
</tr>
<tr>
<td></td>
<td align="center">
    <input type="button" value="Send" onclick="sendData()"/>
    <input type="button" value="Clear Result" onclick="clearData()"/>
</td>
</tr>
</table>
</body>
</html>

Note: This code sample works only with in your domain. If you want to try across domain then please refer Google AJAX APIs.

Google gadget

Goto www.google.com and locate iGoogle (top right).
Sing In to iGoogle. Play around with the default gadgets on iGoogle.

Install Google Gadget Editor.

Read how-to-make-google-gadgets and make your first Google gadget.

Refer Google Gadgets for more info.

Monday, August 23, 2010

Reading cross domain JSON (AJAX)

If you want to read JSON content from a different domain, let us say you want to read JSON content from http://twitter.com, then here is a simple example using JQUERY JSON API.

http://twitter.com JSON content link is http://api.twitter.com/1/statuses/public_timeline.json?callback=?.

Javascript example with jQuery.each() loop
<script type="text/javascript" src="http://code.jquery.com/jquery-1.4.2.min.js"></script>
<script>
var JSONPUBICURL="http://api.twitter.com/1/statuses/public_timeline.json?callback=?";
var TWITTERURL="http://twitter.com/";
function getJSON()
{
var strHTML='';
var imgURL="";
$.getJSON(JSONPUBICURL,
function(data){
strHTML+='<table border="0px">';
$.each(data, function(i, item) {

    imgURL=item.user["profile_image_url"];

    strHTML+='<tr>';
    strHTML+='<td valign="top">';
    strHTML+='<img src="'+imgURL+'" alt="'+item.user["screen_name"]+'" title="'+item.user["screen_name"]+'" height="50px" width="50px"/>';
    strHTML+='</td>';
    strHTML+='<td valign="top" >';
    strHTML+='<a href="'+TWITTERURL+item.user["screen_name"]+'/statuses/'+item.id+'" target="_blank" >'+item.text+'</a><br/>';
    strHTML+=item.created_at+' [via '+item.source+']<br/>';
    strHTML+='</td>';
    strHTML+='</tr>';
});
strHTML+='</table>';
strHTML+='<div align="right" ><a href="'+TWITTERURL+'" target="_blank">more...</a></div>';
document.getElementById("tweets").innerHTML=strHTML;
});
}
</script>
<div id="tweets"></div>
<script>
    $(document).ready(getJSON());
</script>

Note: using this approach you can get the live tweets from http://twitter.com.


Javascript example with for loop
<script type="text/javascript" src="http://code.jquery.com/jquery-1.4.2.min.js"></script>
<script>
var JSONPUBICURL="http://api.twitter.com/1/statuses/public_timeline.json?callback=?";
var TWITTERURL="http://twitter.com/";
function getJSON()
{

var strHTML='';
var imgURL="";

$.getJSON(JSONPUBICURL,
function(data){
strHTML+='<table border="0px">';
var length=data.length;
for(var i=0;i<length;i++)
{
    imgURL=data[i].user["profile_image_url"];
    strHTML+='<tr>';
    strHTML+='<td valign="top">';
    strHTML+='<img src="'+imgURL+'" alt="'+data[i].user["screen_name"]+'" title="'+data[i].user["screen_name"]+'" height="50px" width="50px"/>';
    strHTML+='</td>';
    strHTML+='<td valign="top" >';
    strHTML+='<a href="'+TWITTERURL+data[i].user["screen_name"]+'/statuses/'+data[i].id+'" target="_blank" >'+data[i].text+'</a><br/>';
    strHTML+=data[i].created_at+' [via '+data[i].source+']<br/>';
    strHTML+='</td>';
    strHTML+='</tr>';

}
strHTML+='</table>';
strHTML+='<div align="right" ><a href="'+TWITTERURL+'" target="_blank">more...</a></div>';
document.getElementById("tweets").innerHTML=strHTML;

});

}
</script>
<div id="tweets"></div>
<script>
    $(document).ready(getJSON());
</script>

for loop may be faster than jQuery.each() loop. see jQuery tests in Low Level JavaScript Performance.

Sunday, August 22, 2010

Reading cross domain RSS feeds (AJAX)

If you want to read an RSS feed from a different domain, let us say you want to read an RSS feed from http://digg.com, then here is a simple example using Google AJAX Feed API.

http://digg.com RSS feed link is http://feeds.digg.com/digg/popular.rss.

Javascript example
<script type="text/javascript" src="http://www.google.com/jsapi"></script>
<script>
var RSSURL="http://feeds.digg.com/digg/popular.rss";
var DIGGURL="http://digg.com/";
function getFeed()
{
var strHTML='';
var feed = new google.feeds.Feed(RSSURL);
feed.load(function(result) {
if (!result.error) {    
    var length=result.feed.entries.length;
    for (var i = 0; i < length; i++) {
        var entry = result.feed.entries[i];
        strHTML+='';
        strHTML+='<a href="'+entry.link+'" target="_blank">'+entry.title+'</a><br/>';
        strHTML+=entry.publishedDate+'<br/>';
        strHTML+='<div>';
        strHTML+=entry.contentSnippet+'<br/>';
        strHTML+='</div>';
        strHTML+='<br/>';
    }
    strHTML+='<div align="right"><a href="'+DIGGURL+'" target="_blank">more...</a></div>';
    document.getElementById("digg").innerHTML=strHTML;
}
});
}
</script>
<div id="digg"></div>
<script>
    google.load("feeds", "1");
    google.setOnLoadCallback(getFeed);
</script>

Note: As the Google AJAX Feed API uses Feedfetcher, feed data from the AJAX Feed API may not always be up to date. The Google feed crawler ("Feedfetcher") retrieves feeds from most sites less than once every hour. Some frequently updated sites may be refreshed more often.

Wednesday, August 18, 2010

Naming convention

There are no hard and fast rules as far as naming conventions are concerned, but it has to be consistent at the individual, team and organization level.

The name of the folder, project, file, namespace, class, and function have to be meaningful. The variable (data members, local members or function arguments) must have the following information as part of their name
  • modifier (private, public, etc.) and scope of the variable (member to the class (data member), member to the function (local variable), constant, static)
  • datatype of the variable
  • meaningful name
Along with the above mentioned points you can also add comments where ever necessary. Also indentation of the code would improve the readability.

C# 2.0 example- Below is the Employee.cs file.
using System;
using System.Collections.Generic;
using System.Text;
namespace Sample_v2
{
    class Employee
    {
        private string m_strName=String.Empty;
        private int m_iEmpId=-1;
        public Employee(string strName, int iEmpId)
        {
            m_strName = strName;
            m_iEmpId = iEmpId;
        }
        public string Name
        {
            get
            {
                return m_strName;
            }
            private set { m_strName = value; }
        }
        public int EmpId
        {
            get
            {
                return m_iEmpId;
            }
            private set { m_iEmpId = value; }

        }
        //should not allow empty string or null string
        public bool SetNameWithValidation(string strName)
        {
            bool blnStatus = false;
            if (strName != string.Empty && strName != null)
            {
                m_strName = strName;
                blnStatus = true;
            }
            return blnStatus;
        }
        public override string ToString()
        {
            return string.Format("Name:{0},EmpId:{1}",
                m_strName, m_iEmpId);
        }

    }

}

C# 3.0 example- Below is the Employee.cs file.
using System;
using System.Collections.Generic;
using System.Text;
namespace Sample_v3
{
    class Employee
    {
        public string Name { get; set; }
        public int EmpId { get; set; }
        public Employee()
        {

        }
        //should not allow empty string or null string
        public bool SetName(string strName)
        {
            bool blnStatus = false;
            if (strName != string.Empty && strName != null)
            {
                Name = strName;
                blnStatus = true;
            }
            return blnStatus;
        }
        public override string ToString()
        {
            return string.Format("Name:{0},EmpId:{1}",
                Name,
                EmpId);
        }
    }
}

Note: Alternatively you can follow the naming standard followed by the respective technology (.Net, J2SE, JavasScript, etc). Intellisense feature of the respective integrated development environment (IDE) could help you on this.

Rule: Follow consistent naming convention.

Rule: If you not clear on the final name of the product, module, etc consider using a meaning less code name (e.g. "code123").

OpenID Authentication

If you are developing a web application for internet and your web hosting plan does not support SSL and want to support user Sign Up and Sign In, then consider using OpenID authentication mechanism.

Check this URL Federated Login for Google Account Users.

Using Janrain Engage you can build OpenID Sing In module with in few minutes.

There is another quick and easy OpenID library is Dope OpenID.

Thursday, June 17, 2010

Optimizing C# code

Let us try to understand what is called optimizing a code.
Write a simple logging function which shall
write the given string message to a file.

Step #1 - Write the Logger class with a function which will open/create the text file and append the string message along with time stamp and close the file.

using System;
using System.Collections.Generic;
using System.Text;
using System.IO;
using System.Diagnostics;
using System.Threading;

namespace LoggerTimeElapsed
{

    class Logger
    {
        public string FilePath { get; set; }
        private object m_objLocker;
        public Logger()
        {
            m_objLocker = new object();
            FilePath = @"d:\log.txt";
        }
        //make sure the StreamWriter is closed
        //make sure thr Monitor is exit
        public bool WriteToFile(string strMessage)
        {
            bool blnStatus = false;
            StreamWriter objStreamWriter = null;
            if (strMessage != string.Empty && strMessage != null)
            {
                try
                {
                    Monitor.Enter(m_objLocker);
                    objStreamWriter = new StreamWriter(FilePath, true);
                    //logs only the time and not the date
                    objStreamWriter.WriteLine(
                        DateTime.Now.TimeOfDay + " - " + strMessage
                        );
                    objStreamWriter.Close();
                    Monitor.Exit(m_objLocker);
                    blnStatus = true;
                }
                catch (Exception objEx)
                {
                    //use messagebox if winforms application
                    Console.WriteLine(objEx.StackTrace);
                    if (objStreamWriter != null)
                    {
                        objStreamWriter.Close();
                    }
                    Monitor.Exit(m_objLocker);
                }
                finally
                {
                }
            }
            return blnStatus;
        }
    }
    class Program
    {
        static void Main(string[] args)
        {
            Logger objLogger = null;
            Stopwatch objSW = null;
            int iCount = 100;
            objSW = new Stopwatch();
            objLogger = new Logger();
            objSW.Reset();
            objSW.Start();
            for (int i = 0; i < iCount; i++)
            {
                objLogger.WriteToFile("Unoptimized" + i.ToString());
            }
            objSW.Stop();
            Console.WriteLine("WriteToFile - TimeElapsed");
            Console.WriteLine("TimeElapsed (Stopwatch float):{0}ms",
                objSW.Elapsed.TotalMilliseconds);
            Console.WriteLine("TimeElapsed (Stopwatch rounded):{0}ms",
                objSW.ElapsedMilliseconds);
            Console.ReadLine();
        }
    }
}
Step #2 - Measure the time taken by the function to log 100 messages to the text file.In the above code Stopwatch class is used for measuring the time.
Output:
WriteToFile - TimeElapsed
TimeElapsed (Stopwatch float):319.2352ms
TimeElapsed (Stopwatch rounded):319ms
Step #3 - If the time taken by the function does not meet the throughput requirement, then try to optimize the code. So let us now change the Logger class such that, the text file is opened only once and closed only once.
using System;
using System.Collections.Generic;
using System.Text;
using System.IO;
using System.Diagnostics;
using System.Threading;

namespace LoggerTimeElapsed
{

    class Logger
    {
        public string FilePath { get; set; }
        private StreamWriter m_objStreamWriter = null;
        private object m_objLocker;
        public Logger()
        {
            m_objLocker = new object();
            FilePath = @"d:\log.txt";
        }
        public bool Open()
        {
            bool blnStatus = false;
            try
            {
                m_objStreamWriter = new StreamWriter(FilePath, true);
                blnStatus = true;
            }
            catch (Exception objEx)
            {
                Console.WriteLine(objEx.StackTrace);
            }
            finally
            {
            }
            return blnStatus;
        }
        public bool Close()
        {
            bool blnStatus = false;
            try
            {
                if (m_objStreamWriter != null)
                {
                    m_objStreamWriter.Close();
                    blnStatus = true;
                }
            }
            catch (Exception objEx)
            {
                Console.WriteLine(objEx.StackTrace);
            }
            finally
            {
            }
            return blnStatus;
        }
        //make sure Open is called before calling WriteToFile
        //make sure Close is called once all logging is done
        public bool WriteToFile(string strMessage)
        {
            bool blnStatus = false;
            if (strMessage != string.Empty && strMessage != null)
            {
                try
                {
                    lock (m_objLocker)
                    {
                        if (m_objStreamWriter != null)
                        {
                            //logs only the time and not the date
                            m_objStreamWriter.WriteLine(
                                DateTime.Now.TimeOfDay
                                + " - "
                                + strMessage
                                );
                            blnStatus = true;
                        }

                    }
                }
                catch (Exception objEx)
                {
                    //use messagebox if winforms application
                    Console.WriteLine(objEx.StackTrace);
                }
                finally
                {
                }
            }
            return blnStatus;
        }
    }
    class Program
    {
        static void Main(string[] args)
        {
            Logger objLogger = null;
            Stopwatch objSW = null;
            int iCount = 100;
            objSW = new Stopwatch();
            objLogger = new Logger();
            objLogger.Open();
            objSW.Reset();
            objSW.Start();
            for (int i = 0; i < iCount; i++)
            {
               objLogger.WriteToFile("Optimized" + i.ToString());
            }
            objSW.Stop();
            objLogger.Close();
            Console.WriteLine("WriteToFile - TimeElapsed");
            Console.WriteLine("TimeElapsed (Stopwatch float):{0}ms",
                objSW.Elapsed.TotalMilliseconds);
            Console.WriteLine("TimeElapsed (Stopwatch rounded):{0}ms",
                objSW.ElapsedMilliseconds);
            Console.ReadLine();
        }
    }
}
Step #4 - Measure the time take by the Logger class to log 100 message to the text file.In the above code Stopwatch class is used for measuring the time.
Output:
WriteToFile - TimeElapsed
TimeElapsed (Stopwatch float):4.6166ms
TimeElapsed (Stopwatch rounded):4ms
Step #5 - Analyze the advantages and disadvantages of different approaches and decide the best approach.

Write the code → Measure → Optimize the code → Measure

C# measurement tools

There are two important factor which has to be measured to identify the improvement in the code
  • Time taken to complete some operation
  • Memory usage of the application
Below is the code for measuring memory consumption.
using System;
using System.Collections.Generic;
using System.Text;
using System.Diagnostics;

namespace StructMemoryUsage
{
    struct EmployeeStruct
    {
        public string Name;
        public int EmpId;
    }

    class Program
    {
        static void Main(string[] args)
        {
            long lngGCMemStart = 0;
            long lngGCMemEnd = 0;
            long lngProcessMemStart = 0;
            long lngProcessMemEnd = 0;

            //employee as struct
            EmployeeStruct[] objEmployee;
            int iCount;
            iCount = 100000;

            Process objProcess = Process.GetCurrentProcess();
            //Measure starting point memory
            lngGCMemStart = System.GC.GetTotalMemory(true);
            lngProcessMemStart = objProcess.PrivateMemorySize64;

            objEmployee = new EmployeeStruct[iCount];

            //Measure memory after allocating
            lngGCMemEnd = System.GC.GetTotalMemory(true);
            lngProcessMemEnd = objProcess.PrivateMemorySize64;

            for (int i = 0; i < iCount; i++)
            {
                objEmployee[i].Name = "Emp" + i.ToString();
                objEmployee[i].EmpId = i;
            }
            Console.WriteLine("Struct memory usage.");
            //memoryusage difference
            Console.WriteLine("GC Memory Use:{0} (bytes)",
                lngGCMemEnd - lngGCMemStart);
            Console.WriteLine("Process Memory Use:{0} (bytes)",
                lngProcessMemEnd - lngProcessMemStart);

            Console.WriteLine("GC Memory Start:{0} (bytes)",
                lngGCMemStart.ToString());
            Console.WriteLine("Process Memory Start:{0} (bytes)",
                lngProcessMemStart.ToString());

            Console.WriteLine("GC Memory End:{0} (bytes)",
                lngGCMemEnd.ToString());
            Console.WriteLine("Process Memory End:{0} (bytes)",
                lngProcessMemEnd.ToString());

            Console.ReadLine();
        }
    }
}
Output:
Struct memory usage.
GC Memory Use:802380 (bytes)
Process Memory Use:0 (bytes)
GC Memory Start:126592 (bytes)
Process Memory Start:8937472 (bytes)
GC Memory End:928972 (bytes)
Process Memory End:8937472 (bytes)

Note: Alternatively use perfmon->Add Counters->.NET CLR Memory counters can be used for viewing the memory consumption of selected .NET process.

Below is the code for measuring the time.
using System;
using System.Collections.Generic;
using System.Text;
using System.Diagnostics;

namespace MeasuringTime
{
    class Program
    {
        static void Main(string[] args)
        {
            long lngStartTime = 0;
            long lngEndTime = 0;
            DateTime dtStartTime;
            TimeSpan tsTimeDiff;
            long lngSWFrequency=0;
            Stopwatch objSW;// Only from .Net 2.0

            //If the computer is kept running continuously
            //for 49 days then the Environment.TickCount would
            //start counting backwards
            //So the most significant bit is extracted
            lngStartTime = Environment.TickCount
                & Int32.MaxValue;
            System.Threading.Thread.Sleep(5000);
            lngEndTime = Environment.TickCount
                & Int32.MaxValue;

            Console.WriteLine("TimeElapsed (TickCount):{0}ms",
                lngEndTime - lngStartTime);
            //Resolution of DateTime.Now is 10+ milliseconds
            dtStartTime = DateTime.Now;
            System.Threading.Thread.Sleep(5000);
            tsTimeDiff = DateTime.Now - dtStartTime;


            Console.WriteLine("TimeElapsed (DateTime):{0}ms",
                tsTimeDiff.TotalMilliseconds);
            //Stopwatch uses the hardware timer if it
            //highresolution timer or else uses the DateTime.Now
            //To check the availability of the high
            //resolution timer use IsHighResolution property
            if (true == Stopwatch.IsHighResolution)
            {
                Console.WriteLine(
                    "HighResolutionTimer is present"
                    );
            }
            else
            {
                Console.WriteLine(
                    "HighResolutionTimer is absent"
                    );
            }

            lngSWFrequency = Stopwatch.Frequency;
            Console.WriteLine(
                "Timer frequency in ticks/second:{0}",
                lngSWFrequency);
            objSW = Stopwatch.StartNew();
            System.Threading.Thread.Sleep(5000);
            objSW.Stop();
            Console.WriteLine(
                "TimeElapsed (Stopwatch float):{0}ms",
                objSW.Elapsed.TotalMilliseconds
                );
            Console.WriteLine(
                "TimeElapsed (Stopwatch rounded):{0}ms",
                objSW.ElapsedMilliseconds
                );

            Console.ReadLine();

        }
    }
}

Output:
TimeElapsed (TickCount):4992ms
TimeElapsed (DateTime):5002ms
HighResolutionTimer is present
Timer frequency in ticks/second:14318180
TimeElapsed (Stopwatch float):5000.7317ms
TimeElapsed (Stopwatch rounded):5000ms

Note: Profiling tools can be used for the measuring time and memory leak.

How to write a program?

Program accepts input, performs the function and produces the output.

Accept inputs → Perform the function (logic) → Produce output

Let us try to write a simple calculator. The calculator has to support addition, subtraction, multiplication and division and also display the result.
Try to write the calculator program on a paper by following the steps below
Step #1 - Identify the user inputs.
number1
number2
operation
Step #2 - Identify the output.
result
Step #3 - Write the logic.
if operation is "add"
{
    number1+number2=result
}
if operation is "sub"
{
    number1-number2=result
}
if operation is "mul"
{
    number1*number2=result
}
if operation is "div"
{
    number1/number2=result
}
Step #4 - Display the output (result).
Now try to execute the program on the paper by following the steps
Step #1 - Accept user inputs
number1=8
number2=7
operation="sub"
Step #2 - Nothing to do in this step
Step #3 - Execute the logic
if operation is "add"
{
    number1+number2=result
}
if operation is "sub"
{
    number1-number2=result
    8 - 7 = 1(result)
}
if operation is "mul"
{
    number1*number2=result
}
if operation is "div"
{
    number1/number2=result
}
Step #4 - Display the result
Result is 1
The program works fine on the paper.
C# example- Now open Microsoft Visual Studio
or Microsoft Visual C# 2008 Express Edition and create a
console application (File → New Project → Console Application) and try to write the program as below.
using System;

namespace calculator
{
    class Program
    {
        static void Main(string[] args)
        {
            //Identify the user inputs
            float Number1;
            float Number2;
            string Operation;

            //Identify the output
            float Result=0;

            //Accept user inputs
            //can write code to get the input through the console or user interface
            Number1=8;
            Number2=7;
            Operation = "sub";

            //Write the logic
            if ("add" == Operation)
            {
            Result = Number1+Number2;
            }
            if ("sub" == Operation)
            {
            Result = Number1 - Number2;
            }
            if ("mul" == Operation)
            {
            Result = Number1 * Number2;
            }
            if ("div" == Operation)
            {
            Result = Number1 / Number2;
            }

            //Display the output
            Console.Write("Result is {0}",Result);

            //To make the console wait for the user to read the result
            Console.ReadLine();
        }
    }

}
Output:
Result is 1
The above program works fine. So now try to write the logic
or function part as class as below.
using System;

namespace ConsoleApplication6
{
    class Calc//also called as type
    {
        public Calc()//constructor
        {

        }
        //Logic as function
        public float Add(float Num1, float Num2)//function with arguments/inputs
        {
            float Result;//local variable
            Result = Num1 + Num2;
            return Result;//return Result/output
        }
        //Logic as function
        public float Sub(float Num1, float Num2)//function with arguments/inputs
        {
            float Result;//local variable
            Result = Num1 - Num2;
            return Result;//return Result/output

        }
        //Logic as function
        public float Mul(float Num1, float Num2)//function with arguments/inputs
        {
            float Result;//local variable
            Result = Num1 * Num2;
            return Result;//return Result/output
        }
        //Logic as function
        public float Div(float Num1, float Num2)//function with arguments/inputs
        {
            float Result;//local variable
            Result = Num1 / Num2;
            return Result;//return Result/output
        }
    }
    class Program
    {
        static void Main(string[] args)
        {
            //Identify the user inputs
            float Number1;
            float Number2;
            string Operation;

            //Identify the output
            float Result = 0;

            //Accept user inputs
            //can write code to get the input through the console or user interface
            Number1 = 8;
            Number2 = 7;
            Operation = "sub";

            Calc Calc1 = new Calc();//create new Calc

            //Display the inputs
            Console.WriteLine("Number1 is {0},Number2 is {1}", Number1, Number2);
            //Write the logic
            if ("add" == Operation)
            {
                //Display the operation
                Console.WriteLine("Operation is Add");
                Result=Calc1.Add(Number1, Number2);
            }
            if ("sub" == Operation)
            {
                //Display the operation
                Console.WriteLine("Operation is Sub");
                Result = Calc1.Sub(Number1, Number2);
            }
            if ("mul" == Operation)
            {
                //Display the operation
                Console.WriteLine("Operation is Mul");
                Result = Calc1.Mul(Number1, Number2);
            }
            if ("div" == Operation)
            {
                //Display the operation
                Console.WriteLine("Operation is Div");
                Result = Calc1.Div(Number1, Number2);
            }

            //Display the output
            Console.Write("Result is {0}", Result);

            //To make the console wait for the user to read the result
            Console.ReadLine();



        }
    }
}
Output:
Number1 is 8,Number2 is 7
Operation is Sub
Result is 1
JavaScript example- Now let us write the same
program in JavaScript and dhtml, so open a notepad and try to
write the program as below and save it as .html file.
<html>
    <head>
        <title>Calculator</title>
        <style>
        body{
        background:blue;
        color:white;
        }
        td{
        background:white;
        color:maroon;
        font-family:verdana;
        font-size:15px;
        }
        #cssresult{
        background:fuchsia;
        color:lime;
        }
        .cssbutton{
        background:yellow;
        }
        </style>
        <script>
        function calc(op)
        {
            //Identify the user inputs
            var number1;
            var number2;
            var operation;
            //Identify the output
            var result;
            //Accept user inputs
            number1 = (parseFloat)(document.getElementsByName("txtnum1")[0].value);
            number2 = (parseFloat)(document.getElementsByName("txtnum2")[0].value);
            operation=op;
            //Write the logic
            if(operation == "add")
            {
                result = number1 + number2;
                //Display the result
                document.getElementsByName("txtresult")[0].value=result;
                //Display the result (dhtml)
                document.getElementById("divResult")
                .innerHTML="<b>Result is "+result+"</b>";
                alert("Result is "+result);
            }
            if(operation == "sub")
            {
                result = number1 - number2;
                //Display the result
                document.getElementsByName("txtresult")[0].value=result;
                //Display the result (dhtml)
                document.getElementById("divResult")
                .innerHTML="<b>Result is "+result+"</b>";
                alert("Result is "+result);
            }
            if(operation == "mul")
            {
                result = number1 * number2;
                //Display the result
                document.getElementsByName("txtresult")[0].value=result;
                //Display the result (dhtml)
                document.getElementById("divResult")
                .innerHTML="<b>Result is "+result+"</b>";
                alert("Result is "+result);
            }
            if(operation == "div")
            {
                result = number1 / number2;
                //Display the result
                document.getElementsByName("txtresult")[0].value=result;
                //Display the result (dhtml)
                document.getElementById("divResult")
                .innerHTML="<b>Result is "+result+"</b>";
                alert("Result is "+result);
            }
            if(operation == "clear")
            {
                document.getElementsByName("txtnum1")[0].value="";
                document.getElementsByName("txtnum2")[0].value="";
                document.getElementsByName("txtresult")[0].value="";
                document.getElementById("divResult").innerHTML="";
            }
        }
        </script>
    </head>
    <body >
        Calculator
        <table border="2">
        <tr>
        <td>Number 1</td>
        <td><input type="textbox" name="txtnum1"></td>
        <td class="cssbutton">
            <input type="button" value="Add" onclick="calc('add')">
        </td>
        </tr>
        <tr>
        <td>Number 2</td>
        <td><input type="textbox" name="txtnum2"></td>
        <td class="cssbutton">
            <input type="button" value="Sub" onclick="calc('sub')">
        </td>
        </tr>
        <tr >
        <td>Result</td>
        <td id="cssresult"><input type="textbox" name="txtresult"></td>
        <td class="cssbutton">
            <input type="button" value="Mul" onclick="calc('mul')">
        </td>
        </tr>
        <tr>
        <td colspan="2" class="cssbutton">
            <input type=button value="Clear" onclick="calc('clear')">
        </td>
        <td class="cssbutton">
            <input type="button" value="Div" onclick="calc('div')">
        </td>
        </tr>
        </table>
        <div id="divResult"></div>
    </body>
</html>

Output:
Result is 1

Note: Extend the above program to accept input through the user interface and support more features.

Happy programming!

Note: Please read the guidelines listed in this website for efficient programming.

Software requirements

Requirements of a software form the foundation of the software based product.

Functional and non-functional requirements are derived from the "voice of the customer" (VOC), documents (artifacts) and similar products etc. Success of the software product mainly depends on the non-functional requirements like
  • performance – time taken to perform an operation (throughput) and memory usage
  • scalability - ability to easily expanded or upgraded on demand
  • usability – ease of use and intuitiveness
  • architecture – standalone or client server
  • reliability - ability to yield same result on repeated trials
  • security – ability to protect the system from intruders and protecting the privacy of the users of the software product
  • etc.
and the productivity of software development mainly depends on the non-functional requirements like
  • maintainability (includes extensibility, testability)
  • etc.
Make sure the derived requirements are
  • simple
  • not ambiguous
  • testable
Following are the minimum set of attributes of a requirement
  1. Tag – Requirement tag will be used for traceability (e.g. R1, R2, REQ1, REQ10, FR1, FR10, etc.)
  2. Description

Compact xml

Xml is one of most popular format for storing and exchanging data.
For example if we want to store address in an xml file then it would look some thing as below
<AddressBook>
  <Contact>
    <Name>Person1</Name>
    <Address1><![CDATA[Number101]]></Address1>
    <Address2><![CDATA[Address501]]></Address2>
    <Zip>50001</Zip>
    <Phone><![CDATA[999991]]></Phone>
 </Contact>
</AddressBook>
If we use the xml format to store the data and exchange data in an internal or intranet application then consider changing the format compact as below
<AB>
  <C>
    <N>Person1</N>
    <A1><![CDATA[Number101]]></A1>
    <A2><![CDATA[Address501]]></A2>
    <Z>50001</Z>
    <P><![CDATA[999991]]></P>
 </C>
</AB>
Keeping the tag name shot reduces the overall xml file size. Also have bandwidth advantage if transfered across the network.
Create an xml file with normal tag names with 10000 Contact nodes. Create another xml file with short tag names with 10000 C nodes.
Output:
The size of the xml file with normal tag name is approximately 2.08 MB.
The size of the xml file with short tag name is approximately 1.57 MB.
Below is an example of xml file with short attribute name.
<AB>
  <C N="Person1" Z="50001">
    <A1><![CDATA[Number101]]></A1>
    <A2><![CDATA[Address501]]></A2>
    <P><![CDATA[999991]]></P>
 </C>
</AB>

Rule: Consider short names for xml tags (element name or node name) and attributes.

Return variable

Initialize the failure status value to return variable. So that even if the success value is not set to the return value, the call would always fail and the developer can debug and fix the issue during unit testing or development.

C# example- In the below example blnStatus is initialized to false.
//should not allow empty string or null string
public bool SetName(string strName)
{
    bool blnStatus = false;
    if (strName != string.Empty && strName != null)
    {
        Name = strName;
        blnStatus = true;
    }
    return blnStatus;
}

Rule: Initialize the return variable to failure status value.

Rule: Make sure return variable is set to success status value at the right place.

Single return

Avoid multiple return statements.
C# example- Code with multiple return statement.
//should not allow empty string or null string
public bool SetName(string strName)
{

    if (strName != string.Empty && strName != null)
    {
        m_strName = strName;
        return true;
    }
    return false;

}

C# example- Code with single return statement.
//should not allow empty string or null string
public bool SetName(string strName)
{
    bool blnStatus = false;
    if (strName != string.Empty && strName != null)
    {
        m_strName = strName;
        blnStatus = true;
    }
    return blnStatus;
}

Rule: Have single return statement.

Thread safety

If you are developing a multi threaded application. Make sure you code is thread safe. For better performance try to protect only the resource being accessed for reading or writing across threads and some lines of code.

C#- Make sure the mutex, monito or semaphore, if used, are released properly.

Note: A semaphore with a capacity of one is similar to mutex or lock. Semaphore is thread-agnostic because it has no owner. Any thread can call release a semaphore, but with lock and mutex, only the thread that acquired the resource can release it.


C# example- Below Logger class covers using lock and monitor, releasing monitor and protecting only the resource being shared across threads.
class Logger
{
    public string FilePath { get; set; }
    private StreamWriter m_objStreamWriter = null;
    private object m_objLocker;
    public Logger()
    {
        m_objLocker=new object();
        FilePath = @"d:\log.txt";
    }
    public bool Open()
    {
        bool blnStatus = false;
        try
        {
            m_objStreamWriter = new StreamWriter(FilePath, true);
            blnStatus = true;
        }
        catch (Exception objEx)
        {
            Console.WriteLine(objEx.StackTrace);
        }
        finally
        {
        }
        return blnStatus;
    }
    public bool Close()
    {
        bool blnStatus = false;
        try
        {
            if (m_objStreamWriter != null)
            {
                m_objStreamWriter.Close();
                blnStatus = true;
            }
        }
        catch (Exception objEx)
        {
            Console.WriteLine(objEx.StackTrace);
        }
        finally
        {
        }
        return blnStatus;
    }
    //make sure Open is called before calling WriteToFile
    //make sure Close is called once all logging is done
    public bool WriteToFile(string strMessage)
    {
        bool blnStatus = false;
        if (strMessage != string.Empty && strMessage != null)
        {
            try
            {
                lock (m_objLocker)
                {
                    if (m_objStreamWriter != null)
                    {
                        //logs only the time and not the date
                        m_objStreamWriter.WriteLine(
                            DateTime.Now.TimeOfDay
                            + " - "
                            + strMessage
                            );
                        blnStatus = true;
                    }

                }
            }
            catch (Exception objEx)
            {
                //use messagebox if winforms application
                Console.WriteLine(objEx.StackTrace);
            }
            finally
            {
            }
        }
        return blnStatus;
    }
    //make sure the StreamWriter is closed
    //make sure thr Monitor is exit
    public bool WriteToFile_Local(string strMessage)
    {
        bool blnStatus = false;
        StreamWriter objStreamWriter = null;
        if (strMessage != string.Empty && strMessage != null)
        {
            try
            {
                Monitor.Enter(m_objLocker);
                objStreamWriter = new StreamWriter(FilePath,
                    true);
                //logs only the time and not the date
                objStreamWriter.WriteLine(
                    DateTime.Now.TimeOfDay + " - " + strMessage
                    );
                objStreamWriter.Close();
                Monitor.Exit(m_objLocker);
                blnStatus = true;
            }
            catch (Exception objEx)
            {
                //use messagebox if winforms application
                Console.WriteLine(objEx.StackTrace);
                if (objStreamWriter != null)
                {
                   objStreamWriter.Close();
                }
                Monitor.Exit(m_objLocker);
            }
            finally
            {
            }
        }
        return blnStatus;
    }
    //exception has to be handled by the caller
    //can not be unit tested using UnitTestingTool class
    public void WriteToFile_Local_Using(string strMessage)
    {
        StreamWriter objStreamWriter = null;
        if (strMessage != string.Empty && strMessage != null)
        {
            //private member variable
            lock (m_objLocker)
            {
                using (objStreamWriter =
                    new StreamWriter(FilePath, true))
                {
                    //logs only the time and not the date
                    objStreamWriter.WriteLine(
                        DateTime.Now.TimeOfDay + " - " +
                        strMessage
                        );
                }
            }
        }
    }
}

Rule: Write thread safe code if your application is multi threaded.

Rule: Protecting only the resource being shared across threads or processes.

Rule: Releasing the mutex, monitor or semaphore if used.