Book Review: Domain-Specific Languages by Martin Fowler

March 18th, 2011

Executive Summary

The book succeeds quite well to demystify and rehabilitate the development of domain-specific languages. It points out in particular all the small specialized languages that many of us use every day. Further, it provides a good catalog of useful techniques illustrated by examples in various languages.

 

Full Review

Introduction

Domain-Specific Languages was written by Martin Fowler with Rebecca Parsons and published by Addison Wesley in 2011. It aims at both making the case for using domain-specific languages in everyday programming and providing a set of techniques often used in their implementation.

Structure

The book is divided into five parts. The first one is dedicated to a discussion about DSLs, what they are, when they can be useful, and a quick overview on how to get started. This is the only part of the book to be read linearly. The last four parts are presenting patterns, for lack of a better word, that can be applied when creating a DSL. It is useful to get acquainted with the material but in depth reading can be done as needed.

Content

The book is very rich in content accompanied by a lot of tailored examples. It is more than enough to get you started writing a DSL and making the case for it. There is also enough to get you confused on the best course to follow for a particular application.
On the negative side, regrettably I still fail to form a good idea of what a ‘Semantic Model’ is and truly feel what its benefits are. Martin Fowler is adamant that it is a very useful piece to have between the syntax and the domain model. It would have been nice to see a non-trivial example in the book or a reference to one that is widely available to illustrate the concept.
The second regrettable element in the book is the lack of references to the academic literature on the topic to support exploring some of the concepts in more depth. Not only does a lot of the research on languages in general apply in the simpler context of DSLs, but a lot has been written on the particular topic. Google certainly is helpful but it would have been nice to have a few curated pointers to things written outside the ‘Thoughtworks world’ , in paricular on grammars and on semantics. I am also suspicious of the way Martin Fowler takes great care to install his vocabulary. I sometimes had the feeling that the book was there as much to support ‘Thoughtworks’ business as it was to instruct the reader. That being said I am naturally quite suspicious. This is particularly the case on how the author defines embedded vs internal vs external DSLs.

Style

This is the first book I have read from Martin Fowler but I do follow his Bliki. Unfortunately the style of the book is close to that of the Bliki. And that does not work for me, as I expect a more formal, authoritative style to a book. As it is, the first-person singular is used way too much to my taste. This often turns to be an opinion book (and that is usually stated in-situ by the author himself). In other cases, the author debates alternatives, then concludes to the superiority of one or the other (in his opinion), rarely resorting to other sources to support either side of the argument. Finally a lot of space is devoted to explaining why some topics are not covered, or not expanded once again without redirecting the reader to other sources that discuss it. While a lot of it would be just fine on the context of Bliki, it turned out to be very irritating when reading the book.

Final Words

The book may be self-serving and sometimes fail to expand beyond the author’s opinions into the wider world. Having said that, it is full of valuable information and the last four sections of the book will certainly prove useful to a lot of us. Many of my criticisms can be remedied by searching the web for material on DSLs, formal grammars and formal semantics.

Deliberate practice with tools

October 26th, 2010

In my career I had the luck to hold jobs where I could exchange useful feedback on coding practices with very smart people. I have also held jobs where that is not possible. Back in the not so distant days when I did not use continuous integration and unit tests and such goodies, I was left with learning from experience, painful as it can be. Nowadays however a lot of tools, kindly provided by a wide community, especially for the Java language enable rapid and specific feedback on your work. For the remainder of this post I will stay on the side that I know best with Java.

I have been using static analyzer such as checkstyle, PMD, Findbugs or JDepend for a few years to give me useful information on my code and left it at that. More recently I have used the violations reported by those tools (to which I added Sonar) and started to actively try to reduce the number of violations, focusing on specific ones. The one that yielded the biggest improvement was ‘design for extension’. The package circular dependency analysis also pushed to think more about how packages should be structured where interfaces should go and which classes should be available outside their package. It has been very satisfying to notice how much more liveable my code has become.

To be sure this would not have been possible without a good amount of automated tests and continuous integration and source control management to provide the necessary safety net for experimentation. Next I will work on staying out of the red (I have to admit I originally dismissed this idea when I saw it presented by Joshua Kerievsky) as I am starting to see how valuable it is to leverage modern IDE capabilities and structure the mental processes that underpins refactoring.

How do you do deliberate practice ? What are the tools you would recommend for it ?

What code is worth unit testing ?

August 27th, 2010

This is a topic that came up in a vigorous conversation recently. The example we used was whether or not tests should be written for accessors. I was on the yes side and will expose my arguments here.

My first argument was yes because it has happened time and again to me that the wrong member was returned by the accessor. The counter argument was that code inspection would often reveal those issues.

My second argument was that the tests are not written only to validate the code at the time it is written but also for the future when changes happen. The counter argument being that in the mean time it is that much more code that needs to be maintained.

My final argument was that in any case it was simpler and cheaper to set as a policy that everything should be tested and then agree on exceptions during code reviews compared to debate for every piece of code whether it should be tested or not. That being said the policy might also be ‘test everything except accessors’.

I failed however to make the argument that I find the most useful: if is not worth testing, why is it worth writing ?

Your thoughts, arguments and counter arguments, as always, are very much welcomed.

Testivus on Test Coverage

August 24th, 2010

I love this story by Alberto Savoia. Thanks to Mo for clueing me in on it.

Sonar the quality dashboard tool

July 21st, 2010

I thought I would share my new preferred tool: sonar.

It is a web application that enables to visualize and exploit the results of static analysis tools, tests and dependency analysis tools. It gives a fantastic view of the overall quality of your code, highlights the problem areas and even enable you to visualize the highest priority items.

My favorite piece is the technical debt optional plugin. With some effort you can probably make it somewhat accurate for your particular circumstances. Which would be somewhat missing the point. Ideally you would want to use it as a benchmark value across organizations as the appetite for quality is already reflected in the rules you choose to include in the analysis.

And did I mention it is effortlessly populated from maven ?

Test Driven Development and Design by Contract, the return

July 8th, 2010

I wrote a long time ago about how I would like these two tools to be combined.

In the end I gave it a shot and just posted that on github. I have not tried it in real life yet but I will soon. The README explains the intent and the design assumptions. Check the tests for some examples.

On the other end, nothing is more than valuable than your input so please let me know what you think about it.

Normalizing story cost

May 19th, 2010

This article is the second in the series started with the use of cost.

In agile software development the cost of a story has this interesting property that it is highly correlated to the time it takes to implement it. Consciously or unconsciously cost is used as a proxy variable for time. Actual implementation times in turn tend to be hijacked by managers to measure performance by comparing them to cost estimate. Points are often used to remove that parasitising.

While using points is good, what we really need, the purpose of estimating cost in the first place, is the ability to layout project plans in terms of time. In comes velocity that enables the transformation back from points into time. I have witnessed enough attempts to manipulate the velocity either to look good when reporting in or to transform it into a measure of productivity (including at the individual level) to have entirely lost faith in its usefulness. Burn up charts are a lot more useful. They illustrate trends rather than instant pictures, they keep people at the project level rather than the individual contributor and they provide a view of the evolution of scope.

Finally let us focus on the estimation process. I firmly believe that this process is very important as it is unveiling the real work that will be needed to complete a story. It is a crucial analysis and design process. It is very unfortunate that the cost, the number, that comes out of the process considerably overshadows the other outcome: the establishment of common knowledge in the team. It is the learning that happened that is in practice the all important outcome. This learning is sometimes expressed in artifacts, from new stories being created, to new examples being attached to the story, to a change in the definition of done. All of which are rich expressions. Cost in contrast is the poorest of them all. Why then try to estimate it or even make the focus of the process?

Estimating should not be the focus of the analysis process. The focus of the analysis process should be to ensure the stories are ready to be implemented. In other words make them of a tractable size with an agreed upon definition of done. Tractable size means they all have more or less the same cost. The cost of the story becomes a measurable random variable that provides some indication on the predictability of the process. The distribution probability of that variable can be influenced by changing the process. And in return the effect of process changes can be measured usefully. It provides management with a tool to forecast the future and to influence it. It removes the cat and mouse game that estimate versus actuals tend to become. It helps measure the performance of the project rather than that of individuals. And last but not least it focuses project teams on risk adjusted value rather than cost to prioritise their work.

That is what we have been experimenting with for the last 10 months. Although we do not actually measure the monetary cost of a story but rather its lead time. It is the cost in terms of time, an acceptable approximation considering the previous argument that the bulk of cost is personnel. So far (excluding vacation induced outliers) we average 6.23 calendar days per story from analysis start to close with a standard deviation of 3.82. Our targets for those numbers are 8 and 2.5 respectively meaning we would trade a higher average for less fluctuation. The probability distribution derived from this data also enables us to make useful predictions about the possible lateness of a story, when the lead time breaks the 3 sigma barrier, and to react to it earlier. For instance a story that reaches 8 days of lead time has 28% lateness.

Integer flyweight implementation

April 23rd, 2010

Here is a unit test that illustrates the Fly Weight implementation of Integers in Java.

import junit.framework.TestCase;

public final class TestIntegers extends TestCase {
    public void testValueOfGivesTheSameIntegerForSmallValues() {
        assertSame(Integer.valueOf(1), Integer.valueOf(1));
    }

    public void testValueOfGivesADifferentIntegerForSomeValues() {
        assertNotSame(Integer.valueOf(13333333), Integer.valueOf(13333333));
        assertEquals(Integer.valueOf(13333333), Integer.valueOf(13333333));
    }

    public void testNew() {
        assertNotSame(new Integer(1), new Integer(1));
        assertEquals(new Integer(1), new Integer(1));
    }

    public void testValueOfGivesTheSameIntegerForAutoBoxing() {
        assertSame((Integer) 1, (Integer) 1);
    }

    public void testValueOfGivesADifferentIntegerForAutoBoxing() {
        assertNotSame((Integer) 13333333, (Integer) 13333333);
        assertEquals((Integer) 13333333, (Integer) 13333333);
    }
}

Java BigDecimal equality

March 6th, 2010

Here is why you should use compareTo to find out whether two BigDecimals represent the same number or not.

import java.math.BigDecimal;

import junit.framework.TestCase;

public final class TestBigDecimal extends TestCase {
    public void testBigDecimalZeroEqualsBigDecimalValueOfZero() {
        assertTrue(BigDecimal.ZERO.equals(BigDecimal.valueOf(0)));
    }

    public void testBigDecimalZeroNotEqualsBigDecimalValueOfZeroDot() {
        assertFalse(BigDecimal.ZERO.equals(BigDecimal.valueOf(0.)));
    }

    public void testBigDecimalZeroEqualsBigDecimalValueOfZeroString() {
        assertTrue(BigDecimal.ZERO.equals(new BigDecimal("0")));
    }

    public void testBigDecimalZeroEqualsBigDecimalValueOfZeroDotString() {
        assertTrue(BigDecimal.ZERO.equals(new BigDecimal("0.")));
    }

    public void testBigDecimalZeroNotEqualsBigDecimalValueOfZeroDotZeroString() {
        assertFalse(BigDecimal.ZERO.equals(new BigDecimal("0.0")));
    }

    public void testBigDecimalZeroComparesToBigDecimalValueOfZeroDotAsZero() {
        assertEquals(0, BigDecimal.ZERO.compareTo(BigDecimal.valueOf(0.)));
    }

    public void testBigDecimalZeroComparesToBigDecimalValueOfZeroDotZeroStringAsZero() {
        assertEquals(0, BigDecimal.ZERO.compareTo(new BigDecimal("0.0")));
    }
}

Something for the week-end

February 27th, 2010

I used to like overloading methods to provide a default behaviour for any object and a specialised one for some select types. That’s possible when the language supports multiple dispatch. It is not possible in Java:

import junit.framework.TestCase;

public class TestOverloading extends TestCase {
    public static final class OverloadedClass {
        public String thisIsA(final Object o) {
            return "Object";
        }
        
        public String thisIsA(final String s) {
            return "String";
        }
    }
    
    public void testIsCallingObjectFromObject() {
        final OverloadedClass tested = new OverloadedClass();
        final Object value = new Object();
        
        assertEquals("Object", tested.thisIsA(value));
    }
    
    public void testIsCallingObjectFromString() {
        final OverloadedClass tested = new OverloadedClass();
        final Object value = new String();
        
        assertEquals("Object", tested.thisIsA(value));
    }
    
    public void testIsCallingStringFromString() {
        final OverloadedClass tested = new OverloadedClass();
        final String value = new String();
        
        assertEquals("String", tested.thisIsA(value));
    }
}