About Me

Hello, I'm an eclectic software professional working with enterprise software at SAP. This blog only contains my personal views, thoughts and opinions. It is not endorsed by SAP nor does it constitute any official communication of SAP.

Monday, December 24, 2012

The Acyclic Visitor Pattern

Knock knock

The visitor design pattern is a way to add new operations to a hierarchy of classes without having to change the hierarchy itself.

For example, with a simple hierarchy of fruits, you can have an IFruitVisitor interface that operates on the different classes in the hierarchy (in C#):

interface IFruitVisitor {
  void Visit(Apple apple);
  void Visit(Grape grape);
}

The hierarchy classes then accept the visitor and fulfil the double-dispatching necessary to call the right Visit method:

abstract class Fruit {
  public abstract void Accept(IFruitVisitor visitor);
}

class Apple : Fruit {
  public override void Accept(IFruitVisitor visitor) {
    visitor.Visit(this);
  }
}

class Grape : Fruit {
  public int NumberOfGrapes { get; set; }
  public override void Accept(IFruitVisitor visitor) {
    visitor.Visit(this);
  }
}

Note how each Accept method looks the same but is actually dispatching to a different method in the visitor (Visit(Apple) and Visit(Grape)).

Visitors then implement the IFruitVisitor interface to execute their own specific logic against the hierarchy. Creating new visitors is akin to adding new behavior to the hierarchy classes without changing them. Here's a visitor that picks apples:

class ApplePicker : IFruitVisitor {
  public List<Apple> Apples { get; private set; }

  public ApplePicker() {
    Apples = new List<Apple>();
  }

  public void Visit(Apple apple) {
    Apples.Add(apple);
  }
  public void Visit(Grape grape) { }
}

It works as a builder, collecting all apples from the visited fruits:

List<Fruit> fruits = ....

var applePicker = new ApplePicker();
fruits.ForEach(fruit => fruit.Accept(applePicker));

var allApples = applePicker.Apples;

Other visitors can easily be created without impacting the hierarchy, like a price or a weight calculator visitor:

class FruitWeightCalculatorVisitor : IFruitVisitor {
  public decimal WeightInGrams { get; private set; }

  public void Visit(Apple apple) {
    WeightInGrams += appleWeight;
  }
  public void Visit(Grape grape) { 
    WeightInGrams += grape.NumberOfGrapes * singleGrapeWeight;
  }

  private readonly decimal appleWeight = 150m;
  private readonly decimal singleGrapeWeight = 0.6m;
}

The visitor also has some disadvantages:

  • It's a clumsy pattern: it requires repetitive code in the hierarchy classes to implement double-dispatching. It can be seem as a workaroud for the shortcomings of mainstream languages (e.g. Java, C# and C++). Also, the client code has to deal with the visitors, resulting in a bulky API.
  • It assumes that the hierarchy of visited classes doesn't change. If it changes, the visitor interface and all existing visitors must be updated to accomodate the change. There's a cyclic dependency between the classes in the hierarchy and the methods in the visitor.

Smoke and mirrors

Extension methods can be used to make the pattern look more transparent to users:

static class FruitExtensions {
  public static IEnumerable<Apple> PickApples(this IEnumerable<Fruit> fruits) {
    var applePicker = new ApplePicker();
    foreach (var fruit in fruits) fruit.Accept(applePicker);
    return applePicker.Apples;
  }
}

Clients now don't need to know about the visitor to execute its logic:

List<Fruit> fruits = new List<Fruit>();
var allApples = fruits.PickApples();

Other visitors can introduce similar methods to ease consumption of the added functionality.

The acyclic visitor

To remove the cyclic dependency between hierarchy classes and visitor methods, the acyclic visitor pattern prescribes separate visitor interfaces for each different class in the hierarchy. In C#, a generic interface can be used for this:

interface IFruitVisitor {}
interface IFruitVisitor<TFruit> : IFruitVisitor
  where TFruit : Fruit {
  void Visit(TFruit fruit);
}

In Java, because of type erasure, each class must have its own dedicated interface:

interface FruitVisitor {}
interface AppleVisitor extends FruitVisitor {
  void visit(Apple apple);
}
interface GrapeVisitor extends FruitVisitor {
  void visit(Grape grape);
}

Back to C#, the degenerate interface IFruitVisitor is used in the hierarchy base class:

abstract class Fruit {
  public abstract void Accept(IFruitVisitor visitor);
}

Each visitable class in the hierarchy then checks if the given visitor supports it before calling it:

class Apple : Fruit {
  public override void Accept(IFruitVisitor visitor) {
    if (visitor is IFruitVisitor<Apple>) {
      ((IFruitVisitor<Apple>)visitor).Visit(this);
    }
  }
}

class Grape : Fruit {
  public int NumberOfGrapes { get; set; }
  public override void Accept(IFruitVisitor visitor) {
    if (visitor is IFruitVisitor<Grape>) {
      ((IFruitVisitor<Grape>)visitor).Visit(this);
    }
  }
}

The type checks and casting expressions make many people uncomfortable. They're not a problem though, since each class only checks for its own visitor interface. Apples won't mix with grapes.

Visitor implementations can then pick and choose which hierarchy classes they visit.

The apple picker will only visit apples:

class ApplePicker : IFruitVisitor<Apple> {
  public List<Apple> Apples { get; private set; }

  public ApplePicker() {
    Apples = new List<Apple>();
  }

  public void Visit(Apple apple) {
    Apples.Add(apple);
  }
}

The weight calculator visitor will visit all fruits:

class FruitWeightCalculatorVisitor : 
  IFruitVisitor<Apple>, IFruitVisitor<Grape> {
  ...
}

Adding a new fruit to the hierarchy won't impact all the visitors, only the ones that are interested in the new fruit:

class Banana : Fruit {
  public int NumberOfFingers { get; set; }
  public override void Accept(IFruitVisitor visitor) {
    if (visitor is IFruitVisitor<Banana>) {
      ((IFruitVisitor<Banana>)visitor).Visit(this);
    }
  }
}

The apple picker doesn't need to change, only the weight calculator. To force visitors that always need to know about all fruits to fail compilation, the following interface can be used:

interface IAllFruitsVisitor : 
  IFruitVisitor<Apple>, 
  IFruitVisitor<Grape>, 
  IFruitVisitor<Banana> {}

Then, the introduction of the Banana class (and the change to the above interface) will make the following weight calculator fail compilation until the banana visitor method is implemented:

class FruitWeightCalculatorVisitor : IAllFruitsVisitor {
  ...
  public void Visit(Banana banana) { 
    WeightInGrams += 
      banana.NumberOfFingers * bananaFingerWeight;
  }

  private readonly decimal bananaFingerWeight = 125m;
  ...
}

Also, with the current generic implementation, some visitors can be made generic. The apple picker could become a generic fruit picker:

class FruitPicker<TFruit> : IFruitVisitor<TFruit>
  where TFruit : Fruit {
  public List<TFruit> Fruits { get; private set; }

  public FruitPicker() {
    Fruits = new List<TFruit>();
  }

  public void Visit(TFruit fruit) {
    Fruits.Add(fruit);
  }
}

The acyclic visitor is useful if you foresee changes to the hierarchy and if there are visitors that don't need to know about all types in the hierarchy, especially new ones. This way, adding a new type won't create a ripple effect of changes through all visitors, only to the ones that need to operate on all types.

Epilogue

I first learned about the acyclic visitor from an article by Robert Martin. Unfortunately, I can't seem to find that article on the web anymore. But, you can still find the pattern described in his book Agile Principles, Patterns, and Practices in C#.

Update

References to Robert Martin articles: this article (pdf) talks about the visitor pattern and the acyclic visitor (in Java). This one (pdf) is the article on the acyclic visitor that I was looking for at first (in C++).

Friday, June 29, 2012

Self-types in NRoles

Since roles are weaved into target classes, it's sometimes necessary for them to be able to identify the type of these classes.

NRoles supports self-types through the use of a type parameter with the special name S:

public abstract class REquatable<S> : IEquatable<S>, Role {
  public abstract bool Equals(S other);
  public bool Differs(S other) {
    return !Equals(other);
  }
}

To cast this to the type parameter, just use the Cast<T> extension method:

public class Identity<S> : Role {
  public S Self {
    get { return this.Cast<S>(); }
  }
}

When other roles compose roles with self-types, they must flow the self-type through, since it will ultimately be determined by the target classes that compose them:

public abstract class RComparable<S> : 
  IComparable<S>, Does<REquatable<S>>, Role {
  ...
}

The post-compiler will check all classes that compose roles with self-types and issue an error message if the type parameter is not the target class itself.

public sealed class Money : 
  Does<RComparable<Money>>, Does<REquatable<Money>> {
  ...
}

Constraints added to the self-type become requirements for the target classes to fulfill:

public class MyRole<S> : Role
  where S : ISomeInterface {
  ...
}

public class MyClass : ISomeInterface,
  Does<MyRole<MyClass>> {
  ...
}

This way, roles can work with the type of the classes that compose them generically and safely. It's useful, for example, for fluent interfaces that return the type of this, used for fluent method chaining:

public class PropertyBag<S> : Role {
  public S With(string name, object value) {
    ...
    return this.Cast<S>();
  }
}

Thursday, June 28, 2012

Java 8 virtual extension methods are begging to be free of interfaces

To cope with API evolution and to provide new extensions for lambda-friendly methods, Java 8 will introduce a form of extension methods in interfaces (which were called public defender methods in previous iterations of the proposal). Interface methods will be allowed to have bodies (or just a reference to a static method):

interface MyInterface {
  void method() default {
    System.out.println("A good idea?");
  }
}

A class implementing MyInterface doesn't need to provide an implementation for method(). This is particularly valuable for interface evolution to maintain binary compatibility with classes already compiled with the old interface version. In general, the old binaries would work with the new defaulted interface method without recompilation; it will just use the default implementation.

The default keyword is a deliberate choice not to conflict with the rule that "interfaces have no code". Now they can have default code.

Conflict resolution works by first looking for a method implementation in the class and all its superclasses (even if the method is abstract) and then looking for the more specific interface that provides the default method. If the conflict still persists, the code will throw a linker error (for already compiled code) or won't even compile.

I see two issues with this approach.

First, the decision to treat default methods as just last-resort code does not seem intuitive. A default method implementation won't even win over an abstract method declared in a superclass. In my view, concrete methods should always win over abstract methods in this situation, they should only lose if they're explicitly overridden by abstract methods in the implementing class itself.

Second, this choice is insufficient to cope with other implementation issues that might arise. For example, the usual extract method refactoring won't be possible for a default method because interfaces still won't allow private methods (as far as I know).

The second issue alone makes me question the design of the feature, or at least think that it's still incomplete.

What instead I'd like to see is another construct altogether, like a trait (or role). Traits would not conflict with the semantics of interfaces and would be free to incorporate more interesting options. The migration path from an interface to a trait should be easy: just change the keyword interface to trait and add the modifiers public abstract to all the methods (IDEs could do this automatically). Then, the programmer could add methods with bodies to traits (the equivalent of the current proposal), but would also be able to create methods with other accessibility modifiers (or even final). To not complicate the design too much, instance fields and constructors would still not be allowed:

trait MyTrait {
  public void method() {
    System.out.println("A good idea!");
  }
  // reuse an existing static method that takes the trait type as a first parameter
  public void otherMethod() = 
    SomeClass.someCompatibleStaticMethod;
}

A class (or interface, or trait) would then use (or compose) a trait (or many), hopefully with a revised conflict resolution strategy (but not the one from Scala, which is too implicit):

class MyClass uses MyTrait {
}

interface MyInterface uses MyTrait {
}

Classes or interfaces implementing traits could generate a warning, but traits would be binary-compatible with their interface counterparts:

class MyClass 
  implements MyTrait { // warning: should use `uses` for trait
}

interface MyInterface 
  implements MyTrait { // warning: should use `uses` for trait
}

This design will not take more effort than the current proposal, but I think the change in focus from interfaces to traits would allow the language to evolve in more interesting ways in the future, and not be painted into a corner. Interfaces would be preserved as they are today, and its semantics would not get in the way anymore.

To have an idea of where the design could go, consider these possible features:

Traits could have instance fields, maybe only private ones to avoid difficult conflict situations.

trait PropertyBag {
  private final Map<String, Object> bag = ...

  public void set(String name, Object value) {
    // ...
  }

  public Object get(String name) {
    // ...
  }
}

Since traits need to be composed into target classes, there might be a need to reference the type of those classes in the trait. A self-type would allow for that, in a kind of compiler-backed generic parameter that would be automatically provided for target classes:

trait PropertyBag self TSelf {
  public TSelf with(String name, Object value) {
    // ...
    return this; // TSelf is the type of this
  }
}

class MyClass
  uses PropertyBag // self-type is MyClass
{
  ...
}

A construct that uses many traits could alias trait members to have more meaningful names in its context:

class MyClass uses PropertyBag {
  public void setProperty(String name, Object value) 
    aliases PropertyBag.set;
  public MyClass withProperty(String name, Object value) 
    aliases PropertyBag.with;
}

Traits could publish required traits that should be present in a target class that uses it:

trait MyTrait self (TSelf uses MyOtherTrait) {
  ...
}

Traits could even require interfaces and a specific class (or superclass) for the target class to conform to.

So, a simple change in focus changes the future outlook for the language. For more ideas and a powerful implementation of this concept, just look at Scala (which doesn't even have interfaces).

Thursday, March 1, 2012

Some OO Design

"The critical design tool for software development is a mind well educated in design principles. It is not the UML or any other technology." - Craig Larman

I've recently found the following interview question on stackoverflow:

Basic sales tax is applicable at a rate of 10% on all goods, except books, food, and medical products that are exempt. Import duty is an additional sales tax applicable on all imported goods at a rate of 5%, with no exemptions. When I purchase items I receive a receipt which lists the name of all the items and their price (including tax), finishing with the total cost of the items, and the total amounts of sales taxes paid. The rounding rules for sales tax are that for a tax rate of n%, a shelf price of p contains (np/100 rounded up to the nearest 0.05) amount of sales tax.

This is a very familiar example that can be used as a really good gauge of various software development skills. There are many different ways to solve this problem. I'll use object-oriented techniques and the Java language to show one such possibility. I'll not show a step-by-step process, just some ideas on how I got to the end result.

Introduction

Before writing any line of code (even tests), I like to think about the main entities involved and broadly how they're connected. This can be seen as a very high level Domain Model that will support the described scenario and serve as the foundation for any subsequent requirement.

At a high level, there are Products, Taxes and Orders. I can put Products into Orders, where Taxes will be applied; and I can get a detailed Receipt for all Entries in the Order.

Then, I'll create the first automated acceptance test, what will drive my design choices. For that, I'll create a couple of Taxes, Products, and an Order.

Products

I'll start with the Products. From the requirements, Products have a Name, a Type (or Category), an indication of whether they're Imported, and a Price. This is how I'd like to create one:

Product ddd = Product.create("Domain Driven Design", ProductType.BOOK, ProductOrigin.LOCAL, dollars("69.99"));

There are many assumptions and simplifications here. First, I'm representing ProductType as a simple enumeration:

public enum ProductType {
  BOOK,
  FOOD,
  MEDICAL,
  MOVIE
}

This fixes the types of product in the code. It's more sensible to think that new types can be created at runtime, and that ProductType deserves a class of its own. But, since I want to focus on the sample scenario and finish my acceptance test, I'll just live with fixed types for now. Also, different types of products could have different properties; Movies can have Length and Cast, Books can have Authors and NumberOfPages. For fixed types this could be modeled with Product subclasses; for dynamic types more complicated DynamicProperties (pdf) could be used, with an effort to find the least amount of property "bags" that would describe most product types. These property bags could also be created as subclasses of some ProductProperties class.

The ProductOrigin enum indicates if a product is imported or not:

public enum ProductOrigin {
  LOCAL,
  IMPORTED
}

I could have used a simple boolean, but the enum makes the code readily understandable.

For the price, I'll use a simple Money class, which is a ValueObject that stores an amount as a BigDecimal. Money is a valuable abstraction; it's more work than using raw BigDecimals, but it improves the intention of the code. It's the simpler thing, not the faster thing. Since all my values will be in dollars, I don't even include a Currency, and leave the constructor private to control instantiation through the dollars factory method, which I statically imported to write the Product creation statement. Also, I set the number of decimal places to 2 (the usual for dollars) rounding up.

public class Money {

  public static Money dollars(String amount) {
    return new Money(new BigDecimal(amount));
  }

  private final BigDecimal amount;

  private Money(BigDecimal amount) { 
    this.amount = amount.setScale(2, RoundingMode.UP);
  }

  ...

}

Prices are one of the most volatile Product properties. They can change with time, with store or market; they can have discounts, different values in different currencies and many other variations. The price associated with a product can be seen as its BasePrice, which at a minimum should be a TemporalProperty. But, for the time being, I don't need to address these concerns, but it's still good to keep them in mind.

Taxes

Now I can tackle taxes:

Basic sales tax is applicable at a rate of 10% on all goods, except books, food, and medical products that are exempt.

The first part is easy. Taxes have a Name and a Rate:

Tax basicSalesTax = Tax.create("Basic sales tax", "0.10");

The Rate is stored as a BigDecimal. Doubles and Floats are never suitable for financial calculations, even when used as rates.

But Taxes are not universally applicable, and there needs to be some kind of TaxEligibilityCheck to find out if a Tax should be applied to a Product (actually, it's better to check if it should be applied to an Entry, as eligibility could be based on factors other than Product properties).

One way to do this is to have an abstract method boolean isEligible(OrderEntry entry) (I'm calling Entry an OrderEntry in the code) in Tax, and have a subclass for each different eligibility criteria. The basic sales tax could then be created like this:

Tax basicSalesTax = TaxWithExemptionsOnProductType.
  create(
    "Basic sales tax", "0.10", 
    ProductType.BOOK, ProductType.FOOD, ProductType.MEDICAL);

Here, I'm assuming there's a Tax subclass named TaxWithExemptionsOnProductType that overrides isEligible to check the product type against the given exempt types. I'd also have a subclass named TaxForImportedProducts that's only applicable to imported products. But, if I wanted a tax that's applicable to imported products with certain product type exemptions, it would be awkward. I'd have to start mixing the logic of both classes and possibly create a third one that combines them. No, I'd like to keep each eligibility check Strategy separate, with the possibility of combining them for Composite criteria. Maybe I'll never need criteria different than the ones in the example, and maybe I'll never need to combine them. But, clearly delineating the responsibilities in the design makes it simpler, easier to understand and easier to evolve. Again, the simpler thing is not the faster thing. And so, I need a new abstraction:

public interface TaxEligibilityCheck {
  boolean isEligible(OrderEntry entry);
}

And Tax will now have a TaxEligibilityCheck instance.

I can already imagine using the Specification pattern to create Composite criteria based on logical operators:

Tax basicSalesTax = Tax.
  create(
    "Basic sales tax", "0.10", 
    and(exempt(ProductType.BOOK), exempt(ProductType.FOOD), not(imported())));

This very flexible approach is a possibility with the TaxEligibilityCheck interface. I couldn't get there easily with subclasses. Finding the right balance between current needs and possible future needs is always difficult, and you should never create superfluous or speculative elements. But it's a win-win situation when a more flexible design is even simpler than the obvious, direct design. Following that advice again, I don't need the full Composite Specification pattern right now, so simple one-off implementations will do.

Besides checking for eligibility, the Tax has a Money calculate(Money amount) method that applies its rate to the given amount (I'm also renaming the class to TaxMethod, not to be confused with a calculated tax amount):

public class TaxMethod {

  public static TaxMethod create(String name, String rate, TaxEligibilityCheck eligibilityCheck) {
    return new TaxMethod(name, new BigDecimal(rate), eligibilityCheck);
  }

  private final String name;
  private final BigDecimal rate;
  private final TaxEligibilityCheck eligibilityCheck;

  private TaxMethod(String name, BigDecimal rate, TaxEligibilityCheck eligibilityCheck) {
    this.name = name;
    this.rate = rate;
    this.eligibilityCheck = eligibilityCheck;
  }

  public boolean isEligible(OrderEntry entry) {
    return eligibilityCheck.isEligible(entry);
  }

  public Money calculate(Money amount) {
    return amount.multiply(rate);
  }

  ...

}

Order

With Products and TaxMethods, it's time to create an Order:

Order order = Order.create();
order.addTaxMethod(baseSalesTax);
order.addTaxMethod(importDuty);
order.addProduct(ddd, 1);

I'm adding the tax methods that the Order should use when calculating the tax for products. This could create a kind of temporal coupling, if taxes are calculated at the time products are added, I should first add all tax methods, and then start adding products. Let's eliminate that coupling:

Order order = Order.createWithTaxMethods(baseSalesTax, importDuty);
order.addProduct(ddd, 1);

That's better. Now I'm passing the tax methods to the constructor (ahem, factory method); which must be done before adding any products. Still, it's a little awkward that Orders have to keep a list of TaxMethods. I need some kind of TaxMethod container, something that will let me reuse the same taxes in different orders; a TaxingPractice that will encapsulate the tax methods in use:

TaxingPractice taxingPractice = TaxingPractice.create();
taxingPractice.add(basicSalesTax);
taxingPractice.add(importDuty);

Order order = Order.create(taxingPractice);
order.addProduct(ddd, 1);

Order Entries

The Order needs to store two types of entries: ProductEntries and the derived TaxEntries. Again, there are many ways to do it, and I've chosen to have a common interface for both entries:

public interface OrderEntry {
  Product getProduct();
  Money getAmount();
}

But still I've chosen to keep them in separate collections inside the Order:

private final List<ProductEntry> entries = new ArrayList<ProductEntry>();
private final List<TaxEntry> taxEntries = new ArrayList<TaxEntry>();

This implementation will simplify the calculation of the various totals that I need (SubTotal, TaxTotal and Total); but it's completely encapsulated in Order, and I'd like to be able to change it in the future without impacting any other class. The other possibilities that I see are having a single List<OrderEntry> for both kinds of entries or having a composite Order encapsulating the internal leaf orders ProductOrder and TaxOrder.

When adding products to an order, I calculate taxes right away:

public void add(Product product, int quantity) {
  ProductEntry entry = ProductEntry.create(product, product.getPrice(), quantity);
  entries.add(entry);
  taxEntries.addAll(taxingPractice.apply(entry));
}

The TaxEntries are derived from the created ProductEntry using the TaxingPractice tax methods and put into the taxEntries collection. It's good to keep a link between the product entry and its derived tax entries, so we better know the origin of the calculations and can more easily manipulate the objects, for example: removing a product from an order should also remove its derived tax entries (a "feature" I have not yet implemented).

This is what the TaxingPractice apply method looks like:

public Collection<TaxEntry> apply(ProductEntry entry) {
  List<TaxEntry> entries = new ArrayList<TaxEntry>();
  for (TaxMethod tax : taxes) {
    if (tax.isEligible(entry)) {
      TaxEntry taxEntry = apply(tax, entry);
      entries.add(taxEntry);
    }
  }
  return entries;
}

private TaxEntry apply(TaxMethod tax, ProductEntry entry) {
  Money taxAmount = tax.calculate(entry.getAmount());
  return TaxEntry.create(entry, tax, taxAmount);
}

To calculate totals, then, the Order just needs to sum its entries' amounts:

public Money getSubTotal() {
  return getTotal(entries);
}

public Money getTaxTotal() {
  return getTotal(taxEntries);
}

public Money getTotal() {
  return getSubTotal().add(getTaxTotal());
}

private Money getTotal(Iterable<? extends OrderEntry> entries) {
  Money total = dollars("0.00");
  for (OrderEntry entry : entries) {
    total = total.add(entry.getAmount());
  }
  return total;    
}

Receipt

The information that's in the Order will be used to create a Receipt. But how should that happen? A Receipt features a visual representation of the information contained in the Order, what conceptually could have many different formats. I can think of two ways to do it: let the Receipt derive its information from the Order or let the Order provide its information to the Receipt. I chose to let Order present its information to the Receipt, which will work like a Builder object. To allow for different receipt implementations, I created a Receipt interface:

public interface Receipt {
  void start();
  void printProduct(ProductEntry entry);
  void printTax(TaxEntry entry);
  void printSubTotal(Money subTotal);
  void printTaxTotal(Money taxTotal);
  void printTotal(Money total);
  void end();
}

The Order just provides all the necessary information to the receipt:

public void print(Receipt receipt) {
  receipt.start();
  for (ProductEntry entry : entries) receipt.printProduct(entry);
  for (TaxEntry entry : taxEntries) receipt.printTax(entry);
  receipt.printSubTotal(getSubTotal());
  receipt.printTaxTotal(getTaxTotal());
  receipt.printTotal(getTotal());
  receipt.end();
}

This way, receipts are really independent from orders. I created a very simple receipt that I can use like this to print to the console:

SimpleReceipt receipt = SimpleReceipt.create(System.out);
order.print(receipt);

Putting it all together

An example usage is this:

// configure the system
Product ddd = Product.create("Domain Driven Design", BOOK, LOCAL, dollars("69.99"));
Product goos = Product.create("Growing Object Oriented Software", BOOK, IMPORTED, dollars("49.99"));
Product house1 = Product.create("House M.D. Season 1", MOVIE, LOCAL, dollars("29.99"));
Product house7 = Product.create("House M.D. Season 7", MOVIE, IMPORTED, dollars("34.50"));

TaxMethod basicSalesTax = TaxMethod.create("BST", "0.10", exempt(BOOK, FOOD, MEDICAL));
TaxMethod importDuty = TaxMethod.create("IMD", "0.05", imported());

TaxingPractice taxes = TaxingPractice.create();
taxes.add(basicSalesTax);
taxes.add(importDuty);

// purchase some items
Order order = Order.create(taxes);
order.add(ddd, 1);
order.add(goos, 1);
order.add(house1, 1);
order.add(house7, 1);

// print the receipt
SimpleReceipt receipt = SimpleReceipt.create(System.out);
order.print(receipt);

Which will print this to the console:

------------------ THIS IS YOUR ORDER ------------------
(001)                Domain Driven Design -----   $69.99
(001)    Growing Object Oriented Software -----   $49.99
(001)                 House M.D. Season 1 -----   $29.99
(001)                 House M.D. Season 7 -----   $34.50
(IMD)    Growing Object Oriented Software -----    $2.50
(BST)                 House M.D. Season 1 -----    $3.00
(BST)                 House M.D. Season 7 -----    $3.45
(IMD)                 House M.D. Season 7 -----    $1.73
                                SUB-TOTAL -----  $184.47
                                TAX TOTAL -----   $10.68
                                    TOTAL -----  $195.15
---------------- THANKS FOR CHOOSING US ----------------

Tests

I've also created a couple of acceptance tests while implementing the solution. The tests helped me iterate and refine the design. I didn't create granular unit tests for the classes because the acceptance tests were sufficient to drive the design to this point. It's still a very incomplete solution, and going forward I'd definitely create separate unit tests to evolve some classes independently.

What's left

As I've already mentioned, the solution is still very incomplete. It exercises a happy path scenario; but it already lays a good foundation to build on. A couple things to tackle next would be:

  • Rounding - Event though I'm rounding up all monetary amounts with 2 decimal places, I haven't verified if this suffices for the rounding specified in the requirements.
  • Remove products from an order - the derived taxes should also be removed.
  • Add the same product twice to an order - the existing product entry should be updated to reflect the new quantity for the product; no two product entries should point to the same product.
  • Validation, boundary conditions, design by contract - many values should be checked for null or whether they fall in a predetermined range. For example, quantities should be greater than zero and probably have an upper limit.

Also, further ideas worth exploring might be:

  • Persistence - how would a database to persist all entities change the design?
  • UI - an interactive UI to create orders would be interesting for Customers; same for an administrative UI for the Administrators (to maintain products, taxes, and review orders)

I'm sure you can think of many other possibilities.

Da Code

My solution can be found on github. Take a look and send me your comments and suggestions!

Wednesday, August 17, 2011

Why is composition harder than inheritance?

(just some random thoughts...)

Let's take this Java example:

class Base {
  public void method() {}
}
class Derived extends Base {}

See how easy it is for Derived to "reuse" code from Base? Derived is a subclass of Base, and in its constructor it calls Base's constructor, constructing a Base before constructing a Derived:

class Derived extends Base {

  // this is what gets generated by the compiler:
  public Derived() { super(); }

  // this doesn't exist, but illustrates what happens when we call Derived.method:
  public void method() { super.method(); } 

}

Also, Derived instances have a "forwarding" method, that, when called, will delegate to the corresponding base method (this is not technically what happens, but I'm looking at the "concept" here). Isn't that convenient?

Why isn't the same capability available to compose classes? Composition is always a better strategy than inheritance in "reuse" scenarios. To compose, the delegating methods have to be manually written:

class Composed {
  private Base _base;
  public Composed(Base base) { _base = base; }
  public void method() { _base.method(); }
}

Conceptually, Composed looks a lot like Derived. The differences are obvious to OO-mongers. Inheritance is an is-a (better still, a behaves-like) relationship, and Derived instances can be subtituted whenever Base is needed. Composition is a has-a relationship, and instances of Composed cannot stand in for Base. Composition is more flexible because changes in Base do not force changes in Composed's interface, and we can choose which methods of Base to expose through Composed.

There's a degenerate version of composition called a wrapper, that wraps a class, exposes all its public methods as its own, and delegates all calls (and it can also adjusts some calls, like a proxy). But, as the Composed example shows, it's painful to write compared to the ease of inheritance. So it's not by chance that people use inheritance for the wrong reasons, it's convenience.

What if we had a wrapping "operator", much like the inheritance one?

class Wrapper wraps Base {}

Compare this to:

class Derived extends Base {}

The following constructor would be generated by the compiler (note that it takes a parameter):

class Wrapper wraps Base {
  // "wrap", like "super", does compiler magic:
  public Wrapper(Base wrappedBase) { wrap(wrappedBase); }
}

Wouldn't that bring composition (rather, wrapping) to the same level as inheritance in terms of language support? Would this be worthwhile? I think it would, and it also makes sense to allow multiple-wrapping (as opposed to multiple-inheritance), with some kind of conflict resolution strategy.

Should we be able to substitute a Wrapper for a Base? Maybe. This looks like a stronger form of duck typing, one that's actually verifiable by the compiler. Only within a class derived from Base (or in Base itself) we would be in trouble, if it accesses private or protected members of other instances of the same type. Maybe then a class should only be allowed to access its own private or protected members, and not the ones of other instances, because we don't know whether those instances will be wrappers or not. Scala has this kind of access control (by marking a member as private[this] or protected[this]). We could also declare any interfaces that Base implements in Wrapper, and work with these interfaces. And, wrappers shouldn't break the semantic contract of the wrapped class (and thus adhere to the Liskov Substitution Principle - pdf).

From another angle, traits try to solve exactly the same problem, by creating a new language-level construct (the trait, duh) that composes nicely into classes. Scala has traits. Maybe then, wrappers could be used to work with old code, and new code should be designed with traits.

Friday, June 3, 2011

DCI Example with NRoles

The DCI (Data, Context, Interactions) architecture is a style that proposes an interesting separation of concerns between the domain model of a system (what the system is) and its behavior (what the system does), normally associated with its use cases. The rationale is that, since these parts incur change at different rates, isolating them from each other results in a system that's easier to understand, evolve and maintain.

In order to enact a specific use case, a specialized context instantiates the necessary data objects assigned to the needed roles to run the required "algorithm".

A very common example is that of a bank transfer operation. This example has already been described in C# with the C# quasi-mixins pattern. With NRoles the code for a role lives in a single abstraction, which results in a more compelling implementation. I'll change the example a little bit, to introduce a stateful role; something that's harder to achieve with pure C#.

The stateful role represents a log of events, from a generic type T:

public class RJournal<T> : Role {
  private List<T> _entries = new List<T>();
  public IEnumerable<T> Entries { get { return _entries; } }
  public void Log(T entry) {
    _entries.Add(entry);
  }
}

The next roles are the debitor and the creditor in a transfer operation, a source and a target:

public abstract class RTransferSource : Does<RJournal<string>>, Role {
  public abstract void Withdraw(int amount);
  public void TransferTo(RTransferTarget target, int amount) {
    Withdraw(amount);
    target.Deposit(amount);
    LogWithdraw(amount);
    target.LogDeposit(amount);
  }
  internal void LogWithdraw(int amount) {
    this.As<RJournal<string>>().Log("Withdrew: " + amount);
  }
}

public abstract class RTransferTarget : Does<RJournal<string>>, Role {
  public abstract void Deposit(int amount);
  public void TransferFrom(RTransferSource source, int amount) {
    source.TransferTo(this, amount);
  }
  internal void LogDeposit(int amount) {
    this.As<RJournal<string>>().Log("Deposited: " + amount);
  }
}

They define abstract methods that have to be provided by composing classes. They also compose the Journal<string> role. The Account class composes all preceding roles, which means that it can be a debitor or a creditor in an operation. It provides the required abstract methods:

public class Account : Does<RJournal<string>> 
  Does<RTransferSource>, Does<RTransferTarget> 
{
  public string Id { get; private set; }
  public int Balance { get; private set; }
  public Account(string id, int balance) {
    Id = id;
    Balance = balance;
  }
  public void Withdraw(int amount) {
    Balance -= amount;
  }
  public void Deposit(int amount) {
    Balance += amount;
  }
}

This diagram describes the above constructs:

DCI

Since roles are about composition, and not inheritance, all roles included in a class are flattened. In particular, RJournal<T> ends up only once in Account.

The TransferContext class executes the use case to transfer money from a source to a target:

public class TransferContext {
  public RTransferSource Source { get; private set; }
  public RTransferTarget Target { get; private set; }
  public int Amount { get; private set; }

  public TransferContext(RTransferSource source, RTransferTarget target, int amount) {
    Source = source;
    Target = target;
    Amount = amount;
  }

  public void Execute() {
    Source.TransferTo(Target, Amount);
  }
}

The following sample code invokes the scenario:

var savingsStartBalance = 10000;
var checkingStartBalance = 500;

var savings = new Account("Savings", savingsStartBalance);
var checking = new Account("Checking", checkingStartBalance);

var context = new TransferContext(
  checking.As<RTransferSource>(), 
  savings.As<RTransferTarget>(), 
  100);
context.Execute();

PrintAccount(savingsStartBalance, savings);
Console.WriteLine();
PrintAccount(checkingStartBalance, checking);

Where PrintAccount is simply:

private static void PrintAccount(int startBalance, Account account) {
  Console.WriteLine("{0}:", account.Id);
  Console.WriteLine("Start: " + startBalance);
  account.As<RJournal<string>>().Entries.ToList().ForEach(Console.WriteLine);
  Console.WriteLine("Balance: " + account.Balance);
}

Running it yields this output:

  Savings:
  Start: 9000
  Deposited: 100
  Balance: 9100
  
  Checking:
  Start: 500
  Withdrew: 100
  Balance: 400

To know more and download NRoles, take a look here.

Sunday, May 29, 2011

NRoles: An experiment with roles in C#

In the last months, I've been developing in my spare time a proof-of-concept post-compiler with Mono.Cecil to enable roles in C#: NRoles. Roles are high level constructs that enable better code reuse through easier composition. They are very similar to traits as described in the traits paper (pdf).

Set up

NRoles is hosted on google code. You can get the latest source code with this mercurial command:

  hg clone https://code.google.com/p/nroles/ nroles

You can also download the latest binary package from the downloads page.

To set up a Visual Studio project to use NRoles, unzip the binary package (or compile from source) in a folder accessible to the project. I normally have a project root folder, with folders for the project code (src) and for any used libraries (lib). For example:

  src\
    project files ...
  lib\
    nroles-v0.1.2-bin\
      NRoles.dll
      nutate.exe
      other NRoles binaries ...

In the project, add a reference to the NRoles.dll assembly. This is a very minimal assembly used to annotate the code to enable the post-compiler to create roles and compositions. Then, add a post-build event to the project to run the post-compiler (nutate.exe):

  "$(SolutionDir)..\lib\nroles-v0.1.2-bin\nutate.exe" "$(TargetPath)"

Now nutate.exe runs whenever the project is built, and any errors or warnings are reported in the Visual Studio error list view.

Roles and compositions

Let's take a look at some code based on the examples in the traits paper. Roles are classes marked with the interface NRoles.Role. This is a simple role that implements IEquatable<T> and provides a Differs method:

public abstract class REquatable<T> : IEquatable<T>, Role {
  public abstract bool Equals(T other);
  public bool Differs(T other) {
    return !Equals(other);
  }
}

To distinguish roles from normal classes or interfaces, I prefix them with the letter R. REquatable<T> provides the Differs method, but still requires classes that compose it to implement Equals, since it's abstract.

To compose a role, a class uses the NRoles.Does<TRole> marker interface, with the desired role as a type parameter. A role can also compose other roles. This is a role that implements IComparable<T> and composes REquatable<T>:

public abstract class RComparable<T> : IComparable<T>, Does<REquatable<T>>, Role {
  public bool Equals(T other) {
    return CompareTo(other) == 0;
  }
  public abstract int CompareTo(T other);
  public bool LessThan(T other) {
    return CompareTo(other) < 0;
  }
  public bool GreaterThan(T other) {
    return CompareTo(other) > 0;
  }
  public bool LessThanOrEqualTo(T other) {
    return CompareTo(other) <= 0;
  }
  public bool GreaterThanOrEqualTo(T other) {
    return CompareTo(other) >= 0;
  }
  public bool IsBetween(T min, T max) {
    return GreaterThan(min) && LessThan(max);
  }
}

Classes that compose RComparable<T> will also compose REquatable<T> and gain the implementations of the corresponding IComparable<T> and IEquatable<T> interfaces. RComparable<T> "implements" REquatable<T>.Equals in terms of CompareTo. CompareTo is left abstract and needs to be implemented by further composing classes.

RComparable

The following role represents a circle and composes REquatable<T> and RComparable<T>:

public class RCircle : Does<REquatable<RCircle>>, Does<RComparable<RCircle>>, Role {
  public int Radius { get; set; }
  public double Area { get { return Math.PI * Radius * Radius; } }
  public int CompareTo(RCircle other) {
    if (other == null) throw new ArgumentNullException("other");
    return Radius.CompareTo(other.Radius);
  }
}

All roles in a composition have the same priority. This includes all roles declared in the composition itself and also these roles' roles, and so on. Any role will only appear once in a composition, even if it was composed multiple times through different "paths". This way, it's very different from multiple inheritance, which requires you to consider the whole hierarchy and places different priorities in each class. As a result, conflicting members from multiple roles must be resolved by the composition (more on this here), which is also different from the way that mixin inheritance normally works, where the composition order defines the relative priorities of the mixins.

This simple composition represents the RGB (red, green and blue) values for a color:

public class Rgb : Does<REquatable<Rgb>> {
  public int R { get; set; }
  public int G { get; set; }
  public int B { get; set; }
  public bool Equals(Rgb other) {
    return R == other.R && G == other.G && B == other.B;
  }
}

And this role uses the Rgb composition and represents a color:

public class RColor : Does<REquatable<RColor>>, Role {
  public Rgb Rgb { get; set; }
  public bool Equals(RColor other) {
    return Rgb.Equals(other.Rgb);
  }
}

The next composition is a circle, and uses RCircle, RColor and REquatable<T>:

public class Circle : Does<RCircle>, Does<RColor>, Does<REquatable<Circle>> {
  public bool Equals(Circle other) {
    if (other == null) throw new ArgumentNullException("other");
    return
      this.As<RCircle>().Equals(other.As<RCircle>()) &&
      this.As<RColor>().Equals(other.As<RColor>());
  }
}

Circle has an Equals method that reuses the implementations from RCircle and RColor. Since NRoles works as a post-compiler, to use compositions in the same assembly that they're defined, the As<TRole>() extension method casts the composition type to one of its composed roles. This operation is always safe (provided that you post-compile the assembly). You don't need to use this trick in other assemblies, since the compositions are implicitly convertible to the roles that they compose. The roles become interfaces that the compositions implement (look here for the conceptual idea).

The Circle class ends up composing many behaviors from different roles, hopefully giving a taste of how roles improve the overall separation of concerns of the design.

Circle

NRoles is an experiment in a very early stage. Ideally, roles would be available in the language itself. But, I hope it can already be useful to create better designs; and maybe to show language designers that this is an important concept. So please, download and play with it, and comment on any issues and possibilities. And of course: contribute!