Subjective Opinions on Objects

11th January, 2019

This year I've been trying to practice functional programming, in languages such as Scala and Haskel, but also looking for opportunity to apply these patterns in PHP and JavaScript.

I have used object oriented programming for the past few years and considered it superior to procedural code. It makes large complicated spaghetti code small and modular, only having to consider small pieces of logic or data at a time, and encapsulates behavior with data types. It is also useful because it enables one to use a more abstract type system and forget about implementation details. But I haven't until recently considered the cost or trade offs associated. There are some interesting videos by Brian Will posted below. The titles seem click-bait-y and I don't necessarily agree with all of his opinions; but he does provide some compelling arguments against OOP, namely that state and managing multiple states is hard and error prone. He takes some example OO code and redactors it to use functions and nested functions. This is something that I have started to use more in Haskell; Haskell has temporary variables defined in other functions with let or where keywords. What I mean is that they are scoped variables or nested functions to another function. This makes it easier to write more comprehensible and clearer functions, thinking about smaller parts of a problem, without introducing fluff and polluting the global namespace.

I'm a fan of Rich Hickeys talks (he is the creator of the Clojure programming language). He describes systems as parts that take information in and return information out. His advice for handling data is that 90% of the time, a map [hash or associative array] is good enough. Leverage the fact that you can use generic manipulation built into the language. He argues that whilst we use OOP to help with encapsulation, information itself doesn't have behavior, so there should be no functions or methods to encapsulate! Instead just functions that transform data from one state to another.

As an exercise, a colleague and I tried to refactor an existing OO code base of his. It had 20 classes in the src/ directory alone, plus 10 spec files and several feature files. We tried to distill the package to what it actually does (which happened to be verifying a PayPal instant payment notification or IPN) and were able to reproduce most of the functionality in a 3 line function and a single test file. This was a huge difference, and just highlighted to me how frequently I must over-engineer my solutions to problems in code.

I haven't decided that all OOP is inherently bad (just yet) but I am looking at alternative ways to model my domain in a more functional way.

Object-Oriented Programming is Bad - Brian Will

Object-Oriented Programming is Embarrassing: 4 Short Examples - Brian Will

Rails Conf 2012 Keynote: Simplicity Matters by Rich Hickey

Tagged: design oop


Code Kata - Binary to Decimal

11th January, 2019

Here is a nice little code kata - I've implemented it in JavaScript and Haskell, which I'm learning at the moment.

Given a binary string representation of a number, return its decimal value.

Here's the numbers 0 to 10 represented as base 2 (binary):

'0' // 0
'1' // 1
'10' // 2
'11' // 3
'100' // 4
'101' // 5
'110' // 6
'111' // 7
'1000' // 8
'1001' // 9
'1010' // 10

The first time implementing this my colleagues and I came up with some lengthy implementation, just to get our tests to pass. By the time we'd gotten to test 4/5 the code duplication became quite clear and we were able to refactor it out, as is the third step of TDD.

Here is my javascript test file. I used Tape as a test framework

var test = require('tape'),
    bin2dec = require('./bin2dec')

test(function (t) {
    t.equal(bin2dec('0'), 0);
    t.equal(bin2dec('1'), 1);
    t.equal(bin2dec('10'), 2);
    t.equal(bin2dec('11'), 3);
    t.equal(bin2dec('100'), 4);
    t.equal(bin2dec('101'), 5);
    t.equal(bin2dec('110'), 6);
    t.equal(bin2dec('111'), 7);
    t.equal(bin2dec('1000'), 8);
    t.equal(bin2dec('1001'), 9);
    t.equal(bin2dec('1010'), 10);
    t.end();
});

And this is the final implementation we came up with

module.exports = (binaryString) => 
    Array.from(binaryString).reduce((acc, current) => acc * 2 + Number(current), 0)

That's pretty concise, especially using some ES6 features like anonymous functions and implicit returns.

Here's how the test code looks in Haskell:

import Test.HUnit (Assertion, (@=?), runTestTT, Test(..), Counts(..))
import System.Exit (ExitCode(..), exitWith)
import Bin2dec (bin2dec)

exitProperly :: IO Counts -> IO ()
exitProperly m = do
  counts <- m
  exitWith $ if failures counts /= 0 || errors counts /= 0 then ExitFailure 1 else ExitSuccess

testCase :: String -> Assertion -> Test
testCase label assertion = TestLabel label (TestCase assertion)

main :: IO ()
main = exitProperly $ runTestTT $ TestList
       [ TestList bin2DecTest ]

bin2DecTest :: [Test]
bin2DecTest =
  [ testCase "zero" $
    0 @=? bin2dec "0"
  , testCase "one" $
    1 @=? bin2dec "1"
  , testCase "two" $
    2 @=? bin2dec "10"
  , testCase "three" $
    3 @=? bin2dec "11"
  , testCase "four" $
    4 @=? bin2dec "100"
  , testCase "five" $
    5 @=? bin2dec "101"
  , testCase "six" $
    6 @=? bin2dec "110"
  , testCase "seven" $
    7 @=? bin2dec "111"
  , testCase "eight" $
    8 @=? bin2dec "1000"
  , testCase "nine" $
    9 @=? bin2dec "1001"
  , testCase "ten" $
    10 @=? bin2dec "1010"
  ]

and here's the implementation:

module Bin2dec (bin2dec) where

import Data.Char

bin2dec :: String -> Int
bin2dec = foldl (\acc x -> acc * 2 + digitToInt x) 0

Not bad! Do you have any other solutions that you think are more readable? Which do you prefer?

I must say I prefer the Haskell implementation, but I definitely prefer the JavaScript test file! I'll have to have a look at HUnit to see if I can write something simpler...

UPDATE: Added Scala Implementation

def bin2dec (binaryString: String): Int = {
  binaryString.foldLeft(0)((acc, char) => acc * 2 + char.asDigit)
}

This is basically the same implementation but different language.

"1010"                              // String = 1010
"1010".toList                       // List[Char] = List(1, 0, 1, 0)
"1010".toList.map(_.toInt)          // List[Int] = List(49, 48, 49, 48)
"1010".toList.map(_.toString)       // List[String] = List(1, 0, 1, 0)
"1010".toList.map(_.toString.toInt) // List[Int] = List(1, 0, 1, 0)
"1010".toList.map(_.asDigit)        // List[Int] = List(1, 0, 1, 0)

It's worth noting that converting a Char to Int returns an ASCII encoded value, so you need to use _.toString.toInt or the simpler _.asDigit.

Tagged: kata haskell js tdd


Who do we write code for?

11th January, 2019

I was recently peeking through an open source PHP project code base, out of curiosity, to see how things had been implemented. I cloned the git repository locally and loaded up phpStorm and started browsing. I was immediately struck by the IDE highlighting issues as to undefined methods and unknown parameter types, due there not being any docblocks, type hints or interfaces.

phpStorm highlighting syntax warning

Yellow blocks like the above were cropping up everywhere, because the IDE couldn't infer what types the variables were supposed to have. In the above case I would have expected some Handler type. I dug further into the bootstrapping of the object and found a registerHandler method defined as:

public function registerHandler($handler)
{
    $this->handlers[] = $handler;
}

Can you spot the problem? There is no type hint for a handler here. What's wrong with this? Well as a client I could call this method and pass it a parameter of any type, a string, integer or other class. This would result in a PHP Warning like so:

$string = "I'm a string";
$class->registerHandler($string);
PHP Warning:  Uncaught Error: Call to a member function handle() on string in php shell code:1

The horror! I dug deeper and found that the registerHandler was called three times, and passed objects that were all named *Handler. These objects each had a handle method, which means that the code would have worked as it is written. But none of the Handler classes implemented any interface that explicitly stated they should handle a file, it was just that the developer writing this had to know they each needed a handle method.

A "proper" solution (one with interfaces, I thought), might look more like this:

<?php

// a clearly defined interface
interface Handler
{
    public function handle();
}

// an example handler, implementing the Handler interface
class FooHandler implements Handler
{
    public function handle()
    {
        //...
    }
}

// the registerHandler method, expecting a Handler to be passed
public function registerHandler(Handler $handler)
{
    $this->handlers[] = $handler;
}

Now trying to pass anything other than a Handler (even if I'm passing an object with a handle method) will result in a PHP Fatal Error

PHP Fatal error:  Uncaught TypeError: Argument 1 passed to ClassName::registerHandler() must implement interface Handler, string given, called in ...

Ahh - job done, isn't that much better

...or is it?

Well, now in my code if I try to pass an invalid parameter I will get a different kind of error highlighted in phpStorm as:

phpStorm highlighting syntax warning

At least this gives me a clue about what it expected from me, so I guess that's slightly better. But nothing actually stops me from writing the above and releasing into production. There's still a need for testing and error monitoring. It doesn't mean my code is going to be completely bug free.

I spoke to the developer of this application and he said where he comes from, in the Ruby world, they don't have static, language types, only duck types - as in if you pass an object that quacks it might as well be a duck. Here it is the developers responsibility to make sure they are passing a valid object.

To whose benefit is an interface?

Defining an interface makes me feel safer as a developer. I know that myself or anyone else who uses this code can only pass a valid parameter, the method won't even begin to execute if the passed parameter doesn't match the argument type. But it does add some more boilerplate code.

I think the advantage of having interfaces (and abstract classes) is that it allows me to be explicitly abstract in the design of my code, which brings me closer to the business language. Another plus is that it allows me to assume that if the parameters have made it past the type check, then I can safely rely on the parameters inside the method; I don't have to put in conditional statements and further type checking, thus removing boilerplate. It might also make things easier for other developers (or our future selves) to work with in the future, instead of relying on complex concrete classes with their nitty-gritty implementation details polluting our dependencies we can just look at clean interfaces and focus on the messages passed between the collaborating parts.

Sometimes its worth questioning conventions or challenging our common understanding, and it's a great opportunity to do so when you see something done differently in a project someone else has written. I'd encourage you to think about it, talk to the developer about why they chose a certain implementation over another solution. You'll probably both learn something.

In conclusion: think more. About what you read, about what you write, about the consequences.

Further reading

Drop 'public' not 'var'! - by Evert Pot

Tagged: design php oop