The Developer Day | Staying Curious

Jun/10

26

Expert Python Programming Book Review

Expert Python Programming BookI’ve finished reading Expert Python Programming written by Tarek Ziade. This book is written for Python developers who wish to go further in mastering Python. Expert Python Programming covers a range of topics such as generators, meta programming, naming standards, packaging, continuous integration, writing documentation, test driven development, optimizations and design patterns. Even non Python developers will find this book useful since it covers best practices which are well suited to other programming languages.

There’s a sample chapter available which covers the topic of documentation. We all know how frustrating it is to write documentation. It’s boring, often it feels pointless and it tends to get out of date. The 7 rules of technical writing presented in the book changed my mind. It’s actually one of my personal favourite chapters in the book.

The first chapter of the book is very friendly and covers installation of many Python flavours, packaging tools such as EasyInstall and setuptools, prompt customization and choices of editors.

While the first chapter is very easy going the second chapters dives deep into syntactic intricacies of Python with it’s iterators, generators, decorators and context providers. If the second chapter won’t make your head spin then the third one on class level Python best practices certainly will. Author of the book does a great job at explaining the pitfalls of multiple inheritance, inconsistent super usage, Python’s method resolution order and finally meta programming which allows to change classes’ and objects’ definitions on the fly.

The rest of the book is a lot less confusing but nonetheless rewarding. Chapter four gives some very good advice on naming standards, building API’s and tools that ease might help along the way. Chapter five explains how to create python packages, distribute and deploy them.

What I really like in every book is examples. One example can explain more than a thousand words could. The examples in the second and third chapters are very valuable and help greatly to understand the concepts explained. The book goes even further and provides a complete example of a small application called Atomisator. This example is implemented following the best practices of previous five chapters.

Chapters eight and nine will be very interesting to team leads which explain distributed version control systems such as Mercurial, continuous integration and managing software in an iterative way.

Another very important topic on Test Driven Development or TDD is presented in chapter eleven. I cannot emphasize enough how valuable test driven development is. Though even today it’s not a widely adopted practice and not a well understood one either. This book will try to convince you why you should be doing TDD and if you’re already convinced it will present you with tools that you can use to do TDD. I was very interested to find out about the available unit testing framework alternatives. Further an interesting idea on doc testing is described which while seems a little exotic may be a very efficient way to keep your documentation up to date.

Reading further there’s a great chapter on optimization which describes general principles of optimization and various profiling techniques. Measuring performance may prove difficult on different hardware such as local development machines and stage servers. I was very intrigued to find out about pystones and the general concept behind it which helps to deal with the problem described.

Together with optimization techniques, various profiler tools which you never knew of, the book describes some generic optimization solutions available. Some are well known such as the Big-O notation, some are less known such as Cyclomatic Complexity. I think this book explains the concepts behind multi threading, multi processing and caching very well. Making an informed decision whether to use threads or multi processes for your Python application may as well mean if it’s going to be successful or not.

And finally the last chapter talks of design patterns. While it’s not the most mind blowing chapter of the book it provides some very interesting details why Python doesn’t have interfaces or how certain GoF patterns can be implemented in a Python specific way.

Conclusion

Should you read this book? My answer is yes. Especially if Python earns your bread and butter. Not only you will know the syntactic intricacies of python it will introduce you to many must know concepts of software development. Even if you’re not a day to day Python developer but you do write an occasional Python script or application by all means read the book and read the first six chapters. I will go even further and recommend this book to non Python developers. Simply because it explains concepts that every developer should understand. And as an extra it is always interesting to learn new ideas and to see how things can be done differently.

, , Hide

Jun/10

22

DDD Resources / Papers / Presentations

Jun/10

21

What is DDD or Domain Driven Design?

Domain Driven Design can be described as a philosophy based on domain modelling. More accurately it may be be described as a very large body of patterns and pattern language in its own right. The term Domain Driven Design or DDD was coined by Eric Evans the author of the book Domain-Driven Design: Tackling Complexity in the Heart of Software also known in the DDD community as the “blue book”.

Understanding the DDD philosophy

The Domain Driven Design philosophy states:

  • Most software projects should focus on business domain
  • Complex domain designs should be based on a model

To understand the meaning of these statements one has to understand the meaning of domain and model.

Domain is a sphere of knowledge, influence or activity. The subject area to which the user applies a program is the domain of the software. In other terms if you work for a bank then banking is your domain.

Model is a system of abstractions that describes selected aspects of a domain and can be used to solve problems related to that domain. For example a map is a model designed to solve a specific problem. A treasure map shows how to find a treasure, a political map shows the borders of countries. A model is a simplification. It is an interpretation of reality that focuses on the problem at hand and ignores the extraneous detail.

Models are designed to be useful to solve domain specific problems. For example in the past the universe was viewed in a geocentric way where the universe revolves around Earth. Heliocentric model is another astronomical model in which the Earth and planets revolve around a stationary Sun at the centre of the universe. Even though geocentric model is not realistic it is a valid model in it’s own right designed to solve a problem – the human desire to be in the centre of everything. It’s not a useful model when it’s used to compare planet movements.

Domain Driven Design advocates designing software systems to reflect the domain model in a very literal way, so that the mapping is obvious, also revising the model continuously and modifying it to be implemented more naturally in software. To tie the implementation to a model well requires tools and languages that support a modelling paradigm, such as object-oriented programming.

A well mapped implementation of a model usually expresses an object model that incorporates both behaviour and data. A decomposed domain model consists of common building blocks: entities, aggregates, value objects, services and factories.

Essential Principles of DDD

The greatest value of a domain model is that it provides a ubiquitous language that ties domain experts and technologists together. Ubiquitous language is a language structured around the domain model and used by all team members to connect all activities of the team with the software. It’s a shared, versatile language between team members and domain experts. A well designed model speaks to the developers through the ubiquitous language. It’s important to understand that a change in the model is a change in the language and vice versa.

When multiple models are in play on a large project it’s beneficial to define bounded contexts where these models apply. A bounded context is a linguistic boundary marking the applicability of distinct models. Usually a subsystem or work owned by another team. For example in a typical e-shop web application a sales reporting application could be defined as a separate bounded context.

Every domain consists of subdomains. For example a very common subdomain is billing. Such a subdomain is usually not the driving part of the domain and therefore not as important. It is harsh reality that not all parts of the design are going to be equally refined therefore priorities must be set. DDD suggests distilling the core domain by distinguishing it from other generic subdomains and applying the top talent to work on it.

Conclusion

DDD helps projects to develop a strong internal language, define clear context boundaries, and focus on the core domain. Domain Driven Design brings structure and cohesion into domain modelling which are much appreciated features of any software project in existence. The blue book has been released six years ago and since then it influenced many developers. Yet I feel it hasn’t reached it’s momentum. One can only hope it will reach widespread adoption.

Update: I’ve added a list of available DDD resources such as papers and video presentations.

, , Hide

Apr/10

17

PHPUnit email integration testing using Sendmail

One of the problems when doing functional or integration testing is testing that emails are being sent out with a correct header and body. One such scenario could be a controller action which sends a password reset confirmation email and redirects to another action.

A common way to solve such a problem is to configure the local MTA to store the test emails on the file system. The following shows how this could be done using sendmail. First create a sendmail alias by editing a file located at /etc/mail/aliases and adding a line bellow other aliases:

test-mail: “| cat > /tmp/test-mail”

This tells sendmail that all incoming emails to test-mail will be written (not appended) to /tmp/test-mail. Sendmail needs to be restarted for the changes to take effect.

sudo /etc/init.d/sendmail restart

Depending on the situation it may be necessary to add the user who is going to be reading emails (for example apache) to the mail group.

sudo /usr/sbin/usermod -G mail apache

Now using PHP it should be possible to do this:

$ok = mail('test-mail', 'Hello world!', 'I am an email.');
var_dump($ok);
echo file_get_contents('/tmp/test-mail');

Further PHPUnit could be extended to add the following method to the base test case class:

public function assertEmail($attributes, $emailFilePath, 
$message = '', $delta = 0, $maxDepth = 10, 
$canonicalizeEol = FALSE, $ignoreCase = FALSE)
{
    $mailParser = new Company_Product_MailParser;
    $mailData = $mailParser->parseFile($emailFilePath);

    foreach ($attributes as $attribute => $value) {
        $constraint = new PHPUnit_Framework_Constraint_IsEqual(
            $mailData[$attribute], $delta, $maxDepth, $canonicalizeEol, $ignoreCase
        );
        $this->_test->assertThat($value, $constraint, $message);
    }

    if (is_file($emailFilePath) && is_writable($emailFilePath)) {
        unlink($emailFilePath);
    }
}

The mail parser class name explains itself:

class Company_Product_MailParser
{
    public function parseFile($mailFilePath)
    {
        $emailBody = file_get_contents($mailFilePath);
        $attributes = array(
            'to' => '',
            'from' => '',
            'date' => '',
            'subject' => '',
            'body' => ''
        );

        foreach (array_keys($attributes) as $attribute) {
            if($attribute  == 'body') {
                if (preg_match("/\n\n(.*)/", $emailBody, $matches, PREG_OFFSET_CAPTURE)) {
                    $offset = $matches[1][1];
                    $attributes[$attribute] = quoted_printable_decode(substr($emailBody, $offset));
                }
            } else {
                if (preg_match("/" . ucfirst($attribute) . ": (.*)\n/", $emailBody, $matches)) {
                    $attributes[$attribute] = $matches[1];
                }
            }
        }

        return $attributes;
    }
}

Important notice. Sendmail may not immediately send the email and it may take a few seconds for the file to appear. It may require you to add a sleep for a few seconds before the email file appears. If you find a way how it is possible to make sendmail send an email immediately please let me know.

Hide

Apr/10

15

Skinny Controllers and Fat Models

Most of the modern web application frameworks follow the MVC design pattern. It’s probably one of the most misunderstood design patterns in existence. There are a lot of discussions what kind of responsibilities each letter holds. Common misinterpretation in MVC is regarding the letter M.

The Model should be understood as a domain model. Meaning a collection of domain objects. Usually an application has one model that is the domain model. Models are often mistakenly referenced to as singular domain entities. For example an Order, a User or an Account. This leads unwary developers to common application design problems.

It’s common to see a web application to have a directory named “models” with class files inside it. Upon closer inspection one can often find that those classes are the nouns of the application. For example those nouns could be a User, an Order or a Product. In this scenario the MVC Model stands for singular application entities.

Problems start to surface when an application developer has to create reports, do input validation or to implement an ACL. These kind of problems don’t naturally fit into entities. For example getting a report of top 10 products doesn’t naturally fit into any entity. Validating a complex search filter made out of multiple input fields also doesn’t fit into any of the entities.

It’s common to see developers adding logic that doesn’t fit anywhere naturally to controller classes or somewhat close entities. For example adding a top 10 products report to an Order entity class as a static method call. Or validating complicated search filters inside controller actions.

In time this steadily leads to bloated controller and entity classes that later on become fat spaghetti dishes. Controller classes containing thousands of lines of code with more private methods than public ones, entity classes with few state changing methods and hundreds of lines long SQL report queries with joins to 10 tables.

To prevent this from happening it is crucial to understand what controller and model stands for. A controller’s responsibility is only to receive input and initiate a response for the view by making calls on model objects. This means that controllers should be very light and skinny. Usually doing nothing else just instantiating classes, getting data from the domain objects and passing it to the view. Model is not a singular entity and can consist of an entire web of interconnected domain objects. The definition fat model means having as many domain objects as needed. Be it reports, validators, filters, entities, strategies and so on.

, , , , , Hide

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

<< Latest posts

Older posts >>

Find it!

Theme Design by devolux.org