1 design by responsibility (craig larman) software engineering

71
1 Design by Responsibility (Craig Larman) Software Engineering

Upload: francis-wheeler

Post on 28-Dec-2015

233 views

Category:

Documents


0 download

TRANSCRIPT

1

Design by Responsibility(Craig Larman)

Design by Responsibility(Craig Larman)

Software Engineering

2

Object DesignObject Design

The rough steps followed so far include:Define requirements and model with use cases

Create domain model (conceptual class diag.)

Now to design objects we need to:Add methods to the classes and define messaging

between objects to fulfill the requirements

But that last step isn’t trivial!

The rough steps followed so far include:Define requirements and model with use cases

Create domain model (conceptual class diag.)

Now to design objects we need to:Add methods to the classes and define messaging

between objects to fulfill the requirements

But that last step isn’t trivial!

3

GRASP PatternsGRASP Patterns

GRASP patterns help define normal ways that objects interact with each otherGRASP is Larman’s term; “General Responsibility

Assignment Software Patterns”

We’ll cover five of the patterns in the text

For all 23 standard patterns, see Erich Gamma’s classic Design Patterns (ISBN 0201633612 or 0201634988)

GRASP patterns help define normal ways that objects interact with each otherGRASP is Larman’s term; “General Responsibility

Assignment Software Patterns”

We’ll cover five of the patterns in the text

For all 23 standard patterns, see Erich Gamma’s classic Design Patterns (ISBN 0201633612 or 0201634988)

4

ResponsibilitiesResponsibilities

The responsibilities for an object describe what behavior it needs to fulfill

DoingCreate an object

Perform a calculation

Start action in another object

Control activities in other objects

“Sale is responsible for creating SalesLineItem”

The responsibilities for an object describe what behavior it needs to fulfill

DoingCreate an object

Perform a calculation

Start action in another object

Control activities in other objects

“Sale is responsible for creating SalesLineItem”

5

ResponsibilitiesResponsibilities

KnowingAbout private encapsulated dataAbout related objectsAbout things it can calculate or derive“Sale is responsible for knowing its total”Most ‘knowing’ responsibilities are apparent

from the attributes and associations of the object

KnowingAbout private encapsulated dataAbout related objectsAbout things it can calculate or derive“Sale is responsible for knowing its total”Most ‘knowing’ responsibilities are apparent

from the attributes and associations of the object

6

ResponsibilitiesResponsibilities

Translating responsibilities into classes and methods depends on how detailed or general the responsibilities are

Methods are often implemented to fulfill responsibilities

Translating responsibilities into classes and methods depends on how detailed or general the responsibilities are

Methods are often implemented to fulfill responsibilities

7

Getters and SettersGetters and Setters

Detailed object methods often include a lot of getters and settersGetters ‘get’ some value for the outside

world, e.g. getTotal (a ‘knowing’ responsibility)

Setters ‘set’ some value – like assignment statements, e.g. setSecurityLevel (a ‘doing’ responsibility)

Detailed object methods often include a lot of getters and settersGetters ‘get’ some value for the outside

world, e.g. getTotal (a ‘knowing’ responsibility)

Setters ‘set’ some value – like assignment statements, e.g. setSecurityLevel (a ‘doing’ responsibility)

8

Responsibilities, Methods relatedResponsibilities, Methods related

:Sale

:Payment

makePayment()

create()

From Fig. 16.1, p. 217

makePayment implies Sale objects are responsible for creating Payments

Note Payment shifted down to show its creation

9

Defining PatternsDefining Patterns

Patterns capture well established “best practices” for design

Some are very low level; others are architectural

Each Pattern is defined by its Name, a summary of the Pattern’s Solution, and a description of the Problem it solves

Patterns capture well established “best practices” for design

Some are very low level; others are architectural

Each Pattern is defined by its Name, a summary of the Pattern’s Solution, and a description of the Problem it solves

10

Defining PatternsDefining Patterns

Patterns are not always the best solution

Good pattern descriptions include when the pattern may not apply, or the pros and cons of the pattern

Patterns are not always the best solution

Good pattern descriptions include when the pattern may not apply, or the pros and cons of the pattern

11

The First Five GRASP PatternsThe First Five GRASP PatternsInformation Expert

Creator

High Cohesion

Low Coupling

Controller

Information Expert

Creator

High Cohesion

Low Coupling

Controller

12

Information ExpertInformation Expert

Problem: what is the general principle of assigning responsibilities to objects?

Solution: assign responsibility to the Information Expert – the class which has the information needed to fulfill the responsibilityor Whoever has the data is responsible for managing and sharing it!

Problem: what is the general principle of assigning responsibilities to objects?

Solution: assign responsibility to the Information Expert – the class which has the information needed to fulfill the responsibilityor Whoever has the data is responsible for managing and sharing it!

13

Information ExpertInformation Expert

The domain model should inspire expansion into design classes which will handle all of the data and use it to meet requirements

A key step is that we have to make up the classes we think we’ll need, based on the system characteristics, and see if they can work correctly

The domain model should inspire expansion into design classes which will handle all of the data and use it to meet requirements

A key step is that we have to make up the classes we think we’ll need, based on the system characteristics, and see if they can work correctly

14

Information ExpertInformation Expert

So if we have a class called Sale (like Shipment in the homework assignments), one responsibility might be to provide the total cost of the Sale

We know from a typical invoice that a Sale might consists of a bunch of line items, so we might call their class SalesLineItem

So if we have a class called Sale (like Shipment in the homework assignments), one responsibility might be to provide the total cost of the Sale

We know from a typical invoice that a Sale might consists of a bunch of line items, so we might call their class SalesLineItem

15

Information ExpertInformation Expert

Each SalesLineItem may have a quantity

And each SalesLineItem needs someplace safe to store its description and price, so we’ll put that in a ProductSpecification

After defining the associations and multiplicity, we get Figure 16.3 (p. 222), shown on the next slide

Each SalesLineItem may have a quantity

And each SalesLineItem needs someplace safe to store its description and price, so we’ll put that in a ProductSpecification

After defining the associations and multiplicity, we get Figure 16.3 (p. 222), shown on the next slide

16

Information ExpertInformation Expert

-date-time

Sale

-description-price-itemID

ProductSpecification

-quantity

SalesLineItem

1

1..*

Contains

* 1

Described-by

17

Information ExpertInformation ExpertSo at the highest level, we need to get the

total cost from Sale

But in order to get that, we need the subtotal of each line item – so get that from the information expert for each line item

So at the highest level, we need to get the total cost from Sale

But in order to get that, we need the subtotal of each line item – so get that from the information expert for each line item

:Sale

getTotal()

18

Information ExpertInformation Expert

So each SalesLineItem can get the subtotal of that line; and the Sale will get those subtotals

But each line item needs the price of each item; get from ProductDescription

So each SalesLineItem can get the subtotal of that line; and the Sale will get those subtotals

But each line item needs the price of each item; get from ProductDescription

:Sale

getTotal()

:SalesLineItem

getSubtotal()

19

Information ExpertInformation Expert

Omitting variable assignments we have:

Where each object is responsible for providing the data it owns

Omitting variable assignments we have:

Where each object is responsible for providing the data it owns

:Sale

getTotal()

:SalesLineItem

getSubtotal()

:ProductDescription

getPrice()

20

Information ExpertInformation Expert

The class diagram becomes:The class diagram becomes:

+getTotal()

-date-time

Sale

+getPrice()

-description-price-itemID

ProductSpecification

+getSubtotal()

-quantity

SalesLineItem

1

1..*

Contains

* 1

Described-by

21

Information ExpertInformation Expert

Information Expert is used very frequently in object design

May not be suitable when coupling or cohesion dictate otherwise (see later)

Information Expert is used very frequently in object design

May not be suitable when coupling or cohesion dictate otherwise (see later)

22

CreatorCreator

Problem: Who is responsible for creating a new instance of a class?

Solution: Let B create instances of A if:B aggregates (is made up of) A

B contains (holds) A objects

B records instance of A objects

B closely uses A objects

B has data needed when A is created

Problem: Who is responsible for creating a new instance of a class?

Solution: Let B create instances of A if:B aggregates (is made up of) A

B contains (holds) A objects

B records instance of A objects

B closely uses A objects

B has data needed when A is created

23

CreatorCreator

Creation of objects is also a very common activity

In the previous example, Sale aggregates (contains) many SalesLineItem objects (one object per line in the Sale), hence is makes sense for Sale to be a Creator of SalesLineItem instances

Creation of objects is also a very common activity

In the previous example, Sale aggregates (contains) many SalesLineItem objects (one object per line in the Sale), hence is makes sense for Sale to be a Creator of SalesLineItem instances

24

CreatorCreator

Hence a responsibility of the system is that a Sale needs a method to makeLineItem

If you want add X (quantity) widgets to a shopping cart, then Sale adds them to

the cart

Hence a responsibility of the system is that a Sale needs a method to makeLineItem

If you want add X (quantity) widgets to a shopping cart, then Sale adds them to

the cart

25

CreatorCreator

The sequence diagram would be:The sequence diagram would be:

:Register :Sale

:SalesLineItem

makeLineItem()

create()

Fig. 16.8, p. 227

26

CreatorCreator

If the creation of an object is very complex, then the Factory pattern would be better (see Ch. 23)

If the creation of an object is very complex, then the Factory pattern would be better (see Ch. 23)

27

Best practice -create loosely coupled

components

Best practice -create loosely coupled

components High Level Modules should not depend upon

low

level modules and vice-versa. Both should

depend on abstractions.

Abstractions should not depend on details.

Details must depend on abstractions.

High Level Modules should not depend upon low

level modules and vice-versa. Both should

depend on abstractions.

Abstractions should not depend on details.

Details must depend on abstractions.

28

GOF Solution – Factory PatternGOF Solution – Factory Pattern

Use a Factory class to instantiate the component you need

Only the Factory knows about the concrete class, not your application

Use a Factory class to instantiate the component you need

Only the Factory knows about the concrete class, not your application

29

GOF Solution – Factory PatternGOF Solution – Factory Pattern

Pros – Helps to resolve tight coupling Cons – Intrusive: Components need to be requested

explicitly Need recompiling to change specific component inapplication

Pros – Helps to resolve tight coupling Cons – Intrusive: Components need to be requested

explicitly Need recompiling to change specific component inapplication

30

Alternative -Hollywood PrincipalAlternative -Hollywood Principal

aka “don’t call us, we’ll call you”

– Components should not be explicitly requested

– Components will be provided as needed

aka Inversion of Control

aka “don’t call us, we’ll call you”

– Components should not be explicitly requested

– Components will be provided as needed

aka Inversion of Control

31

Dependency InjectionDependency Injection

When IoC is about looking up plugin

implementation, Martin Fowler calls it

Dependency injection

Dependency injection is a term used to

resolve component dependencies by

injecting an instantiated component to satisfy

a dependency

When IoC is about looking up plugin

implementation, Martin Fowler calls it

Dependency injection

Dependency injection is a term used to

resolve component dependencies by

injecting an instantiated component to satisfy

a dependency

32

Inversion of Control/Dependency InjectionBeans do not depend on frameworkContainer injects the dependencies

Spring lightweight containerConfigure and manage beans

Inversion of Control/Dependency InjectionBeans do not depend on frameworkContainer injects the dependencies

Spring lightweight containerConfigure and manage beans

IoC/Dependency InjectionIoC/Dependency Injection

33

Dependency injectionBeans define their dependencies through constructor arguments or

propertiesThe container provides the injection at runtime

“Don’t talk to strangers”Also known as the Hollywood principle – “don’t call me I will

call you”Decouples object creators and locators from application logicEasy to maintain and reuseTesting is easier

Dependency injectionBeans define their dependencies through constructor arguments or

propertiesThe container provides the injection at runtime

“Don’t talk to strangers”Also known as the Hollywood principle – “don’t call me I will

call you”Decouples object creators and locators from application logicEasy to maintain and reuseTesting is easier

Inversion of ControlInversion of Control

34

Inversion of ControlInversion of ControlGirl want a boy friend

三种方式:1 青梅竹马; 2 亲友介绍; 3 父母包办

35

Inversion of ControlInversion of Control青梅竹马

public class Girl { void kiss(){ Boy boy = new Boy(); }}

36

Inversion of ControlInversion of Control亲友介绍

public class Girl { void kiss(){ Boy boy = BoyFactory.createBoy(); }}

37

Inversion of ControlInversion of Control父母包办

public class Girl { void kiss(Boy boy){ // kiss boy boy.kiss(); }}

38

Inversion of ControlInversion of Control

39

Inversion of Control (Type 0)Inversion of Control (Type 0)public class Girl implements Servicable {

private Kissable kissable;

public Girl() {

kissable = new Boy();

}

public void kissYourKissable() {

kissable.kiss();

}

}

40

Inversion of Control (Type 1)Inversion of Control (Type 1)

public class Girl implements Servicable {

Kissable kissable;

public void service(ServiceManager mgr) {

kissable = (Kissable) mgr.lookup(“kissable”);

}

public void kissYourKissable() {

kissable.kiss();

}

}

<container>    <component name=“kissable“ class=“Boy">                     <configuration> … </configuration>    </component>

    <component name=“girl" class=“Girl" /></container>

41

Inversion of Control (Type 2)Inversion of Control (Type 2)public class Girl {

private Kissable kissable;

public void setKissable(Kissable kissable) {

this.kissable = kissable;

}

public void kissYourKissable() {

kissable.kiss();

}

}

<beans>    <bean id=“boy" class=“Boy"/>    <bean id=“girl“ class=“Girl">        <property name=“kissable">           <ref bean=“boy"/>        </property>    </bean></beans>

42

Inversion of Control (Type 3)Inversion of Control (Type 3)public class Girl {

private Kissable kissable;

public Girl(Kissable kissable) {

this.kissable = kissable;

}

public void kissYourKissable() {

kissable.kiss();

}

}

PicoContainer container = new DefaultPicoContainer();container.registerComponentImplementation(Boy.class);container.registerComponentImplementation(Girl.class);Girl girl = (Girl) container.getComponentInstance(Girl.class);girl.kissYourKissable();

43

Low CouplingLow Coupling

Problem: How can we support low dependency among classes, low impact of changes, and increase reuse of classes?

Solution: Assign responsibilities so that coupling remains low

Coupling describes the extent of interconnection among classes

Problem: How can we support low dependency among classes, low impact of changes, and increase reuse of classes?

Solution: Assign responsibilities so that coupling remains low

Coupling describes the extent of interconnection among classes

44

Low CouplingLow Coupling

Notice that some coupling is needed – otherwise the classes don’t interact

Too much coupling means that changes to one class might have unexpected changes elsewhere

Related to “visibility” – how many other objects does each one need to see?

Notice that some coupling is needed – otherwise the classes don’t interact

Too much coupling means that changes to one class might have unexpected changes elsewhere

Related to “visibility” – how many other objects does each one need to see?

45

“ Stair” Object Structure“ Stair” Object StructureObject1 Object2 Object3 Object4 Object5

Message1()

Message2()

Message3()

Message4()

Message5()

Message6()

Message7()

Message8()

Low coupling (decentralized)Each object sees two other objects at most

46

“ Fork” Object Structure“ Fork” Object StructureObject1 Object2 Object3 Object4 Object5

Message1()

Message2()

Message3()

Message4()

Message5()

Message6()

Message7()

Message8()

High coupling (centralized)Object1 must see all other objects

47

Low CouplingLow Coupling

The Stair structure is generally preferred where possible

Might have to use Fork structure ifThe sequence of operations may change, and/or

New operations may be needed frequently

Subclasses are, by definition, high levels of coupling between objects

The Stair structure is generally preferred where possible

Might have to use Fork structure ifThe sequence of operations may change, and/or

New operations may be needed frequently

Subclasses are, by definition, high levels of coupling between objects

48

Low CouplingLow Coupling

Particularly avoid high coupling for objects which may change interface, implementation, or existence frequently

Desire for low coupling may conflict with Expert or High Cohesion patterns

No firm measure of what level of coupling is “good”

Particularly avoid high coupling for objects which may change interface, implementation, or existence frequently

Desire for low coupling may conflict with Expert or High Cohesion patterns

No firm measure of what level of coupling is “good”

49

High CohesionHigh Cohesion

Problem: how do you keep complexity manageable?

Solution: Assign responsibilities so that cohesion remains high

Cohesion is a measure of how closely related an object’s responsibilities are

High cohesion means a closely related set of narrowly defined responsibilities

Problem: how do you keep complexity manageable?

Solution: Assign responsibilities so that cohesion remains high

Cohesion is a measure of how closely related an object’s responsibilities are

High cohesion means a closely related set of narrowly defined responsibilities

50

High CohesionHigh Cohesion

In other words, don’t make an object do too much work!

Low cohesion generally results from remaining too abstract when defining responsibilities

Per Booch, high cohesion is when the elements of a class “all work together to produce some well-bounded behavior”

In other words, don’t make an object do too much work!

Low cohesion generally results from remaining too abstract when defining responsibilities

Per Booch, high cohesion is when the elements of a class “all work together to produce some well-bounded behavior”

51

High CohesionHigh Cohesion

An object which has a kitchen-sink function (it catches all the functions except the kitchen sink) generally has very low cohesion

A single complex function can result in low cohesion

Moderate cohesion would have similar, but not closely related, functions together

An object which has a kitchen-sink function (it catches all the functions except the kitchen sink) generally has very low cohesion

A single complex function can result in low cohesion

Moderate cohesion would have similar, but not closely related, functions together

52

High CohesionHigh Cohesion

High cohesion classes have some responsibilities in one set of functions, and use other objects to accomplish them

Modular design is a similar concept as ‘low coupling and high cohesion’

Conversely, high coupling and low cohesion often appear together

High cohesion classes have some responsibilities in one set of functions, and use other objects to accomplish them

Modular design is a similar concept as ‘low coupling and high cohesion’

Conversely, high coupling and low cohesion often appear together

53

High CohesionHigh Cohesion

Deliberately violating high cohesion is rare

Might have to do it:To isolate related functions (rare)

To distribute object to different servers

To manage an external interface

Deliberately violating high cohesion is rare

Might have to do it:To isolate related functions (rare)

To distribute object to different servers

To manage an external interface

54

ControllerController

Problem: who is responsible for handling external input system events?

Solution: assign the responsibility to a Controller objectFaçade controller represents the entire

subsystem or interfaceSession controller handles an entire use

case where some events may occur

Problem: who is responsible for handling external input system events?

Solution: assign the responsibility to a Controller objectFaçade controller represents the entire

subsystem or interfaceSession controller handles an entire use

case where some events may occur

55

ControllerController

An ‘input system event’ is some event from an external actor (human or not)

The Controller object is responsible for deciding what to do with the input system event

An ‘input system event’ is some event from an external actor (human or not)

The Controller object is responsible for deciding what to do with the input system event

56

ControllerController

So the Controller pattern applies to both management of external system interfaces (capture the entire interface in a single controller class), and managing inputs from user interfaces

User interface controllers generally end with <>Handler, <>Coordinator, or <>Session, where <> = <Use Case Name>

So the Controller pattern applies to both management of external system interfaces (capture the entire interface in a single controller class), and managing inputs from user interfaces

User interface controllers generally end with <>Handler, <>Coordinator, or <>Session, where <> = <Use Case Name>

57

ControllerController

Note that user interfaces (e.g. windows, views, or documents) are NOT part of the Controller’s job – those belong to an object at the Interface (or Presentation) Layer

Controller acts as a façade between interface and the application

Controllers DELEGATE work to other objects – they don’t do it themselves

Note that user interfaces (e.g. windows, views, or documents) are NOT part of the Controller’s job – those belong to an object at the Interface (or Presentation) Layer

Controller acts as a façade between interface and the application

Controllers DELEGATE work to other objects – they don’t do it themselves

58

BCE ObjectsBCE Objects

We can break objects into three major types for many purposesBoundary objects (user interface window, buttons,

etc.)

Control objects (controllers who make decisions, here also called ‘use case handlers’)

Entity objects (persistent objects which contain data)

We can break objects into three major types for many purposesBoundary objects (user interface window, buttons,

etc.)

Control objects (controllers who make decisions, here also called ‘use case handlers’)

Entity objects (persistent objects which contain data)

59

BCE ObjectsBCE Objects

These might be correlated to the kinds of computers involved in processing themUser interface might be at a PC level

(e.g. web browser)

Controller objects might run on an application server (captures logic, e.g. web server)

Entity objects might run on a database server (stores data)

These might be correlated to the kinds of computers involved in processing themUser interface might be at a PC level

(e.g. web browser)

Controller objects might run on an application server (captures logic, e.g. web server)

Entity objects might run on a database server (stores data)

60

Façade ControllerFaçade Controller

Façade controllers hide an entire system or subsystem under one class, such as Register or SystemAvoid except for simple external systems

Works well if only a few events to manage; otherwise may need use case controllers to break down system functions into smaller sets (p. 241)

Façade controllers hide an entire system or subsystem under one class, such as Register or SystemAvoid except for simple external systems

Works well if only a few events to manage; otherwise may need use case controllers to break down system functions into smaller sets (p. 241)

61

Façade ControllerFaçade Controller

System

facade externalSystem

Object6

Object7

Object8

Object9

62

Avoiding Bloated ControllersAvoiding Bloated ControllersEven a façade controller should generally have

more than one class

Beware of controllers which perform work without calling another class

Controllers should have few or no attributes

Fix bloat by adding more controller classes, and/or redesign to delegate more work

Even a façade controller should generally have more than one class

Beware of controllers which perform work without calling another class

Controllers should have few or no attributes

Fix bloat by adding more controller classes, and/or redesign to delegate more work

63

Use Case RealizationUse Case Realization

Every scenario in a use case can become a ‘use case realization,’ which shows how the design model meets the requirements for that use case

Use Case Realization is UP term, not UML

Interaction diagrams help express Use Case Realization

Every scenario in a use case can become a ‘use case realization,’ which shows how the design model meets the requirements for that use case

Use Case Realization is UP term, not UML

Interaction diagrams help express Use Case Realization

64

Use Case RealizationUse Case Realization

Use case suggests system events shown in system sequence diagram

Effect of operations may be documented in operation contracts

Events represent messages which initiate interaction diagrams

Interaction diagrams describe communication between classes

Use case suggests system events shown in system sequence diagram

Effect of operations may be documented in operation contracts

Events represent messages which initiate interaction diagrams

Interaction diagrams describe communication between classes

65

Interaction DiagramsInteraction Diagrams

Recall the collaboration diagrams are specific to one use case

Sequence diagrams generally show one scenario for one use case; might show extensions

Operations contracts describe the conditions for one event in one use case

Recall the collaboration diagrams are specific to one use case

Sequence diagrams generally show one scenario for one use case; might show extensions

Operations contracts describe the conditions for one event in one use case

66

Models Don’t Start PerfectModels Don’t Start Perfect

Expect that early requirements, and the initial domain model (conceptual class diagram) will not be perfectBut that doesn’t mean do them poorly!

Maintain contact with customer and subject experts to keep improving models

Conceptual classes inspire design classesBut many additional classes likely needed

Expect that early requirements, and the initial domain model (conceptual class diagram) will not be perfectBut that doesn’t mean do them poorly!

Maintain contact with customer and subject experts to keep improving models

Conceptual classes inspire design classesBut many additional classes likely needed

67

Model-View SeparationModel-View Separation

Non-GUI objects should not be involved in output tasks

This reinforces the Boundary/Control/Entity object distinction earlier

Controllers should know the information to be displayed in output, but actual output is a boundary object’s purpose

Non-GUI objects should not be involved in output tasks

This reinforces the Boundary/Control/Entity object distinction earlier

Controllers should know the information to be displayed in output, but actual output is a boundary object’s purpose

68

More UML NotationMore UML NotationConstraints are tagged with curly brackets {}. An algorithm may be

shown if needed.

Notes are in text boxes which also have the upper right corner dog-eared

Constraints are tagged with curly brackets {}. An algorithm may be shown if needed.

Notes are in text boxes which also have the upper right corner dog-eared

This the the body of a Note box. It also has a Name, which isn't visible.

{s.isComplete = true} <- Constraint

<- Note

69

Object Constraint LanguageObject Constraint Language

70

Iteration 2Iteration 2

The text’s second iteration assumes that in iteration 1 everything was done through development of the design class diagram, and major architecturally important parts of the system have been coded and tested

Iteration 2 is refining the design through additional patterns (which we aren’t covering)

The text’s second iteration assumes that in iteration 1 everything was done through development of the design class diagram, and major architecturally important parts of the system have been coded and tested

Iteration 2 is refining the design through additional patterns (which we aren’t covering)

71

Iteration 2Iteration 2

Iteration 2 also adds more scenarios to the foundation already established

Additional lower priority use cases may be fully defined

The system sequence diagram may be expanded to include external systems (p. 324)

Iteration 2 also adds more scenarios to the foundation already established

Additional lower priority use cases may be fully defined

The system sequence diagram may be expanded to include external systems (p. 324)