Crisp Home

Alexander Tarnowski

Alexander Tarnowski

Professional Software Development

Slides from the Selenium Conference

I gave a presentation called ”Being good at waiting – Using Selenium to test Ajax-intensive pages” in an unconf session at the Selenium Conference in London.

The audience was great! Thanks everybody! I certainly didn’t know everything there’s to know about the subject, and that resulted in an interactive session where people from the audience would share their experience and answer some questions. That was so cool :)
read more »

Is your system a black box?

Surprisingly often an organization exposes itself to a multitude of risks by not knowing enough about its systems, infrastructure, and applications. This doesn’t manifest itself as a lack of “enterprise architecture” documents (while some could help). The implications are far more down-to-earth. Does any of this sound familiar?

  • Upgrading both hardware and software is unproportionally difficult and the outcome isn’t predictable
  • There exist tasks that must be performed by a specific person
  • There exist artifacts that everybody thinks need to be there, but no one dares to touch, delete, or upgrade
  • Introduction of new employees is difficult

read more »

Learning, understanding, and horizontal development

As developers feel the daily pressure to deliver, they tend to skip a crucial step in the process: learning and understanding the system. There’s a huge difference between just adding more lines of code to the codebase and making changes that maintain the conceptual integrity of the system.

Horizontal development is the result of not spending enough time learning and understanding the system you’re working on. By starting to churn out code too soon, you’ll inevitably be adding silos of functionality in parallel to existing functionality.

The outcome is legacy code. It doesn’t matter how well factored it is, and what test coverage it has!

read more »

The link between testability and object-orientation

If you do TDD or write unit tests you soon start to feel reluctant about parameters and scalar data types. Why?
Consider the function below. Is it easy to test? Would it be created if TDD were used?


bool result = f(int p1, long p2, Object p3);

Pretend that the function above lives in a business layer and determines whether a customer can get a discount a particular month given a set of conditions embodied in the object otherConditions. Thus the above could be rewritten as:

bool eligibleForDiscount = canCustomerGetDiscount(int month, long customerNumber, Object otherConditions);

Without thinking about it, we would most likely refactor it by introducing types for month and customer number. This would save us from cluttering the first lines of the function with code related to checking the validity of those parameters. Some people would call this object-oriented programming, others would stretch as far as calling it domain-driven design. Irrespectively of the term chosen, the function above would most likely be refactored into something like:


bool eligibleForDiscount = canCustomerGetDiscount(Month month, CustomerNumber customerNumber, Object otherConditions);

While at it, we would probably discover that this code needs to live in a context, and we would place it in a class that handles business rules related to discounts. That class, whatever its name and function, would assume the responsibility of handling discounts, which would make the otherConditions parameter unnecessary. Of course this parameter was never actually an Object, rather another class in the business domain. However, I didn’t want to complicate the example.


bool eligibleForDiscount
= discountManager.canCustomerGetDiscount(Month month, CustomerNumber customerNumber);

At this point we could feel quite happy about the function.

  1. It has a good name
  2. Its invocation honors the Single Responsibility Principle (SRP), as the DiscountManager’s only responsibility seems to be handling discounts, while validation and domain-compliance are handled in Month and CustomerNumber.
  3. It doesn’t take too many parameters
  4. It feels quite testable (based on its signature, at least)

But what did we actually do to make this happen? Is there a way to formalize these refactorings?

It turns out there is, although we have to borrow a definition from the testing domain.
I came across an article that mentions quite an interesting metric: The Domain-to-Range Ratio. It’s defined as the cardinality of the domain of the specification over the cardinality of the range:

DRR = |D| / |R|

Without being too formal about it, we can say that the lower the DRR, the better. For example:
|D| = cardinality of a 32-bit integer type, |R| cardinality of a 1-bit boolean type, which would produce a function like f(int32) → bool

Is that testable? How many unit tests do you need to make sure that the function behaves correctly? One, ten, or 232?

Returning to the discount function, we see that its DRR would be a scalar product of cardinalities in the magnitude of 232, 264, and the combined DRR of all members of otherConditions that are queried by the function.

While it’s not apparent how complex the condition object actually is (it could be as simple as a boolean flag), we see that introducing a Month class reduces the cardinality of the first parameter from 232 to 12, and that introducing a CustomerNumber class at least halves the cardinality of the second, as customer numbers are most likely not negative.

In this light, we see that refactorings like:
Scalar → enum, Scalar → object, Remove parameter, start making sense in a formal sort of way.

It also happens that such refactorings make the code object-oriented…