managing dependencies - web.cecs.pdx.eduweb.cecs.pdx.edu/~black/oop/lectures/managing...

25
Managing dependencies Andrew P. Black 1 Based on Chapter 3 of POODR

Upload: others

Post on 21-Aug-2020

2 views

Category:

Documents


0 download

TRANSCRIPT

Page 1: Managing Dependencies - web.cecs.pdx.eduweb.cecs.pdx.edu/~black/OOP/Lectures/Managing Dependencies.pdf · other objects, coupling Gear to five different things. When the underlying

Managing dependenciesAndrew P. Black

1

Based on Chapter 3 of POODR

Page 2: Managing Dependencies - web.cecs.pdx.eduweb.cecs.pdx.edu/~black/OOP/Lectures/Managing Dependencies.pdf · other objects, coupling Gear to five different things. When the underlying

Why Dependencies?

• A single object can't do everything, so it will have to talk to other objects

2

Page 3: Managing Dependencies - web.cecs.pdx.eduweb.cecs.pdx.edu/~black/OOP/Lectures/Managing Dependencies.pdf · other objects, coupling Gear to five different things. When the underlying

For any desired behaviour:

• an object can either:1. know it itself,

2. inherit it, or

3. know another object that knows it.

• This chapter is about 3.

3

Page 4: Managing Dependencies - web.cecs.pdx.eduweb.cecs.pdx.edu/~black/OOP/Lectures/Managing Dependencies.pdf · other objects, coupling Gear to five different things. When the underlying

Collaboration

• Collaborating with another object introduces a dependency

• That is, if the other object changes, you might be forced to change too.

4

Page 5: Managing Dependencies - web.cecs.pdx.eduweb.cecs.pdx.edu/~black/OOP/Lectures/Managing Dependencies.pdf · other objects, coupling Gear to five different things. When the underlying

Dependencies exist when:

• an object has a dependency when it knows:‣ The name of another object (Metz says “class”)

‣ the name of a request that it makes on someone other than self

‣ the arguments of a request (number and position)

5

Page 6: Managing Dependencies - web.cecs.pdx.eduweb.cecs.pdx.edu/~black/OOP/Lectures/Managing Dependencies.pdf · other objects, coupling Gear to five different things. When the underlying

Why limit dependencies?

• The more dependencies you have, the greater are the chances that minor tweaks turn into major undertakings.

• Dependencies create coupling‣ an object and its dependencies act like a single

big object; you can’t reuse (or test) the object without also reusing (or testing) its dependencies too.

6

Page 7: Managing Dependencies - web.cecs.pdx.eduweb.cecs.pdx.edu/~black/OOP/Lectures/Managing Dependencies.pdf · other objects, coupling Gear to five different things. When the underlying

7

ptg8315951

Figure 3.1 illustrates the problem. In this case, Gear depends on Wheel and fourother objects, coupling Gear to five different things. When the underlying code wasfirst written everything worked fine. The problem lies dormant until you attempt touse Gear in another context or to change one of the classes upon which Geardepends. When that day comes the cold hard truth is revealed; despite appearances,Gear is not an independent entity. Each of its dependencies is a place where anotherobject is stuck to it. 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 aunit, it’s impossible to reuse just one. Changes to one object force changes to all. Leftunchecked, 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 DependenciesThe remainder of this chapter examines the four kinds of dependencies listed aboveand suggests techniques for avoiding the problems they create. However, before goingforward it’s worth mentioning a few other common dependency related issues thatwill be covered in other chapters.

One especially destructive kind of dependency occurs where an object knowsanother who knows another who knows something; that is, where many messages arechained together to reach behavior that lives in a distant object. This is the “knowingthe name of a message you plan to send to someone other than self ” dependency, onlymagnified. Message chaining creates a dependency between the original object and

38 Chapter 3. Managing Dependencies

Gear depends on wheel, A, B, C and D Gear and its dependencies act like one thing

Gear Gear

Wheel

Whe

el

B

B

A A

C C

DD

Figure 3.1 Dependencies entangle objects with one another.

From the Library of Avi Flombaum

Page 8: Managing Dependencies - web.cecs.pdx.eduweb.cecs.pdx.edu/~black/OOP/Lectures/Managing Dependencies.pdf · other objects, coupling Gear to five different things. When the underlying

Law of Demeter

• Law of Demeter violation is a particular case of case 3: knowing another object that knows … another object that can respond to your request.

• Design interfaces to avoid it

8

Page 9: Managing Dependencies - web.cecs.pdx.eduweb.cecs.pdx.edu/~black/OOP/Lectures/Managing Dependencies.pdf · other objects, coupling Gear to five different things. When the underlying

Dependencies in Testing

• Tests must depend on code

• write tests to avoid over-coupling

9

Page 10: Managing Dependencies - web.cecs.pdx.eduweb.cecs.pdx.edu/~black/OOP/Lectures/Managing Dependencies.pdf · other objects, coupling Gear to five different things. When the underlying

Dependencies in Gear• Gear depends on Wheel class‣ Metz: “Gear becomes less useful when it knows

too much about other objects; if it knew less, it could do more”

‣ My paraphrase: smart objects know how to delegate

• Instead, give a gear a wheel instance when the gear is created.‣ Called: “Dependency Injection”

10

Page 11: Managing Dependencies - web.cecs.pdx.eduweb.cecs.pdx.edu/~black/OOP/Lectures/Managing Dependencies.pdf · other objects, coupling Gear to five different things. When the underlying

(Removed) Dependencies in Gear

11

Page 12: Managing Dependencies - web.cecs.pdx.eduweb.cecs.pdx.edu/~black/OOP/Lectures/Managing Dependencies.pdf · other objects, coupling Gear to five different things. When the underlying

• If you can't remove class dependencies, isolate them by:

• moving them to instance initialization, or

• moving them to their own method.

12

Page 13: Managing Dependencies - web.cecs.pdx.eduweb.cecs.pdx.edu/~black/OOP/Lectures/Managing Dependencies.pdf · other objects, coupling Gear to five different things. When the underlying

Gear knows:

• what requests some other objects understand

• replace these requests (wheel.diameter) with self-requests:

• add a diameter method to self‣ isolates the knowledge that wheel understands

diameter

13

Page 14: Managing Dependencies - web.cecs.pdx.eduweb.cecs.pdx.edu/~black/OOP/Lectures/Managing Dependencies.pdf · other objects, coupling Gear to five different things. When the underlying

Argument–Parameter Dependencies

• Knowing the parameters of a request is a dependency

• Sometimes, you can pass a dictionary containing the arguments.

• This may be a good approach if the parameters are likely to grow or shrink, or if you need defaults.

14

Page 15: Managing Dependencies - web.cecs.pdx.eduweb.cecs.pdx.edu/~black/OOP/Lectures/Managing Dependencies.pdf · other objects, coupling Gear to five different things. When the underlying

Pros and Cons of Dictionary Parameters

• Fixed named arguments are simpler today, but increase the risk that changes will be harder tomorrow.

• There is still a dependency on the keys used for the parameters‣ and it can’t be checked statically

15

Page 16: Managing Dependencies - web.cecs.pdx.eduweb.cecs.pdx.edu/~black/OOP/Lectures/Managing Dependencies.pdf · other objects, coupling Gear to five different things. When the underlying

• Using new for instance creation means that confusion over the meaning and position of parameters is likely

• Grace avoids this problem by encouraging you to give intention revealing names for instance creation method (aka classes)

16

Page 17: Managing Dependencies - web.cecs.pdx.eduweb.cecs.pdx.edu/~black/OOP/Lectures/Managing Dependencies.pdf · other objects, coupling Gear to five different things. When the underlying

• Using many creation-time arguments means that confusion over the meaning and position of parameters is likely

• Having a long parameter list is a code smell: get rid of it

• use replace parameter with method, preserve whole object, and introduce parameter object.

17

Page 18: Managing Dependencies - web.cecs.pdx.eduweb.cecs.pdx.edu/~black/OOP/Lectures/Managing Dependencies.pdf · other objects, coupling Gear to five different things. When the underlying

• Dictionaries make it easy to make arguments optional and to have defaults

• Fixed parameter lists can lead to a combinatorial explosion of variants with and without the optional parameters

18

Page 19: Managing Dependencies - web.cecs.pdx.eduweb.cecs.pdx.edu/~black/OOP/Lectures/Managing Dependencies.pdf · other objects, coupling Gear to five different things. When the underlying

Defaults

• Default parameters are best specified:‣ in a separate method for each default value

‣ in a defaults method (requires merge of dictionaries)

19

Page 20: Managing Dependencies - web.cecs.pdx.eduweb.cecs.pdx.edu/~black/OOP/Lectures/Managing Dependencies.pdf · other objects, coupling Gear to five different things. When the underlying

External modules

• if you don't control the interface of the offending request,‣ wrap it in a factory method that you do own and

control.

• put that method on a singleton object (Ruby module)‣ In Grace, you can just leave it as a factory method

at the top-level of your own module

20

Page 21: Managing Dependencies - web.cecs.pdx.eduweb.cecs.pdx.edu/~black/OOP/Lectures/Managing Dependencies.pdf · other objects, coupling Gear to five different things. When the underlying

Direction of dependencies

• The direction of a dependency matters

• gear depends on wheel ≠ wheel depends on gear‣ You can make either “work”

• getting direction “right” means that your application will be pleasant to work on and easy to maintain into the future.

21

Page 22: Managing Dependencies - web.cecs.pdx.eduweb.cecs.pdx.edu/~black/OOP/Lectures/Managing Dependencies.pdf · other objects, coupling Gear to five different things. When the underlying

What’s “Right”?• Key idea: depend on things that will change

less often than you do.

• Some objects are more likely than others to have changes in requirements‣ Basic libraries, vendor frameworks, application code

• implementations are more likely to change than interfaces

• depend on abstractions rather than on concretions

22

Page 23: Managing Dependencies - web.cecs.pdx.eduweb.cecs.pdx.edu/~black/OOP/Lectures/Managing Dependencies.pdf · other objects, coupling Gear to five different things. When the underlying

Beware!

• Classes with lots of dependents are unlikely to ever change!

• Metz: “Your application will be permanently handicapped by your reluctance to pay the price required to make a change to this class”

23

Page 24: Managing Dependencies - web.cecs.pdx.eduweb.cecs.pdx.edu/~black/OOP/Lectures/Managing Dependencies.pdf · other objects, coupling Gear to five different things. When the underlying

Classifying dependencies• Put them on this grid:

24

were extracted. Depending on an abstraction is always safer than depending on aconcretion because by its very nature, the abstraction is more stable. Ruby does notmake you explicitly declare the abstraction in order to define the interface, but fordesign purposes you can behave as if your virtual interface is as real as a class. Indeed, inthe 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.

Avoiding Dependent-Laden Classes

The final idea, the notion that having dependent-laden objects has many conse-quences, also bears deeper examination. The consequences of changing a dependent-laden class are quite obvious—not so apparent are the consequences of even having adependent-laden class. A class that, if changed, will cause changes to ripple throughthe application, will be under enormous pressure to never change. Ever. Under anycircumstances whatsoever. Your application may be permanently handicapped by yourreluctance to pay the price required to make a change to this class.

Finding the Dependencies That Matter

Imagine each of these truths as a continuum along which all application code falls.Classes vary in their likelihood of change, their level of abstraction, and their numberof dependents. Each quality matters, but the interesting design decisions occur at theplace where likelihood of change intersects with number of dependents. Some of thepossible combinations are healthy for your application; others are deadly.

Figure 3.2 summarizes the possibilities.

55Managing Dependency Direction

CAB

DNeutral Zone:

Less

ManyDependents Few

Likelihood of Requirements Change

More

Changes are unlikelyand have few sideeffects.

Neutral Zone:Changes are likely butthey have few sideeffects.

Danger Zone:These classes WILLchange and thechanges will cascadeinto dependents.

Abstract Zone:Changes are unlikelybut, if they occur, willhave broad effects.

Figure 3.2 Likelihood of change versus number of dependents

Fix

them!

Page 25: Managing Dependencies - web.cecs.pdx.eduweb.cecs.pdx.edu/~black/OOP/Lectures/Managing Dependencies.pdf · other objects, coupling Gear to five different things. When the underlying

Summary1. Injecting dependencies creates self-

contained objects that can be reused in ways that you might never have guessed

2. Isolating dependencies lets you react to changes, when they come, quickly and easily

3. Depend on things that change less often than you do.‣ When possible, depend on abstractions rather than

concretions.

25