DDD & TDD. Part III

As the result of previous parts we have domain with core classes and services. Actually we can generate and process any amount of data with methods provided by domain services. But there are some issues:

  • How user will input data;
  • How data will reconstitute/persist.

Domain by nature and the general plan must be absolutely independent and free from technology aspects as GUI/user interaction (WPF, WinForms, Web) and the data layer implementation (MSSQL, MySQL, Oracle, etc.)

Layers

Step by step we realize that application should be multi layered. And there are minimum possible set of layers, as I see it:

  • Domain –business logic layer. In this layer described HOW to work with data.
  • Data layer. At this level implemented saving and recovering data to/from external data storage to domain objects. Extracting these actions in separate layer makes application more agile, i.e. it’s easy to deal with several different DB without changing other parts of the application.
  • Presentation layer. Here we say WHAT to do with data: define specific sequence of domain services and return calculated result to GUI. So, this layer connects Domain and Front End.
  • User Interface (Front End). This level can be console, win forms, web, even mental transmission to mind! =) Try to keep this layer as dumb as possible. No data changes, no application flow logic – only do what other says with any initiative.

Now when we know layers responsibilities, next goal is to understand how they interconnect with each other.

Once again, domain has no reference to any other part of application, it fully independent. Data layer have reference to domain, because of necessity to save and reconstitute data from external storages. Presentation layer refers to domain and data layer. GUI refers to the Presentation. In details I’m going to write below in text, while now we can draw links in following scheme:

In order to continue the post, I should tell few words about Inversion Of Control/Dependency Injection pattern.

Inversion of Control/Dependency Injection

In short, this pattern allows you to break hard reference link between objects.

Without this pattern, domain will depends from Data Façade in order to deploy necessary data for domain service (for example, load missed or additional data). As the result in domain will be translators and repositories. Instead of this we are going to create interfaces for main structures and classes from data layer. I hope the next example will make explanation clearer.

Was:

Domain code

public class DomainService {
    public int CalculationWithDataLayer() {
        var repository = new Repository();
        var list = repository.GetData();
        // calculations
    }
}

Data Facade

public class Repository {
    public List<object> GetData() {
        // alculations
    }
}

Now:

Domain code

public interface IRepository {
    List<object> GetData();
}

public class DomainService {
    public int CalculationWithDataLayer(IRepository repository) {
        var list = repository.GetData();
        // calculations
    }
}

Data Facade

public class Repository : IRepository {
    public List<object> GetData() {
        // calculations
    }
}

In words, Façade implement interface from Domain.

The same story is with GUI: in presentation layer defined interfaces for views, which will be implemented in GUI layer.

Testing

Assume that domain services implemented without interfaces. We have to write a huge preparation code to make test green. It be so hellish boring and hard that you’ll think about to get rid of tests at all. At the other hand with interfaces we are able to create fake classes.

For example, we’d like to test domain service’ behavior that called another service. Each one contains of complex and time consuming calculations.

public class ServiceA {
    public int LongCalcA() {
        var result = 0;
        Thread.Sleep(1000000);
        return result;
    }
}

public class ServiceB {
    public int LongCalcB(ServiceA serviceA) {
        var a = serviceA.LongCalcA();
        a += 42;
        return a;
    }
}

Test on the service B will looks like this:

[TestMethod]
public void CalcTest() {
    var a = new ServiceA();
    var b = new ServiceB();
    Assert.AreEqual(42, b.LongCalcB(a));
}

What do you think, how long does it take? Do you wish to run this test each time? I don’t want to definitely!

Now we a going to perform special street magic by speeding up test run significantly! To make it true, we have to extract interfaces from services.

public interface IServiceB {}

public interface IServiceA {
        int LongCalcA();
}

public class ServiceA : IServiceA {
    public int LongCalcA() {
        var result = 0;
        Thread.Sleep(1000000);
        return result;
    }
}

public class ServiceB : IServiceB {
    public int LongCalcB(IServiceA serviceA) {
        var a = serviceA.LongCalcA();
        a += 42;
        return a;
    }
}

Now, when we have interfaces, it’s possible to create fake service A. Also, for more comfortable usage, I suggest to create property that will set value for needed method.

public class ServiceAFake : IServiceA {
    public int LongCalcAResult{get;set;}
        public int LongCalcA() {
        return LongCalcAResult;
    }
}

Now we can rewrite the test on B service in the following way:

[TestMethod]
public void CalcTest() {
    var a = new ServiceAFake{ LongCalcAResult = 0};
    var b = new ServiceB();
    Assert.AreEqual(42, b.LongCalcB(a));
}

And it will take about 1000000 times fewer!!! Unbelievable! ;) But test on the A service still will be time consuming, sad but true, you can’t avoid it. But the A’s usage will be fast in other tests and it’s good. I think you for catching the main idea how to test services.

Launch application.

When you implement enough features, you’d like to test it in action. And there is a question how to start application? We can create nothing from GUI; there is no class that can be control center. What to do?

Create special control library, which will be visible to GUI and can run necessary scenarios. You can call it AppRunner (Application). In this library in the simplest case can be only one class “Runner” that know all possible scenarios and can launch them by GUI request. Runner can contain only one public method that accept parameter pointing to actual scenario.

The launch order is:

  1. Start application. At the same time the Runner starts with initial value, that select on Welcome scenario, for example.
  2. User click on menu item.
  3. Triggered event that call the Runner with new parameter that points to new scenario.
  4. Scenario launched from Presentation layer.
  5. All actions that not related to menu navigation handled by running scenario.

This part of story may be a little bit confusing, but it depends on the origin of the program structure, how scenarios were implemented. By the way, Application can refer to Data Façade.

Any questions, suggestion are welcome!

Hard’n’heavy!

Tagged , . Bookmark the permalink.

Leave a Reply

Your email address will not be published. Required fields are marked *

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>