Tuesday, March 7, 2017

On the Road to Type A Nominalization

I studied computer science at university in the early nineties.  It's a long time ago now, and although it wasn't all mainframes, terminals and punch cards, it was still relatively early in terms of a real understanding of how to build complex software.  There was a lot of talk about object orientation, CASE tools, code generation and expert systems.

Prior to university, I'd done hobby programming in Z80 assembler, GW Basic, Turbo Pascal and 'C'. I couldn't imagine anything other than procedural programming because that's what I'd been doing up to that point, and getting some pretty good results with it too.

Learning how to use some crappy code generation tool that would create 30 almost empty Ada files with a marginal boiler-plate benefit did not set my world on fire.  However, the object orientation stuff was much more appealing.


It made sense to me that if you were writing code to solve real world problems, then your code constructs should mirror the real world objects that you were modelling. 

The learnings from those days kept resurfacing throughout the years in domain driven design and Uncle Bob's 'screaming architecture'.  However, it took me a little while to break the limitations of what my brain had been programmed with in those university lectures. 

A memory from a computing lecture back in those days was the oversimplified description of how to get started building a system with OO principles.  Now, although I've paraphrased and simplified further for comic effect, it went something along the lines of this:

"Write a paragraph of plain English describing your requirement, underline all the nouns and verbs. The nouns will likely be the objects in your system, and the verbs will be the operations or methods on those objects".

Wow - I can only think myself lucky that I wasn't paying £9000 a year for this wisdom. You see, if you follow this advice blindly, what you end up with is a hospital patient administration system with 7 million lines of code spread across 5 key objects.  That patient.cpp file is a hoot.  At 2.3 million lines, the developers realised the error of their ways and decided to split it into patient1.cpp, patient2.cpp ....  You get the picture .

Over the years, we learned to break our major objects into smaller parts and sub objects, making them so small that we could actually explain what they did - because they only did one thing, and that one action (almost a verb) was often something that we embedded into the name of the class itself.

Hang on a minute Nige.  Didn't university OO 101 say that the verbs were the operations or methods within our objects? Well, yes they did - but we saw how that worked out for our patient administration system.

So, in the quest for finding lots more objects within our systems, (so that we could have shorter files and still believe in object orientation as a solution to all programming problems), we started looking at the verbs as potential classes. Now, if only they had noun-like names, we could still feel good about ourselves and know that we were not breaking the rules.  Nounification is the result, and OO codebases are littered with it.

If you've go any sort of Formatter, Builder, Reader, Writer, Manager, Parser, Mapper, Translator, Validator, Controller, Presenter or Notifier class in your code, then you're already there.  Don't be ashamed or embarrassed - it's an unavoidable destination when working in any popular OO style language.  You're doing the best you can with what you've been given. You've got  a blunt instrument and all your problems are starting to look pointy.

I started using the term nounification many years ago to describe this phenomenon, without caring whether or not it was a real word - many people I worked with had a habit of making up words which sounded like they should exist and seemed obvious enough, so I jumped on that band wagon.  I recently googled it, and  found some other software guys talking about it too, but I also found the real name for it - Type A Nominalization.

In writing, nominalization is a tool that can be used to soften or weaken the effect of a strong verb where required, adding different 'textures' to a written piece.  In software class naming, it produces code that sounds like advanced medical machinery.  Is anyone working on the LexicalOrderTransmogrifier?

One of the things I liked about 'C' programming back in the day, was that you could just write a function, and get a pointer to it, and give it name, and pass it as a parameter to another function where it would be executed.  Whilst the syntax in straight 'C' may not have been particularly pretty, it was cool stuff - and insanely powerful.  It's how we implemented 'generic' sorting algorithms - we separated the comparison of items from the underlying sorting algorithm, passing in, or 'injecting' (for want of a more popular term) the comparison function.  

When C++ came along, I found myself distraught if I couldn't find a home for a piece of code because it didn't seem to belong in any of the objects I had in my hands.  I'd been blinded by the wonder of OO and it took my mentor (who'd been round the development fad block 3 or 4 times already) to say "not all code has to live in a class - C++ is still 'C' under the covers" and to lift the guilt I was feeling for failing to be 100% OO.

My desire at the time was to try to fit functionality into the class where it belonged - but sometimes it was not obvious.  I constructed elaborated class hierarchies to try to make things live in the most appropriate place, but sometimes, your class looked like it had elements of two or more parent classes. C++ gave you multiple inheritance (along with more confusing syntax  to  manage the extra complexity that had been introduced) to try to solve this problem, and sometimes, I just about got away with it. Someimes I didn't, and I ended up with 'helper' classes and felt slightly dirty.

Our OO language frameworks followed a similar path and we ended up with 'classes' that felt a bit strange like the 'Math' class. they didn't meld with our notion of modelling real world objects, but instead seemed to be a collection of 'functions' loosely bound by related functional area. They seemed that way because that's exactly what they are.

The recent resurgence of functional programming is testament that our industry is starting to come of age, and that having tried several paradigms for building complex yet maintainable software, we often have to bend the rules as well as using several tools from the toolbox.  Our OO languages are embracing concepts from the functional world and vice versa.  Zealots in one space or the other are seldom correct, as the best answer often lies in the middle.  Some problems are best solved from an imperative approach, some from a functional, some from a declarative.  The good teams will recognise when to use each of them, and blend them seamlessly to build awesome stuff.  The rest of us will continue to beat screws with a lump hammer.

Our future remains interesting...






No comments: