Tuesday 24 April 2012

Offshore to Onshore software development experience:

More than half of my professional career so far as a software developer involved implementing bespoke systems for various industries.  I spent my early days in offshore software development house writing small to fairly medium size windows based applications mainly for customers based in US.  Some of the smaller contracts were delivered within a week engaging a single developer whereas larger ones took us many months (8-15) with 4-5 developers working in a team practicing SCRUM principles. It was a fun. Real fun! Looking back it feels so good. I am grateful to my back then employer (HimalayanTechies).  I was given “licence to learn” freedom to play with state of art technologies. They were very supportive throughout my time with them. The best part was you are the one to decide which development tools and platforms to choose for you next project.
Moving on from Offshore to Onshore software development experience, it has been quite nice to be honest. I am not quite sure whether the term “onshore development” is the correct one to refer to someone developing software for customers with whom they are within easily commutable distance -more importantly in the same time zone. New culture, new lifestyle and far away from your friends you have grown-up with. So on and so forth. Everything is new. Once you get used to with the new environment you start to feel comfortable. Better news is that you are not new to your s/w development methodologies, principles and the best practices. It’s the same. It might have been slightly amended to fit each organisation’s working practices and interpretations. That’s alright. It shouldn’t scare anyone.  Leaving the financial side to smart people, working Onshore is quite exciting for a developer.  Working in the same time zone, understanding the culture and current market trends obviously helps you as developer to perceive of customer’s requirements quickly. It is easier to make decisions like choosing UI layout, colour themes and work flow of the business process. In addition, you get the chance to use out of the shelf third party stable commercial components to make your development experience nice and easy (RAD) allowing you to focus on business requirements thus you are in a better position to delivery product in time and within budget and hopefully less buggy systems :) assuming you came from an Offshore development team where affordability of purchasing commercial product is remote. 

Monday 23 April 2012

EF4.x: A dependent property in a ReferentialConstraint is mapped to a store-generated column

Next time, if I see this error again "A dependent property in a ReferentialConstraint is mapped to a store-generated column..." I will look into my Foreign Key constraint in SQL table design rather than looking for a solution within the codebase itself!

If foreign key relationship is pointing to wrong column of the table, you might lose your precise development time and mood.

E.g.
Employee (EmpID [PK], FName, Surname) 
Qualification(QualID [PK], EmpID [FY], QName, GraduationYear)

Careless mistake like - Instead of EmpID of Qualification table, you make QualID having FK relationship with EmpID of Employee table. BOOM!!!

No error during Entity Diagram generation but when you try to insert record into Qualification table with EmpID value that does not exist in Employee table, you will be presented with the above runtime error.


Cheers,
Milan Gurung



Wednesday 18 April 2012

SQL Federation - is it good for existing systems migration to Windows Azure platform?


I have been looking into SQL Federation since the first release. Database sharding is out of the box. You can split your database to multiple smaller databases when it grows. Federated databases maintain throughput thus your application can serve data without degradation.

Million dollar question: Is SQL Federation good for existing systems?

I am in the same boat as most of the other colleagues. I love SQL Federation. Without thinking twice I will embrace it for Greenfield projects in future.

Reasons -

SQL Federation requires radical change in existing database schema structure. It doesn't support IDENTITY column. Developers have to generate their own. Every table structure must have Clustered Index or else data insertion fails :(  Our product line has more than 50 tables. Change in those tables means changes in data access layer. In addition, there is no support for MERGE command yet.

What solution do we have now? 

Rather than using SQL Federation, existing systems will use just SQL Azure database. Perhaps each database for each customer just for the sake of argument.Although this architecture suffers from 'Connection Pool Fragemention', migration to Windows Azure platform would be easier with less modifications to existing codebase and database re-architecture.

'Connection Pool Fragmentation' issue is explained clearly by Cihan in his blog here


Cheers,
Milan Gurung

Windows Azure must have free tools for every developer

Two most important free Windows Azure tools all Azure developers must have:

1. SQL Azure Migration Wizard by George Huey: 

Provides all data migration features to transfer your database along with data to SQL Azure and down to local SQL Server. In addition, it has the coolest feature to analyse your database before moving to SQL Azure. It reports failure well ahead if you have used CLR and Full Text Search features in your local database. These are not yet supported by current version of SQL Azure.

It can be download from Codeplex.com 

2. Azure Storage Explorer:

Very nice another small application that allows developers to interrogate Blog storage. I have always used it to see whether the data have been uploaded to Blob container or not. Whether any message has been written to the Queue or not. It's always handy. It gives you a extra security to make you feel whether your code is working as it should be :)

It can be downloaded from Codeplex.com

Cheers,
Milan Gurung

Drawing Windows Controls During Runtime Based on XML Feed


Published in CodeProject.com on 01/Aug/2011


Introduction

We design Windows native application by dragging and dropping components on the form directly using an IDE like Visual Studio. Nothing new – every Windows developer is familiar. It enables rapid application development and gives us more time to concentrate on implementing business rules efficiently that drives the whole system. All is good and fine so far. In other times, we might have to add these very widgets during runtime. One of the reasons might be that we want our system as flexible as possible. Drawing these components during runtime is fun and equally challenging. This article focuses on designing a simple GUI where the form components are added dynamically rather than during design time.

XML Feed

For this application, we will use XML document to describe its content and content–type. This allows us to launch different applications from a single form. One of the examples can be installation application that you might want to create in future. XPath is used to traverse through it. XML document looks like this:


<?xml version="1.0"?>
<MenuItem BasePath="c:\SampleApplication">
  <SideMenuItem Title="Documents">
    <Item ID="Document"
          LinkText="PDF Document"
          DetailText="View my pdf document"
          LinkType="pdf"
          Icon="\Icons\pdf.ico"
          ResourceLocation="\Resources\sampleDoc.pdf"
          />
   </SideMenuItem>
  <SideMenuItem Title="Softwares">
    <Item ID="CoolApp"
          LinkText="Next Cool Application"
          DetailText="Launch Cool Application"
          LinkType="exe"
          Icon="\Icons\exe.ico"
          ResourceLocation="="\Resources\CoolApp.exe"
          />
    <Item ID="KillerApp"
          LinkText="Next Killer application"
          DetailText="Launch Killer Application"
          LinkType="exe"
          Icon="\Icons\exe.ico"
          ResourceLocation="\Resources\KillerApp.exe "
          />
   </SideMenuItem>
  <SideMenuItem Title="Support">
    <Item ID="SupportSite"
          LinkText="Support Site"
          DetailText="Visit Support Site"
          LinkType="url"
           Icon="\Icons\ie.ico"
          ResourceLocation="\Resources\support.htm"
          />
  </SideMenuItem>
</MenuItem>
The above XML document describes two categories – Document and Software. Within each category, it has two items each. Category or “MainLink” tag makes side menu item and “Item” tag describes content and content link for our Windows Form. XPath traverses each node and retrieves necessary values.

Parsing XML Document

XmlDocument class is used to load XML feed.


XmlDocument  xDoc = new XmlDocument();
Once loaded in xDoc object, the following XPath expression retrieves all “MainLink” items.

Get all “<MainLink>”:


XmlNodeList nodeSideMenuItems = doc.SelectNodes("MenuItem/SideMenuItem");
Then it carries on traversing items within.


XmlNodeList nodes = sNode.SelectNodes("Item");
SideMenuItem is the class representing XML document. During XML parsing, all relevant node values are stored in List<SideMenuItem>. Class definition is shown below:


public class SideMenuItem
    {
        public string TagName { get; set; }
        public List<ContentMenuItem> MenuItemList { get; set; }
    }

public class ContentMenuItem
    {
        public string TagName { get; set; }
        public string LinkText { get; set; }
        public string DetailText { get; set; }
        public string LinkType { get; set; }
        public string IconLocation { get; set; }
        public string ResourceLocation { get; set; }
    }

Controls at Runtime

We have done our homework by parsing Feed.xml document and populated List<SideMenuItem> lists. The fun part begins now. We will add the controls both to side and content panel and register required events. Main methods responsible are briefly explained.

Code snippet for GenerateSidePanelControls() – Adds “Label” control to side panel of type “Panel” class and registers Click, Mouse Enter and Mouse Leave events.

int topPosition = 15;
       foreach (SideMenuItem sItem in _sideMenuItemList)
        {
          Label objLabel = new Label();
          objLabel.Name = sItem.TagName;
          objLabel.Text = sItem.TagName;
          objLabel.Left = 15;
          objLabel.Top = topPosition;
          objLabel.Font = _normalFont;
          sidePanel.Controls.Add(objLabel);
          topPosition += 25;

          objLabel.Click += new System.EventHandler(SideLabel_Click);
                 objLabel.MouseEnter +=
new System.EventHandler(SideLabel_MouseEnter);
          objLabel.MouseLeave += new System.EventHandler(SideLabel_MouseLeave);
         }
Code snippet for SideLabel_Click() – Adds main content controls when use clicks on the side menu items.

Label objLabel = (Label)sender;
       objLabel.Font = _boldFont;
       //Make rest of the Side Label have normal font
       foreach (Control ctrl in sidePanel.Controls)
        {
               if (ctrl is Label)
               {
                    if (ctrl.Name != objLabel.Name)
                     {
                       ctrl.Font = _normalFont;
                     }
                  }
               }
               GenerateContentPanelControls(objLabel.Name);
Code snippet for GenerateContentPanelControls(string sTagName) – Adds main content controls when user clicks on side menu item based side menu item title or tag name.

//Get the side menu item based on tagName
                SideMenuItem sMenuItem = null;
                foreach (SideMenuItem sItem in _sideMenuItemList)
                {
                    if (sItem.TagName == sTagName)
                    {
                        sMenuItem = sItem;
                        break;
                    }
                }
                contentPanel.Controls.Clear();

                Label spacer = new Label();
                spacer.Height = 10;
                spacer.Width = 562;
                contentPanel.Controls.Add(spacer);

                foreach (ContentMenuItem cItem in sMenuItem.MenuItemList)
                {
                    FlowLayoutPanel flowLayoutPanel = new FlowLayoutPanel();
                    flowLayoutPanel.Width = 550;
                    flowLayoutPanel.AutoSize = true;

                    // <IconLocation> tag control
                    string iconLocation = cItem.IconLocation;
                    PictureBox icon = new PictureBox();
                    icon.Size = new Size(50, 50);
                    icon.Image = new Bitmap(iconLocation);
                    icon.SizeMode = PictureBoxSizeMode.CenterImage;
                    flowLayoutPanel.Controls.Add(icon);

                    // innerFlowPanel
                    FlowLayoutPanel innerFlowPanel = new FlowLayoutPanel();
                    innerFlowPanel.Width = 500;

                    // <LinkText> tag control
                    string linkText = cItem.LinkText;
                    Label lblLinkText = new Label();
                    lblLinkText.Name = cItem.TagName;
                    lblLinkText.Text = linkText;
                    lblLinkText.Font = _normalFont;
                    lblLinkText.ForeColor = Color.Blue;
                    lblLinkText.AutoSize = true;
                    innerFlowPanel.Controls.Add(lblLinkText);

                    // linebreak
                    Label lineBreak = new Label();
                    lineBreak.Height = 0;
                    lineBreak.Width = 562 - (lblLinkText.Width + icon.Width);
                    innerFlowPanel.Controls.Add(lineBreak);

                    // <DetailText>
                    string detailText = cItem.DetailText;
                    Label lblDetailText = new Label();
                    lblDetailText.Text = detailText;
                    lblDetailText.Font = _normalFont;
                    lblDetailText.AutoSize = true;
                    innerFlowPanel.Controls.Add(lblDetailText);

                    innerFlowPanel.Height = lblLinkText.DisplayRectangle.Height +
                    lblDetailText.DisplayRectangle.Height + 5;

                    flowLayoutPanel.Controls.Add(innerFlowPanel);

                    contentPanel.Controls.Add(flowLayoutPanel);

                    //Register events
                    lblLinkText.Click +=
new System.EventHandler(ContentLabel_Click);
                    lblLinkText.MouseEnter +=
new System.EventHandler(ContentLabel_MouseEnter);
                    lblLinkText.MouseLeave +=
new System.EventHandler(ContentLabel_MouseLeave);
                }
UI Look

As per the feed.xml, the following components are drawn on the form at run-time:



Conclusion

Adding controls at runtime provides a different benefit. We don’t have to design the form again and again when the content changes. We simply inject different XML feed.

Let’s share ideas. Thank you for finding time to read.

Cheers,
Milan Gurung

Using C# Interfaces to Make Applications Resilient to Changes


Published in CodeProject.com on 24/Feb/2012

Introduction

There is a plethora of books and articles on this topic mostly on object oriented programming topics. This article is my understanding of it and just wanting to share a lovely principle and utilizing it to create a future proof system that can adapt to changes. We will be looking at how we can take advantage of interface based programming by writing a simple application in C#. The idea can be easily transferred to write data-driven applications emerging from various data stores – database, files, Web Services, etc.

Why is it important?

The benefits of using interface based programming, as I can think of while writing this small piece of article, are outlined below. Please note that there might be many others.

Enables to write loosely coupled systems. With the help of interfaces, if required in future, we can simply change the implementation thus making it easy for our application to adapt to changes.
Developers’ roles are segregated. Developers writing interface based components don’t have to worry about how it’s being implemented. They only need to know how to invoke functionalities available within it. UI developers can start working on the UI without a concrete implementation of the interface. At the same time, component developers can concentrate in implementing the agreed interface definition.  This enables parallel development as one does not have to depend on another’s work during the development process.
As long as the interface definitions are not changed, adding new features or re-implementing existing features for various reasons like changes in business rules will not break the existing system, rather makes it rich and efficient over a period of time.
Generates maintainable and clean source code – UI related code is separated from other parts of the system like data access layer and business/domain related layer.
Unit testing that every developer should embrace can be utilised. It can be performed independent of the UI or any other layer consuming functionalities of the interface based classes.

What is an interface?

Before going forward, let me make myself clear that when I use the word interface, it is not the end-user interface that has visual components, rather it is a bridge that developers use underneath their heap of classes to interact with other classes. Defining an interface allows a component of the system to communicate with another without knowing how it has been implemented. A good analogy would be a computer hardware repairer who does not have to know how a circuit board is designed in the hard disk or the mother board as long as he knows that if he replaced it by a new one with the correct specification, it would work perfectly. The same principal can be applied in software engineering. You write your own world changing algorithms and expose it to other developers via an interface to integrate into their different user interfaces. It can be an ASP.NET application or a Windows based form or even a mobile device based application. It opens a whole new world to components based programming. Like our hardware repairer, we can have software components designed and implemented.  These components can be the building blocks of our new enterprise applications.


How is this done in C#?

A. Defining the interface

Fire up your Visual Studio.

Add a “Class Library” project and name it “SearchLibrary”.
Add an interface “ISearch”. The naming convention for the interface is to prefix it with “I”.
Define a method within the interface called “GetSearchResult” with a string parameter, and a return type of List<string>.
Your interface definition should look like:

 Collapse | Copy Code
namespace SearchLibrary
{
    interface ISearch
    {
        List<string> GetSearchResult(string searchPhrase);
    }
}
Now as long as both the UI developer and the component developer agrees to this interface definition, they can start working in parallel. One concentrates on the implementation and the other starts to work on the end user interface.

B. Implementing the interface

Add a class “Search”. This class implements the “ISearch” interface.
It is a must to implement method(s) defined within the interface. In our case, we need to implement the GetSearchResult(..) method.  Look carefully in the class declaration to see how it is done - class_ name : interface_name.
The “Search” class should look like:


namespace SearchLibrary
{
    public class Search:ISearch
    {
        public List<string> GetSearchResult(string searchPhrase)
        {
            searchPhrase = searchPhrase.ToUpper();
 
            List<string> sports = new List<string> { "Football",
              "Volleyball", "Basketball", "Badminton", "Baseball",
              "Swimming", "Rugby", "American Football", "Hockey", "Cricket" };

                List<string> results = new List<string>();
                results = (from sport in sports
                        where sport.StartsWith(searchPhrase)
                        select sport).ToList();

                return results;
            }
        }
    }
The component developer starts implementing the interface. Although over a period the implementation might change for a particular method definition, it will not break the existing system as long as the earlier definition has not changed. Adding a new method/function definition will not break the system, rather makes it rich!

C. Console based application

To make the example straightforward, I will depend on a console based application as the end user interface. It can be replaced with a web based or window based form fairly easily.

Add a new console based project in the same solution.
Add references to your “SearchLibrary” project if both the projects are within the same solution. If they are not, then reference “SearchLibrary.dll” located in the bin folder.
Import the namespace “SearchLibrary”. This allows our console based application to have access to the ISearch interface and Search class.
Now the tricky bit is we declare a variable “mySearch” of type “ISearch” and assign the instance of the “Search” class. The idea being we communicate via the interface.
Your console application should like:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using SearchLibrary; //Forget not to import this namespace

namespace ConsoleSearchApp
{
    class Program
    {
        static void Main(string[] args)
        {
            Console.WriteLine("#### Interface based Programming example");

            ISearch mySearch = new Search();
            List<string> results = mySearch.GetSearchResult("F");
            Console.WriteLine("Search results: ");
            foreach (string result in results)
            {
                Console.WriteLine(result);
            }
            Console.ReadLine();
        }
    }
}
As mentioned in the introduction, the sample principle can be used to write a data access layer. I will leave the implementation to the readers who, I sure, know how to access a database in .NET using ADO.NET and LINQ to SQL. Therefore, allow me only to define the interface and the skeleton structure of the implementing class.

Let’s say we are working with a user related SQL table to perform the usual actions. We can define the user related methods within the interface IUserRepository.  The SQL scripts to create a table and insert dummy records and Stored Procedures are supplied along with the running source code.


// IUserRepository.cs

namespace DataLayer
{
    public interface IUserRepository
    {
        int GetTotalUsers();
        void AddNewUser(string fName, string lName);
        void DeleteUser(int userID);
    }
}
ADO.NET implementation

The first implementation is purely based on ADO.NET programming against SQL Server. For better performance and easier to read/maintain code, Stored Procedures are used even though they are not doing anything magical apart from normal insert/delete operations in this example, but in real-life applications, there will be a necessity to join multiple tables to get a result back to the user interface. Following such a pattern helps immensely in writing clean, easy to maintain, and high performance data-driven applications.


//UserRepository.cs implementation using ADO.NET
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Data;
using System.Data.SqlClient;

namespace DataLayer
{
    public class UserRepository: IUserRepository
    {
        //Change connection string as per your sql server
        //Store it in App.Config
        private const string strConection =
          "Data Source=localhost;Initial Catalog=test;User Id=testUser;Password=welcome;";
        #region IUserRepository Members
        /// <summary>
        /// Returns Total Number of Users using Stored Procedure "SampleDb_TotalUsers"
        /// </summary>
        /// <returns>int</returns>
        public int GetTotalUsers()
        {
            try
            {
                int totalUsers = -1;
                SqlConnection myCon = new SqlConnection(strConection);
                myCon.Open();
                SqlCommand com = new SqlCommand();
                com.Connection = myCon;
                com.CommandType = CommandType.StoredProcedure;
                com.CommandText = "SampleDb_TotalUsers";
                SqlParameter paramOut = new SqlParameter("@TotalUsers", DbType.Int32);
                paramOut.Direction = ParameterDirection.Output;
                com.Parameters.Add(paramOut);
                com.ExecuteNonQuery();
                if (com.Parameters["@TotalUsers"] != null)
                {
                    totalUsers = Convert.ToInt32(com.Parameters["@TotalUsers"].Value);
                }
                myCon.Close();
                return totalUsers;
            }
            catch (SqlException sExp)
            {
                throw new Exception(sExp.ToString());
            }
            catch (Exception exp)
            {
                throw new Exception(exp.ToString());
            }
        }
        /// <summary>
        /// Inserts new user
        /// </summary>
        /// <param name="fName">string</param>
        /// <param name="lName">string</param>
        public void AddNewUser(string fName, string lName)
        {
            try
            {
                SqlConnection myCon = new SqlConnection(strConection);
                myCon.Open();
                SqlCommand com = new SqlCommand();
                com.Connection = myCon;
                com.CommandType = CommandType.StoredProcedure;
                com.CommandText = "SampleDb_AddUser";

                SqlParameter paramFirstName =
                  new SqlParameter("@FirstName", SqlDbType.NVarChar, 50);
                paramFirstName.Value = fName;
                paramFirstName.Direction = ParameterDirection.Input;
                com.Parameters.Add(paramFirstName);

                SqlParameter paramLastName =
                  new SqlParameter("@LastName", SqlDbType.NVarChar, 50);
                paramLastName.Value = lName;
                paramLastName.Direction = ParameterDirection.Input;
                com.Parameters.Add(paramLastName);

                com.ExecuteNonQuery();
                myCon.Close();
            }
            catch (SqlException sExp)
            {
                throw new Exception(sExp.ToString());
            }
            catch (Exception exp)
            {
                throw new Exception(exp.ToString());
            }
        }
        /// <summary>
        /// Deletes user based on ID
        /// </summary>
        /// <param name="userID"></param>
        public  void DeleteUser(int userID)
        {
            try
            {
                SqlConnection myCon = new SqlConnection(strConection);
                myCon.Open();
                SqlCommand com = new SqlCommand();
                com.Connection = myCon;
                com.CommandType = CommandType.StoredProcedure;
                com.CommandText = "SampleDb_DeleteUser";

                SqlParameter paramUserID =
                  new SqlParameter("@UserID", SqlDbType.Int,32);
                paramUserID.Value = userID;
                paramUserID.Direction = ParameterDirection.Input;
                com.Parameters.Add(paramUserID);

                com.ExecuteNonQuery();
                myCon.Close();
            }
            catch (SqlException sExp)
            {
                throw new Exception(sExp.ToString());
            }
            catch (Exception exp)
            {
                throw new Exception(exp.ToString());
            }
        }
        #endregion
    }
}
Our simple console application makes use of the above data access repository as follows. Please remember to add a reference to the above class library project before importing the right namespace. The console application code should look like below:


using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using DataLayer; //Our data Access Namespace
namespace Console_App
{
    class Program
    {
        static void Main(string[] args)
        {
            try
            {
                Console.WriteLine("######## Consume DataLayer ##########");
                //Add New User
                IUserRepository userRep = new UserRepository();
                userRep.AddNewUser("Bob", "Dylon");
                //Delete User
                userRep.DeleteUser(4);
                //Total Users in the table
                int totalUsers = userRep.GetTotalUsers();
                Console.WriteLine("Total Number of Users:" + totalUsers);
                Console.ReadLine();
            }
            catch (Exception exp)
            {
                Console.WriteLine(exp.Message);
                Console.ReadLine();
            }
        }
    }
}

LINQ to SQL implementation

Later in the future, there might be a need to re-implement the same system using an ORM technology like LINQ to SQL. As we have developed our application based on “interface” definitions, we can simply plug-in a new implementation without affecting the presentation or the UI layer. All we need is to implement the IUserRepository interface using LINQ to SQL and instantiate the right class object in the UI layer.

Assume we managed to do so in the AnotherUserRepository class. It might look as follows. I will leave the real implementation job to you :)

 Collapse | Copy Code
//AnotherUserRepository.cs implementation using LINQ TO SQL
namespace DataLayerLINQToSQL
{
    public class UserRepository: IUserRepository
    {
        public int GetTotalUsers()
        {
            //LINQ TO SQL
        }
        public void AddNewUser(string username, string firstname)
        {
            //LINQ TO SQL
        }
        public void DeleteUser(int userID)
        {
            //LINQ TO SQL
        }
    }
}
The UI layer (the above console based application) code just needs to import the right namespace and instantiate the right class.

Here is the code snippet...


using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using DataLayerLINQToSQL; //Our new data Access layer namespace
namespace Console_App
{
    class Program
    {
        static void Main(string[] args)
        {
            try
            {
                Console.WriteLine("######## Consume DataLayer ##########");
                //Add New User
                IUserRepository userRep = new AnotherUserRepository();
                userRep.AddNewUser("Bob", "Dylon");
                //Delete User
                userRep.DeleteUser(4);
                //Total Users in the table
                int totalUsers = userRep.GetTotalUsers();
                Console.WriteLine("Total Number of Users:" + totalUsers);
                Console.ReadLine();
            }
            catch (Exception exp)
            {
                Console.WriteLine(exp.Message);
                Console.ReadLine();
            }
        }
    }
}
The idea of moving data access related code into repository classes is called the “Repository Pattern” which forms a very important concept in the Model-View-Controller architecture.

Conclusion

I hope we are convinced of one very simple principle – with the use of interface definitions, it is possible to write loosely coupled applications that can adapt to changes.

Enjoy programming!

Milan Gurung