Role of Software Architecture in Agile Software Development

Introduction

Recently, there was an agile meet up at Colombo. I could not attend it since I had an important client meeting scheduled on the same day. From what I heard from my friends, there was an interesting discussion on the role of software architecture in agile projects. I am writing this blog to discuss my thoughts on the same topic. I use scrum terminology in this article. However the concepts discussed in this blog are applicable for any agile development process.

Software Architecture – The Definition

The term “Software Architecture” has wide range of definitions that creates ambiguity and confusions. Therefore, let me define this term as used in the rest of this discussion,

“Software Architecture is the set of constrains that defines the structure and the characteristics of a software system”.

Software Architecture for Agile Projects

If an agile development process is used for the software development, the software system that is being developed should be necessarily agile. A software system will be agile only if it is easy to change. A software system will be easy to change only if there is order and structure. It is the software architecture that gives the order and the structure to the software system. A software system developed without architecture is like a society without law and order.

There are two things that brings in the order to the application and increases the maintainability (and hence the agility) of an application. They are

  • Software Architecture (macro level)
  • Coding standards (micro level)

Usually software architecture is defined in application level and should be agile by itself. However the coding standards that make the code more readable and therefore agile should be defined in the vender/community level or organizational level (vender/community level standards are preferred over that of organizational level since this makes the code more readable for new team members, external consultants, etc.) and should never be changed within the life cycle of the software.

If an agile team starts developing software without a defined architecture, each individual developer will develop his user stories in his own way. Continuous integration will ensure that each component integrates well and unit testing will ensure the correctness of each component. However, very soon, the system will end-up being a chaos, that nobody can easily understand and change. Chaos brings fragility rather than agility. Therefore that will be the end of agile development.

On the other hand, if an agile team consult an architect who is expected to design an architecture that can support all current and future functional and none functional requirements and dictate how the software should be developed during its whole lifetime, then the team will get a comprehensive architecture document with lots of complex diagrams. This type of architecture is called “Ivory Tower Architecture” that has the following characteristics,

  • It is not possible to validate if this architecture can satisfy none-functional requirements that it claims to satisfy, until the later stage of the development life cycle, leaving the whole project at high risk. Not being able to get early feedback from the execution platform (i.e. target hardware, OS, middleware, etc.) on whether the system would be able to satisfy the required none-functional requirements is a violation of agile principles.
  • The developers would not fully understand this architecture since it is available only in diagrams and documents, and would implement it differently, differing the whole purpose of the architecture.
  • If there are any users stories that cannot be achieved using this architecture, developers will tend to use hacks, rather than properly refactoring the architecture to support these new requirements. This will eventually resulted in a fragile system that is no longer agile.
  • It introduces lots of complexity into the system to support possible future requirements that would never be needed (YANGI – You Aren’t Goanna Need It). Any complexity that introduces flexibility in one direction introduces rigidity and fragility to the changes of any other directions. Therefore, such architecture would very soon be failed to support changes in real future requirements and make the software no longer agile.

Therefore agile software requires an agile architecture that is developed based on the values defined in agile manifesto. Therefore an agile architecture should

  • Always be defined as working software rather than a comprehensive documentation.
  • Should provide early feedback on its capabilities

That means the architecture of the software should be developed as a thin slice of the full system (trace bullet) that implements one or very few number of selected user stories.

This trace bullet should be the simplest possible implementation of these user stories that complies with the following two qualities,

  • Satisfy all none-functional requirements selected for the current sprint
  • Components introduced in each layer are decoupled enough to be easily unit testable

The first quality ensures that all none functional requirements that brings in direct value to the customer can be met by this architecture. This avoids the risk of realizing that the system cannot meet the none-functional requirements at the last few days of the sprint.

The second quality ensures that the system has the following two qualities that bring in the agility.

  • Testability
  • Maintainability

Testability is the key for agility. The application architecture should ensure that the application is testable for all its functional and none-functional requirements. Whenever possible, all tests including the test for none-functional requirements should be automated.

Designing an architecture that brings in the maintainability is quite challenging, since it requires achieving following two contradicting objectives.

  • Maintain the simplicity of the code
  • Make the components decoupled

Decoupling increase the flexibility, however introduce complexity that makes the code brittle. Therefore, agile architecture should achieve the right level of decoupling that enables each component to be unit testable using automated unit tests. This indirectly introduces the right level of decoupling that gives the flexibility for the future changes.

Agile Architecture Documentation

The software architecture should be originated as working code. However, in order to enable easy communication among team members and the stake holders, the application architecture should be documented with proper diagrams. However this should be a live document that evolves with the architectural refactorings. Simple and just enough documentation enable the easy maintenance.

Software Architecture – Redefined for Agile Projects

One of the basic principles of agile manifesto is that the best architecture and design should emerge from the self-organizing teams. Therefore the architecture of an agile project should not be defined by one person or at one time. It should be defined by a cross functional team and should be evolved into the best architecture over time.

The initial application architecture should be a complete production quality implementation of one or more carefully selected user stories as a trace bullet. This should be developed collectively by the whole team and should be able to provide the early feedback on its capabilities.

Therefore let me redefine the term “Software Architecture” in agile development as,

“Software architecture is a set of constraints self-imposed by the team to control their own development activities to ensure that it brings in a structure that is capable of achieving the current functional and none-functional requirements and maintain the agility of the application”.

Evolving Software Architecture

Since the architecture is a self-imposed set of constraints, the team can change these constraints at any time as a collective decision, if any of the user stories planned for the current sprint cannot be satisfied by the current architecture.

Generally this has to be planned during the spring planning, however can be decided even in daily standup meetings. Once the team has decided to change the architecture,

  • The team should refactor the exiting trace bullet to demonstrate the new changes.
  • One or more user stories that cause these changes should be incorporated into it.
  • This new architecture should prove itself (using acceptance test cases)
  • Application should be refactored to comply with this new architecture
  • Architecture document is updated with the changes

Identify Architecturally Significant of User Stories

In order to enable smooth architectural evolution, the architecturally significant user stories should be prioritized into early sprints. User stories should be prioritized based on the architecturally significance as follows,

  • Pick one or two user stories with the highest business priority. These users stories defines the initial structure and the deployment model of the applications
  • Pick any other user stories that have different none-functional requirements (and probably require a totally different deployment model) and prioritize them based on the possible impact on the initial architecture

In order to enable smoother architectural evolution, architectural significant user stories should be prioritized into early sprints. It is these user stories that should be used to develop the trace bullet.

Early Feedback from the Execution Platform

The criterion for prioritizing user stories for early sprints is how early we need the feedback on that. This minimizes the cost of rework that may occur due to any miss-understanding. Reducing the rework improves the team productivity.

An application requires feedback from two sources

  • From end users – on functional requirements
  • From execution platform (hardware, OS, middleware, etc.) – on none-functional requirements

Therefore, the development team should work closely with the product owner to ensure that the architecturally significant user stories are prioritized together with the user stories that are significant to the business. This will ensure that the early feedback is obtained from the end users as well as the execution platform. The team should also ensure that all the none-functional requirements are correctly captured in acceptance test cases. These test cases should be executed in an environment similar to the target production environment. The results of these acceptance test cases are considered as the feedback from the execution platform.

Dealing with Technically Challenging Requirements

A basic principle of agile development is an application cannot be designed to fully satisfy the business requirements of the users in one step. Similarly, when there are technically challenging none-functional requirements, an application architecture cannot be designed to be fully complied with all none-functional requirements in one step. Therefore, just like the business requirements, the correct architecture should evolve over multiple sprints, with close feedback from the target executing platform (hardware, OS, middleware, etc.).

When an application has complex none-functional requirements, the team should work with the product owner to prioritize the none-functional requirements over functional requirements for the initial sprints. The business requirements can be developed at a lesser cost, once the architecture is stabilized.

The architecture should evolve in the initial iterations as follows,

  • Team should initially design an architecture that can satisfy the none-functional requirements selected for the first iteration for the best of their knowledge.
  • Once the implementation of the architectural thin slice (trace bullet) is completed, acceptance test cases should be executed on that to get the feedback from execution environment.
  • If the tests are failed, then the team should analyze the system to figure out the causes of them. For example if there are performance issues, then the team should figure out what act as the performance bottlenecks (the memory, processing power, database, disk IO, network bandwidth, etc.)
  • Team should identify one of more solutions for the identified problems (e.g. introducing a caching layer).
  • The identified solutions should be added to the product backlog as new user stories

These steps lead to a gradual evolution of the architecture to its correct shape (lead the best architecture to be emerged over time).

Reducing the risk using spikes

A spike is a software component developed as a research or to get early feedback. These spikes are not part of the main application and mostly contain throw-away code. Spikes should be developed within a pre-defined time frame. If a spike could not be developed within the given time frame, that will be abandoned. Spikes should be included into the product backlog and selected to the sprint backlog as any other user story.

If an application has complex business requirements, the user stories with high business significance should be prioritized to get early feedback from actual users of the application. However if this application has one or more technically challenging requirements, then spikes should be include into the early sprints to get early feedback on the planned technical solutions. This type of a spike is called a Proof of Concept (POC). If the concept is proved by the POC, then a new user story should be added to the product backlog to incorporate that into the current architecture. The team should pay attention on developing the components that can be reused in actual implementation, if the POC is successful.

If an application has complex technical requirements, the user stories with high technical significance should be prioritized to get early feedback from the execution platform. Then the team should plan for spikes to obtain early feedback on business requirements from actual users of the application. This type of spike is called a UI prototype. The team should pay attention on developing the components that can be reused in actual implementation, once the prototype is in-line with the user expectations. For example, if this is a web application, HTML, CSS and JavaScript pages of this prototype should be developed in production quality to ensure that all these are reusable in the actual application and can be incorporated into it, once the architecture is stabilized.

Summery

  • Software architecture brings in structure to an application and therefore is a basic requirement for agility.
  • Software architecture of an agile project should be defined as working software and then documented to enable better communication.
  • Agile software architecture is a set of constraints self-imposed by the development team and can be changed at any time with the team consensus
  • Software architecture should start simple and evolve over time
  • Early feedback from the execution platform is very important for the architectural evolution
Advertisements

My Presentation at Stack Overflow meetup in Sri Lanka

https://skydrive.live.com/view.aspx?cid=4D0BEC1753B9F70B&resid=4D0BEC1753B9F70B%21336 

Real-time Web Applications with SignalR

Real-time Web Applications with SignalR

Introduction

Web applications are supposed to be more and more interactive today. Displaying the most up-to-date information is very important for modern applications. Latest news updates, scores of a cricket match, or the KPI (Key Performance Indicators) of an enterprise application are good examples for that. There are three techniques of doing this.

  • Poll the server at constant intervals
  • Long polling
  • HTML 5 Web Sockets

Polling the server at constant intervals is the most common approach that is used in most of the applications, since it is straight forward to implement. However this approach can only deliver results in near real time. The results will be more accurate if the polling interval is low. However this will increase the bandwidth utilization and the load on the server.

Both long poling and Web Sockets allows real time communication with server. Web sockets specification is not yet a finalized standard and not all browsers and web servers support it. Long poling is kind of a hack to the HTTP protocol. SignalR library developed by Microsoft as an Open Source library that supports both these approaches to enable real time communication with the server.

This makes the web applications development with real-time data to be very easy with ASP.NET.

With modern rich web client applications becoming more and more popular, the importance of JSON API is getting more and more increased. SignalR will become one of the three JSON API styles to be used in future ASP.NET. The other two will be ASP.NET Web API and direct JSON responses return from normal MVC controls. Each of these API will be used for following functions,

  • Direct unstructured JSON API calls – Normal MVC controllers with JSON response (jQuery as client)
  • Structured RESTfull API – ASP.NET Web API (use upshot.js as the client)
  • API that supports realtime by-directional communication – SingalR (SignalR.js as client)

Add SignalR to your application

Adding SignalR to your application is very straight forward with NuGet.

  • Create an ASP.NET WebForm or MVC application (I use a WebForm sample in this example due to its simplicity).
  • Open your “Package Manager Console” using “Tools->Library Package Manager” menu option in VS 2010 SP1 and type,
    • PS> install-package signalr

Create your first SignalR Hub

SignalR supports two levels or API. A high level Hub API and low level Persisted Connection API. I am only covering high level Hub API in this blog since it is sufficient for most of our normal work.
Therefore first step to do is to add Hub to your web application. To do so, you just have to add a normal class that derived from the base class “SignalR.Hubs.Hub”. My hub class looks like the one below,

namespace MyNameSpace
{
    [SignalR.Hubs.HubName("testHub")]
    public class TestHub : SignalR.Hubs.Hub
    {

    }
}

Add following script references to your Site.Master page

    <script src="../Scripts/jquery-1.6.4.js" type="text/javascript"></script>
    <script src="../Scripts/jquery.signalR.js" type="text/javascript"></script>
    <script src="../signalr/hubs" type="text/javascript"></script>

Then create an ASPX page named “test1.aspx” with the above master page and add the following JavaScript and HTML code

    <div id="responsesDiv">
    </div>
   <script type="text/javascript">
        $(document).ready(function () {
            var hub = $.connection.testHub;

            hub.showMessage = function (message) {
                $("#responsesDiv").append(message + "<br/>");
            };

            $.connection.hub.start();
        });
    </script>

This JavaScript code automatically starts the connection with the above hub (“TestHub”) when test1.aspx page is loaded. In addition to that, this code registers a client side function “showMessage” with the hub. Now when serer wants to show a message, it can call this client side “showMessage” method to push that message to the client.

Usage Patterns

Broadcasting

If you want to broadcast the same results to all clients (like the latest news items or cricket match score) you can use one of the following patterns.
Broadcast results
Create a web page named “test2.aspx” and add a button to it. Write the following code in its button click event,

        protected void Button1_Click(object sender, EventArgs e)
        {
            var clients = GetClients();
            clients.showMessage("Hello World");
        }

        private static dynamic GetClients()
        {
            return AspNetHost.DependencyResolver.Resolve<IConnectionManager>().GetClients<TestHub>();
        }

Ensure that the following namespaces are added to the page,

using SignalR;
using SignalR.Hosting.AspNet;
using SignalR.Infrastructure;

Get clients method in this sample code shows how to retrieve all the clients registered with TestHub from outside of the hub. Button1_Click method uses this method to retrieve the Clients dynamic object and calls its showMessage method to call the corresponding JavaScript showMessage method in all registered client browsers.

Now, open test1.aspx and test2.aspx pages into two tabs of the browser and click Button1 of test2.aspx. Our “Hello World” message will appear in test1.aspx page immediately. You can try this with multiple tabs of test1.aspx opened.

Broadcast Requests from the same Hub

Sometimes you might want to use SignalR to trigger the broadcast. This can be achieved as follows.

Add following method to TestHub class,

public void Broadcast(string message)
{
    this.Clients.showMessage(message);
}

Clients property of the Hub class represents all the client registered with this hub. Therefore the above methods class showMessage method with the message value in all registered client side hubs.

Now, add an HTML button control (“<input type=’button’ />”) into your “test1.aspx” page with id “broadcastButton” and add the following JavaScript code in $(document).ready method,

$("#broadcastButton").click(function () {
    hub.broadcast("Test Message to All");
});

Now open multiple tabs of “test1.aspx” page and see the response to your broadcast button clicks.

Request – Response style communication using SignalR

Even though the primary purpose of SignalR is not to create Request-Response style communication, it is possible to do with SignalR. This can be achieved as shown below,

Add following method to TestHub class,

public string SayHello()
{
    return "Hello " + Context.User.Identity.Name;
}

This code uses the Context property of the Hub class to get the current user details (Ensure that Windows Authentication is enabled before doing this).

Now, add another HTML button control into your “test1.aspx” page with id “requestResponseButton” and add the following JavaScript code in $(document).ready method,

$("#requestResponseButton").click(function () {
    hub.sayHello()
        .done(function (response) {
            alert(response);
        });
});

Now open “test1.aspx” click this button and see the response.

Update Long Running Process status with SignalR

This is a common requirement in most web applications. SignalR makes this implementation very easy. In order to see how this works, add the following code to your TestHub class,


public void LongRunningMethod()
{
    Thread.Sleep(1000);
    this.Caller.showMessage("25% Completed");
    Thread.Sleep(1000);
    this.Caller.showMessage("50% Completed");
    Thread.Sleep(1000);
    this.Caller.showMessage("75% Completed");
    Thread.Sleep(1000);
    this.Caller.showMessage("Done");
}

This method simulates a log running process that updates its progress as it proceeds. It updates its status by calling the client side “showMessage” method. The Caller property of Hub class represents the current caller of the method.

Now, add another HTML button control into your “test1.aspx” page with id “longRunningMethodButton” and add the following JavaScript code in $(document).ready method,

$("#longRunningMethodButton").click(function () {
    hub.longRunningMethod();
});

Then open test1.aspx page and see the results.

Publisher – Subscriber Pattern with SignalR

Most of the use cases of SignalR will be based on this patter. Therefore SignalR has a built-in feature called “Groups” to support this use case. We can achieve this as follows,

Add following two methods to TestHub class,

public void Subscribe(string category)
{
    this.AddToGroup(category);
}

public void Publish(string category, string message)
{
    this.Clients[category].showMessage(message);
}

Above code consider each subscription category as the client grouping criteria and add the client connection to that group. Then whenever a message is received in Publish method, it calls the showMessage client side method of all connections added to the corresponding group.

Then create a new page named “test3.aspx” with the same master page and add the following HTML and JavaScript code into it.

    <div style="padding:10px">
        <input type="button" id="subscribeToCategoryAButton" value="Subscribe To Category A" />
        <input type="button" id="subscribeToCategoryBButton" value="Subscribe To Category B" />
    </div>
    <div style="padding:10px">
        <input type="button" id="publishToCategoryAButton" value="Publish To Category A" />
        <input type="button" id="publishToCategoryBButton" value="Publish To Category B" />
    </div>

    <div id="responsesDiv">
    </div>

    <script type="text/javascript">
        $(document).ready(function () {
            var hub = $.connection.testHub;

            hub.showMessage = function (message) {
                $("#responsesDiv").append(message + "<br/>");
            };

            $.connection.hub.start();

            $("#subscribeToCategoryAButton").click(function () {
                hub.subscribe("A");
            });

            $("#subscribeToCategoryBButton").click(function () {
                hub.subscribe("B");
            });

            $("#publishToCategoryAButton").click(function () {
                hub.publish("A", "Message to A");
            });

            $("#publishToCategoryBButton").click(function () {
                hub.publish("B", "Message to B");
            });
        });
    </script>

Now, open multiple tabs of this page and click on either “Subscribe to Category A” or “Subscribe to Category B” button in each page. Then click on either “Publish to Category A” or “Publish to Category B” buttons and see the response in each page.

Sample Code

The source code of the above sample application can be downloaded from here

How to Reduce Cyclomatic Complexity of a method

How to Reduce Cyclomatic Complexity of a method

Key Steps

Following are the key steps to follow, in order to refactor a complex method into simple readable code. Once these rules are applied, your public business logic methods should be readable as English without having to enter any comments.

  • Add private methods with meaningful names to remove duplicate code
  • Add private methods with meaningful names to wrap any functionalities that are not directly related to business logic such as
    • Data access code
    • Web service calls
    • Plumbing code for design patterns, etc.
    • Add private methods with meaningful names to wrap each meaningful piece of domain logic
    • Refactor each method using following rules
      • Perform input validations first and either return an error output  or throw an exception if the validation fails
      • Then perform business data validations and either return an error output  or throw an exception if the validation fails
      • Then execute the business operation
      • Add comments that say why rather than what
      • Apply Following rules
        • Do not declare all the variables at the beginning of the method. Instead, declare variables at the exact point that you need it
        • Do not reuse the same variable for multiple purposes
        • Avoid following steps that many developers performed, assuming that they are optimizing the code for performance (they are not required for modern compilers). These actions reduces the readability but does not give any performance or any other advantage)
          • Do not try to minimize the number of method calls
          • Do not declare all the variables at the beginning of the method. Instead, declare variables at the exact point that you need it
          • Allow multiple returns from a method, if it improves the readability and cyclomatic complexity
          • Do not use following patterns  to check for equality,
            • if (10 == n)
            • if (n.Equals(10))
  • Do not use string.Concat to concatenate strings, use ‘+’ symbol instead.

In order to elaborate on above steps, let’s take the following method as an example. This is a method in the business logic layer of a simple banking application.

This method implements the following algorithm,

  • Check if the requested amount to withdraw is less than the current account balance
  • If so, perform the withdrawal
  • If not,
    • Check users credit history to see if he is eligible for an OD
    • If credit history is bad, reject the request
    • Calculate the limit of the OD amount that can be processed without manager’s approval. This calculation logic depends on the account type.
    • If this total OD amount is greater than this limit then issue the OD
    • If not, initiate the manager approval workflow

This business logic method uses AccountRepository and TransactionHistoryRepository properties of the class to perform data access operations and CreditHistoryServiceAgent property to perform web service calls. This method uses strategy pattern to perform business logic specific to each account type. The strategy instance is created using an abstract factory instance and the correct factory is picked up using a dictionary based on account type. This method also initiates a workflow if an approval is needed.

/// <summary>
/// Withdraw money from a bank account
/// </summary>
/// <param name="request">withdrawal request</param>
/// <returns>A response that indicate the results of the processing of request</returns>
/// <exception cref="ArgumentNullException">Throws when the input request object is null</exception>
/// <exception cref="ArgumentException">Throws when the requested account no is invalid</exception>
public TransactionResponse Withdraw(WithdrawRequest request)
{
    TransactionResponse response = null;

    //Check if the request is null
    if (request != null)
    {
        using (TransactionScope transactionScope = new TransactionScope())
        {
            //Get account
            Account account = AccountRepository.GetAccount(request.AccountNo);

            //Check if account is null
            if (account != null)
            {
                //Check if amount is less than the account balance
                if (request.Amount < account.Balance)
                {
                    //Reduce the amout from the balance
                    account.Balance -= request.Amount;
                    AccountRepository.Save(account);

                    //Create history entry
                    TransactionHistory history = new TransactionHistory();
                    history.TransactionType = (int)TransactionType.Withdraw;
                    history.AccountId = account.AccountId;
                    history.Time = DateTime.Now;
                    history.Amount = request.Amount;
                    TransactionHistoryRepository.Add(history);

                    //Return success response
                    response = new TransactionResponse()
                    {
                        ResponseCode = (int)TransactionResponseCodes.Succeeded,
                        ResponseMessage = Resources.TransactionCompleted,
                    };
                }
                else
                {
                    //Check if OD can be issued based for the customer
                    PersonIdentity identify = new PersonIdentity()
                    {
                        FullName = account.Owner.FullName,
                        NationalIdentityCardNo = account.Owner.NationalIdentityCardNo,
                    };
                    bool canIssueOD = CreditHistoryServiceAgent.CanIssueOD(identify);

                    if (canIssueOD)
                    {
                        //Process OD

                        //Retrieve the amount that can be withdrawn without any approval
                        IAccountStrategyFactory stratergyFactory;
                        if (!accountStratergyFactories.TryGetValue(account.Type, out stratergyFactory))
                        {
                            throw new ArgumentException("Invalid Account Type");
                        }

                        IAccountWithdrawalStrategy withdrawalStratergy = stratergyFactory.GetWithdrawalStrategy();
                        decimal withdrawalLimit = withdrawalStratergy.GetODLimitWithoutApproval(account);

                        //check if the amount is less than the withdrawal limit
                        if (account.Balance - request.Amount > withdrawalLimit)
                        {
                            //reduce the amount from account balance
                            account.Balance -= request.Amount;
                            AccountRepository.Save(account);

                            //create transaction history entry
                            TransactionHistory history = new TransactionHistory();
                            history.TransactionType = (int)TransactionType.Withdraw;
                            history.Time = DateTime.Now;
                            history.Amount = request.Amount;
                            TransactionHistoryRepository.Add(history);

                            //Return success response
                            response = new TransactionResponse()
                            {
                                ResponseCode = (int)TransactionResponseCodes.Succeeded,
                                ResponseMessage = Resources.TransactionCompleted,
                            };
                        }
                        else
                        {
                            //Initiate approval workflow
                            IWithdrawalApprovalWorkflow workflow = WorkflowFactory.GetWithdrawApprovalWorkflow();
                            workflow.Request = request;
                            workflow.Start();

                            //Return pending approval response
                            response = new TransactionResponse()
                            {
                                ResponseCode = (int)TransactionResponseCodes.PendingApproval,
                                ResponseMessage = Resources.PendingApproval,
                            };

                        }
                    }
                    else
                    {
                        //Return request failed response
                        response = new TransactionResponse()
                        {
                            ResponseCode = (int)TransactionResponseCodes.Failed,
                            ResponseMessage = Resources.FailedDueToBadCreditHistory,
                        };
                    }
                }
            }
            else
            {
                throw new ArgumentException("Invalid Account No");
            }

            //Mark the transaction to be commited
            transactionScope.Complete();
        }
    }
    else
    {
        throw new ArgumentNullException("request");
    }

    return response;
}

Refactoring’s

Use Visual Studio IDE to perform the following refactoring’s

  1. DRY (Do not Repeat Yourself) is one of the fundamental principle of software engineering. Therefore, let’s remove the duplicates first by creating a new method as follows,
private TransactionResponse PerformWithdrawal(WithdrawRequest request, TransactionResponse response, Account account)
{
    //Reduce the amout from the balance
    account.Balance -= request.Amount;
    AccountRepository.Save(account);

    //Create history entry
    TransactionHistory history = new TransactionHistory();
    history.TransactionType = (int)TransactionType.Withdraw;
    history.AccountId = account.AccountId;
    history.Time = DateTime.Now;
    history.Amount = request.Amount;
    TransactionHistoryRepository.Add(history);

    //Return success response
    response = new TransactionResponse()
    {
        ResponseCode = (int)TransactionResponseCodes.Succeeded,
        ResponseMessage = Resources.TransactionCompleted,
    };
    return response;
}
  1. Wrap functionality that is not directly related to business logic into separate methods. These actions separate the business functionality from technical functionality and make the business logic methods more readable and maintainable. Then the business logic methods gets simplified as follows,
public TransactionResponse Withdraw(WithdrawRequest request)
{
    TransactionResponse response = null;

    //Check if the request is null
    if (request != null)
    {
        using (TransactionScope transactionScope = new TransactionScope())
        {
            //Get account
            Account account = AccountRepository.GetAccount(request.AccountNo);

            //Check if account is null
            if (account != null)
            {
                //Check if amount is less than the account balance
                if (request.Amount < account.Balance)
                {
                    response = PerformWithdrawal(request, response, account);
                }
                else
                {
                    if (CanIssueODBasedOnCreditHistory(account))
                    {
                        //Process OD

                        decimal withdrawalLimit = GetODLimitWithoutApproval(account);

                        //check if the amount is less than the withdrawal limit
                        if (account.Balance - request.Amount > withdrawalLimit)
                        {
                            response = PerformWithdrawal(request, response, account);
                        }
                        else
                        {
                            response = StartWithdrawApprovalWorkflow(request, response);
                        }
                    }
                    else
                    {
                        //Return request failed response
                        response = GetFailedResponse(response);
                    }
                }
            }
            else
            {
                throw new ArgumentException("Invalid Account No");
            }

            //Mark the transaction to be commited
            transactionScope.Complete();
        }
    }
    else
    {
        throw new ArgumentNullException("request");
    }

    return response;
}

private TransactionResponse PerformWithdrawal(WithdrawRequest request, 
TransactionResponse response, Account account)
{
    //Reduce the amout from the balance
    account.Balance -= request.Amount;
    AccountRepository.Save(account);

    CreateWithdrawalHistoryEntry(request, account);

    //Return success response
    return GetSuccessResponse(ref response);
}
  1. Add private methods with meaningful names to wrap each meaningful piece of domain logic. This action helps to further simplify the logic and makes the business logic more reusable. Then this method can be broken as follows,
public TransactionResponse Withdraw(WithdrawRequest request)
{
    TransactionResponse response = null;

    //Check if the request is null
    if (request != null)
    {
        using (TransactionScope transactionScope = new TransactionScope())
        {
            //Get account
            Account account = AccountRepository.GetAccount(request.AccountNo);

            //Check if account is null
            if (account != null)
            {
                //Check if amount is less than the account balance
                if (request.Amount < account.Balance)
                {
                    response = PerformWithdrawal(request, response, account);
                }
                else
                {
                    response = ProcessAsOD(request, response, account);
                }
            }
            else
            {
                throw new ArgumentException("Invalid Account No");
            }

            //Mark the transaction to be commited
            transactionScope.Complete();
        }
    }
    else
    {
        throw new ArgumentNullException("request");
    }

    return response;
}

private TransactionResponse ProcessAsOD(WithdrawRequest request, TransactionResponse 
response, Account account)
{
    if (CanIssueODBasedOnCreditHistory(account))
    {
        //Process OD

        decimal withdrawalLimit = GetODLimitWithoutApproval(account);

        //check if the amount is less than the withdrawal limit
        if (account.Balance - request.Amount > withdrawalLimit)
        {
            response = PerformWithdrawal(request, response, account);
        }
        else
        {
            response = StartWithdrawApprovalWorkflow(request, response);
        }
    }
    else
    {
        //Return request failed response
        response = GetFailedResponse(response);
    }
    return response;
}

  1. Refactor each method using following rules
  • Perform input validations first and either return an error output  or throw an exception if the validation fails
  • Then perform business data validations and either return an error output  or throw an exception if the validation fails
  • Then execute the business operation

Then add the comments that explain why (what is now clearly visible from the code)

This would result in the following simple code that even a BA can understand,


public TransactionResponse Withdraw(WithdrawRequest request)
{
    TransactionResponse response = null;

    //Validate input parameters
    if (request != null)
    {
        throw new ArgumentNullException("request");
    }

    //Perform business logic in a transaction
    using (TransactionScope transactionScope = new TransactionScope())
    {
        //Get account
        Account account = AccountRepository.GetAccount(request.AccountNo);
        if (account != null)
        {
            throw new ArgumentException("Invalid Account No");
        }

        if (request.Amount < account.Balance)
        {
            //If the requested amount is less than the balance then 
            //the withdrawal can be performed directly
            response = PerformWithdrawal(request, response, account);
        }
        else
        {
            //Otherwise the request has to be performed as an OD
            response = ProcessAsOD(request, response, account);
        }

        //Mark the transaction to be committed
        transactionScope.Complete();
    }

    return response;
}

private TransactionResponse ProcessAsOD(WithdrawRequest request, TransactionResponse 
response, Account account)
{
    //Check if the requested customer can receive and OD based on his credit history
    //Reject the request if he has a bad credit history
    if (CanIssueODBasedOnCreditHistory(account))
    {
        return GetFailedResponse(response);
    }

    //Check if the requested amount is less than the OD limit for the account type
    //If so perform the request
    //Else initiate the approval workflow to get branch managers approval
    decimal withdrawalLimit = GetODLimitWithoutApproval(account);
    if (account.Balance - request.Amount > withdrawalLimit)
    {
        return PerformWithdrawal(request, response, account);
    }
    else
    {
        return StartWithdrawApprovalWorkflow(request, response);
    }
}

private TransactionResponse PerformWithdrawal(WithdrawRequest request, 
TransactionResponse response, Account account)
{
    //Reduce the amout from the balance
    account.Balance -= request.Amount;
    AccountRepository.Save(account);

    CreateWithdrawalHistoryEntry(request, account);

    return GetSuccessResponse(ref response);
}
  • Apply Following rules
    • Do not declare all the variables at the beginning of the method. Instead, declare variables at the exact point that you need it
    • Do not reuse the same variable for multiple purposes

Let’s take the following example,

public double FindEffortInManDays(RequirementDefinition requirements, 
                       ComplexityFactors complexity, EnvironmentFactors environment)
{
    double functionPoints = CalculateFunctionPoints(requirements);
    double adjustedFunctionPoints = CalculateAdjustedFunctionPoints(functionPoints, complexity);
    double effortInManDays = CalculateEffort(adjustedFunctionPoints, environment);
    return effortInManDays;
}

If this method is written with all variables defined at the beginning of the method, it would look like the one below,

public double FindEffortInManDays3(RequirementDefinition requirements, 
                   ComplexityFactors complexity, EnvironmentFactors environment)
{
    double functionPoints = 0.0;
    double adjustedFunctionPoints = 0.0;
    double effortInManDays = 0.0;

    functionPoints = CalculateFunctionPoints(requirements);
    adjustedFunctionPoints = CalculateAdjustedFunctionPoints(functionPoints, complexity);
    effortInManDays = CalculateEffort(adjustedFunctionPoints, environment);
    return effortInManDays;
}

Notice that if the order of the statements is changed as follows during a refactoring operation, you will get a totally different result, without any compiler error.

public double FindEffortInManDays31(RequirementDefinition requirements, 
ComplexityFactors complexity, EnvironmentFactors environment)
{
    double functionPoints = 0.0;
    double adjustedFunctionPoints = 0.0;
    double effortInManDays = 0.0;

    adjustedFunctionPoints = CalculateAdjustedFunctionPoints(functionPoints, complexity);
    functionPoints = CalculateFunctionPoints(requirements);
    effortInManDays = CalculateEffort(adjustedFunctionPoints, environment);
    return effortInManDays;
}

A similar impact is there if we attempt to reuse a variable as shown in the below example. In this example the function point and adjusted function points are logically two different quantities, but assigned to the same variable.

public double FindEffortInManDays2(RequirementDefinition requirements, 
ComplexityFactors complexity, EnvironmentFactors environment)
{
    double functionPoints = CalculateFunctionPoints(requirements);
    functionPoints = CalculateAdjustedFunctionPoints(functionPoints, complexity);
    double effortInManDays = CalculateEffort(functionPoints, environment);
    return effortInManDays;
}

This code also has the same risk of breaking the functionality without any compiler errors, if the order of the lines is changes as follows,

public double FindEffortInManDays21(RequirementDefinition requirements, 
ComplexityFactors complexity, EnvironmentFactors environment)
{
    double functionPoints = CalculateFunctionPoints(requirements);
    double effortInManDays = CalculateEffort(functionPoints, environment);
    functionPoints = CalculateAdjustedFunctionPoints(functionPoints, complexity);
    return effortInManDays;
}


Now, let’s discuss further about the following invalid optimizations that many developers try to perform,

  • Avoid following steps that many developers performed, assuming that they are optimizing the code for performance (they are not required for modern compilers). These actions reduces the readability but does not give any performance or any other advantage)
    • Do not try to minimize the number of method calls
    • Do not declare all the variables at the beginning of the method. Instead, declare variables at the exact point that you need it
    • Allow multiple returns from a method, if it improves the readability and cyclomatic complexity
    • Do not use following patterns  to check for equality,
      • if (10 == n)
      • if (n.Equals(10))
  • Do not use string.Concat to concatenate strings, use ‘+’ symbol instead.

Do not try to minimize the number of method calls

Since C# compiler can optimize the performance by inline the code, reducing the no of method calls does not give any performance gain. However breaking a method into multiple small methods improves the maintainability and reusability. However we have to ensure that methods are named property.

Do not use following patterns to check for equality,

  • if (10 == n)
  • if (n.Equals(10))

Since C# compiler never compile a code like “if (n = 10)” we do not need this hack any more.

Write the conditions as

  • if  (n == 10)

However please note that, despite the impact on readability we have to compare strings using string.Equals method as shown below,

  • if (string.Equals(string1, string2, StringComparison.Ordinal))

This is due to the fact that .Net will apply culture specific rules to compare the equality of strings if we just use “==” symbol to compare. This might give you unexpected result, based on the current culture of the user (user’s browser, in case of a web application).  Therefore we always have to be specific in string comparison method. Ordinal comparison will perform

Do not use string.Concat to concatenate strings, use ‘+’ symbol instead

a = b + c + d;

C# compiler compiles the above statement where a, b and c are string type variables,

a = string.Concat(a, b, c);

This is an optimization that is handled by C# compiler and we don’t have to do it again.

Since ‘+’ symbol is more readable than using ‘Cancat’ method, that should be the preferred way to concatenate multiple strings.

Sri Lanka .Net Forum Presentation

The PowerPoint presentation that I am planning to use in my Sri Lanka .Net Forum Presentation on ASP.NET security is available here.

Want to develop Windows 8 native applications, Learn ASP.NET MVC 4 today

There are basically 3 types of Windows 8 Applications,

  • Native C++ applications that uses XAML for UI layer (if you are familier with C++ and your application needs to be highly optimized for memory or processor utilization, this is the best choice)
  • .Net applications that uses XAML for UI layer (if you are familier with WPF or Silverlight, this is the best option)
  • JavaScript applications that users HTML 5 for UI layer (if you are familier with Web platform or need a solution that can be easily port to several different platforms, this is the best choice).

From this list, the first two options will be able to better utilize the native UI features of the platform. However JavaScript applications also can utilize all WinRT API other than the XAML based UI.

However if we write JavaScript applications that does not utilize WinRT API (new set of API introduced in Windows 8 to replace Win32 API), then we can,

  • Package them as native applications for Windows 8
  • Use open source library like PhoneGap and package in a naïve container for iPad, iPhone and Android.
  • Make them accessible over web.

This type of HTML 5 and JavaScript applications can be easily written using ASP.NET MVC 4 Single Page Application template. These applications can provide the user experiance of a Native Application, while still being a web application. These applications utilize the following technologies,

  • HTML 5 to render rich client UI
  • Knockout Java Scrip library to provide MVVM support for HTML 5 (a pattern that we normally used only with WPF and Silverlight)
  • ASP.NET WEB API (Expose server side operations as JSON based REST API to JavaScript client application)
  • UpShot JavaScript library to support server side data access and caching

In addition to that we can use Windows Live Sky Drive to store user files. Sky Drive is accessible for Windows 8 users in the same way that they access their native file system. Our web app also can easily access the same files through Sky Drive API in Windows Live SDK.

Adding Ajax Loader into an ASP.NET MVC application

Ajax is used in almost all ASP.NET MVC applications developed today. Normally jQuery library is used to make AJAX operations. It is usually very common to show an Ajax Loader image (some animated gif file centered in the page) to the user while these asynchronous Ajax operations are being performed. These loaders help users to figure out when the AJAX operation is completed.

Unfortunately jQuery does not provide built-in feature to display an AJAX loader while it is performing AJAX operations (Note: jQuery AJAX support is designed to not to be coupled with any UI approach).

We can implement this feature by adding a hidden div tag with the an animated gif image and set its display attribute when ajax operation is being performed. However this solution has the following issues,

  • GIF image will not be visible if the user scroll down, change the browser window size or use a different screen resolution.
  • Need to include this image in every page that need ajax support

However, we can easily solve these issues as shown in the below example. In this example, we delay loading some contents (start loading these contents after the page is loaded). The reason for the delay loading is to improve the perceived response time (the response time as perceived by the user). This same technique can be used for any other type of AJAX requests (such as POST requests, JSON requests, etc.) as well.

Create an animated gif file and copy it into Contents folder (an animated gif file can be created using following web site, http://ajaxload.info/  ). In my example, this file name is “ajax-loader.gif, and both its width and height are 24pxs.

Add following class to your CSS file (change image file name and its width and height accordingly). Note: The image file URL should be defined, relative to CSS file path. In this example, both the CSS file and the image file are located in the same folder.

.ajaxLoader
{
    outline-style: none;
    outline-color: invert;
    outline-width: 0px;
    width:24px;
    height:24px;
    background-image: url("ajax-loade.gif");
}

Then add the following JavaScript into your page. This code checks if a div tag with id “__AjaxLoader” is present in the page. If not, it creates a new tag with the required styles. The above class is also applied to this div. Then this div is centered in the browser widow and displayed to the user.

<script type="text/javascript">

    $(document).ready(function () {
        function showAjaxLoader() {
            //find ajax loader div tag
            var loaderDiv = $("#__AjaxLoader");
            if (loaderDiv.length === 0) {
                //create ajax loader div tag, if not present
                loaderDiv = $("&lt;div /&gt;")
                .attr("id", "__AjaxLoader")
                .css("position", "absolute")
                .css("display", "block")
                .css("z-index", "10000")
                .addClass("ajaxLoader");
                loaderDiv.appendTo("body");
            }

            //center ajax loader div tag in the browser window
            var doc = $(document);
            loaderDiv.css('top', (doc.height() - loaderDiv.height()) / 2);
            loaderDiv.css('left', (doc.width() - loaderDiv.width()) / 2);
           
            //show it
            loaderDiv.show();
        }

        function hideAjaxLoader() {
            //hide ajax loader div tag, if present
            $("#__AjaxLoader").hide();
        }

        //Initiate delay loading asynchronously
        showAjaxLoader();
        $.get('@Url.Action("LoadContents")', function (data) {
            $("#delayLoadedContents").html(data);
            hideAjaxLoader();
        });
    });

</script>