Thursday 24 October 2013

Dynamic vhosts using a central DNS server

I was inspired by Evans & Robs blogpost about dynamic vhosts using nginx/apache and we used this a fair amount at our office but it's not really useful if you want to quickly share your work with colleagues.

Links to their blogposts
http://blog.evan.pro/how-to-set-up-dynamic-virtual-hosts-for-web-development (Nginx)
http://akrabat.com/computing/automatic-apache-vhosts/ (Apache)

I set about setting up a centralised DNS server that i could use fake TLD's to point to each persons computer. If i would have used dnsmasq instead it would have been a lot easier.... But unluckily i had a fat configuration of bind that i didn't want to migrate to dnsmasq.

Doing this with bind9 step 1

Edit /etc/bind/named.conf.local and add a section zone for each colleague
zone "antoine" {
        type master;
        file "/etc/bind/db.antoine";
};

zone "jonas" {
        type master;
        file "/etc/bind/db.jonas";
};


Save and create a new file for each zone that you have created
; BIND db file for antoine

$TTL 86400

@       IN      SOA     |NAMESERVER DOMAIN|.      |EMAIL DOT DOMAIN|. (
                        2013102401      ; serial number YYMMDDNN
                        28800           ; Refresh
                        7200            ; Retry
                        864000          ; Expire
                        86400           ; Min TTL
                        )

                NS      |NAMESERVER DOMAIN|.

$ORIGIN antoine.

*       3600    A       192.168.0.7


So for us that would be
; BIND db file for antoine

$TTL 86400

@       IN      SOA     router.pmg.se.      spam.pmg.se. (
                        2013102401      ; serial number YYMMDDNN
                        28800           ; Refresh
                        7200            ; Retry
                        864000          ; Expire
                        86400           ; Min TTL
                        )

                NS      router.pmg.se.

$ORIGIN antoine.

*       3600    A       192.168.0.7

I will be frank when i say i have no idea why i have to specify an email in the zone SOA declaration or why it's in that format. I might even have done something terrible wrong.... but it works and it allows me to visit my collegues projects without having to edit my /etc/hosts

Tuesday 1 October 2013

Why i wish to remove getServiceLocator from AbstractController

Heya good people!

This is the first post on this blog so bare with me! So a few days ago i started a discussion after a PR was made against the ZF2. Here

I especially like the remarks from from a few people
https://github.com/zendframework/zf2/issues/5168#issuecomment-25174848
https://github.com/zendframework/zf2/issues/5168#issuecomment-25232532
https://github.com/zendframework/zf2/issues/5168#issuecomment-25205969

But none of these explicitly tell us why having the ServiceLocatorAwareInterface is an anti-pattern.
So here are my five cents to the discussion.

1, Using the service locator directly within the controller it's really easy to request new services. Which means it's very easy to lose track of the single responsibility principle (SRP) your controller should have.

2, Testing becomes more complicated because you will need to mock the service locator making your tests more fragile. Below you will find the difference between injecting dependencies and use the service locator

First example is using "proper" injection
class ExampleController extends AbstractActionController
{
    public function __construct(FooServiceInterface $fooService, BarServiceInterface $barService)
    {
        $this->fooService = $fooService;
        $this->barService = $barService;
    }

    public function testAction()
    {
        return $this->fooService->foo();
    }

    public function test2Action()
    {
        return $this->barService->bar();
    }
}
And here comes the test
class ExampleControllerTest
{
    protected function setUp()
    { 
        $this->fooService = $this->getMock('FooServiceInterface');
        $this->barService = $this->getMock('BarServiceInterface');

        $this->controller = new ExampleController($this->fooService, $this->barService);
    }
}
Second example is using the service locator anti-pattern
class ExampleController extends AbstractActionController
{
    public function testAction()
    {
        return $this->getServiceLocator()->get('fooService')->foo();
    }

    public function test2Action()
    {
        return $this->getServiceLocator()->get('barService')->bar();
    }
}
And it's test case
class ExampleControllerTest
{
    protected function setUp()
    { 
        $this->fooService = $this->getMock('FooServiceInterface');
        $this->barService = $this->getMock('BarServiceInterface');

        $sm = new ServiceManager();
        $sm->setService('fooService', $this->fooService);
        $sm->setService('barService', $this->barService);

        $this->controller = new ExampleController();
        $this->controller->setServiceLocator($sm);    
    }
}

Note
Both of the setup for our controllers are really quick and dirty and are far from perfect examples of how to properly test a controller.

Conclusion
As you noticed in the second example we also need to setup the ServiceManager and it's not a perfect setup. One could argue that i should modify the ServiceManager that is created by running the bootstrap on the Module. But that means we are doing more then we should be doing in the setUp method.

3, If your lazy like me you love the autocomplete of your favorite IDE but the docblock return param is mixed so your IDE won't be playing nice with you!

Well...... I could just add an annotation

/** @var FooServiceInterface $service */
$service = $this->getServiceLocator()->get('FooService');
return $service->foo();


So my final conclusion
We use the service locator anti-pattern for it's convenience but in the end we still end up writing the same amount of code that is harder to test, less readable and more confusing for new developers that join the project.