We have a really good interview process here at Huddle, but it’s lengthy, so we use phone screens as a way of filtering out applicants who are likely to perform poorly. It’s also a nice excuse for me to take twenty minutes out of my day to talk about code and software engineering to a variety of sharp people. Most people don’t get through a phone screen, for a host of entertaining reasons (me:“So you know Haskell, huh? Explain monads to me” – him:“er… I put that on my CV by accident”) It turns out that one of the major hurdles – for applicants at all levels of experience – is object oriented programming.

This is kinda weird to me – we’re hiring for C# developers and C# is rooted very firmly in OO principles. Like Java – C# belongs in the Kingdom of the Nouns but the history of C# web development, with its origins for many people in VBScript ASP, mean that a lot of people are writing procedural C#. Procedural OO, or POO as I call it, is a great way to get yourself into a tangled unmaintainable mess.

Since I’m a nice guy (and since Zuz is hassling me about the total dearth of blog posts recently) I want to take some time and cover each of the four OO questions that I usually ask during a phone screen, delving into each question a little to try and give an overview of object orientation for the perplexed. Like everything else I write, this series is largely going to be lashed together at high-speed when I roll out of a nightclub, so if you think I’ve screwed something up, you’re probably right. If you think I’m a complete idiot, come to a DrinkTank event and call me on it in person.

I think I need to address this tirade at a particular person, so I’m going to call you Michael – can I call you Michael? Good.

So, the first question I ask is this:

What are the advantages of OO programming?

If the first answer that comes to mind is “re-use, because you can put code in a base class and share it in order to reduce duplication” then UR DOIN IT RONG. No dice, Michael, you’ll have to try harder than that. Reusability is the textbook answer, and it’s the answer I’m most commonly given. Over the course of this series I want to try and show why I think that OO design is about reuse of concepts not reuse of code, and to show how misapplications of OO techniques, can lead to brittle, tangled code.

When people first start developing in an OO language, they tend to think about their objects as reusable components, and try to plan how they might use those objects in the future. In theory, this is good practice, but in the real world, it doesn’t often work. The reason is this: Planned reuse of objects tends to increase the level of coupling in a system. People tend to use the same re-use techniques in an OO language that served them well in a procedural environment.

If there’s one thing I want you to take from this series, Michael, it’s this: Good object oriented code does not have to be terse. If you’re writing lots of javascript (the old way, not this fancy JQuery muck) then you very quickly become proficient at spotting patterns in the code, and refactoring the code so that you move common code into reusable functions. This saves on the bandwidth you use for serving JS and increases your win.

Extract Method is one of the simplest and most important refactorings, whatever language you’re working in – you should definitely keep doing it, Michael. The problem is that methods are not globally accessible in an object oriented system – they’re scoped to a single class, and this leads to the most common OO mistake I’ve seen in the wild. Here’s a stupid and contrived example:

// some JS function showItToTheUser(it){ // extra formatting goes here alert(it); } function helloWorld(){ ShowItToTheUser("Hello World"); } function reportError(error){ ShowItToTheUser( error.Message ); } // some C# public class HelloWorld { static void Main(string[] args) { ShowItToTheUser("Hello world"); } static void ShowItToTheUser(string it) {// extra formatting goes here Console.WriteLine(it); } } public class ExceptionHandler { public void ReportError(Exception ex) { ShowItToTheUser(ex.Message); Log(ex); } private void ShowItToTheUser(string it) { Console.WriteLine(it); } private void Log(Exception ex) { // Log is a static class. Log.Warn(ex); } }

How do you remove the duplication in the C# version? Use inheritance of course!!!!

public class DisplayerOfThingsToUser { protected void ShowItToTheUser(string it) { } } public class HelloWorld : DisplayerOfThingsToUser { } public class ExceptionProcessor : DisplayerOfThingsToUser { }

Michael: this is wrong. The HelloWorld program might be a “displayer of things to user”, but the exception processor is definitely NOT. By using inheritance to reduce duplication, we have wrongly conflated the two entities. In this stupid example, it’s obvious, but over and over again, I see people reaching for inheritance as the primary means of code reuse.

Here’s a better version

public interface IOutput { void Display(string it); } public class ConsoleDisplayerOfThingsToUser : IOutput { public void Display(string it) { Console.WriteLine(it); } } public class HelloWorld { static void Main(string[] args) { var output = new ConsoleDisplayerOfThingsToUser(); output.Display("Hello world); } } public class ExceptionProcessor { private IOutput _Displayer; private ILog _Log; public ExceptionProcessor(IOutput displayer, ILog log) { _Displayer = displayer; _Log = log; } public void ReportError(Exception error) { _Displayer.Display(error.Message); _Log.Warn(error); } }

You see Michael? Now the two classes are unrelated again, except that they both have a requirement to display things to user, which they do via an instance of IOutput. Rather than Extract Method, we have used Extract Class If we want to change the way that we display things to the user, we can provide a different implementation of IOutput. The ConsoleDisplayerOfThingsToUser is genuinely reusable, but our line count has gone up, not down. Incidentally, this is the kind of thing that makes me wish C# supported Traits (pdf, but worth the read).

The first thing we learn when we discover OO is the difference between an “Is-A” relationship, and a “Has-A” relationship. We write those futile Animal classes, where Dog and Duck both inherit from Animal and they overload the Speak method. I want to find out who first wrote that example and kill them with a fork. Most of the teaching resources for OO focus on inheritance as the key feature. Michael, I hardly ever inherit from another class, and when I do, I feel slightly dirty. When you inherit from A in order to create B, you are stating that B is a kind of A. 95% of the time, when you state that B “Is-A Kind Of” A, you are wrong: instead, both B and A need to make use of some C.

When you inherit from class A in order to create class B, you are coupling classes A and B, and the more that you couple your classes, the harder your life is going to be.

Avoid coupling at all costs – the point of OO is not to reduce duplication by putting everything into a base class.

So how would I answer this question? I’d give a three-part answer:

1) Object Orientation allows developers to think in terms of composable parts.

A business requirement: if you’re an enterprise Huddle user, you get a custom domain name, and your own company logos and colour scheme. The branding rules are linked to your domain name. If you’re in a workspace, then the branding should be the same as the branding of the account that owns the workspace.

public string DefaultWorkspaceLogo { get { if(CurrentWorkspace != null) return CurrentWorkspace.Account.Branding.DefaultWorkspaceLogoUrl; else return CurrentDomain.Branding.DefaultWorkspaceLogoUrl; } }

Simple huh? Because we’ve written the code in terms of the business entities, it’s trivial to write the business rules in a human-readable way. This is the biggest benefit of object orientation – anyone who knows what Huddle is can come along and understand the rules for resolving the default workspace logo.

2) Object Orientation allows developers to create constraints on data, and provide richer information about those data.

public class Postcode { private string _Value; public Postcode(string input, PostcodeValidation validator) { if(validator.IsValid(input)) { _Value = input; } else { throw new InvalidFormatException("{0} is not a valid postcode", input); } } } // this works var myPostcode = new Postcode("E1 6LP"); // this throws an error var myWonkyPostcode = new Postcode("10 green bottles hanging on a wall");

By using a Postcode class instead of a naked string, we have a type-safe guarantee that the postcode has been validated. It is literally impossible to get hold of a Postcode object that does not contain valid data (unless your PostcodeValidator is screwed, natch). This means that your methods can have signatures like this:

public void UpdateAddress(int houseNumber, Postcode postcode) { ... }

Where you know for a fact that nobody can ever pass you an invalid postcode.

Before Reddit start berating me, I’m perfectly aware that you can do this kind of thing in non-OO strongly typed systems, but if you know how the Hindley-Milner type system works, then you’re reading the wrong blog – go back to LTU . – Object orientation makes it easy to create this kind of data constraint because 1) Object Orientation allows developers to think in terms of business entities.

Another example from a recent interview: let’s imagine that we have a program which controls a robot. This robot is listening for commands, and sending back data from its sensors. The data are strings of the form

[dataType] [data] n

where data type might be “TEMP” for temperature in millikelvin, or “WARN” for error codes, or “LATD” and “LONG” for GPS positioning data. To make the robot move, we might issue a command like

TURN 300 MOVE 10000

where TURN takes an angle in milliradians and MOVE takes a distance in centimetres and our robot might respond with

LONG 51515793 LATD -71926 TEMP 268528

My candidate had implemented a similar system, and had used strings and switch statements throughout his code to represent the data. I asked him “How would you replace the switch statements with polymorphism?” and he replied “I wouldn’t because the different types of data had no duplication they were just strings“.

Because there was no duplication, he could see no point in creating an object.

abstract class RoboData { public long Data{ get; set} public abstract string DataType{ get; } } public class RoboDataReader : IEnumerable { private stream _DataStream; public RoboDataReader(Stream input) { _DataStream = input; } public IEnumerator GetEnumerator() { var data = string.Empty; while(data != null) { data = _DataStream.ReadLine; yield return Read(data); } yield break; } } public class TurnCommand : RoboData { public override string DataType { get { return “TURN”; } } } public class TemperatureReading : RoboData { public override string DataType { get { return “TEMP”; } } } //etc.

Now we have a single place to parse those strings. The rest of the code can remain completely ignorant of the underlying string format. All we need to do is

var data = new RoboDataReader( dataSource ); foreach(var datum in data) { Process(datum); }

Additionally, we can require that individual methods can only respond to certain types of data:

public void TurnRobot(TurnCommand c){} public void ConvertToCelsius(TemperatureReading t){}

or explicitly state that a method issues a certain command

public TurnCommand OnJoystickMoved(JoystickEventArgs e) {}

We can take this a step further and use the abstract classes RoboCommand and RoboResponse, which are both types of RoboData – now we can enforce the business rule that commands are sent to the robot and data is sent back – this constraint can be statically checked by the compiler, you never need worry that your data are going to show up in the wrong place and cause you an error.

if we had stuck to using strings throughout the system, we would have no way of enforcing such constraints. These constraints make the system easier to understand and easier to debug. By using a bunch of classes instead of a string and some parsing helpers, we might not have removed any duplication – we have probably written more code – but we have represented our system in terms of type-safe business entities.

If the format of our data changes with version 2 of the robot, we can change the definition of RoboDataReader and RoboDataWriter and we’re good to go – everything else remains the same.

3) Object orientation gives developers the tools to write testable, modular, chunks of code.

The ConsoleDisplayerOfThingsToUser can be used by multiple clients because it is modular – it does a single job, according to a declared interface. We can replace the ConsoleDisplayerOfThingsToUser with a MessageBoxDisplayerOfThingsToUser or a FakeDisplayerOfThingsToUser and the rest of the code stays unchanged.

This allows you to test components in isolation and, yes, to reuse code across teams and applications.

If we have a business requirement that anything we display to a user is logged to the database, there is only one class that needs to be updated. This kind of modularity, again, can be duplicated in procedural or functional languages, but is made simpler in OO because 1) Object Orientation allows developers to think in terms of discrete, composable entities.

Okay, so my wine glass is empty – and I’ve gone on far longer than I intended. Next time I want to cover the second question: What IS an object anyway?

tl;dr : favour composition over inheritance. OO is primarily a way of mapping mental concepts into human-readable code.


Request a Demo
trillatron

© 2006 - 2019. All Rights Reserved.