Tuesday 4 February 2014

A most Practical lesson in Clean Code

Our wireless thermostat recently shuffled off its digital coil and I can only assume is on its descent to robot hell.  The maldesign on the device is subtle that you can imagine even a half-competent engineer signing off the specifications without noticing the error.

Just to be clear - this isn’t a metaphor or some contrived example to prove a point - although I’m hoping one day it will be. Our thermostat is broken, its the middle of winter and we are very cold.

The thermostats wireless receiver is a mains powered device that sits in an operations chain in series with the timer control unit. Every few minutes the thermostat receiver polls the wireless thermostat and the input line from the timer. If both are true, it flipflops its output to TRUE - and the heating comes on.

As an additional feature the unit also has a manual override button - so if you want to ignore the thermostat and timer input you can force your heating on. I won’t go all UML on this right now, but you can imagine a reasonably simple diagram that explains this all.

But what I’m facing with a faulty thermostat and its faulty “Manual Override” button. I’ve seen the wiring diagram - an override switch that bypassed the circuitry isn’t very difficult to add. It’d literally be a switch that shorts two physical wires. I don’t want a “manual override” button that relies on the same faulty circuitry that I’m trying to override - I want an external independent mechanism.

The override should adhere to the same interface declaration as the normal thermostat, have the same dependencies at a factory level, but its operation entirely driven by a public method. That way, it could be injected into a test with an instantiated timer or used if thermostasis isn’t a customer requirement for this sprint.

And then BAM! My thermostat was just a metaphor* for The Substitution Principle all along!  Its not always enough just to assume that because you declared an interface and implemented it that you have covered all the bases. Zero-To-One is a great step, but Zero-To-One-To-Many is the path you are trying to lay down to make maintenance easier.

And that’s the take-home lesson for today, in a very practical sense. Clean-Code programming lessons in applied engineering:
  • The Thermostat, the Override and the Timer should all fill the signal control interface. (Substitution Principle)
  • The signal control interface should just be concerned with being a programmable gate. Two input wires, One output wire. (Interface Segregation)
  • Each component should do what is says on the tin (Ronseals Law)
  • The factory should be responsible for constructing and wiring them together (Factory Construction)
  • Each object should pass its signal on to the next (Dependency Injection)
  • The override responsibility and the thermostat responsibility should not live in the same object (Single Responsibility Principle)
Until next time: Enjoy your warm house, keep coding, and remember to think inside the box!

 * = Actually not a metaphor, our house really is brass monkeys right now.

No comments:

Post a Comment