You are a person, but clearly you are much more than that. You are good looking and very intelligent and you have a wide range of outstanding skills. You may be great at cooking, an outstanding pianist and perhaps one of the best parents in the world.
However, if I were to interview you for a ColdFusion developer role I would not be very interested in knowing that you make a mean red curry. Although you are a great many things to many people, I would primarily be interested in your skills as a developer. Do you write clean code? Have you used some of the community frameworks? How many years have you been working with ColdFusion? And so on.
In fact my focus would only be on a small part of what you are. I would be focusing on the essential characteristics in you that particularly suited my needs. I would ignore all of the wonderful things about you that are not directly relevant. I have abstracted you into something more generalised and less detailed. You become the abstraction "ColdFusion Developer." Consider the object that represents You:
Then what you would look like after being abstracted into a ColdFusion Developer:
Let’s look at a definition of abstraction from Grady Booch (one of the authors of the Unified Modeling Language):
"An abstraction denotes the essential characteristics of an object that distinguish it from all other kinds of object and thus provide crisply defined conceptual boundaries, relative to the perspective of the viewer."
And a process to find an abstraction from Wikipedia:
"Abstraction is the process of generalization by reducing the information content of a concept or an observable phenomenon, typically in order to retain only information which is relevant for a particular purpose."
Abstractions are intended to simplify things by isolating only what is required for a particular purpose.
So what’s the point?
Hal Helms has written a good article on abstraction, and in it he writes:
"But people engaged in application design too often mistake their mission: they think they’re writing code instead of designing abstraction layers. Thus, they concentrate on the implementation and neglect to abstract the details into a simpler interface."
What Hal is saying is that we need to stop focusing on the how we implement each particular function, and instead spend more time identifying generalised and simplified sets of functions to use in our components.
This is a very important idea – so let’s work through an example through two different views; Tony, who does not use abstractions and Jennifer who makes use of abstractions.
You are given a query which needs to be saved to one of several file formats: An XML file, a comma separated file and a tab delimited file. Your task is to design the components required and the corresponding functions, and not worry about actual implementation at this stage.
Let’s start with Tony, who does not have any familiarity with abstractions. Keep in mind that Tony is an excellent developer who has come from a non object oriented background, so his solution is likely to be good, but without any particular focus on abstractions.
Abstractions; why bother?
Hi, I’m Tony. I have never thought about abstractions during my development. I don’t really understand what that they are, but at the same time I have never really had a problem.
So here’s how I would solve the task – with a QueryToFile.cfc.
To use this in code you would have something like:
<cfset queryToFile = createObject("component","QueryToFile").init()> <cfif fileType eq "xml"> <cfset queryToFile.saveQueryToXmlFile(myQuery,myFile)> <cfelseif fileType eq "csv"> <cfset queryToFile.saveQueryToDelimitedFile(myQuery, COMMA_CHAR, myFile)> <cfelseif fileType eq "tab"> <cfset queryToFile.saveQueryToDelimitedFile(myQuery, TAB_CHAR, myFile)> <cfelse> <cfoutput>Unknown file type</cfoutput> </cfif>
So what I have here is my QueryToFile.cfc and you just call whichever function you require – easy, simple and works!
Abstractions; make me sound smart!
Hi, I’m Jennifer. I like Tony’s solution, but I have recently begun exploring abstractions and have come up with another approach.
Firstly I can see that we need to
a) Write a query to an XML file, and
b) Write a query to a comma separated file
c) Write a query to a tab separated file.
Well, these are all writing queries to files, so perhaps I can generalise this idea to say that these are all Query File Writers. Also, (b) and (c) are both delimited files, so I can generalise this idea to say that these two are Delimited Query File Writers, however this is just a more specific version of the Query File Writer idea.
So what does the generalised Query File Writer do? Well, in its simplest form, it will just take a query and write to a file, so I would perhaps write my Query File Writer as follows:
This is an abstraction, because it extracts the essential features of what the writers need to do in this case – convert a query to a file.
However this doesn’t help us much on its own because at some point we need to indicate if we are saving to an XML or a delimited file.
We can achieve this by creating two more specific (less generalised) components:
You can see that the XML and Delimited Query File Writers extend the original QueryFileWriter.
To use this in code you would have something like:
<cfif fileType eq "xml"> <cfset queryFileWriter = createObject("component","XmlQueryFileWriter").init()> <cfelseif fileType eq "csv"> <cfset queryFileWriter = createObject("component","DelimitedQueryFileWriter").init(COMMA_CHAR)> <cfelseif fileType eq "tab"> <cfset queryFileWriter = createObject("component","DelimitedQueryFileWriter").init(TAB_CHAR)> <cfelse> <cfoutput>Unknown file type</cfoutput> </cfif> <cfset queryFileWriter.write(myQuery,myFile)>
Actually, it would be better if the creation of the query file writers was in another component, say a "factory" that knows how to make the query file writer objects. This is another abstraction – to generalise the creation of objects:
<cfset queryFileWriter = factory.getQueryFileWriter(fileType)> <cfset queryFileWriter.write(myQuery,myFile)>
Abstractions do not mean less code
Keep in mind that abstractions do not reduce the amount of code you write. In fact you may need to write more code. At the end of the day, the actual implementation still has to be written, but abstractions just organise this code in a different way.
What are the benefits of abstractions?
Abstractions are about identifying the essential characteristics in things and creating generalisations of those things accordingly. This brings with it a several important benefits:
Easy to revise the implementation
Abstractions hide away how something is implemented – all you need to know about is the public facing functions.
Suppose, for example, that the code to build the XML file above used string concatenation to build the output file. It was then decided to change this process to use ColdFusion’s built in XML capabilities instead. The benefit is that the code that uses components above does not need to be changed.
Same interface, different behaviour
In this situation you implement multiple components that have the same set of functions and parameters, but the underlying behaviour of each is different.
For example, with Jennifer’s QueryFileWriters, both the XML and delimited writers have the same function: write(). When we retrieve the object from the factory, we don’t know which type of QueryFileWriter it is – and it really doesn’t matter at that point in the code. All that matters is that it has a write() function which takes a query and filename as parameters.
Abstractions are intended to provide you with the essential functions that you need to get the task done. As a user of the abstraction, you only need to learn the functions the abstraction provides and do not need to be concerned with the complexity of detail that may lie beyond.
Where to from here?
Thinking in a more abstract way is not easy. Abstractions are often not very clear – particularly when a non abstract solution is staring you in the face. I believe the best way to get started with abstractions is by studying design patterns. They will set your brain on the right path to seeing what abstractions really look like.