The Developer Day | Staying Curious

Archive for March 2010

Mar/10

16

Pair Programming Explained

There’s a lot of confusion over pair programming. It’s been widely known for a long time and there are a lot of famous companies such as ThoughtWorks actively using pair programming but on the other side there are still a lot of people not knowing what exactly pair programming is, how it works, what are it’s benefits and downsides. The greatest resource on the matter so far that I’ve read is Stuart Wray’s paper for the January 2010 edition of IEEE Software Magazine entitled “How Pair Programming Really Works“. I really enjoyed reading this article because of it’s scientific approach to the problem.

The main benefits of pair programming are these:

  • Communication. While developers explain software problems to each other they often suddenly experience enlightenment and find the solution they were looking for.
  • Noticing details. Experiments prove that focused people can miss an elephant in the room. Pair programming partners are usually very helpful to notice various details. For example noticing typos in the code.
  • Following code standards. Developers tend to follow best practices more when they work in pairs.
  • Expertise judgement. Working with another person in pair is one of the best ways to judge expertise and productivity.

The downside of pair programming is that developers get burnt out. On one hand it forces developers to keep working instead of reading blogs and emails, but after a while developers might get mentally tired and become counter productive. It’s important to allow developers to have some “slack time” if they need to and do some work solo.

ThoughtWorks made a great presentation on how they use pair programming on one of their projects. I highly recommend watching it.

, , Hide

Mar/10

10

Zend Framework Advanced Error Controller

The default Zend Framework Error Controller generated by Zend_Tool is quite simple. It displays a simple error message, sets a response status and if exception display is enabled in the current environment, an exception message, stack trace and request variables are displayed.

While such a standard error controller may work well for many web applications it may not be suitable for everyone. The main disadvantage of the default error controller is that it does not notify developers of the errors that occurred and instead silently logs them. Many enterprise web applications will find this unacceptable and will try to implement their means of solving the issue. In this post I’ll try to show how a more advanced Zend Framework error controller could be implemented to help developers tackle errors quickly.

class ErrorController extends Zend_Controller_Action
{
    private $_notifier;
    private $_error;
    private $_environment;

    public function init()
    {
        parent::init();

        $bootstrap = $this->getInvokeArg('bootstrap');

        $environment = $bootstrap->getEnvironment();
        $error = $this->_getParam('error_handler');
        $mailer = new Zend_Mail();
        $session = new Zend_Session_Namespace();
        $database = $bootstrap->getResource('Database');
        $profiler = $database->getProfiler();

        $this->_notifier = new Application_Service_Notifier_Error(
            $environment,
            $error,
            $mailer,
            $session,
            $profiler,
            $_SERVER
        );

        $this->_error = $error;
        $this->_environment = $environment;
   }

    public function errorAction()
    {
        switch ($this->_error->type) {
            case Zend_Controller_Plugin_ErrorHandler::EXCEPTION_NO_CONTROLLER:
            case Zend_Controller_Plugin_ErrorHandler::EXCEPTION_NO_ACTION:
                $this->getResponse()->setHttpResponseCode(404);
                $this->view->message = 'Page not found';
                break;

            default:
                $this->getResponse()->setHttpResponseCode(500);
                $this->_applicationError();
                break;
        }

        // Log exception, if logger available
        if ($log = $this->_getLog()) {
            $log->crit($this->view->message, $this->_error->exception);
        }
    }

    private function _applicationError()
    {
        $fullMessage = $this->_notifier->getFullErrorMessage();
        $shortMessage = $this->_notifier->getShortErrorMessage();

        switch ($this->_environment) {
            case 'live':
                $this->view->message = $shortMessage;
                break;
            case 'test':
                $this->_helper->layout->setLayout('blank');
                $this->_helper->viewRenderer->setNoRender();

                $this->getResponse()->appendBody($shortMessage);
                break;
            default:
                $this->view->message = nl2br($fullMessage);
        }

        $this->_notifier->notify();
    }

    private function _getLog()
    {
        $bootstrap = $this->getInvokeArg('bootstrap');
        if (!$bootstrap->hasPluginResource('Log')) {
            return false;
        }
        $log = $bootstrap->getResource('Log');
        return $log;
    }
}

The modified error controller is aware of the environment it is running in. It’s likely that depending on the environment you would want to display different layouts with different information. For example while debugging Zend Controller Tests you may want to reduce the amount of HTML appearing in your terminal screen by disabling the layout while running in the test environment. You’ll also notice the Application_Service_Notifier_Error class dependency. This class is responsible for deciding whether to send an email to the developers and gathers potentially helpful information from different sources. You’ll also notice how the dependencies for the notifier are instantiated. It can be done in different ways using dependency injection frameworks, using bootstrap resources and so on. It’s up to you to decide what fits your application better.

class Application_Service_Notifier_Error
{
    protected $_environment;
    protected $_mailer;
    protected $_session;
    protected $_error;
    protected $_profiler;

    public function __construct(
        $environment,
        ArrayObject $error,
        Zend_Mail $mailer,
        Zend_Session_Namespace $session,
        Zend_Db_Profiler $profiler,
        Array $server)
    {
        $this->_environment = $environment;
        $this->_mailer = $mailer;
        $this->_error = $error;
        $this->_session = $session;
        $this->_profiler = $profiler;
        $this->_server = $server;
    }

    public function getFullErrorMessage()
    {
        $message = '';

        if (!empty($this->_server['SERVER_ADDR'])) {
            $message .= "Server IP: " . $this->_server['SERVER_ADDR'] . "\n";
        }

        if (!empty($this->_server['HTTP_USER_AGENT'])) {
            $message .= "User agent: " . $this->_server['HTTP_USER_AGENT'] . "\n";
        }

        if (!empty($this->_server['HTTP_X_REQUESTED_WITH'])) {
            $message .= "Request type: " . $this->_server['HTTP_X_REQUESTED_WITH'] . "\n";
        }

        $message .= "Server time: " . date("Y-m-d H:i:s") . "\n";
        $message .= "RequestURI: " . $this->_error->request->getRequestUri() . "\n";

        if (!empty($this->_server['HTTP_REFERER'])) {
            $message .= "Referer: " . $this->_server['HTTP_REFERER'] . "\n";
        }

        $message .= "Message: " . $this->_error->exception->getMessage() . "\n\n";
        $message .= "Trace:\n" . $this->_error->exception->getTraceAsString() . "\n\n";
        $message .= "Request data: " . var_export($this->_error->request->getParams(), true) . "\n\n";

        $it = $this->_session->getIterator();

        $message .= "Session data:\n\n";
        foreach ($it as $key => $value) {
            $message .= $key . ": " . var_export($value, true) . "\n";
        }
        $message .= "\n";

        $query = $this->_profiler->getLastQueryProfile()->getQuery();
        $queryParams = $this->_profiler->getLastQueryProfile()->getQueryParams();

        $message .= "Last database query: " . $query . "\n\n";
        $message .= "Last database query params: " . var_export($queryParams, true) . "\n\n";

        return $message;
    }

    public function getShortErrorMessage()
    {
        $message = '';

        switch ($this->_environment) {
            case 'live':
                $message .= "It seems you have just encountered an unknown issue.";
                $message .= "Our team has been notified and will deal with the problem as soon as possible.";
                break;
            default:
                $message .= "Message: " . $this->_error->exception->getMessage() . "\n\n";
                $message .= "Trace:\n" . $this->_error->exception->getTraceAsString() . "\n\n";
        }

        return $message;
    }

    public function notify()
    {
        if (!in_array($this->_environment, array('live', 'stage'))) {
            return false;
        }

        $this->_mailer->setFrom('do-not-reply@domain.com');
        $this->_mailer->setSubject("Exception on Application");
        $this->_mailer->setBodyText($this->getFullErrorMessage());
        $this->_mailer->addTo('alerts@domain.com');

        return $this->_mailer->send();
    }
}

This class provides an extensive report providing helpful details in what state the application was when an exception occurred. What’s the IP address of the server (maybe the application is distributed on many servers), what was the time, was it an AJAX request, what was user’s session data, request data.

One of the nice things to have is to be able to tell what was the last database query executed. This is especially useful if some dynamic database query fails or someone is trying to make an SQL injection. The easiest way to achieve this is to use a Zend_Db_Profiler. But the default profiler consumes a lot of server resources and should not be enabled on production environments. To work around this we use a custom dummy profiler that does no profiling at all and just stores the last query information in memory.

class Application_Db_Profiler extends Zend_Db_Profiler
{
    protected $_lastQueryText;
    protected $_lastQueryType;

    public function queryStart($queryText, $queryType = null)
    {
        $this->_lastQueryText = $queryText;
        $this->_lastQueryType = $queryType;

        return null;
    }

    public function queryEnd($queryId)
    {
        return;
    }

    public function getQueryProfile($queryId)
    {
        return null;
    }

    public function getLastQueryProfile()
    {
        $queryId = parent::queryStart($this->_lastQueryText, $this->_lastQueryType);

        return parent::getLastQueryProfile();
    }
}

The custom error controller will only notify developers of errors that occur on production and stage environments to avoid spamming people with exceptions from the unstable development environment. The Application_Service_Notify_Error class is also highly testable. All the dependencies can be mocked, no global variables or constants are used. The class itself could be more refined by employing polymorphism instead of if statements but I believe it’s better to keep the example simple to make it easily understandable.

Depending on which version of the Zend Framework is being used the implementation for the custom error controller may be a little different, but the general idea is the same. In short the advanced error controller provides additional information such as session data, database queries, server variables and also is capable of notifying developers when errors occur on production or stage environments. Please let me know if this is helpful by providing feedback in the comments.

, , , , Hide

Mar/10

9

Avoiding Brittle Tests / Testing Output

While unit tests have benefits they can also cause trouble. Having tests to catch software bugs is great but having tests that break whenever the application is at least slightly changed might not be very pleasant. The latter effect is called brittle tests. It may work well for applications which change rarely but may be counterproductive for applications that change rapidly. Test brittleness can be caused by a variety of implementation details. This post aims to describe few of these details and explain ways how brittle tests can be avoided.

Deciding how detailed the tests should be

It’s important to have an at least general idea what tests should test and what should be left untested. Imagine having to functional test a web application UI displaying a form made of various input fields populated with values coming from the database. Quite a few things could be tested. Are all the values displayed? Are all radios, check boxes, drop-downs properly selected? Are validation messages displayed and are they correct? Are all labels displayed and correct? Are attached javascript events working? Can the form be submitted and is the data passed to the underlying layer? Is the confirmation message displayed?

The more things there are to test more likely that the tests will break not because of a bug but of a minor change. It’s important to pick only the important battles to fight. Even though it’s possible to test a lot of things it may not be practical to do so. It would certainly be possible to run a spelling checker on every displayed word but if it’s not critical to the application it may not be worthwhile to do so. For example testing javascript integration requires use of Selenium. To work with continuous building it would require a Selenium RC server to run all the browsers. Tests recorded by a selenium recorder may be brittle to a slightest HTML structure change unless designed very carefully. While selenium would provide the ultimate functional testing power it might be overkill for a simple web application. Decide what is critical to your application, which things are more likely to break than others and test those things only. Adapt to reoccurring software problems by adding additional tests.

Testing output not implementation

When developing unit tests the most effective way to test is by testing the output of method calls instead of testing the internal implementation. For example testing a simple multiplication function which multiplies a and b is straightforward. More sophisticated units which rely on other units require use of mocks. If possible it’s best to avoid testing that a mock was used or how many times a mock was called and what kind of data it was passed. Otherwise the test is tightly hooked to the internal implementation and is more likely to break when it changes. It comes to the first principle deciding how detailed a test should be. If you are fairly comfortable that the code is less likely to change or break or it’s less critical, hooking deep into the mocks might be avoided. Imagine having to test the following piece of code:

class Notifier
{
    public function __construct(Zend_Mail $mailer)
    {
        $this->_mailer = $mailer;
    }

    public function notify()
    {  
        $this->_mailer->setBodyText('This is the text of the mail.');
        $this->_mailer->setFrom('somebody@example.com', 'Some Sender');
        $this->_mailer->addTo('someone@example.com', 'Some Recipient');
        $this->_mailer->setSubject('TestSubject');
        return $this->_mailer->send();
    }
}

In this case the mock is the _mailer. All it’s method calls could be mocked and tested against that they are called only once and are passed the correct data. In turn that would make the test more likely to break whenever this function is changed. Instead it may be enough to test that function notify() returns true whenever send() returns true. On other hand such a test might seem not sufficient enough and more hooks may be required. For example adding a test for addTo() function call. Or if the functionality is extremely critical an integration test could be created to test that an actual message was sent to the mail server with the correct header and body.

Final Words

In the end it’s a challenge of trying to find the the acceptable balance between testing application functionality and avoiding having too many brittle tests. Try to identify what’s important to your application, and test those things only, prefer testing output of method calls over hooking deeply into implementation. Let your tests work for you and not against you.

, , , Hide

Mar/10

6

PHP Anti Patterns

Another talk I’ve atended at PHPUK 2010 was AntiPHPatterns by Stefan Priebsch. While design patterns are core implementation independent solutions to problems that occur over and over again which also serve as a great vocabulary, anti patterns are software patterns that are ineffective or counterproductive. In his presentation Stefan describes some of these anti patterns:

1. Constantitis. Excessive use of global constants is considered to be a code smell. Global constants can be defined anywhere in the code base, there is a risk of name clashes if a constant is already defined, global constants make the code more coupled, testing gets more complicated since constants have to be known beforehand and defined explicitly which might be even more troubling if a constant has to change it’s value for another test. Since class constants are not global it’s OK to use them. Cure for constantitis is not to use global constants and instead use dependency injection.

2. Globalomania. Global variables share the same problems as global constants. Because global variables can be changed it makes them more dangerous than global constants since a change in one part of the codebase can affect the other without anyone noticing. Global variables can be cured by using dependency injection.

3. Singletonitis. Singleton is one of the most popular design patterns. It’s wide success is due to the fact that singletons by implementation are available globally in the entire application. The problem that singleton design pattern tries to solve is to prevent having multiple instances of the same class. This is rarely the problem in most applications and most singletons are being used as global variables instead. Singletons share the same problems as global constants and global variables and therefore should be avoided. Singletonitis has the same cure as constantitis and globalomania.

4. God classes. According to object oriented best practices classes should do one thing only and do it well. Classes should be refined and granular. One of the ways to think about this is to ask yourself what are the responsibilities of this class. In an ideal case you will be able to describe it in one sentence without any “and’s”. When classes start having too many  responsibilities they become god classes. Usually the whole application relies on one of the god classes which makes the application tight coupled and therefore more difficult to maintain. To cure god classes minimize class responsibilities so that objects know everything about themselves and little about others.

, , , , Hide

Mar/10

4

Lost Art of Simplicity PHP UK 2010

Lost Art of Simplicity by Josh Holmes was the keynote talk at the PHP UK 2010 conference. I found it to be an interesting talk with lots of good advice. While listening to Josh I was able to identify myself in the past participating in all the common software development pitfalls. I would like to share what I consider to be at least some of the most important points from the talk:

  1. Work with your users. Focus on them and their exact needs. As developers we often tend to forget that actual users will be using our systems. We should stop and think is what we’re doing going to fulfill the actual needs of our users.
  2. When deciding which tools to use for a particular problem or a project always carefully weigh all the benefits and downsides to pick the best tools for the job. If for example most of your company’s software is written in PHP and is using MySQL doesn’t necessarily mean that you should keep doing so. It might be that another language such as Python or another type of a data store such as CouchDB might be a better choice for your next project. Developers also like to play with new shiny experimental toys but it doesn’t mean that it’s the best idea for your company to use it for a particular problem.
  3. Do the simplest thing possible. As Albert Einstein once said “Things should be made as simple as possible, but not any simpler”. “Cleverness” might not always be a good solution. Complexity involves more moving parts and more possibilities for things to fail. As developers we tend to think about possible future developments. While it is good to do so it is also important not to over do it. While it may be reasonable to believe that a different caching mechanism might be used for a project that you work on it’s less likely that another database vendor will be used in the future.
  4. Invented here syndrome. It is very likely that any problem you will have will be already solved by many other people before you. If instead of inventing your own solution to the problem you can use someone else’s tools by all means do so. Not every tool might do exactly what you need, not every tool might seem trustworthy enough but there’s no excuse for not trying to find the best available tools.

If you are interested to learn more take a look at Josh’s blog where presentation slides and a full transcript is available.

, , Hide

Find it!

Theme Design by devolux.org