Showing posts with label Resharper. Show all posts
Showing posts with label Resharper. Show all posts

Tuesday, March 25, 2014

Law of Demeter - Refactoring to Hide Delegate

The Law of Demeter is a design guideline for developing software, particularly object-oriented programs. In its general form, the law is a specific case of loose coupling. The fundamental notion of the law is that a given object should assume as little as possible about the structure or properties of anything else (including its subcomponents), in accordance with the principle of "information hiding".
For E.g. the code given below shows that the client calls the method on the dependent object of the client rather than on the object itself. This increases the coupling between classes.
var manager = john.GetDepartment().GetManager();
The Hide Delegate refactoring principle can be applied to this design to solve the issue.












public Manager GetManager()

{
    return Department.GetManager();

}

Tuesday, October 9, 2012

Refactoring out parameters code smell to Tuple


Using out parameters in methods are usually a code smell with indicates that you want to effectively return two results from a method. Out parameters are mostly introduced when developers realize the need of an additional return value from an already existing method. The problem with out parameters is that they introduce the risk of side effects and are hard to debug.
You can use the Transform out parameters refactoring to transform out parameters to a tuple in C#.
Later you can convert the tuple with a class or struct with a static create method to enhance readability and maintainability.

For e.g., we can refactor the below given code
[TestMethod]
public void AddEmployeeReturnsTrueIfEmployeeWasSaved()
{
    var employee = new Employee {Name = "Prajeesh Prathap"};
    var repository = new EmployeeRepository();
    int employeeId = 0;
    var success = repository.Add(employee, out employeeId);
    Assert.IsTrue(success);
    repository.RemoveAll();
}
public bool Add(Employee employee, out int employeeId)
{
    employeeId = 0;
    if (_employees.Any(x => x.Name == employee.Name)) return false;
    employee.Id = _employees.Any() ? _employees.Max(x => x.Id) + 1 : 1;
    employeeId = employee.Id;
    _employees.Add(employee);
    return true;
}

Using the transform out parameters refactoring pattern to...




[TestMethod]
public void AddEmployeeReturnsTrueIfEmployeeWasSaved()
{
    var employee = new Employee {Name = "Prajeesh Prathap"};
    var repository = new EmployeeRepository();
    var add = repository.Add(employee);
    var success = add.Item1;
    Assert.IsTrue(success);
    repository.RemoveAll();
}

public Tuple<bool, int> Add(Employee employee)
{
    int employeeId = 0;
    if (_employees.Any(x => x.Name == employee.Name)) return Tuple.Create(false, employeeId);
    employee.Id = _employees.Any() ? _employees.Max(x => x.Id) + 1 : 1;
    employeeId = employee.Id;
    _employees.Add(employee);
    return Tuple.Create(true, employeeId);
}

Further improvement can be achieved by encapsulating the parameters in a class as given below

public class AddOutput
{
    public bool Result { get; set; }
    public int Id { get; set; }

    public static AddOutput Create(bool success, int id)
    {
        return new AddOutput {Result = success, Id = id};
    }
}
public AddOutput Add(Employee employee)
{
    int employeeId = 0;
    if (_employees.Any(x => x.Name == employee.Name)) return AddOutput.Create(false, employeeId);
    employee.Id = _employees.Any() ? _employees.Max(x => x.Id) + 1 : 1;
    employeeId = employee.Id;
    _employees.Add(employee);
    return AddOutput.Create(true, employeeId);
}
[TestMethod]
public void AddEmployeeReturnsTrueIfEmployeeWasSaved()
{
    var employee = new Employee {Name = "Prajeesh Prathap"};
    var repository = new EmployeeRepository();
    var add = repository.Add(employee);
    var success = add.Result;
    Assert.IsTrue(success);
    repository.RemoveAll();
}

Sunday, September 9, 2012

Refactoring implicit language elements to form interpreters


In business applications, while creating searching algorithms you need to create a search context which consists of a combination of multiple algebraic expressions. A simple example is given below where the filter for searching books is created by combining multiple expressions as in the code sample below.

[TestMethod]
public void GetAllBooksInRangeByTopicShouldReturnAllBooksInThePriceRangeFilteredByTopic()
{
    var amazonService = new BookStore();
    const decimal fromRange = 50;
    const decimal toRange = 100;
    const string genre = "Travel Guide";
    var books = amazonService.GetBooksByPriceRangeAndGenre(fromRange, toRange, genre);
    Assert.IsTrue(books.Any());
}

public IEnumerable<Book> GetBooksByPriceRangeAndGenre(decimal from, decimal to, string genre)
{
    return GetAll().Where(x => x.Genre.Name.ToLower().Contains(genre.Trim().ToLower())
                                && (x.Price >= from && x.Price <= to));
}

We can refactor these expressions to a more readable and maintainable structure by creating specifications using the interpreter pattern as given below.


public IEnumerable<Book> GetBooksByPriceRangeAndGenre(decimal from, decimal to, string genre)
{
    var bookSpec = GetBookSpec(genre, from, to);
    return GetAll().Where(bookSpec.SatisfiedBy());
}

private BookSpecification GetBookSpec(string genre, decimal from, decimal to)
{
    return new BookSpecification(from, to, genre);
}

public class BookSpecification : ISpecification<Book>
{
    private readonly decimal _from;
    private readonly decimal _to;
    private readonly string _genre;

    public BookSpecification(decimal from, decimal to, string genre)
    {
        _from = from;
        _to = to;
        _genre = genre;
    }

    public Expression<Func<Book, bool>> SatisfiedBy()
    {
        return new GenreSpecification(_genre).AND(new PriceRangeSpecification(_from, _to)).SatisfiedBy();
    }
}

public class GenreSpecification : ISpecification<Book>
{
    private readonly string _genre;

    public GenreSpecification(string genre)
    {
        _genre = genre.Trim().ToLower();
    }
       
    public Expression<Func<Book, bool>> SatisfiedBy()
    {
        return new Specification<Book>(x => x.Genre.Name.ToLower().Contains(_genre)).SatisfiedBy();
    }
}

public class PriceRangeSpecification : ISpecification<Book>
{
    private readonly decimal _from;
    private readonly decimal _to;

    public PriceRangeSpecification(decimal from, decimal to)
    {
        _from = from;
        _to = to;
    }

    public Expression<Func<Book, bool>> SatisfiedBy()
    {
        return new Specification<Book>(x => x.Price >= _from && x.Price <= _to).SatisfiedBy();
    }
}

Monday, July 11, 2011

Resharper series - Create Template Methods

Template method pattern defines the skeleton of an algorithm in an operation, deferring some steps to subclasses. Template Method lets subclasses redefine certain steps of an algorithm without changing the algorithm's structure. In your code if two or more methods in subclasses perform similar steps in the same order with different logic or steps you can make use of the extract template method refactoring steps to generalize the methods by extracting their steps into methods with identical signatures and pull up these to form the Template Method.

For e.g., the below given code samples simulate the withdrawal functionality on different bank accounts.
public class SavingsAccount
{
    private readonly User _user;
    private decimal _balance;

    public SavingsAccount(User user)
    {
        _user = user;
    }

    public string GetUserName()
    {
        return _user.GetName();
    }

    public void SetBalance(decimal balance)
    {
        _balance = balance;
    }

    public void HasSufficientBalanceForTransfer(decimal amountToWithdraw)
    {
        if(amountToWithdraw > _balance)
            throw new InsufficientBalancesException();
    }

    public decimal GetServiceChargeForWithdrawal()
    {
        return 0M;
    }

    public void WithdrawAmount(decimal amountToWithdraw)
    {
        _balance -= amountToWithdraw + GetServiceChargeForWithdrawal();
    }

    public decimal GetBalance()
    {
        return _balance;
    }
}

public class CurrentAccount
{
    private readonly User _user;
    private decimal _balance;

    public CurrentAccount(User user)
    {
        _user = user;
    }

    public string GetUserName()
    {
        return _user.GetName();
    }

    public void SetBalance(decimal balance)
    {
        _balance = balance;
    }

    public void HasSufficientBalanceForTransfer(decimal amountToWithdraw)
    {
        if(amountToWithdraw > _balance)
            throw new InsufficientBalancesException();
    }

    public decimal GetServiceChargeForWithdrawal()
    {
        return 0M;
    }

    public void WithdrawAmount(decimal amountToWithdraw)
    {
        _balance -= amountToWithdraw + GetServiceChargeForWithdrawal();
    }

    public decimal GetBalance()
    {
        return _balance;
    }
}

The test cases on the current account for the withdrawal function

[TestMethod]
[ExpectedException(typeof(InsufficientBalancesException))]
public void ifUserTriesToWithdrawMoreMoneyThanAvailableBalanceShouldThrowException()
{
    var currentAccount = _bank.CreateSavingsAccount(_user);
    const decimal balance = 100M;
    currentAccount.SetBalance(balance);

    const decimal amountToWithdraw = 500M;
    currentAccount.HasSufficientBalanceForTransfer(amountToWithdraw);
}

[TestMethod]
public void currentAccountDoesNotDeductServiceChargeOnWithdrawal()
{
    var currentAccount = _bank.CreateSavingsAccount(_user);
    const decimal balance = 100M;
    currentAccount.SetBalance(balance);

    var serviceCharge = currentAccount.GetServiceChargeForWithdrawal();
    Assert.IsTrue(serviceCharge == 0M);
}

[TestMethod]
public void ifUserTriesToWithdrawAmountAvailableInAccountShouldProccedWithTransaction()
{
    var currentAccount = _bank.CreateSavingsAccount(_user);
    const decimal balance = 100M;
    currentAccount.SetBalance(balance);

    const decimal amountToWithdraw = 50M;

    currentAccount.WithdrawAmount(amountToWithdraw);
    Assert.AreEqual(currentAccount.GetBalance(), 50M);
}

As you can see from the test code, the withdraw functionality follows a series of steps to complete the actual withdrawal of money from the account like checking available balances, calculating the service charge etc. We can try to apply the template method by generalizing these actions and pulling up the template method to an abstract Account class.
First we apply the Extract superclass refactoring to create a superclass that holds the template method.



After applying the refactoring our Current and Savings account classes now looks like.
public class CurrentAccount : Account
{
    public CurrentAccount(User user)
    {
        _user = user;
    }

    public void HasSufficientBalanceForTransfer(decimal amountToWithdraw)
    {
        if(amountToWithdraw > _balance)
            throw new InsufficientBalancesException();
    }

    public decimal GetServiceChargeForWithdrawal()
    {
        return 0M;
    }

    public void WithdrawAmount(decimal amountToWithdraw)
    {
        _balance -= amountToWithdraw + GetServiceChargeForWithdrawal();
    }
}

public class SavingsAccount : Account
{
    public SavingsAccount(User user)
    {
        _user = user;
    }

    public void HasSufficientBalanceForTransfer(decimal amountToWithdraw)
    {
        if(amountToWithdraw > _balance)
            throw new InsufficientBalancesException();
    }

    public decimal GetServiceChargeForWithdrawal()
    {
        return 25M;
    }

    public void WithdrawAmount(decimal amountToWithdraw)
    {
        _balance -= amountToWithdraw + GetServiceChargeForWithdrawal();
    }
}

Next we apply the pull members up refactoring to pull the generalized methods to the super class and then implement the abstract methods in the respective child classes.



The final output looks like.
public abstract class Account
{
    protected User _user;
    protected decimal _balance;

    public string GetUserName()
    {
        return _user.GetName();
    }

    public void SetBalance(decimal balance)
    {
        _balance = balance;
    }

    public decimal GetBalance()
    {
        return _balance;
    }

    public abstract void HasSufficientBalanceForTransfer(decimal amountToWithdraw);
    public abstract decimal GetServiceChargeForWithdrawal();

    public void WithdrawAmount(decimal amountToWithdraw)
    {
        HasSufficientBalanceForTransfer(amountToWithdraw);
        var serviceCharge = GetServiceChargeForWithdrawal();
        _balance -= amountToWithdraw + serviceCharge;
    }
}

public class CurrentAccount : Account
{
    public CurrentAccount(User user)
    {
        _user = user;
    }

    public override void HasSufficientBalanceForTransfer(decimal amountToWithdraw)
    {
        if(amountToWithdraw > _balance)
            throw new InsufficientBalancesException();
    }

    public override decimal GetServiceChargeForWithdrawal()
    {
        return 0M;
    }
}

public class SavingsAccount : Account
{
    public SavingsAccount(User user)
    {
        _user = user;
    }

    public override void HasSufficientBalanceForTransfer(decimal amountToWithdraw)
    {
        if(amountToWithdraw > _balance)
            throw new InsufficientBalancesException();
    }

    public override decimal GetServiceChargeForWithdrawal()
    {
        return 25M;
    }
}