Designing domain specific language



When you spin up a framework such as Laravel, Symfony etc. The first thing you'll notice, is that they have their own 'feel'. I often joke that Symfony2 is like Java and Laravel is like Ruby.

But what gives an application or a framework a 'feel'? Domain specific language or 'DSL'.

Domain specific language is almost like a syntax or a language specific to your application and ecosystem. DSL is what makes your applications code unique and more usable.

One technique I've adopted is actually designing the syntax first, then abstracting the logic afterwards. For example, I was recently tasked with writing a large API in Laravel. I wanted to include proper HTTP statuses for each response type, I wanted to transform the response to obfuscate our table structure, and I wanted to convert each request to JSON.

I started out imagining what syntax I'd like to be able to write to get all of those tasks done.

<?php  
...
class ThingController extends ResourceController  
{
    public function show($id)
    {
        $thing = Thing::find($id);    

        return $this->setTransformer(new ThingTransformer())
                    ->setItem($thing)
                    ->get();
    }
}

This pretty much said all I wanted to say, it was succinct, but still allowed a great deal of flexibility.

This may not seem like a lot, but previously, you might have done something like...

<?php  
...
class ThingController extends Controller  
{
    protected $fractal;

    protected $transformer;

    public function __construct(Larasponse $fractal, Transformer $transformer)
    {
        $this->fractal = App::make('Serializer');
        $this->transformer = $transformer;
    }

    public function show($id)
    {
        $thing = Thing::find($id);

        $data = $this->fractal->setItem($thing, $this->transformer);

        return response()->json($data, 200);
    }
}

Which may only seem like a few lines longer, but this would add up over the course of a large project.

So now I went backwards into the resource controller.

<?php

class ResourceController extends Controller  
{
    const HTTP_OK = 200;
    ....
    public function get()
    {
        return response()->json($this->data, self::HTTP_OK);    
    }
}

I used setters to let us customise the response, such as setting a transformer.

<?php  
...

class ResourceController extends Controller  
{
    public function setTransform(Transformer $transformer)
    {
        $this->transformer = $transformer;

        return $this;
    }
}

The return $this; allows us to 'chain' further objects or parameters to the final response.

So now, if you want to alter how your application transforms your data, or change a http status code, or even add events or additional logging, you can do all of that from one class, as opposed to updating all of your controllers for example.

So, to design usable domain specific syntax, start at the front. In other words the part you'll be writing the most, and then work backwards to abstract the logic and make it actually work.