Sunday, January 29, 2012

Type hinting is bad!

Type hinting is bad..if it's done wrong.

Type hinting was introduced in PHP 5 allowing you to force parameters to be specific types of objects or an array. At first glance this is great because of the built-in support for type validation. In the example below there's a type hint on the function transport forcing $car to be of type Car.
class Car {
 public function load(array $cargo) { ... }

 public function go() { ... }
}

function transport(Car $car) {
 $cargo = array('groceries', 'children', 'misc items');
 $car->load($cargo);
 $car->go();
}

$car = new Car();
transport($car);
We can use $car without have to write code to check it's type. A fatal error is thrown if $car is not an instance of type Car.

The problem with this style of programming is you're sacrificing one of the biggest strengths of PHP: the ability to duck type. After all this time of programming with a dynamic language why have we become so concerned with types? Had we not put a type hint on the transport function the code would have still worked. Let's remove the Car type hint.
function transport($car) {
 $cargo = array('groceries', 'children', 'misc items');
 $car->load($cargo);
 $car->go();
}

$car = new Car();
transport($car);
This is better because it is more flexible. $car can be anything as long as it can load() and go(). You can change $car to be a Van and you'll still get your cargo safely loaded and transported assuming Van can load() and go().
$car = new Van();
transport($car);

Can't you use inheritance in this case and still utilize type hinting?
Inheritance could be used and the function would take advantage of subtype polymorphism.
abstract class Vehicle {
  abstract public function load(array $cargo);
  abstract public function go();
}

class Car extends Vehicle { ... }

class Van extends Vehicle { ...}

function transport(Vehicle $vehicle) {
 $cargo = array('groceries', 'children', 'misc items');
 $vehicle->load($cargo);
 $vehicle->go();
}

$vehicle = new Van();
transport($vehicle);
This is still not ideal. What if you wanted to use something other than a Vehicle to do your transportation (e.g. Boat, Train, or Horse and Wagon)? To make this code more reusable we should follow an object-oriented design principle: "Program to an interface, not an implementation". Fundamentally we don't care what an object is; instead we care about what an object can do.
interface ITransporter {
  public function load(array $cargo);
  public function go();
}

class Car implements ITransporter { ... }

class Van implements ITransporter { ... }

class Horse implements ITransporter { ... }

function transport(ITransporter $transporter) {
  $cargo = array('groceries', 'children', 'misc items');
  $transporter->load($cargo);
  $transporter->go();
}

$transporter = new Horse();
transport($transporter);
If you wanted maximum flexibility why even put an object or interface type hint? As long as the parameter can load() and go() the transport function should work. The type hint validation is only enforced at runtime. If an object was passed into the transport function that didn't have a load or go method you would still get a fatal runtime error. It seems like the type hint isn't useful.
That's almost completely true. There is a subtlety. Using a type hint would error sooner. This may or may not be important to you.
function transport(ITransporter $transporter) {
  $cargo = getCargo();
  $transporter->load($cargo);
  $transporter->go();
}
In this example, what if getCargo() uses an external service like a database connection or a web service. It's nice to know $transporter can load() and go() before using resources to getCargo(). If $transporter didn't support the necessary interface then an error would be thrown immediately and no resources would be wasted. It's up to you to decide which is more important: the ability to error early or the flexibility of using duck typing.
I use type hinting because my IDE uses it to provide code completion.
You can use annotations and/or interface type hinting and your IDE will provide code completion. You don't have to sacrifice good object oriented design for the sake of your IDE.

Thursday, April 7, 2011

Ruby Koans: Greed Dice Game

I was working on the Greed dice game in the Ruby Koans. My goal was to come up with an algorithm that was elegant, readable, and rubyesque. This is what I came up with:

def score(dice)
  score = 0
  points = Hash.new(0)
  points[1] = 100
  points[5] = 50
  
  counts = Hash.new(0)
  dice.each { |number| counts[number] += 1 }

  counts.each do |number, count|
    if count >= 3
      if number == 1
        score += 1000
      else
        score += (number * 100)
      end
      count = count - 3
    end
    
    score += points[number] * count
  end
  
  score
end



If you're not familiar with the ruby koans, here's the link to the path of enlightenment: Ruby koans

Friday, January 28, 2011

QUnit tests under Continuous Integration

My team is addicted to writing unit tests and our CI is always hungry for more. So we decided to write unit tests for our javascript. There are a lot of choices of javascript testing frameworks. We chose to go with QUnit mostly because we use jQuery. Writing the QUnit tests were really easy and fun. Now we wanted to take it further and run our QUnit tests within our TeamCity Continuous Integration. To run the QUnit tests we wanted to use Selenium to open up the web pages with our tests and parse the results. I googled around to find if anyone else had already solved this problem, but the closest result I found was someone who used Watir instead.

http://www.lostechies.com/blogs/joshuaflanagan/archive/2008/09/18/running-jquery-qunit-tests-under-continuous-integration.aspx


Learning from the lost techies example, I wrote a parser using Selenium. I have a QUnit class which extends my Selenium class. The QUnit base class opens the supplied webpage with the QUnit tests using Selenium, reads all the html results, converts it to xml, traverses the xml and parses the results. This simply checks to see all your qunit test results pass. If one of them fails the entire Selenium test fails.

Here is the base class for all my QUnit tests:
using System;
using System.Collections;
using System.IO;
using System.Text;
using System.Xml;
using System.Xml.XPath;
using NUnit.Framework;
using TidyNet;

namespace MyProject.UI.Tests {
 [TestFixture]
 public abstract class QunitTest : SeleniumTest {

  public string WebPage;

  [SetUp]
  public override void SetUp () {
   base.SetUp();
  }

  [TearDown]
  public override void TearDown () {
   base.TearDown();
  }

  public void RunQunitTests () {

   Selenium.Open(WebPage);
   var tests = GetQUnitTestResults();

   foreach (UnitTest test in tests) {
    Assert.IsTrue(test.pass, test.message);
   }

  }

  protected IEnumerable GetQUnitTestResults () {
   var html = new StringBuilder("<" + "html>"); //I can't have an html tag in my blogger post :X
   html.Append(Selenium.GetHtmlSource());
   html.Append("<" + "/html>");
   var xml = convertToXML(html.ToString());
   var stream = new StringReader(xml);
   var xmlReader = new XmlTextReader(stream);
   var xpathDoc = new XPathDocument(xmlReader);
   var xpathNav = xpathDoc.CreateNavigator();
   var nodeIterator = xpathNav.Select("//ol[@id='qunit-tests']/li");
   var unitTests = new ArrayList();
   try {
    while (nodeIterator.MoveNext()) {
     var testResult = new UnitTest {
      pass = nodeIterator.Current.GetAttribute("class", "") == "pass"
     };
     nodeIterator.Current.MoveToFollowing("span", "");
     testResult.module = nodeIterator.Current.Value.Replace(Environment.NewLine, " ");
     nodeIterator.Current.MoveToFollowing("span", "");
     testResult.testName = nodeIterator.Current.Value.Replace(Environment.NewLine, " ");

     if (!testResult.pass) {
      nodeIterator.Current.MoveToParent();
      nodeIterator.Current.MoveToFollowing("ol", "");
      var messages = nodeIterator.Current.SelectDescendants("span", "", false);
      messages.MoveNext();
      testResult.message = messages.Current.Value.Replace(Environment.NewLine, " ");
      messages.MoveNext();
      testResult.expected = messages.Current.Value.Replace(Environment.NewLine, " ");
      messages.MoveNext();
      testResult.actual = messages.Current.Value.Replace(Environment.NewLine, " ");
     }

     unitTests.Add(testResult);
    }
   } catch {

   }

   return unitTests;
  }

  private string convertToXML (string html) {
   var tidy = new Tidy();

   /* Set the options you want */
   tidy.Options.DocType = DocType.Omit;
   tidy.Options.DropFontTags = true;
   tidy.Options.LogicalEmphasis = true;
   tidy.Options.Xhtml = true;
   tidy.Options.XmlOut = true;
   tidy.Options.MakeClean = true;
   tidy.Options.TidyMark = false;

   /* Declare the parameters that is needed */
   var tmc = new TidyMessageCollection();
   var input = new MemoryStream();
   var output = new MemoryStream();

   byte [] byteArray = Encoding.UTF8.GetBytes(html);
   input.Write(byteArray, 0, byteArray.Length);
   input.Position = 0;
   tidy.Parse(input, output, tmc);

   string result = Encoding.UTF8.GetString(output.ToArray());
   return result;

  }

 }
}



Here is a test which utilizes my QUnit base class:



Putting our javascript unit tests into our CI process has been extremely valuable. We've caught multiple javascript bugs within seconds of a bad js check in. If anyone is doing any cool stuff with QUnit or Selenium and continuous integration I'd love to know.

Tuesday, August 10, 2010

Best advice for giving a presentation


I googled for tips on public speaking and on the first page of links less than half of them had this tip. If they had this tip, it wasn't listed at the top and wasn't emphasized as much as it absolutely needs to be. It's not about the background color of your slides, it's not about trying to insert a joke to keep your audience's attention, or how you should imagine everyone in their underwear. In fact the best advice doesn't even take place during your presentation.

It happens before your presentation. I'll let you in on it...

PRACTICE

I have to give credit to author and speaker Scott Berkun for enlightening me on this subject. I highly recommend reading his book Confessions of a Public Speaker. Basically the advantage a speaker has over the audience is they know what is coming next. Speakers can emphasize this advantage by practicing. Go over your slides. Stand up and speak to each and everyone of them to make sure they make sense and clearly illustrate your point. If you can, try to practice in the same room or venue you'll be presenting in. This way you'll know how much energy and volume you'll need to be able to project to the whole room. You'll know if there's any gotchas with setting up the projector, what to set your screen resolution to, if you need to bring your mac dongle, if you'll be needing a mouse, or if you'll have access to wifi.

There's been so many presentations I've seen where presenters assume everything will go right and end up wasting ten to fifteen minutes of the audience's time configuring their machine, flipping back and forth to find the right slide, or apologizing for not knowing how to right click on their track pad. Don't be apologetic! Every time you apologize I stop listening to you and I spend the next two minutes of my life irritated wondering why you didn't spend two minutes to prepare for this. Sure there's room for error, but if you practiced enough you'll be able to avoid all the big avoidable mistakes and know how to recover back into your presentation.

If you take the number of people attending your presentation and multiply that by the length of your presentation (e.g. 10 people x 1 hour = 10 hours), practicing is a small investment in comparison to how much time people are investing in you.

Wednesday, July 21, 2010

Selenium, XPath, and Firebug

Armed with Selenium, Xpath, and Firebug you're ready to automate almost any web test case. Looking at the Selenium Reference guide most of the actions take a locator. The easiest locator to use is the id attribute of the element you are performing the action on. If you or you're team are developing with automated web tests in mind, then there should be an id on all the significant elements. If there is no id on the element, don't fret you can use my next favorite locator: XPath.

Here's a tutorial to XPath if you are not familiar with the language.

...

Okay so now you've got your selenium script and the xpath of that link inside the table you want to click (for example). You run your selenium script and it errors saying the element you're trying to click does not exist or could not be found. You go back to your script and try to figure out what's wrong with your XPath expression

selenium.click("//table/td/a[contains(.,'Important link')]");

In my head I'm thinking "Click on the cell that contains the link that says Important link". What the heck is wrongs with this code?!? After trial and error you figure out it's missing the tr in the path

selenium.click("//table/tr/td/a[contains(.,'Important link')]");

When I first started with XPath and Selenium I would spend hours developing the XPath expression, run the selenium test, watch it fail on the XPath command, edit it, and repeat till it worked. This was an inefficient use of time and brain power.

That's when Firebug came in to save the day. Firebug has an awesome console where you can do javascript debugging and object inspection. Using the console you can test your XPath expression and determine if the element actually exists before putting it into your selenium script. To use it navigate to the page you want to test and then open up firebug. Click on the console tab, then click on the little red triangle pointing upward to expand the console. Inside the console you can write javascript to evaluate your XPath expression. Fortunately firebug comes with a built in function that evaluates XPath expressions, $x.

Here's the snippet of code I use

var node = $x( [your xpath expression here] );
console.dir(node);

Click run and if your XPath is valid it should return the dom element allowing you to inspect it. If your XPath is invalid it won't return anything. Here's a screen shot





Now you can test your XPath independently of your selenium script and be sure that your locator is correct. This will save you lots of time and increase your confidence in what your selenium actions are doing.