Comparing software development to constructing a building says that software is solid and difficult to change. Instead, we should compare software development to gardening as a garden changes all the time. Software Gardening embraces practices and tools that help you create the best possible garden for your software, allowing it to grow and change with less effort. Learn more in What is Software Gardening.
How are you going to grow anything in your garden without seeds? You may argue that you can buy young plants and replant them. This is often done with tomatoes, flowers, and trees. But at some point, those young plants too began as seeds. You also need to plant at the proper time. In the early spring, when the frost can cover the ground in the morning, you should only plant seeds that can withstand the colder mornings. The depth of the hole is important. The seed needs enough moisture and warmth from the sun that it can germinate and take root, yet not be so shallow that cold mornings will kill it completely. Finally, you need to take into account things like the gestation and growing time. Some plants grow quickly and are ready to harvest in early summer, others not until fall.
This article is published from the DotNetCurry .NET Magazine – A Free High Quality Digital Magazine for .NET professionals published once every two months. Subscribe to this eMagazine for Free and get access to hundreds of free .NET tutorials from experts
This issue, I begin talking about Object Oriented Programming (OOP), starting with the basics. In the next few issues, we’ll get into other OOP topics. Beware that I may challenge the way many of you think about and use OOP.
The first question to ask is what is an object? The simple answer is it is a software construct (class) that represents or models something, say a person. More correctly, a class is a definition of the object. The object is the instantiated class. The object contains data (attributes or properties) about the thing being modeled. It also has procedures (methods) that give behavior or functionality to what is being modeled. Coming back to the person example, properties could be things like name, eye color, hair color, height, or weight. Methods could be walk, talk, eat, or snore.
Three pillars of Object Oriented Programming
Of all the topics in OOP, three stand out as the topics that support everything else. These are inheritance, polymorphism, and encapsulation. Let’s look at each of these.
Each of us has inherited traits from our parents. Eye color, hair color, and medical conditions are attributes we inherit. We also can inherit behavior such as our sense of humor, extrovert or introvert, and others. Classes can have a parent or parents and inherit attributes or behavior.
A class can have a single class and inherit all the behavior and attributes from the parent class. This is called implementation inheritance. In .Net, the child class can change or override the behavior. The child can also call into the parent’s method to get the default behavior. In .Net, a class can only do implementation inheritance from a single parent class. In some languages, such as C++, the child can inherit from multiple classes.
Another type of inheritance is interface inheritance. In humans, you have two eyes, just like your parents, but your eyes may have a different color than either parents. Or you may behave differently in a similar situation when compared to mom and dad. In OOP languages, when a class supports interface inheritance, it only gets the property names and types and method names, parameter types, and return types for each behavior defined in the parent. It is up to the child class whether or not the particular method will have any behavior. However, the child must define each property or method defined in the parent. In .Net, a child can have one or more parent classes using interface inheritance.
What an interesting word. Polymorphism comes from two Greek words, poly which means many and morph which means shapes. So it literally means many shapes. It shouldn’t be surprising that there are different types of polymorphism.
One type of polymorphism is when you have multiple method names in the same class. This is commonly called method overloading. For example, you may have multiple constructors on a class, each with different parameters.
Generics is a second type of polymorphism. With generics, you can reference different data types with the same class. For example, think of a generic list. You can define List or List or even use a custom type such as List.
A third type is called Subtyping polymorphism. The best way to understand this is with an example that I have adapted from Wikipedia.
static void Main(string args)
private static void MakeNoise(Car c)
class Ford : Car
public override string Honk()
class Beetle : Car
public override string Honk()
return "Beep! Beep!";
abstract class Car
public abstract string Honk();
Note the MakeNoise() method. It expects Car as a parameter, yet when we pass a subclass of Car and call the Honk() method, we get the proper sound for that type of Car. The MakeNoise() method uses Subtyping polymorphism.
The final pillar of OOP is encapsulation. There are two types of encapsulation.
The first is used to restrict access to the object’s components. One way to do this is data hiding. You don’t let outside components have direct access to the data or you prevent it entirely. Another way to do this is by defining methods as private so they can’t be used externally.
Now that we have looked at the three pillars, let’s look at a couple of other important concepts we should strive for in defining classes, loose coupling and tight cohesion.
With loose coupling, one class has little knowledge of another class. Every time we new an object, we are tight coupling one class to another. It may be better to define an interface and pass in instances of a class rather than new-ing it where it’s used.
The classic example of this is a logging class. It shouldn’t matter if we log to a text file, a data, or the event log. If we define the logging type externally, then pass that instance into where it’s used, the result will be the type of logging we desire and the code that actually uses the log has no idea where the log is being written to, nor does it care.
Cohesion is kind of the opposite of loose coupling. When a class has tight cohesion, its methods and properties are tightly related. Going back to the logging class, if it has a method that updates a customer record, that method would be out of place. It doesn’t belong in a logging class.
Was this too basic for you? Well, we should all know these basics, but how do you actually determine what classes your application needs? If you have good Soil or Agile methodologies for your team, you will be using something like a Use Case at the beginning of your analysis and design. A Use Case is a very simple description of how the user sees the system as functioning. In other words, you start with how the application should function before you get into details of the data that functionality needs.
In the 2004 book “Object Thinking”, Dr David West wrote: “Only when you are satisfied with the distribution of responsibilities among your objects are you ready to make a decision about what they need to know to fulfill those responsibilities and which part of that knowledge they need to keep as part of their structure” (Object Thinking, p. 124). In other words, you need to know what an object will do before you know what it needs to do it. Today, this book still stands out as a must read. Safari recently named it one of the most influential books in software.
Do you think about what a class should do before you define the data it needs? After talking to many developers, I feel pretty safe to say that you don’t. It seems most developers start with the data.
Another thing we often do wrong is define classes and methods, but then use methods procedurally. In other words, we may define a method to perform a complex function then put all the code needed into that single method. This method is doing more than one thing, making it more likely to have bugs and more difficult to unit test.
Thinking about how we define classes has a big impact on maintaining our code and our ability to have fewer bugs. Planting the right seeds at the right time means you are growing the right things. After all, you plant seeds so that the right things will grow and keep your code lush, green, and vibrant.
Read our entire Software Gardening article series.