Everything in Ruby is an object, all the way down to the lowliest integers. These objects package up functionality and can maintain their state independent of other objects which gives them enormous power to help you design more modular and scalable code.
This is because using objects empowers the actual data of your program to come alive and take on some of the responsibility of executing tasks. Otherwise, you're left running your program from a single procedure or set of procedures who need to know way too much about all the data in the system. That quickly becomes unwieldy and problematic.
In Object Orientation, according to Mark Slagell:
We stop treating each piece of data as a box with an open lid that lets us reach in and throw things around.
We start treating each piece of data as a working machine with a closed lid and a few well-marked switches and dials.
Breaking the system into objects lets you encapsulate that data nicely with whatever parts of the system need it while keeping the rest of the system clean and clear.
The philosophy of Object Orientation is simply about embracing these objects. On a granular object level, it means giving objects the autonomy to perform their tasks as independently as possible. At a systems level, it means embracing modularity and encapsulation.
Objects are just things with state of their own and which come with the knowledge of how to respond to certain messages. They communicate with each other using these messages. When you call a method, you're really passing a message to an object and asking it to respond.
For instance, when you pass the
length message to an
Array object (e.g.
[1,2,3].length), the array first checks whether it knows how to respond to that message (is there a method or variable you can access by that name?). Since the array is an instance of the Array class and thus inherits the
length method, the array responds by giving you some information about its state, in this case by returning the number of items it contains.
The principle applies to small data types like Arrays or giant systems -- they're all asking each other to do things by passing messages like 6th graders. The real trick of Object-Oriented Programming (OOP) is figuring out which objects should know what about each other and how they should communicate.
Objects are great because you can forget about them. For instance, I don't care how old the
Sven object is but, if I need to know, I can just ask it with
Sven.age. That way I don't need to keep every piece of information about my system's objects immediately at hand all the time.
OOP also allows you to produce code that is more maintainable and scalable at the systems level.
OO systems are more maintainable because you can isolate specific components of the system and alter them while knowing you won't break the whole thing. As long as you don't screw up how an object communicates with other objects, you're in the clear.
OO systems are more scalable for the same reason -- you can sub out components and replace them with more performant components for the reasons stated above.
You'll start to see these benefits in some of the problems later in the unit.
In theory, warm fuzzy ideas like modularity sound great. Sign me up!
The real trick, though, is figuring out how to break your system into objects, what kinds of objects to use, and then how interconnected those objects need to be. That's where characteristics of good modular systems and SOLID design principles start to come in. They give us some rules of thumb when deciding how to break a problem into components.
If you recall, the 3 characteristics of good modular systems are:
We'll see over the next few lessons (and units) how these ideas can be applied to your Ruby code.
More immediately, we'll look at the parts of Ruby that help you apply good modular design to your solutions. You've already worked with a slew of basic objects in Ruby but we'll show you how to create your own Classes and use them to achieve all the benefits of modularity yourself.
How would you create a Tic Tac Toe game? What about something more complicated like Poker? Or even more complicated still like a role-playing game or Chess? You're going to need objects to model all the parts of these systems and we'll show you how.
The coming section will continue to delve into some of Ruby's as-yet-unexplored magic (like the Enumerable Module) but we'll start bringing the arc back towards object orientation so we can help you use Ruby to actually solve meaningful problems like those. We'll work with methods, classes, and best practices for dealing with them.
Finally, we'll walk through using OOP principles to build an actual program (it's about time!).