Following my last article, why do we use nil, I thought it’d be a good idea to ask this question for other things that we take for granted.
Like…
Why do we use classes instead of having just one GIGANT blob of ugly code?
At a fundamental level, we use classes to organize code & data into logical units.
But there is more to it than that.
A class allows you to create an abstraction.
What Is An Abstraction?
You use abstractions every single day, every single minute.
The keyboard I’m typing this on is made of:
- A cable
- Cherry MX black switches
- The plastic casing that holds everything together
- The circuit board that transmits electrical signals to my computer
A keyboard is just a concept that emerges from putting these things together in the right way.
It’s an abstraction because you don’t need to know how it works internally to use it. You don’t even need to know the components it’s made of!
You just plug it in & start typing.
That’s exactly what classes allow you to do.
Why Is Abstraction Important?
Abstraction helps you manage complexity.
As Steve McConnell says:
“The single most important reason to create a class is to reduce a program’s complexity”
How does abstraction accomplish this?
By hiding the details about how something works & exposing its services with a public interface.
In a Ruby class the interface is composed of its public methods. While the details are hidden with private methods.
With details I mean:
- instance variables
- internal methods
- algorithms & data structures
When those are hidden you can change them whenever you want, without affecting the users of your class.
For example:
If you have a GPS
class that uses an array to store data, and you have to know that on index 0 of that array you’ll find the latitude & index 1 is the longitude, these are details you shouldn’t have to know as a user of the class.
How To Write a Good Class
Now, this is a big topic.
A lot of things go into creating a good class, like following the SOLID principles.
But most importantly, your classes must have some kind of role, and not be made up of random methods.
For example, you want to separate business logic (calculations, rules) from presentation logic (formatting) because they are different roles.
Look at this code:
require 'rest-client' require 'nokogiri' class ImageCounter def initialize(url) @url = url end def find_images_and_report data = RestClient.get(@url).body html = Nokogiri::HTML.parse(data) images = html.css("img") report = "" report << "=" * 40 << "\n" report << "Found #{images.size} images on #{@url} \n" report << "=" * 40 << "\n" end end reporter = ImageCounter.new("rubyguides.com") report = reporter.find_images_and_report
You can see how this class is concerned with both the calculations & the presentation. This is fine if you are writing a "quick & dirty" script, but for a more serious application you want to separate them.
When you separate the responsibilities you can plug in a different presentation layer, or you can change the business rules & reuse the same presentation.
This code reuse aspect of classes is another good reason to write more of them.
There are more ideas to help you write better classes.
Here's some to help you explore further:
Knowing why we write classes in the first place is a good place to start, so good job if you read the whole article!
Summary
You learned why we write classes, what is abstraction & why it's important. You also learned the fundamentals of writing good classes & I gave you some pointers on what to read more about.
Unless you want your code to become a Big Ball of Mud start applying some of these concepts now to improve your class design 🙂
Don't forget to share this article on Twitter if you found it useful!