Skip to content
Alan Maciel edited this page Sep 15, 2015 · 9 revisions

POODR Notes

1. Object-Oriented Design

The first requirement for learning object-oriented design is to immerse yourself in objects; once you acquire an object-oriented perspective the rest follows naturally.

Software gets build for a reason.

Design Principles

  • SOLID (Single responsibility, Open-Closed, Liskov substitution, Interface segregation, Dependency inversion)
  • DRY (Don't Repeat Yourself)
  • Law of Demeter (LoD)
  • Design Patterns

2. Designing Classes with a Single Responsibility

The foundation of an object-oriented system is the message, but the most visible organizational structure is the class.

The goal is to model the application, using classes, such it does what is supposed to do right now and is also easy to change later.

### Deciding what belongs in a class The problem us to know how to write the code but not knowing where to put it.

Organize the code to allow easy of changes

Definition of easy to change

  • Changes have no unexpected side effects
  • Small changes in requirements require correspondingly small changes in code.
  • Existing code is easy to reuse
  • The easiest way yo make a change is to add code that in itself is easy to change.

#### The Code should have the following qualities

  • Transparent The consequences of change should be obvious in the code that is changing and in distant code relies upon it.
  • Reasonable The cost of any change should be proportional to the benefits the change achieves.
  • Usable Existing code should be usable in new and unexpected contexts.
  • Exemplary The code itself should encourage those who change it to perpetuate these qualities.

Code that is Transparent Reasonable Usable and Exemplary (TRUE) meets today's needs but can also be changed to meet the needs of the future.

The first step in creating code that is TRUE is to ensure that each class has a single, well-defined responsibility.

Create Classes That Have a Single Responsibility

A class should do the smallest possible useful thing.

Why Single Responsibility Matters

Applications that are easy to change consist of classes that are easy to reuse. Reusable classes are pluggable units of well-defined behavior that have few entanglements. An application that is easy to change is like a box of building blocks; you can select just the pieces you need and assemble them in unanticipated ways.

Determine if a class has a single responsibility

Pretend that the class is sentient and to interrogate it, rephrase everyone of its methods as a question, if the question seems perfectly reasonable you are on solid ground.

Another way is to know if a class has a single responsibility is trying to describe it in one sentence. A class should do the smallest possible useful thing, that thing ought to be simple to describe. If you use the word "and" the class likely has more than one responsibility, if you use the word "or" the class has more than one responsibility and they aren't very related (this is known as Cohesion).

Single Responsibility Principle (SRP)

"A class has responsibilities that fulfill its purpose"

SRP does'n require that a class do only one very narrow thing or that it change for only a single nitpicky reason.

SRP requires a class be cohesive, that everything the class does be highly related to its purpose.

Determining When to Make Design Decisions

It’s common to find yourself in a situation where you know something isn’t quite right with a class.

Do not feel compelled to make design decisions prematurely. Resist, even if you fear your code would dismay the design gurus. Ask yourself: "What is the future cost of doing nothing today?"

When the future cost of doing nothing is the same as the current cost, postpone the decision. Make decisions only when you must with the info you have at that time.

The structure of every class is a message to future maintainers of the app. It reveals your design intentions. For better or for worse, the patterns you establish today will be replicated forever.

This "improve it now" versus "improve it later" tension always exists. Applications are never perfectly designed. Every choice has a price. A good designer understands this tension and minimizes costs by making informed tradeoffs between the needs of the present and the possibilities of the future.

Writing Code That Embraces Change

Because change is inevitable, coding in a changeable style has a big future payoffs. As an additional bonus, coding in these styles will improve your code, today at no extra cost.

Techniques well-known to embrace change

Depend on Behavior, Not Data

Behavior is captured in methods and invoked by sending messages. When you create classes that have a single responsibility, every tiny bit of behavior lives in one and only one place. The phrase “Don’t Repeat Yourself” (DRY) is a shortcut for this idea. DRY code tolerates change because any change in behavior can be made by changing code in just one place.

Behavior is captured in methods and invoked by sending messages. When you create classes that have a single responsibility, every tiny bit of behavior lives in one and only one place. The phrase “Don’t Repeat Yourself” (DRY) is a shortcut for this idea. DRY code tolerates change because any change in behavior can be made by changing code in just one place.

In addition to behavior, objects often contain data. Data is held in an instance variable and can be anything from a simple string or a complex hash. Data can be accessed in one of two ways; you can refer directly to the instance variable or you can wrap the instance variable in an accessor method.

Hide Instance Variables

Always wrap instance variables in accessor methods instead of directly referring to variables. Ruby provides attr_reader as an easy way to create the encapsulating methods. Now the method you define is the only place in the code that understands what your instance variable means. The instance variable becomes the result of a message send. Implementing this method changes from data(referenced all over) to behavior(which is defined once).

If the instance variable is referenced 10 times and it suddenly needs to change, you will need many changes. If it is wrapped in a method you can change what the variable means implementing your own version of the method.

Because it’s possible to wrap every instance variable in a method and to therefore treat any variable as if it’s just another object, the distinction between data and a regular object begins to disappear. While it’s sometimes expedient to think of parts of your application as behavior-less data, most things are better thought of as plain old objects.

You should hide data from yourself. Doing so protects the code from being affected by unexpected changes. Data very often has behavior that you don’t yet know about. Send messages to access variables, even if you think of them as data.

Hide Data Structures

Enforce Single Responsibility Everywhere

Extract Extra Responsibilities from Methods

Methods that have a single responsibility confer the following benefits:

  • Expose previously hidden qualities
  • Avoid the need for comments
  • Encourage reuse
  • Small methods are easy to move to another class

Isolate Extra Responsibilities in Classes

The path to changeable and maintainable object-oriented software begins with classes that have a single responsibility. Classes that do one thing isolate that thing from the rest of your application. This isolation allows change without consequence and reuse without duplication.

## 3. Managing Dependencies


    1. Creating Flexible Interfaces
    1. Reducing Costs with Duck Typing
    1. Acquiring Behavior Through Inheritance
    1. Sharing Role Behavior with Modules
    1. Combining Objects with Composition
    1. Designing Cost-Effective Tests

Clone this wiki locally