• Using the atkMockDb February 11, 2008

    If you develop an ATK application but do not have the luxury of a separate test-database, and can only test against actual databases, it is not safe to run test cases that actually add records to the database. Even though test cases can be built to clean-up test data afterward, this is not without risk. For instance, when a test case breaks halfway through the code with a PHP parse error, any test data that was already added will stay there. Besides the fact that this can break any future executions of your test case, the test record stays in the live database and possibly break the live site.

    This is where the atkMockDb kicks in.

    What is the atkMockDb?

    The atkMockDb is a normal atkDb class but it doesn’t actually execute any queries on the database. This prevents the problem of executing INSERT or UPDATE queries on a live environment, but it also prevents SELECT queries from returning any data. Since ATK performs quite some database queries in order to execute its functions, we need a way to simulate some results for any query that is executed. The atkMockDb provides just that!

    Configuring the atkMockDb

    Create the test case using the atkTestCase as its base class, so you can use the setMockDb() method to easily configure your test cases to use the atkMockDb.

    Example:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    
    <?php
     
    class test_mynode extends atkTestCase
    { 
        public function test_asimpletestcase() 
     
        {<br>
           $this->setMockDb(); // tell ATK to use it
           // Some tests... 
     
        } 
    }
     
    ?>

    setResult

    When you know the exact query that will be executed, you can set the records that will be returned by the mock database: you can use the setResult method for that purpose.

    Example:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    
    <?php
    // Create a result record
    $record = array('id'=>2, 'name'=>'test');
     
    // The EXACT query on which we want the $record to be returned.
    $sql= "SELECT * FROM mynodetablename WHERE id='2'"; // tell atkMockDb to return the mockRec on the given query.
     
    $db = atkGetDb();
    $db->setResult(array($record), $sql);
     
    // rest of testcase ...  
     
    ?>

    Now whenever ATK tries to execute this exact query, the given record will be returned.

    Final note

    Note that using atkMockDb is not foolproof, it doesn’t guarantee that the syntax of the queries is correct and that MySQL will properly execute the query, you only check if ATK tries to execute the queries, and simulate the result. Test cases for a certain function should only test that function. For example: constrain the tests that check if atkNode::updateDb() is executed properly, to the test cases for atkNode.

    The atkMockDb has some more possibilities such as using regular expressions to determine on which queries certain records should be returned. A more complete howto on using the atkMockDb can be found on the ATK wiki.

  • Backward compatibility, bane of the developer February 7, 2008

    Recently ‘A List Apart’ posted an article about the new X-UA-Compatible switch that Microsoft will be implementing in Internet Explorer 8.

    In short, you can target versions of the IE renderer with the switch; you can say: I want this page to be rendered like IE7 would render it and then IE8 (and IE9 and IE10 presumably) would render it similarly to IE7.

    Now this provoked a lot of reactions, and it got me thinking about one of the most painful subjects among developers (PHP and in general): backward compatibility.

    Why backward compatibility is a problem

    APIs are rarely perfect at first. They require time to mature. Sometimes APIs are just plain flawed when they get used. Anyone who has done webdevelopment for IE is painfully aware of this fact. In new versions we would like to fix these flaws and imperfect APIs; however, if a lot of other sites/applications depend on your initial flawed API, fixing the API will break their functionality.

    Why we MUST HAVE backward compatibility

    Reasons for this depend on the product: for instance IE must have backward compatibility because a large part of the web is old and no longer being maintained; getting these websites to migrate is unrealistic.

    With PHP projects, we can’t change the code in products we use in multiple projects (for instance, the ATK Framework or the Zend Framework) without taking into consideration all other projects that make use of that component.

    Having to fix your project every time a new version of the underlying framework comes out is unrealistic and would be very frustrating.

    What can be done about it?

    1. Think hard about your API

      “To prevent is better than to cure” – Dutch proverb

      First of all, remember when you create something that is meant to last that it should be built to last.

      I have found that unit testing helps iron out the initial imperfections: be the first to use your code in as much ways as you can, before you release it.

      Positive: If it is done right the first time, backward compatibility is not a problem.
      Negative: Utopian; APIs will change, but striving for a perfect API is recommended.

    2. Incubation
      I like the approach of the Zend Framework: make the functionality available in a special way, marking it as ‘unstable’ and once it has matured, integrate it with the rest of the functionality.

      Positive: APIs can mature at their own pace.
      Negative: If you use incubator functionality for your project, you still have to patch your application once the functionality migrates to the trunk. And even though an API may have survived the incubator, it may still need to be changed at a future date.

    3. Deprecation

      Mark old API/functionality as deprecated (and warn users that they are using something that is deprecated) so that hopefully, in the future once no one uses the functionality, you can remove it.

      Positive: Your application will support both the new API as well as the old one for some time, easing transition.

      Negative: Not all changes lend themselves to this approach (all changes to a particular method would require a completely new method), your API gets ‘bloated’ with deprecated methods and upgrading very old projects will still require an upgrade path.

    4. Versioning

      Version x of product y works with version x of product z. The approach that IE took in the given example.

      Positive: Full backward compatibility.
      Negative: Increases complexity and maintenance dramatically, every time you make a change in your API and release it you are creating a new version you have to maintain. Only works for products which have very few releases.

    5. Upgrade paths

      Break backward compatibility but notify the user who wants to upgrade what needs to be changed.

      Positive: Easier for the developer.
      Negative: Makes upgrading projects an (often arduous) chore.

    6. Reboot

      The developer favorite, abandon the old code and start again, without promises of backward compatibility.

      Positive: No more problems associated with backward compatibility.
      Negative: Users/projects can’t migrate any more; causes animosity among users and clients.

    7. More?

      Unfortunately there is no one way to keep a product backward compatible, you usually end up using a combination of the above mentioned methods: Striving for the best possible API from the get go, but easing transition from the old to the new API if you do have to make changes.

    For more info about backwards compatibility a good starting point is the English Wikipedia article.

  • The usability of a use-case February 4, 2008

    A impressive website is not only nice to look at and packed with technological wizbang, but is also usable. Usable not only by the people who wrote it, but by the actual users that are going to visit the site.

    This is why it’s important to think about usability while designing a website, while building the functionality and while putting in the content and the final tweaks.

    A good way to analyze the usability of a website is by asking yourself questions about the visitor; Why did they stumble upon the site? What are they expecting? What can they do once they get there, and how can we communicate that as fast as possible.

    (more…)