Wednesday, January 23, 2013

TDD approaches - Outside In vs.Inside Out


When you start to solve a problem in TDD, one of the questions that most of the developers have is about the correct place to start testing the code.

 Is it better to start with a high level functional test (Outside-In) at a user story and drill down into the low level tests as you  progress or to come with an initial low level design and then start writing tests from the lowest component (Inside-Out) in the design and progress to the higher level components?

A short answer would be that it depends on your / team's coding preference or approach.

If you're not sure how your code should look like or how it will interact or communicate with other parts of your system, it's better to have a small design discussion with the team to identify the best possible design solution and start with the low level component and let it evolve as you write more tests.

But if your design already exists (Layered approach, where the layered components are identified like controllers, services, repositories etc.), you can start with the Outside-In approach.

As you see, Inside out testing implies a developer would probably consider the high-level design and break them up into low level components that interact with each other to provide the desired functionality. The developer thinks about how each component will be used by its client components and tests accordingly.

The advantage is that the team can deliver working software quickly as they have started with a proper design in his mind. However, since the code delivered was not written considering the high level user requirements, it may produce code that doesn't go well with the YAGNI principle and also have a risk of not meeting the actual functionality.

In the Outside In approach, the part of system that has the closest correlation to the user requirements are tested first, guarantees that the critical parts of the application is tested first. Here the focus is more on how the user interacts with the system, rather than how the components interact with each other. The test cases generated hence supports the usability of the system.

Monday, January 21, 2013

Implementing roles in domain models - Role object pattern


It is a common scenario in domain modeling to implement roles such as Manager, Salesman, and Engineer etc. in the applications, which are basically subclasses of a common role player class such as an Employee. However, this means that different instances of the role classes are actually different objects with different state and different identity, even if they are meant to represent the same logical entity.

At first glance it sounds like a case for inheritance, but there are complications as the same object may show multiple behavior or can make changes to another role during its lifetime. For e.g. an Engineer may become an Architect or a Manager in the organization. The expectation is to have a model where a class could be seen as more than one concept or role, and where attributes specific to one of those concepts can be specified.

The Role Object Pattern addresses this problem by representing an object and its roles as a composition of one role player object and arbitrarily many role objects. The role class model provides the flexibility of the association with role-specific attributes and even class operations, if needed.

Using the role object pattern the above problem statement can be addressed like


The employee class defines methods for managing roles via the RoleObject abstraction. The common superclasses for employee specific roles are provided by the EmployeeRole class. The concrete implementations for the EmployeeRole like Engineer, Salesman or Manager define and implement the interface for specific roles. The role objects are instantiated at runtime and added to the employee to add operations specific the role.

[TestClass]
public class EngineerRoleTests
{
    private Employee _employee;

    [TestInitialize]
    public void Initialize()
    {
        _employee = new Employee("Prajeesh Prathap");
        _employee.AddRole(new Engineer());
    }

    [TestMethod]
    public void CanRetrieveARoleFromAnObjectAtALaterPoint()
    {
        var manager = _employee.GetRoleOf<Engineer>();
        Assert.IsNotNull(manager);
    }
}