*“A deep model contains the central concepts and abstractions that can succinctly and flexibly express essential knowledge of the users’ activities, their problems and their solutions.”*

*“Ultimately … this should make the software more in tune with the way the domain experts think and more responsive to the users’ needs”*

**Domain-Driven Design, by Eric Evans **

* *

Domain-Driven Design situates the domain model in a central and convergent role, tightly articulating semantics and syntax for problem definition, solution design and software implementation.

**In this post, we bring the domain semantics to our refactoring process.** We want a deeper perspective to analyse modularity problems and to direct improvements towards greater relevance to our design objectives. So, let’s resume the Fowler’s Video Store refactoring and explore alternative design decisions based on greater emphasis on model semantics.

Fowler’s Video Store didactic program has two main functions: rental calculations and customer statement printing. This post focuses on the domain concepts that are most relevant to the rental calculations. Next posts will explore additional design alternatives for rental calculations and customer statement printing.

### Initial Rental Calculations Design

Rental calculations include charge and frequent renter points. Both calculations are a function of the rental period and whether the video is either a new release, for children or regular.

The initial program defines a price code attribute for each video; this information is used to select the right calculation formulas embedded in `switch`

programming statements inside the customer `statement`

method. The complexity of such design grows as new price codes are added. It becomes specially dangerous if the `statement`

method is duplicated to implement the HTML format.

### Refactoring with Inheritance and Polymorphism

As we saw previously, the refactoring book evolves this design solution first by extracting the calculations to the methods `getCharge `

and `getPoints `

and moving them to the `Video`

class. This eliminates the need of duplicating the formulas when creating a new `statement`

method.

The next step is to isolate the formulas from the `Video`

class, replacing the price code with a new `Price`

class. This class is then further specialised into the `NewRelease`

, `Children`

or `Regular`

subclasses, so that the price code can be replaced by a polymorphic `Price`

reference to an object of the respective subclass.

The following figure shows the design solution adopted by the refactoring book.

The recommended refactoring improves modularity by using inheritance and polymorphism to adopt a **typical object oriented syntax**, that implements the strategy design pattern. The refactoring steps end up constituting the Replace Conditional Logic with Strategy refactoring pattern.

It looks like **the** right way to go. Doesn’t it? Well, let’s explore a design alternative.

### Finding Relevant Implicit Concepts

The rental model for prices and terms is implicitly codified in the following formulas scattered along the `Price`

class hierarchy implementation:

regularCharge = 2.0; if (daysRented > 2) regularCharge += (daysRented - 2) * 1.5; childrensCharge = 1.5; if (daysRented > 3) childrensCharge += (daysRented - 3) * 1.5; newReleaseCharge = daysRented * 3;

If we look closely enough at these formulas, we discover they are actually three instances of the same formula:

charge = initialPrice; if (daysRented > initialTerm) charge += (daysRented - initialTerm) * extraPricePerDay;

The implicit concepts of **initial term**,** initial price** and **extra price per day** have just emerged as relevant to our design! They define a **clearer, explicit, flexible and unified** pricing model, replacing three static functions by a single meaningfully parameterised function. The same is true for the frequent renter points calculations. The emerged concepts can be articulated as **rental conditions**.

Naturally, all relevant domain abstractions must be institutionalised as part of the language effectively practised in the business and expressed in the software. Therefore, emerging concepts must be presented, discussed, reviewed where necessary and validated with the business domain experts.

### Making the Relevant Concepts Explicit in the Design

As part of this this convergence process, we propose to **explicitly define the RentalConditions value object as a substitute for the Price class hierarchy**. The parameters initial term, initial price, extra price and extra points are invariant for regular, children’s and new releases. Therefore they can be defined at construction time:

RentalConditions regular = new RentalConditions(2, 2.0, 1.5, 0); RentalConditions childrens = new RentalConditions(3, 1.5, 1.5, 0); RentalConditions newRelease = new RentalConditions(1, 3.0, 3.0, 1);

The parameter `daysRented`

is defined at calling time for the functions `getCharge`

and `getPoints`

.

public class RentalConditions { private final int _initialTerm; private final double _initialPrice; private final double _extraPricePerDay; private final int _INITIAL_POINTS = 1; private final int _extraPoints; public RentalConditions (int initialTerm, double initialPrice, double extraPricePerDay, int extraPoints) { _initialTerm = initialTerm; _initialPrice = initialPrice; _extraPricePerDay = extraPricePerDay; _extraPoints = extraPoints; } public double getCharge (int daysRented) { double charge = _initialPrice; if (daysRented > _initialTerm) charge += (daysRented - _initialTerm) * _extraPricePerDay; return (charge); } public int getPoints (int daysRented) { int points = _INITIAL_POINTS; if (daysRented > _initialTerm) points += _extraPoints; return (points); } }

After all changes the new domain model implementation is:

### Conclusions

Refactoring at the semantic level improves the matching between business, model and implementation, adds flexibility where needed and addresses the major stakeholders’ concerns. As usual, we should always listen the domain experts, strive for simplicity and use a maintenance need as an opportunity for refactoring.

The initial program calculates rental charges and frequent renter points as conditional expressions. Standard object oriented design practice focuses on the conditions to **specialise the expressions** and implement the strategy design pattern for each calculation. This post focuses instead on the expressions themselves to identify the **relevant domain concepts** that **generalise the expressions**.

Bringing domain semantics to the process enabled us to propose a **Extract Value Object** refactoring, as an alternative to the **Replace Conditional Logic with Strategy** refactoring, with the following benefits:

**decoupling**: duplication in the multiple formulas is eliminated;**expressiveness**: changes can be more clearly and easily applied;**simplicity**: the program’s design structure is simplified.

Programs that instantiate an Anaemic Domain Model can be greatly improved by simple and straightforward refactoring aimed at adopting proper object oriented syntax. Additional improvements, however, require deeper thinking and carefully considering the domain model semantics in order to select the course of action from multiple design options.

Picture by Readerwalker’s photo stream. Original at Flickr.

[…] Duke on Revisiting Fowler’s Video Store: Refactoring Code, Refining AbstractionsRaoul Duke on Revisiting Fowler’s Video Store: Making Implicit Concepts ExplicitRafael Peixoto de Azevedo on Revisiting Fowler’s Video Store: Making Implicit Concepts […]

[…] Duke on Revisiting Fowler’s Video Store: Refactoring Code, Refining AbstractionsRaoul Duke on Revisiting Fowler’s Video Store: Making Implicit Concepts ExplicitRafael Peixoto de Azevedo on Revisiting Fowler’s Video Store: Making Implicit Concepts […]