“The single most important reason to create a class is to reduce a programs complexity.”
Steve McConnell – Code Complete 2
“Always write code like the person who will maintain it is a serial killer and knows where you live”
Unknown
I’m going to assume you know what a class is and how to write one, so if this is not true, I suggest you look that up before reading this article.
So why or when should we create a class? This is one of those great theoretical questions, but has many real world consequences. There are many specific reasons to create a class. McConnell goes into detail identifying many reasons and elaborating on them. Since I have no desire to transcribe his wonderful book or write a book length article, I’ll point you in his direction after you’ve read this more entry point article.
For a lot of beginning programmers, classes are seen as real world objects. A button, a menu, or a gallery. While these are valid to be represented in their own classes, it isn’t the right reason to have put them in a class. For me a class is everything needed to contain a single responsibility. So while managing the display and control of a menu is a responsibility, so is parsing an xml file or grouping and representing the data that constitutes an employee. So creating classes strictly to represent real world objects doesn’t go nearly far enough.
I’m not just pulling the single responsibility idea out of the ether, it’s actually called the Single Responsibility Principle. I’ve added a link to the Wikipedia page at the bottom of the article.
Side note: The Single Responsibility Principle is the S of the SOLID principles. Link below as well.
To expand the menu example, displaying the menu and controlling it based on user interaction can be broken down into 2 responsibilities which therefor could be broken down into 2 classes. If the menu gets its information externally, from an XML file for example, the loading and storing of the information might be a 3rd responsibility and class. If we used the parser example, we get a 4th.
Side note: I’m unintentionally starting to describe the MVC (Model-View-Controller) design pattern.
You might be thinking that separating out all this code into several different classes makes things more complex since you have more things to deal with. It really makes things easier for a few reasons. For starters, it is just easier to look at a smaller class and be able to quickly see what its responsibility is, what it’s doing. If I see a class called MenuXMLParser and it has a method parse(), I know exactly what it is and what it does. I don’t need to read every line of code and I don’t have to look through a bunch of parsing code in an onLoadComplete() event handler. I like that, it makes my life easier.
While I’m reading through the onLoadComplete() method, I probably don’t care about how the xml is being parsed. All I care about is that it IS getting parsed. Seperating out the parsing code again, just makes the reading of the code easier. When I decide I care about how the XML is being parsed, then I open MenuXMLParser and I’m not distracted by all the display and animation code.
Another way it makes my life easier is the case of reuse. What if I have another menu that uses the exact same data as my first menu. If this situation happens, I can just use the same data loading/storage class(es) as my first menu and I don’t need to rewrite it, (cringe) copy and paste it, or any other terrible thing. Now that I’m using the same classes for both my menus, if the data stored in my xml file changes in a way that requires a change in the parsing or storage, I can edit the code in one place and both my menus will be working again. Duplicate code is one of those big, ugly, nasty, no-no’s that make experienced engineers cry blood. Duplicating the same code across more than 1 class is even worse.
Since this is a higher level article, I’m going to intentionally omit some other reasons, at least directly. I’ve snuck a few in, just by example, not name. You can find a wonderful list in Steve McConnell’s Code Complete 2. A book I believe everyone that writes any code should have.
Naming a class is a very important step as well. Why is it so important? Because when I see the name of the class, I want to know what it is. I don’t want to have to read through it, line by line, to figure out what it does. It is very common to find classes that do far more than their names suggest. I’ve even come across classes that don’t even do what the class name suggests. Class names should always be nouns and never a verb. While classes don’t always represent a real world object, they are still objects. If you want to verify that, follow the inheritance chain of any class to the bottom and you’ll always find Object. Some examples of good class names would be:
TopMainMenu
TopMenuXMLParser
Bad Class names would be:
Menu (which menu?)
ParseXML (verb)
The size of a class is important too. If we stick tightly to the 1 responsibility rule then our classes tend to be of a manageable size and a lot of the bad things of having large classes tend to disappear. Our classes tend to be easier to read, have less of a chance of error, and are more likely to be reused. I’ve had to maintain and refactor some classes that were 1000, 2000, even 4000 lines long. These things go by many names, I tend to use “do everything” class. Because what does it do? Absolutely everything. 300 lines tend to be the point where I take a step back and look to see if I’ve overload the responsibility of this class. 200 lines or less is my happy place. Once in a while to adhere to the 1 responsibility principle a class does get bigger than I’d like, but that is rare.
So now we get to the constructor. Yes, there is theory about how a class constructor should be built. The general rule for constructors is to keep them as small as possible. Do your assignments and call it quits. If your class has some complex setup routine that it needs to do, put that in its own function which is often called init(). For one, that keeps things cleaner, second, if you need to reset your object, you can just call your setup function again.
If you find yourself passing in a long list of arguments in your class’s constructor, there’s probably a better way to do it. Instead of passing in each variable that describes an employee, passing in an Employee class would be a lot cleaner. Or your class is just doing too much.
Class variables are another topic we should talk about. If you are not aware of the difference between the terms class variable and local variable, class variables are accessible from any function in the class and typically defined above the constructor, local variables are defined within a function and only accessible from within that function. It’s really a matter of scope. If the term scope is unfamiliar, then you should probably look that up before continuing.
Side note: Flash has an atypical scope system. Local variables defined in a code block like an If statement or for loop have the same scope as those outside the code block. Every other language I’ve used treats them as being in a different scope. I prefer the way other classes do it over Flash. If for nothing else, declaring var i:int in 2 loops in the same function wouldn’t throw a warning!!
Class variables should almost always be private. I’ll talk about the only reason they should be public be in a minute. The reason they should be private gets into the OOP principle of Encapsulation. I’ll save that specific topic for another article, but the basic reasons are that when using a class I shouldn’t know how it’s built (i.e. what variables it has) or have direct access to its data. The first is just good clean code as defined by OOP. The second reason is data security. Anything and everything shouldn’t be able to change data at any and every time.
The one case where I believe class variables should be public, and I’m sure there are people that will disagree with me, is in the case of data objects. Data objects are classes whose sole responsibility is to hold data. The Employee example is a great one, and widely used. It does nothing other than store information like first name, last name, start data, department, salary, etc. It doesn’t do anything with the data, doesn’t load it from a database, doesn’t save it back, and doesn’t handle changing the salary. It does nothing but represent that employee by holding their information. In other languages this data object is called a struct. A struct isn’t a class, it can’t have methods, it is nothing other than a collection of variables. Since AS3 doesn’t have structs, the closest we can get to them is creating a class with public variables.
There is also a naming convention for class variables defined by Adobe. Every language has its own conventions and should be adhered to when using that language. Again this is for the reason of readability. In AS3, class variables start with an underscore. Arguments and local variables do not.
The number of class variables is also a matter of debate. McConnell says the number of acceptable class variables is 7 +/- 2. The reason for this number is based on the average number of things the human brain can remember at any given time. Think of a phone number, 555-5555. Even then with 7 numbers we break it into 2 sets to make it easier to remember. Not to mention we’ve somehow collectively given phone numbers a rhythm. Another reason to limit the number of class variables is classes with a lot tend to being doing too much. In other words, it has too many responsibilities. If I’m working on a class, look up and find I have 15 class variables, it is a pretty clear clue I should step back, take a look at my class, and see if I should break it up. I very well may have got carried away in solving my problem and not seen how I was overloading my class.
Properties are the things that define an object. If you think about it in a real world context, hair color, eye color, height, and weight are all properties of a person. Properties are always publicly accessible values, usually by getters and setters. What the properties should be for a class really depends on the class. If they should be read/write (getter and setter) or read-only (getter only) again starts to get into the topic of Encapsulation. Write-only (setter only) properties really make my skin crawl. If I’m using an object and I type object.property, but I can’t access its value, but I’m able to change it, I’ll start twitching out of angry confusion. If I have something on my class that is read-only, then I take the Java approach and create a setSomething() method. At least at that point I know I can only set a value.
If a class is a responsibility, then a function is 1 task necessary to accomplishing that responsibility. Functions are the verbs of their containing noun and are what allow the object to do stuff. If you have a class whose responsibility is to represent a person, what verbs are necessary to accomplish that responsibility. We may have a functions like walk(), run(), smile(), and talk(). We would not have functions like hairColor(), height(). Those are properties of our Person object so would be .hairColor and .height.
To ditch the abstract example. If I had a radio button I’d have a select() method and deselect() method. Both verbs allowing a radio button to do radio button things.
The size of a function is another thing to be aware of. If we write all our functions with the idea that it is just supposed to perform 1 task, then a lot of the other reasons to keep functions small pretty much happen naturally. Although the other reasons to keep functions small pretty much mirror the reasons to keep classes small. Easier to read, less chance of error, and more likely to be reused.
“With great power comes great responsibility”
Uncle Ben (Spiderman, not rice)… or the guy that said it before him
There is always a balancing act between code bloat and class bloat. The ideas in this article can be taken too far. Every line of code doesn’t need to be in its own function just to better describe what it does.
private function findSumOfTwoNumbers(number1:Number, number2:Number):Number
{
return number1 + number2;
}
A function like this would be absurd!
If we write an XML parser we don’t need to write a new class to parse each node type because “it should be responsible for parsing this node type” or “I might need to parse this node type again”. Maybe if the node is some giant convoluted blasphemy, but putting it into its own function(s) in the parser class would make a WHOLE lot more sense.
Be pragmatic about it and use your brain and common sense. Just remember, these principles, philosophies and theories were developed to help us manage and understand the work that we are doing because the work we are doing can be very complex and hard for even the smartest people to do. The principles are more of a compass than an exact road map.
More reading:
http://en.wikipedia.org/wiki/Single_responsibility_principle
http://en.wikipedia.org/wiki/SOLID_%28object-oriented_design%29