What Is A Class (and why to avoid static methods)

There are many debates in software development, from how to test, to languages, to frameworks, and everything under the sun. Despite my oblivion to the technical details of many of these debates, what I’ve seen is that many of them hover around the lofty heights of roof trusses without understanding the subterranean foundations that build the houses they are comparing (wow, that was poetic: +1500 hipster points).

In my short software development career thus far, I have been introduced to 2 paradigms of software development: procedural and object-oriented. And my understanding was that languages like SQL were procedural, and other languages like Java, C# or Python were object oriented, because you could create objects that interact with each other. Yet, over the past lil’ while, I’ve seen that the distinction between procedural and object-oriented is not necessarily the language that is being used, but the approach taken when using that language.

The foundation of object-oriented languages is the class, as these define the objects that interact with each other to fulfil some kind of intention. In his book Code Complete, Steven McConnell explains the concept of classes by introducing the idea of an ‘abstract data type’. He defines it as follows:

An abstract data type is a collection of data and operations that work on that data. The operations both describe the data to the rest of the program and allow the rest of the program to change the data.

He then mentions why he introduces abstract data types as a way of explaining classes:

Understanding ADTs is essential to understanding object-oriented programming. Without understanding ADTs, programmers create classes that are “classes” in name only – in reality, they are little more than convenient carrying cases for loosely related collections of data and routines.

Abstract data types can be implemented as classes. What is key is that it encapsulates data, and exposes operations that work on that data. Normally, these classes should represent some kind of real-world object, or a single entity or idea. A simple example would be the creation of a value object for money. In many applications, a decimal or related type is used to represent money, but this can be its own object:

class Money 
    attr_reader :amount 
    attr_reader :currency 

    def initialize(amount, currency) 
        @amount = amount 
        @currency = currency 
    end 

    def to_s 
        return @currency.is_symbol_on_left ? "#{@currency.symbol} #{'%.02f' % @amount}" : "#{'%.02f' % @amount} #{@currency.symbol}" 
    end 

    def ==(other_object) 
        return false if other_object.nil? 
        return false if !other_object.is_a?(Money) 
        return false if (other_object.amount != self.amount || other_object.currency != self.currency)   
        return true 
    end 
end

The above code is a “collection of data” (the amount and the currency) and “operations that work on that data” (getting the string value of the amount). In this way, the money object can be used throughout the application as a single concept and have repeatable results when other objects interact with it.

Now, where the whole ‘class’ thing sometimes go wrong is in the creation of ‘god objects’ (i.e. objects that do too many things) and static methods.

Now, in C#, an implementation of the above logic could be as follows:

public static class MoneyManipulator 
{ 
    public static string GetCurrencyString(decimal amount, string currencySymbol, bool isSymbolOnLeft) 
    { 
        return isSymbolOnLeft ? string.Format("{0}{1}", currencySymbol, amount.ToString()) : string.Format("{0}{1}", amount.ToString(), currencySymbol); 
    } 
}

As can be seen, the static method above does the same thing as what was written above with the Money object, but this isn’t an ‘object’ that other objects can interact with, but a piece of procedural code decorating itself in object-oriented language.  The method above isn’t a collection of data, as it doesn’t actually have any data (a similar pattern is found in many god objects). Therefore, there can’t be any operations on the data which it does not have.

Creating actual ‘objects’ makes the code a lot more reusable, extensible and understandable as the classes describe the data they encapsulate, instead of  the ‘I can be anything to anyone’ objects as above.

Patrick Kayongo

I create and maintain software. Pan-African.

Johannesburg, South Africa