POODR - Ch4: Creating Flexible Interfaces

There is design detail that must be captured at this level but an object-oriented application is more than just classes. It is made up of classes but defined by messages. Classes control what’s in your source code repository; messages reflect the living, ani- mated application. Design, therefore, must be concerned with the messages that pass between ob- jects. It deals not only with what objects know (their responsibilities) and who they know (their dependencies), but how they talk to one another. The conversation be- tween objects takes place using their interfaces.

##Defining Public Interfaces The kitchen does many things but does not, thankfully, expose them all to its customers. It has a public interface that customers are expected to use; the menu. Within the kitchen many things happen, many other messages get passed, but these messages are private and thus invisible to customers. Each of your classes is like a kitchen. The class exists to fulfill a single responsibil- ity but implements many methods.

###Public Interfaces The methods that make up the public interface of your class comprise the face it presents to the world. They: • Reveal its primary responsibility • Are expected to be invoked by others • Will not change on a whim • Are safe for others to depend on • Are thoroughly documented in the tests

Private Interfaces

All other methods in the class are part of its private interface. They: • Handle implementation details • Are not expected to be sent by other objects • Can change for any reason whatsoever • Are unsafe for others to depend on • May not even be referenced in the tests

Domain objects are easy to find but they are not at the design center of your application. Instead, they are a trap for the unwary. If you fixate on domain objects you will tend to coerce behavior into them. Design experts notice domain objects without concentrating on them; they focus not on these objects but on the messages that pass between them. These messages are guides that lead you to discover other objects, ones that are just as necessary but far less obvious.

Before you sit at the keyboard and start typing you should form an intention about the objects and the messages needed to satisfy this use case.

Using Sequence Diagrams

There is a perfect, low-cost way to experiment with objects and messages: sequence diagrams. Therein lies the value of sequence diagrams. They explicitly specify the messages that pass between objects, and because objects should only communicate using public interfaces, sequence diagrams are a vehicle for exposing, experimenting with, and ultimately defining those interfaces.

Also, notice now that you have drawn a sequence diagram, this design conversation has been inverted. The previous design emphasis was on classes and who and what they knew. Suddenly, the conversation has changed; it is now revolving around mes- sages. Instead of deciding on a class and then figuring out its responsibilities, you are now deciding on a message and figuring out where to send it.

This transition from class-based design to message-based design is a turning point in your design career. The message-based perspective yields more flexible applications than does the class-based perspective. Changing the fundamental design question from “I know I need this class, what should it do?” to “I need to send this message, who should respond to it?” is the first step in that direction. You don’t send messages because you have objects, you have objects because you send messages.

Asking for “What” Instead of Telling “How”

The distinction between a message that asks for what the sender wants and a message that tells the receiver how to behave may seem subtle but the consequences are significant. Understanding this difference is a key part of creating reusable classes with well-defined public interfaces.

Seeking Context Independence

The context that an object expects has a direct effect on how difficult it is to reuse. Objects that have a simple context are easy to use and easy to test; they expect few things from their surroundings. Objects that have a complicated context are hard to use and hard to test; they require complicated setup before they can do anything. The best possible situation is for an object to be completely independent of its context. An object that could collaborate with others without knowing who they are or what they do could be reused in novel and unanticipated ways. You already know the technique for collaborating with others without knowing who they are—dependency injection.

Trusting Other Objects

If objects were human and could describe their own relationships, in Figure 4.5 Trip would be telling Mechanic: “I know what I want and I know how you do it;” in Figure 4.6: “I know what I want and I know what you do” and in Figure 4.7: “I know what I want and I trust you to do your part.” This blind trust is a keystone of object-oriented design. It allows objects to collab- orate without binding themselves to context and is necessary in any application that expects to grow and change.

Create Explicit Interfaces

Your goal is to write code that works today, that can easily be reused, and that can be adapted for unexpected use in the future. Other people will invoke your methods; it is your obligation to communicate which ones are dependable. www.it-ebooks.info Writing Code That Puts Its Best (Inter)Face Forward 77 Every time you create a class, declare its interfaces. Methods in the public interface should • Be explicitly identified as such • Be more about what than how • Have names that, insofar as you can anticipate, will not change • Take a hash as an options parameter

Be just as intentional about the private interface; make it inescapably obvious. Tests, because they serve as documentation, can support this endeavor. Either do not test private methods or, if you must, segregate those tests from the tests of public methods. Do not allow your tests to fool others into unintentionally depending on the changeable, private interface. Ruby provides three relevant keywords: public, protected, and private. Use of these keywords serves two distinct purposes. First, they indicate which methods are stable and which are unstable. Second, they control how visible a method is to other parts of your application. These two purposes are very different. Conveying informa- tion that a method is stable or unstable is one thing; attempting to control how others use it is quite another. Public, Protected, and Private Keywords The private keyword denotes the least stable kind of method and provides the most restricted visibility. Private methods must be called with an implicit receiver, or, inversely, may never be called with an explicit receiver.

The protected keyword also indicates an unstable method, but one with slightly different visibility restrictions. Protected methods allow explicit receivers as long as the receiver is self or an instance of the same class or subclass of self.

Honor the Public Interfaces of Others Do your best to interact with other classes using only their public interfaces.f your design forces the use of a private method in another class, first rethink your design. It’s possible that a committed effort will unearth an alternative; you should try very hard to find one. A dependency on a private method of an external framework is a form of technical debt. Avoid these dependencies.

Minimize Context Construct public interfaces with an eye toward minimizing the context they require from others. Keep the what versus how distinction in mind; create public methods that allow senders to get what they want without knowing how your class implements its behavior.

Do what best suits your needs, but create some kind of defined public interface and use it. This reduces your class’s context, making it easier to reuse and simpler to test.

POODR - Ch3: Mangaging Dependencies

Each message is initiated by an object to invoke some bit of behavior. All of the behavior is dispersed among the objects. Therefore, for any desired behavior:

  • an object either knows it personally,
  • inherits it, or
  • knows another object who knows it.

This chapter is about the third, getting access to behavior when that behavior is implemented in other objects.

Because well designed objects have a single responsibility, their very nature requires that they collaborate to accomplish complex tasks. This collaboration is powerful and perilous. To collaborate, an object must know something know about others. Knowing creates a dependency. If not managed carefully, these dependencies will strangle your application.

Understanding Dependencies

An object depends on another object if, when one object changes, the other might be forced to change in turn.

Recognizing Dependencies

An object has a dependency when it knows • The name of another class. Gear expects a class named Wheel to exist. • The name of a message that it intends to send to someone other than self. Gear expects a Wheel instance to respond to diameter. • The arguments that a message requires. Gear knows that Wheel.new requires a rim and a tire. • The order of those arguments. Gear knows the first argument to Wheel.new should be rim, the second, tire.

Your design challenge is to manage dependencies so that each class has the fewest possible; a class should know just enough to do its job and not one thing more

Coupling Between Objects (CBO)

Alternatively, you could say that each coupling creates a dependency.The dependencies cause these objects to act like a single thing. They move in lockstep; they change together. When two (or three or more) objects are so tightly coupled that they behave as a unit, it’s impossible to reuse just one. Changes to one object force changes to all. Left unchecked, unmanaged dependencies cause an entire application to become an entan- gled mess. A day will come when it’s easier to rewrite everything than to change anything.

Other Dependencies

One especially destructive kind of dependency occurs where an object knows another who knows another who knows something; that is, where many messages are chained together to reach behavior that lives in a distant object. This is the “knowing the name of a message you plan to send to someone other than self ” dependency, only magnified. Message chaining creates a dependency between the original object and every object and message along the way to its ultimate target. These additional couplings greatly increase the chance that the first object will be forced to change because a change to any of the intermediate objects might affect it. This is a Law of Demeter Violation.

Writing Loosley Coupled Code

Inject Dependencies

Referring to another class by name create a sticky spot.

Change:

class Gear
attr_reader :chainring, :cog, :rim:, :tire
  def initialize(chainring, cog, rim, tire)
    @chainring = chainring
    @cog = cog
    @rim = rim
    @tire = tire
  end

  def gear_inches
    ratio * Wheel.new(rim,tire).diameter
  end
end

Gear.new(52, 11, 26, 1.5).gear_inches

to:

class Gear
attr_reader :chainring, :cog, :wheel
  def initialize(chainring, cog, wheel)
    @chainring = chainring
    @cog = cog
    @wheel = wheel
  end

  def gear_inches
    ratio * wheel.diameter
  end
end

Gear.new(52, 11, Wheel.new(26, 1.5)).gear_inches

Gear can now collaborate with any object that implements diameter.

This technique is known as dependency injection. Despite its fearsome reputation, dependency injection truly is this simple. Gear previously had explicit dependencies on the Wheel class and on the type and order of its initialization arguments, but through injection these dependencies have been reduced to a single dependency on the diameter method. Gear is now smarter because it knows less.

Using dependency injection to shape code relies on your ability to recognize that the responsibility for knowing the name of a class and the responsibility for knowing the name of a message to send to that class may belong in different objects.

Isolate Dependencies

It’s best to break all unnecessary dependences but, unfortunately, while this is always technically possible it may not be actually possible. Therefore, if you cannot remove unnecessary dependencies, you should isolate them within your class.

Isolate Instance Creation

In the first, creation of the new instance of Wheel has been moved from Gear’s gearinches method to Gear’s initialization method. This cleans up the gearinches method and publicly exposes the dependency in the initialize method.

class Gear
attr_reader :chainring, :cog, :rim, :tire
  def initialize(chainring, cog, rim, tire)
    @chainring = chainring
    @cog = cog
    @wheel = Wheel.new(rim, tire)
  end

The next alternative isolates creation of a new Wheel in its own explicitly defined wheel method. This new method lazily creates a new instance of Wheel, using Ruby’s ||= operator. In this case, creation of a new instance of Wheel is deferred until gear_inches invokes the new wheel method.

class Gear
attr_reader :chainring, :cog, :rim, :tire
  def initialize(chainring, cog, rim, tire)
      @chainring = chainring
      @cog       = cog
      @rim       = rim
      @tire      = tire
  end
  def gear_inches
    ratio * wheel.diameter
  end
  def wheel
    @wheel ||= Wheel.new(rim, tire)
  end
end

Isolate Vulnerable External Messages

Now that you’ve isolated references to external class names it’s time to turn your attention to external messages, that is, messages that are “sent to someone other than self.” This technique becomes necessary when a class contains embedded references to a message that is likely to change. Isolating the reference provides some insurance against being affected by that change. Although not every external method is a candi- date for this preemptive isolation, it’s worth examining your code, looking for and wrapping the most vulnerable dependencies.

An alternative way to eliminate these side effects is to avoid the problem from the very beginning by reversing the direction of the dependency. This idea will be addressed soon but first there’s one more coding technique to cover.

Remove Arguement-Order Dependencies

Explicitly Define Defaults

When you send a message that requires arguments, you, as the sender, cannot avoid having knowledge of those arguments. This dependency is unavoidable. However, passing arguments often involves a second, more subtle, dependency. Many method signatures not only require arguments, but they also require that those arguments be passed in a specific, fixed order.

Use Hashes for Initialization Arguments

There’s a simple way to avoid depending on fixed-order arguments. If you have control over the Gear initialize method, change the code to take a hash of options instead of a fixed list of parameters. The initialize method now takes just one argument, args, a hash that contains all of the inputs. The above technique has several advantages. The first and most obvious is that it removes every dependency on argument order. This technique adds verbosity. In many situations verbosity is a detriment, but in this case it has value. The verbosity exists at the intersection between the needs of the present and the uncertainty of the future. Using fixed-order arguments requires less code today but you pay for this decrease in volume of code with an increase in the risk that changes will cascade into dependents later.

Explicitly Define Defaults

There are many techniques for adding defaults. Simple non-boolean defaults can be specified using Ruby’s || method. This is a common technique but one you should use with caution; there are situations in which it might not do what you want. The || method acts as an or condition; it first evaluates the left-hand expression and then, if the expression returns false or nil, proceeds to evaluate and return the result of the right-hand expression. The use of || above therefore, relies on the fact that the [] method of Hash returns nil for missing keys. In the case where args contains a :boolean_thing key that defaults to true, use of || in this way makes it impossible for the caller to ever explicitly set the final variable to false or nil.

The above technique for substituting an options hash for a list of fixed-order arguments is perfect for cases where you are forced to depend on external interfaces that you cannot change. Do not allow these kinds of external dependencies to permeate your code; protect yourself by wrapping each in a method that is owned by your own application.

Managing Dependecy Direction

Reversing Dependecies

Choosing Dependency Direction

Pretend for a moment that your classes are people. If you were to give them advice about how to behave you would tell them to depend on things that change less often than you do. This short statement belies the sophistication of the idea, which is based on three simple truths about code: • Some classes are more likely than others to have changes in requirements. • Concrete classes are more likely to change than abstract classes. • Changing a class that has many dependents will result in widespread consequences.

Recognizing Concretions and Abstractions

The second idea concerns itself with the concreteness and abstractness of code. The term abstract is used here just as Merriam-Webster defines it, as “disassociated from any specific instance,” and, as so many things in Ruby, represents an idea about code as opposed to a specific technical restriction.

The wonderful thing about abstractions is that they represent common, stable qualities. They are less likely to change than are the concrete classes from which they were extracted. Depending on an abstraction is always safer than depending on a concretion because by its very nature, the abstraction is more stable. Ruby does not make you explicitly declare the abstraction in order to define the interface, but for design purposes you can behave as if your virtual interface is as real as a class. Indeed, in the rest of this discussion, the term “class” stands for both class and this kind of interface. These interfaces can have dependents and so must be taken into account during design.

Depend on things that change less often than you do is a heuristic that stands in for all the ideas in this section. The zones are a useful way to organize your thoughts but in the fog of development it may not be obvious which classes go where.

POODR - Ch2: Designing Classes with a Single Responsibility

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

OO Questions:

What are your classes? How many should you have? What behavior will they implement? How much do they know about the other classes? How much of themselves should the expose?

At this stage, your first obligation is to take a deep breath and insist that it be simple. Your goal is to model your application, using classes, such that is does what is is supposed to do right now. Design is more the art of perserving changability than it is the act of achieving perfection.

Code should be TRUE:

Transparent: The consquences of change should be obvious in the code that is changing and in distant code thst relies on it.

Reasonsable: The cost of any change should be proportional to the benefit thr change acheives

Usable: Existing code should be usable in a new and unexpected contents.

Expemplary: The cod itself should encourage those who change it to perpetuate these qualities. TRUE ensures that each class has a single, well-defined responsibilty.

Creating Classes That have a Single Responsibility

A class should do the smallest posbbile useful thing, that is - it should have a sing responsibility.

Why Single Responsibility Matters

Appliciations that are easy to change consist of classes that are easy to reuse. Reusable classes are pluggable into units of well-defined behavior that have few entanglements.

A class that has more than one responsibility is difficult to reuse. If you want to resuse some (but not all) of it behavior, it is impossible to get only the parts you need.

If the responsibilties are so coupled that you cannot use just the beviour you need, you could duplicat the code of interest.

Deterimining If a Class Has Single Responsibility

How can you determine if a class contains the behavior or belongs somewhere else? Ask it! "Mr Gear, What is your ratio?"

Another way to figure it out is to attempt to describe the class in one sentence. If the simplest description you can devise includes "and", the class likely has more than one responsibility. If the description includes "or", then the class has more than one responsibility and they aren't even related.

When a class is related to it's purpose, its considered "highly cohesive" or to have single responsibility (Single Responsibility Principle)

Determining when to make design decisions:

Don't feel compelled to make design decisions prematurely. When the future cost of doing nothing is the same as the current cost, postpone the decision. Make the decision only when you must with the information you have at the time.

Writing Code that Embraces Change

Here are a few well known techniques that you can use to create code that embaces change:

1. Depend on Behavior, not Data

Behavior is captured in methods anid invoked by sending messages. In addition to behavior, objects often contain data. Data is held in an instance variable and can be anything from an simple string to complex hash. Data can be accessed in 2 ways: 1. you can refer directly to the instance variable 2. you can wrap the intance variable in an accessor method

Hide Data Structures

1. Always wrap instance variables in accessor methods insteadof directly referring to the variables

2. Use Structs

Direct references into complicated structure are confusing, because they obscure what the data really is and the maintenance is a nightmare. In Ruby, it's easy to seperate structure from meaning - just as you use a method to wrap an instance variable, you can use a Ruby Struct class to wrap a structure. Ruby defines Struct as "a convenient way to bundle a number of attributes together, using accessor methods, without having to write an explicit class.

2. Enforce Single Responsibilities Everywhere

3. Extract Extra Responsibilities from Methods

Methods, like classes should have single responsibility so they are easier to use. Apply the same design techniques as you would with classes.

  • Seperating iteration from the action that's being performed on each element is a common case of multiple responsibitlity that is easy to recognize.

The imapct of the single refactoring like ithis is small, but the cumulative effect of this coding style is huge. Methods that have single resonsibility confer the following benefits:

1. Expose previously hidden qualities
2. Avoid the need for comments
3. Encourage reuse
4. Easy to move to another class

Isolate Extra Responsibilities in Classes

Once every method has a single responsibility, the scope of your class will be more apparent

The path to changeable and maintable 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 consquence and reuse without duplication.

POODR - Ch1: Object Oriented Design

Object Oriented Design requires that you shift from thinking about the world as a collection of predefined procedures to modeling th world as a series of messages that are past between objects.

In Praise of Design

Desgin really doesn't become a concern if nothing ever changes (requirements). But something always changes and it is the need for change that makes desugn matter.

Why is Change Hard?

Object oriented applications are made of partst that interact to produce the behavior of the whole. The parts are objects, interactions are emobodied in the messages that pass between them.

OOD is about managing dependencies. It's a set of coding techniques that arrange dependencies such that objects can tolerate change. Changing one object forces change upon its collabortors.

However when objects know too much, they have expectations about the world in which they reside. And these expectations contstrain them.

A Practical Definition of Design

Design is an art of arranging code. Design has two components: You must not only write code for the feature you plan to deliver today, you must also create code that is amendable to being changed later.

Design that is that anticipates specific future requirements almost always ends badly. It shouldn't guess hte future, but rather perserves options for accomodating the future, leaving you room to move.

Primary goal is to allow you to desiglm later, and its primary goal is reduce the cost of change.

Design Principles

SOLID stands for Single Responsibilty, Open-Closed, Liskov Substitution, Interface Segregation, & Dependancy Inversion

DRY - Don't Repeat Yourself

LoD - Law of Demeter

Design Patterns

give us the power to name common problems and solve those problems in common ways, allowing us to big fuzzy things into focus.

The Act of Design

How design fails: 1. Lack of it - programmers typically now little about design 2. Under-designed - lack of knowledge of design principles 3. Over-design - seasoned devs may disgn relentlessly 4. Object Oriented Desgin fails when the act of design is seperated from the act of programming. The feedback loop should be timely and incremental; the iterative techniques of the Agile Development are perfect for well-designd OO applications.

When to Design

Agile believes that the mot cost-effective way to produce what customers's really want is to collaborate with the, building software one bit at atime such that each deivered bit has the opprotunity to alter ideas about the next.

There is no need to do BUFD (Big Upfront Design)

The Agile Process gaurantees change and yu ability to do so depneds on your design (sinple, flexibe, and malleable code).

Judging Design

Back in the day, design was jusged by the number of lines of code (sometimes referred to as SLOC). The ultimate software metric would be cost per feature over the time interval the matters.

Failure to design increases your technical debt.

Your decision about design depends on two things.: your skills and your timeframe.

A brief introduction to Object Oriented Programming:

OO applications are made of objects and messages that pass between them.

Procedural Langauges

is a non-object oriented progamming technique. Every possible data type and po]eration already exists, you can't make up wholly new operations or brand new data types.

Object Oriented Programming

Ruby has a string object instead of a string data type. Because Ruby string objects supply their own operations, Ruby doesn't have to know anything in particular about the string data type but rather it only need to know how to send object messages.

Ruby allows to you to provide classes tha essentially blueprints for the consturction of similar objects. A class defines methods (definitions of behavior) and attributes(definitons of variables), while also allowing you to instantiate new objects with same operations or behavior.

Build Robust & Production Quality Applications - Lesson 6: Mailgun

Mailgun

Mailgun is an email service for developers - which is clear in its interface. It has a ver low-level design that is easy for tweaking and has alot of options.

  • It focuses on transaction emails and it optimized for deliverability.
  • It also allows for the receipt of emails.
  • You can specify an email address that you want mailgun to listen. Mailgun can pre-process the message and parse out parts of the email and send to your app for processing.
  • It can handle campaign emails, number of clicks, etc.

How to Integrate Mailgun into our Server

We are using Heroku and there is a Mailgun/Heroku add-on. There is a free option that limits to 300 emails/day.

It's pretty simple beyond that. You just log into Heroku, select your app, and run the command:

heroku addons:create mailgun

Read Documentation on Sending Emails via SMTP

Go to your configuation for your production env, and change the setting to those listed. Make sure you keep stmp as the delivery method. Env variables will be set by Heroku, so you don't have to worry about that.

Mailgun supports two delivery methods. The reason we can use smtp is becasue ActionMailer will help us to prepare to proper map format. But HTTP is also an option. You don't have to rely on Rails to do that. You can just use REST client that will use an HTTP POST. Check the API documentation to see what other headers can be sent.