Five Tips To Make Good Object-Oriented Code Better
Out Of Date Warning
Languages change. Perspectives are different. Ideas move on. This article was published on October 28, 2009 which is more than two years ago. It may be out of date. You should verify that technical information in this article is still current before relying upon it for your own purposes.
Last week, I did a talk at the Frederick Web meetup about tips and tricks for improving your object-oriented code. A lot of these tips were adapted from a fabulous presentation by Stefan Priebsch but the ideas are by no means original to him, and they’re exceptionally good ideas when you’re talking about object-oriented code. Slides are at the end of this blog post, and I’m happy to do this talk over again for local groups.
#1 Use Objects. Lots of Objects
This point is taken directly out of Stefan’s slides, because it’s such a good point. There seems to be a perception in the PHP world that using lots of objects is slow, cumbersome, or plain difficult to maintain. But the reality is that this is not true at all (for example the object model in PHP 5.3 is vastly improved over older models).
By using lots of objects, you can make sure that each object has one job and only one job. You don’t have to make objects smart, either; instead you can rely on other objects to do work for you, and give you the things that you need. Adding lots of objects makes it easy, once you understand the architecture, to make changes without having to change massive amounts of code. The best object-oriented framework I ever worked on often required only one or two line changes to make massive improvements in performance, features, or the resolution of bugs.
Hardware is inexpensive, and there are options to optimize and improve your performance. You should make use of them.
#2 Use Interfaces To Make APIs Predictable
Interfaces are a great way to enforce a design. The concept of “design by contract” is the point of interfaces: you establish your contract, and you then use it.
Interfaces allow for strict typehinting, and by typehinting you can ensure that certain methods are always available for your use. Beyond that, interfaces make your API consistent, which is a big boon, especially as your team gets larger. Each interface will provide the model to utilize, and your teams will know that they have to implement a few methods each time they wish to make use of a particular interface.
#3 Use Dependency Injection
For the longest time I didn’t realize the importance of dependency injection. But dependency injection is critically important, especially if you want to write or utilize a framework or do any kind of unit testing.
Many programmers attempt to instantiate objects directly in their code, or grab objects out of singletons. This is a bad approach, because it makes testing impossible. You cannot inject a mock object; you also have trouble with mock data. For example, if you create your database object inside your controller object, you always have to create a database to test with, which adds another variable for possible failure of your unit test.
Learn to use dependency injection. It will make testing and feature addition easier.
For example, an apple “is a” fruit, while an apple “has a” seed. You would never say that a fruit could be a seed, but you could say that a fruit could be an apple. This distinction is important.
Stefan mentions that well-written classes can be extended no matter the circumstances, and I think he’s right. I also know that the more simple your classes, the better off they are in terms of abstraction. Always carefully consider whether or not objects are doing their jobs and what those jobs are.
#5 Create Loosely Coupled Classes
Often times when a developer gives each object only one responsibility, they tightly couple objects together. This is a mistake, because it makes reuse harder later on. Objects will often request information from other objects, and while this is not avoidable in all situations, these tightly coupled classes that rely on one another’s functionality makes pulling those objects apart impossible.
Zend Framework offers a good example of classes that are more loosely coupled. You can generally make use of Zend components without using the entire Zend Framework; likewise, you can opt to use the entire framework, but this is entirely optional. I make use of a number of the Zend components (Zend_Validate, for example), without using the MVC pattern that Zend utilizes.
These tips will enhance and improve your object-oriented projects. Architecture is difficult, but the more time and effort you spend doing it the easier developing will become.