Refractoring Code: Design for the future

by sunil ravulapalli /4. September 2013 07:17 /software-design /Comments (0)
AccountInformation accountInformation = getInfo();
string allNames = accountInformation.SignerName  + " " +  accountInformation.CoSignerName  + " " +  accountInformation.CoSignerName2;

Lets say you have a class like this which you are using in multiple places in your program:

public class AccountInformation
{
	public string SignerName { get; set; }
	public string CoSignerName { get; set; }	
}

One of the instances where it is being used is as follows:

AccountInformation accountInformation = getInfo();
string allNames = accountInformation.SignerName + " " + accountInformation.CoSignerName;

One fine day you are informed of a business rule which states that AccountInformation can have second Co Signer.
How would you redesign this class?
One option would be to do this:

public class AccountInformation
{
	public string SignerName { get; set; }
	public string CoSignerName { get; set; }
	public string CoSignerName2 { get; set; }
}

Now, next thing you have to do is find all places where AccountInformation is used and add CoSignerName2 for the additional information like follows:

public class AccountInformation
{
	public string SignerName { get; set; }
	public List<string> CoSignerNames { get; set; }	
}

This seems easy. But what if you need to add another Co Signer? Will you add CoSignerName3? This can go on endlessly.
A good programmer would recognize this possibility and he/she would have made a provision for this scenario. AccountInformation could have been changed as follows:

public class AccountInformation
{
	public string SignerName { get; set; }
	public List<string> CoSignerNames { get; set; }	
}

All the usages of AccountInformation would have to be changed to something like this:

AccountInformation accountInformation = getInfo();
string allNames = accountInformation.SignerName + getAllCoSignerNames(accountInformation.CoSignerNames);

where

public string getAllCoSignerNames(List<string> coSignerNames)
{
	string allCoSignerNames = String.Empty;
	foreach(string coSignerName in coSignerNames)
	{
		allCoSignerNames += coSignerName + " "
	}
	return allCoSignerNames;
}

Yes, this definitely more work than just adding CoSignerName2. But we have to realize that this is future proof! No matter how many Co Signers are allowable in future, you don't have to touch a line of code. You are done! This saves both the programmer and the business so much time, just because you though ahead and designed your system.

 

 

Step 6: Solution with Front End

by sunil ravulapalli /30. July 2013 00:35 /software-design /Comments (0)

Add Ninject binding to DataNinjectModule in the Data project.

public class DataNinjectModule : NinjectModule
{ 
  public override void Load() 
  {  
     Kernel.Bind<IUnitOfWork>().To<UnitOfWork>(); 
  }
}

Add Ninject binding to ServiceNinjectModule in the Data project.

public class ServiceNinjectModule : NinjectModule
{ 
  public override void Load() 
  {  
    Kernel.Bind<IWishlistService>().To<WishlistService>(); 
  }
}

Add a controller class in the Web project.

public class WishlistController : Controller
{ 
  private readonly WishlistService _wishlistService; 
  public WishlistController(WishlistService wishlistService) 
  {  
    _wishlistService = wishlistService; 
  } 
  public ActionResult Add() 
  {  
    return View(); 
  } 
  [HttpPost] 
  public ActionResult Add(WishListItemViewModel wishListItemViewModel) 
  {  
    _wishlistService.AddWishlistItem(wishListItemViewModel.Description, wishListItemViewModel.Quantity);  
    return RedirectToAction("All"); 
  } 
  public ActionResult All() 
  {  
    return View(_wishlistService.GetAllWishlistItems()); 
  }
}


Add a view model class.
Add corresponding views.
Modify routes
Add a connection string in Web.config.

<add name="CompanyDbContext" providerName="System.Data.SqlClient" connectionString="Data Source=MYMACHINE\SQLEXPRESS;Initial Catalog=Wishlist.Data.CompanyDbContext;Integrated Security=True;Connect Timeout=15;Encrypt=False;TrustServerCertificate=False" />

You can find the solution on GitHub.
https://github.com/sunilrav/Wishlist.6.SolutionWithFrontEnd


 

Step 5: Solution with a Service class

by sunil ravulapalli /12. July 2013 22:49 /software-design /Comments (0)

Add the Core, the Data project references to the Service project

Add interface IWishlistService to the Core project

public interface IWishlistService
{ 
   void AddWishlistItem(string description, int quantity); 
   IList<WishListItem> GetAllWishlistItems();
}

Add class WishlistService to to the Service project

public class WishlistService : IWishlistService
{ 
  readonly IUnitOfWork _unitOfWork; 
  public WishlistService(IUnitOfWork unitOfWork) 
  {  
     _unitOfWork = unitOfWork; 
  } 
  public void AddWishlistItem(string description, int quantity) 
  {  
      var wishListItem = new WishListItem  
      {   
            Description = description,   Quantity = quantity  
      };  
      using (_unitOfWork)  
      {   
         _unitOfWork.WishListItemRepository.Insert(wishListItem);   
         _unitOfWork.Save();  
      } 
  } 
  public IList<WishListItem> GetAllWishlistItems() 
  {  
     using (_unitOfWork)  
     {   
       return (List<WishListItem>)_unitOfWork.WishListItemRepository.GetAll();  
     }
  }
}

You can find the solution on GitHub.

https://github.com/sunilrav/Wishlist.5.SolutionWithService

Step 4: Solution with Unit of Work pattern

by sunil ravulapalli /5. July 2013 23:18 /software-design /Comments (0)

Add IGenericRepository the Core project

public interface IGenericRepository<T> where T : class
{ 
   void Insert(T entity); IEnumerable<T> GetAll();
}

Add IUnitOfWork to the Core project

public interface IUnitOfWork : IDisposable
{ 
   IGenericRepository<WishListItem> WishListItemRepository { get; } 
   void Save();
}

Add GenericRepository to the Data project

public class GenericRepository<T> : IGenericRepository<T> where T : class 
{ 
  readonly CompanyDbContext _context; 
  readonly DbSet<T> _dbSet; 
  public GenericRepository(CompanyDbContext context) 
  {  
     _context = context;  
     _dbSet = context.Set<T>(); 
  } 
  public void Insert(T entity) 
  { 
      _dbSet.Add(entity); 
  } 
  public IEnumerable<T> GetAll() 
  {  
     return _dbSet.AsEnumerable(); 
  }
}

Add UnitOfWork to the Data project

public class UnitOfWork : IUnitOfWork
{ 
   readonly CompanyDbContext _context; 
   public UnitOfWork() 
   {  
     _context = new CompanyDbContext(); 
   } 
   private bool _disposed; 
   protected virtual void Dispose(bool disposing) 
   {  
       if (!_disposed)  
      {   
          if (disposing)   
          {    
              _context.Dispose();   
          }  
      }  
      _disposed = true; 
    } 
    public void Dispose() 
    {  
      Dispose(true);  
      GC.SuppressFinalize(this); 
     }       
     public void Save() 
     {  
        _context.SaveChanges(); 
      } 
      public IGenericRepository<WishListItem> WishListItemRepository 
      {  
          get { return new GenericRepository<WishListItem>(_context); } 
      }
}

You can find the solution on GitHub.

https://github.com/sunilrav/Wishlist.4.SolutionWithUnitOfWork.git

Step 3: Solution with Entity Framework

by sunil ravulapalli /24. June 2013 22:08 /software-design /Comments (0)

Create wishlist item class in the Core project.

public class WishListItem
{ 
   public int Id { get; set; } 
   public string Description { get; set; } 
   public int Quantity { get; set; }
}

Add Entity framework using nuget to Data project.
Add reference to Core project in the Data project.
Create a context class in the Data project.

public class CompanyDbContext : DbContext
{ 
   public DbSet<WishListItem> WishListItems { get; set; }
}

Using the nuget console run "enable-migratons" for the Data project.
Also, using the nuget console run "update-database" for the Data project.

This will create the database in SQL express or LocalDb if the machine does not have SQL express. 


You can find the solution on GitHub.

https://github.com/sunilrav/Wishlist.3.SolutionWithEntityFramework.git
 

 

Step 2: Basic solution structure of an ASP.NET MVC in Visual Studio with Ninject

by sunil ravulapalli /15. June 2013 00:16 /software-design /Comments (0)

Add Ninject using Nuget to the Data and Service projects.

Add Ninject.Mvc3 using Nuget to the Web project.

In Data project add a class called DataNinjectModule which looks like this

using System;
using Ninject.Modules;
namespace Wishlist.Data.DependencyConfiguration
{    
    public class DataNinjectModule : NinjectModule    
    {        
       public override void Load()        
       {            
           throw new NotImplementedException();
        }
    }
}

In Service project add a class ServiceNinjectModule which looks like this

using System;
using Ninject.Modules;
namespace Wishlist.Service
{    
     public class ServiceNinjectModule : NinjectModule    
     {        
          public override void Load()        
          {            
                  throw new NotImplementedException();
          }    
     }
}

In Web project add these lines of code to the RegisterServices class in the NinjectWebCommon class found in the App_Start folder.(Substitute "Wishlist" with your project name)

kernel.Load("Wishlist.Data.dll");
kernel.Load("Wishlist.Service.dll");

You can find the solution on GitHub.

https://github.com/sunilrav/Wishlist.2.BasicSolutionWithNinject

Step 1: Basic solution structure of an ASP.NET MVC in Visual Studio

by sunil ravulapalli /8. June 2013 01:10 /software-design /Comments (0)

This is a basic solution structure of how to set up a web application like ASP.NET MVC in Visual Studio. 

Core, Data, Service are Class Library projects.

Web is a MVC 4 project.

Service.Test and Web.Tests are Unit Test projects.

 You can find the solution on GitHub.

https://github.com/sunilrav/Wishlist.1.BasicSolutionStructure

 

Code design:Advanced use of interfaces

by sunil ravulapalli /9. August 2010 17:37 /software-design /Comments (0)

Suppose, I have a class like this

public class EmployeeRepository
{
  public DataSet GetAll()
  {
    string connectionString = @"Data Source=.\SQLEXPRESS;AttachDbFilename=***.mdf;
    Integrated Security=True;User Instance=True";
    DataSet employee = new DataSet();
    using (SqlConnection connection = new SqlConnection(connectionString))
    {
      string queryString = "SELECT EmpId, EmpName FROM Employee";
      SqlDataAdapter adapter = new SqlDataAdapter(queryString, connection);
      adapter.Fill(employee, "Employees");
      return employee;
    }
  }
}

Lets assume, I use it like this "several times" all over my implementaion code:

EmployeeRepository repository = new EmployeeRepository();
DataSet dataset = repository.GetAll();

Now, lets say we have a new class called UppercaseEmployeeRespository which looks like this. It is only slightly different from "EmployeeRepository".(notice i changed the query string):

public class UppercaseEmployeeRespository
{
  public DataSet GetAll()
  {
    string connectionString = @"Data Source=.\SQLEXPRESS;AttachDbFilename=***.mdf;
    Integrated Security=True;User Instance=True";
    DataSet employee = new DataSet();
    using (SqlConnection connection = new SqlConnection(connectionString))
    {
      string queryString = "SELECT EmpId, UPPER(EmpName) FROM Employee";
      SqlDataAdapter adapter = new SqlDataAdapter(queryString, connection);

      adapter.Fill(employee, "Employees");
      return employee;
    }
  }
}

Now, I need to globally replace the use of "EmployeeRespository" with "UppercaseEmployeeRespository"? How do I do that? Simple, globally Find & Replace, "EmployeeRespository" with "UppercaseEmployeeRespository"? :) Well, in a badly designed solution, thats all you can do. But lets say we have chance to Re-Arch our solution, how can we restructure this code?Stage 1: Extract the interface and make the class implement the interface.

public interface IRepository
{
  DataSet GetAll();
}
public class EmployeeRepository : IRepository
{
  public DataSet GetAll()
  {
     string connectionString = @"Data Source=.\SQLEXPRESS;AttachDbFilename=***.mdf;
     Integrated Security=True;User Instance=True";
     DataSet employee = new DataSet();
     using (SqlConnection connection = new SqlConnection(connectionString))
     {
       string queryString = "SELECT EmpId, EmpName FROM Employee";
       SqlDataAdapter adapter = new SqlDataAdapter(queryString, connection);

       adapter.Fill(employee, "Employees");
       return employee;
     }
  }
}

Now, the implementaion code changes to

IRepository repository = new EmployeeRepository();
DataSet dataset = repository.GetAll();

Whoever gives you a new class, has to implement IRepository, the new class now looks like this:

public class UppercaseEmployeeRespository : IRepository
{
  public DataSet GetAll()
  {
    string connectionString = @"Data Source=.\SQLEXPRESS;AttachDbFilename=***.mdf;
    Integrated Security=True;User Instance=True";
    DataSet employee = new DataSet();
    using (SqlConnection connection = new SqlConnection(connectionString))
    {
      string queryString = "SELECT EmpId, UPPER(EmpName) FROM Employee";
      SqlDataAdapter adapter = new SqlDataAdapter(queryString, connection);

      adapter.Fill(employee, "Employees");
      return employee;
    }
  }
}

Now, if you want to swap, you still have to globally Find & Replace "EmployeeRepository" with "UppercaseEmployeeRespository".

IRepository repository = new UppercaseEmployeeRespository();
DataSet dataset = repository.GetAll();

But, thats no good. What else can we do? Lets change our implementation code a little bit.Stage 2: Restructure the implementaion codeLets replace "new EmployeeRepository()" with a method call "RepositoryInstance.GetInstance()"where "GetInstance()" is a static method.

IRepository repository = new EmployeeRepository();
DataSet dataset = repository.GetAll();

becomes

IRepository repository = RepositoryInstance.GetInstance();
DataSet dataset = repository.GetAll();

where the class "RepositoryInstance" looks like this:

public static class RepositoryInstance
{
  public static IRepository GetInstance()
  {
    return new EmployeeRepository();
  }
}

The static function GetInstance() currently returns an instance of EmployeeRepository. This looks great! Now, if I want to swap out all "EmployeeRepository" with "UppercaseEmployeeRespository" all I have to replace is one line of code in "GetInstance()". Replace "return new EmployeeRepository()" with "return new UppercaseEmployeeRespository()"; Thats it!!Final, code recap:

public interface IRepository
{
  DataSet GetAll();
}

public class EmployeeRepository : IRepository
{
  public DataSet GetAll()
  {
    string connectionString = @"Data Source=.\SQLEXPRESS;AttachDbFilename=***.mdf;
    Integrated Security=True;User Instance=True";
    DataSet employee = new DataSet();
    using (SqlConnection connection = new SqlConnection(connectionString))
    {
      string queryString = "SELECT EmpId, EmpName FROM Employee";
      SqlDataAdapter adapter = new SqlDataAdapter(queryString, connection);
      adapter.Fill(employee, "Employees");
      return employee;
    }
  }
}


public class UppercaseEmployeeRespository : IRepository
{
  public DataSet GetAll()
  {
    string connectionString = @"Data Source=.\SQLEXPRESS;AttachDbFilename=***.mdf;
    Integrated Security=True;User Instance=True";
    DataSet employee = new DataSet();
    using (SqlConnection connection = new SqlConnection(connectionString))
    {
      string queryString = "SELECT EmpId, UPPER(EmpName) FROM Employee";
      SqlDataAdapter adapter = new SqlDataAdapter(queryString, connection);

      adapter.Fill(employee, "Employees");
      return employee;
    }
  }
}

IRepository repository = RepositoryInstance.GetInstance();
DataSet dataset = repository.GetAll();

public static class RepositoryInstance
{
  public static IRepository GetInstance()
  {
    return new UppercaseEmployeeRespository();
  }
}

Code design:Static methods

by sunil ravulapalli /9. August 2010 16:24 /software-design /Comments (0)

Static methods are methods which belong to a class and not an instance of a class.

Normally, if you have a class like this:

public class Utility
{
 public string GetConnectionString()
 {
  return @"Data Source=.\SQLEXPRESS;AttachDbFilename=|***.mdf;Integrated Security=True;User Instance=True";
 }
}

you will use it like this:

Utility u = new Utility();
string conString = u.GetConnectionString();


But, lets say you want to use this all over your code and don't want to create an instance each time, you can redesign it like this:

public class Utility
{
 public static string GetConnectionString()
 {
  return @"Data Source=.\SQLEXPRESS;AttachDbFilename=***.mdf;Integrated Security=True;User Instance=True";
 }
}

you can just use it like this everywhere:

string conString = Utility.GetConnectionString();


Look, no instance!

Code design:Simple use of interfaces

by sunil ravulapalli /6. July 2010 20:00 /software-design /Comments (0)

In short, the answer is 'flexibility'. I am not going to go into any complex detailed examples in this post. This post will just set up a base for future posts on interfaces. Lets begin with 2 classes as show below.

public class EmployeeRepository
{
  public DataSet GetAll()
  {
     string connectionString = "*********"
     DataSet employee = new DataSet();   
     using (SqlConnection connection = new SqlConnection(connectionString))
     {
        string queryString = "SELECT EmpId, EmpName FROM Employee";
        SqlDataAdapter adapter = new SqlDataAdapter(queryString, connection);

        adapter.Fill(employee, "Employees");
        return employee;
     }
  }
}

public class CustomersRepository
{
  public DataSet GetAll()
  {
     string connectionString = "*********"
     DataSet customers = new DataSet();
     using (SqlConnection connection = new SqlConnection(connectionString))
     {
        string queryString = "SELECT CustomerId, CustomerName, FROM Customer";
        SqlDataAdapter adapter = new SqlDataAdapter(queryString, connection);

        adapter.Fill(customers, "Customers");
        return customers;
     }
  }
}

Normally, we would use these classes like this:

EmployeeRepository employeerepository = new EmployeeRepository();
DataSet dataset = repository.GetAll();

and

CustomerRepository customerrepository = new CustomerRepository();
DataSet dataset = repository.GetAll();

Now, lets redesign our classes using interfaces?How do we do that? Notice, that both our classes have the same method called "GetAll()" with the "same return type". With that observation lets make an interface. It looks like this

public interface IRepository
{
    DataSet GetAll();
}

Now, our classes can be made to look like this:

public class EmployeeRepository : IRepository
{
   public DataSet GetAll()
   {
      //Same as before
   }
}
public class CustomersRepository : IRepository
{
   public DataSet GetAll()
   {
     //Same as before
   }
}

Great, we are now using interfaces! But wait, what good is it? It just added more code to my program! The real good will come in how we can instantiate our classes and then call our methods. Look at the following implementaion code:

IRepository repository = new EmployeeRepository();
DataSet dataset = repository.GetAll();

and

IRepository repository = new CustomerRepository();
DataSet dataset = repository.GetAll();

Notice, that we are now using IRepository for both implementations rather EmployeeRepository and CustomerRepository to call our "GetAll()" method i.e. we are now using a common interface rather than a concrete class. Although this may not be a "blow your mind" example of interface usage, it definitely forms basis for understanding things such as "Dependency Injection(DI)" etc. which will "blow your mind"!.