James Coplien: Trygve - Oct 17, 2016

139
A taste of trygve Jim Coplien Former C++ Programmer & Author Gertrud & Cope Helsingør, Danmark jcoplien@gmail 1 20161017FooCafé.key - 28 October 2016

Transcript of James Coplien: Trygve - Oct 17, 2016

A taste of trygve

Jim Coplien Former C++ Programmer & Author

Gertrud & Cope Helsingør, Danmark

jcoplien@gmail

1 20161017FooCafé.key - 28 October 2016

Pointers…

• DCI documentation & downloads:

• http://fulloo.info

• trygve on GitHub:

• https://github.com/jcoplien/trygve

2 20161017FooCafé.key - 28 October 2016

My greatest contribution to computing is that I never invented a programming language.

– Jerry Weinberg

3 20161017FooCafé.key - 28 October 2016

In 1972, Kay coined the term: “Object-Oriented Programming”• In his 1972 paper the word “class” appears only once

• Objects: operational models, in the machine, to extend the capabilities of the human mind

• Classes came into Smalltalk ca. 1976 (from Simula 67)

• trygve: conceived to address the largest gaps between current OOP and the benefits of the original vision, through DCI

4 20161017FooCafé.key - 28 October 2016

G&C5-1 20161017FooCafé.key - 28 October 2016

G&C

We feel that a child is a "verb" rather than a "noun", an actor rather than an object; he is not a scaled-up pigeon or rat; he is trying to acquire a model of his surrounding environment in order to deal with it ... We would like to hook into his current modes of thought in order to influence him rather than just trying to replace his model with one of our own.

5-2 20161017FooCafé.key - 28 October 2016

G&C

We feel that a child is a "verb" rather than a "noun", an actor rather than an object; he is not a scaled-up pigeon or rat; he is trying to acquire a model of his surrounding environment in order to deal with it ... We would like to hook into his current modes of thought in order to influence him rather than just trying to replace his model with one of our own.

Alan Kay

5-3 20161017FooCafé.key - 28 October 2016

G&C5-4 20161017FooCafé.key - 28 October 2016

G&C6 20161017FooCafé.key - 28 October 2016

But we *do* design

7-1 20161017FooCafé.key - 28 October 2016

But we *do* design

• What kinds of tools / notations / models do you use?

7-2 20161017FooCafé.key - 28 October 2016

But we *do* design

• What kinds of tools / notations / models do you use?

• “… a modeling language is what the language designers omitted to include in the programming languages” — Reenskaug

7-3 20161017FooCafé.key - 28 October 2016

Java Programs as Modelspublic void setParentScope(final StaticScope scope) { parentScope_ = scope;}public List<ObjectDeclaration> objectDeclarations() { final List<ObjectDeclaration> retval = new ArrayList<ObjectDeclaration>(); for (final Map.Entry<String, ObjectDeclaration> objectDecl : objectDeclarationDictionary_.entrySet()) { retval.add(objectDecl.getValue()); } return retval;}public List<ClassDeclaration> classDeclarations() { final List<ClassDeclaration> retval = new ArrayList<ClassDeclaration>(); for (final Map.Entry<String, ClassDeclaration> classDecl : classDeclarationDictionary_.entrySet()) { retval.add(classDecl.getValue()); } return retval;}

Class (domain) structure

Use case structure

Roles (application)

8-1 20161017FooCafé.key - 28 October 2016

Java Programs as Modelspublic void setParentScope(final StaticScope scope) { parentScope_ = scope;}public List<ObjectDeclaration> objectDeclarations() { final List<ObjectDeclaration> retval = new ArrayList<ObjectDeclaration>(); for (final Map.Entry<String, ObjectDeclaration> objectDecl : objectDeclarationDictionary_.entrySet()) { retval.add(objectDecl.getValue()); } return retval;}public List<ClassDeclaration> classDeclarations() { final List<ClassDeclaration> retval = new ArrayList<ClassDeclaration>(); for (final Map.Entry<String, ClassDeclaration> classDecl : classDeclarationDictionary_.entrySet()) { retval.add(classDecl.getValue()); } return retval;}

• I can find only classes in Java code• A simplistic hierarchy• No objects• No networks of collaboration• No dynamics (because I can’t!!!

By design!!!)

Class (domain) structure

Use case structure

Roles (application)

8-2 20161017FooCafé.key - 28 October 2016

Class (domain) structure

trygve Programs as Models

Use case structure

Roles (application)

class Range { public Range(int a, int b) { … } public int start() const { return start_ } public int end() const { return end_ }}

class Scanner { }

context SpellCheck { role [] Words { public void check() { Words[lastIndex].review } public void review() public void reviewAWord() } role Document { public int len() { return length() } private String wordStartingAt(int start) { … } … }}

9-1 20161017FooCafé.key - 28 October 2016

Class (domain) structure

trygve Programs as Models

Use case structure

Roles (application)

DCI Conceptualization:• objects• the roles the objects play• the classes to which they belong, and• the operational models of their interaction

class Range { public Range(int a, int b) { … } public int start() const { return start_ } public int end() const { return end_ }}

class Scanner { }

context SpellCheck { role [] Words { public void check() { Words[lastIndex].review } public void review() public void reviewAWord() } role Document { public int len() { return length() } private String wordStartingAt(int start) { … } … }}

9-2 20161017FooCafé.key - 28 October 2016

Research Results• From Héctor Adrián Valdecantos, RIT

• “to state with high statistical significance that the context element in a DCI system plays an important role in code comprehension.”

• “the correctness analysis shows that in general programmers following the DCI-trygve approach perform better than programmers using the OO-java approach.“

10 20161017FooCafé.key - 28 October 2016

But couldn’t you just…Use multiple dispatch

That’s chooses one algorithm based on multiple types, rather than a sequencing of multiple algorithms based on multiple types

Use aspects The joinpoints are still dictated by the class structure

Use mix-ins Close, but how do they talk to each other?

Just use objects (e.g., self) A good start, but not enough

Use multi-paradigm design Undesired decoupling and lack of cohesion

11 20161017FooCafé.key - 28 October 2016

G&C

Action Between Objects

1st Qtr2nd Qtr3rd Qtr4th Qtr

V0

10

20

30

40

50

60

70

80

90

1st Qtr 2nd Qtr 3rd Qtr 4th Qtr

EastWestNorth

ModelView

Controller

Skip

12-1 20161017FooCafé.key - 28 October 2016

G&C

Action Between Objects

1st Qtr2nd Qtr3rd Qtr4th Qtr

V0

10

20

30

40

50

60

70

80

90

1st Qtr 2nd Qtr 3rd Qtr 4th Qtr

EastWestNorth

Skip

12-2 20161017FooCafé.key - 28 October 2016

G&C

Action Between Objects

1st Qtr2nd Qtr3rd Qtr4th Qtr

V0

10

20

30

40

50

60

70

80

90

1st Qtr 2nd Qtr 3rd Qtr 4th Qtr

EastWestNorth

The programmer must consider the

system:action between

objects

Skip

12-3 20161017FooCafé.key - 28 October 2016

G&C

Action Between Objects

1st Qtr2nd Qtr3rd Qtr4th Qtr

V0

10

20

30

40

50

60

70

80

90

1st Qtr 2nd Qtr 3rd Qtr 4th Qtr

EastWestNorth

13-1 20161017FooCafé.key - 28 October 2016

G&C

1st Qtr2nd Qtr3rd Qtr4th Qtr

V0

10

20

30

40

50

60

70

80

90

1st Qtr 2nd Qtr 3rd Qtr 4th Qtr

EastWestNorth

Programmers’ objects interactwith objects previously conceived by other programmers

13-2 20161017FooCafé.key - 28 October 2016

G&C14 20161017FooCafé.key - 28 October 2016

G&C

System Operations

15-1 20161017FooCafé.key - 28 October 2016

G&C

System Operations

While the specific interactions are

emergent, the form of the interactions

is designed.

15-2 20161017FooCafé.key - 28 October 2016

G&C

System Operations

This form lives within no single object or class.

15-3 20161017FooCafé.key - 28 October 2016

G&C

System Operations

Objects are an overly small concept,

conceived for the revenge of the nerds,

each owning their individual classes

15-4 20161017FooCafé.key - 28 October 2016

G&C

System Operations

16-1 20161017FooCafé.key - 28 October 2016

G&C

System Operations

context TripReservation

}

{

16-2 20161017FooCafé.key - 28 October 2016

G&C

System Operations

context TripReservation

}

{role JourneyEnd { City city() { … } ….

}role JourneyStart { City city() { … } ….

}role RouteMap { Path pfinder() { … } …. }

16-3 20161017FooCafé.key - 28 October 2016

G&C

System Operations

context TripReservation

}

{role JourneyEnd { City city() { … } ….

}role JourneyStart { City city() { … } ….

}role RouteMap { Path pfinder() { … } …. }

16-4 20161017FooCafé.key - 28 October 2016

Teaching Actors their Scriptscontext TripReservation { role JourneyStart { … } role JourneyEnd { … } public TripReservation(Object jStart, Object jEnd){ JourneyStart = jStart; JourneyEnd = jEnd } }

17-1 20161017FooCafé.key - 28 October 2016

Teaching Actors their Scriptscontext TripReservation { role JourneyStart { … } role JourneyEnd { … } public TripReservation(Object jStart, Object jEnd){ JourneyStart = jStart; JourneyEnd = jEnd } }

17-2 20161017FooCafé.key - 28 October 2016

Contextualized Polymorphism

Skip

18-1 20161017FooCafé.key - 28 October 2016

Contextualized Polymorphism

foo

foo

foo

foo

foo

?

Skip

18-2 20161017FooCafé.key - 28 October 2016

Contextualized Polymorphism

foo

foo

foo

foo

bar

bar

bar

bar

bar

?

Skip

18-3 20161017FooCafé.key - 28 October 2016

Contextualized Polymorphism

foo

foo

foo

foo bar

bar

bar

bar

sna

sna

snasna

sna

?

Skip

18-4 20161017FooCafé.key - 28 October 2016

Contextualized Polymorphism

foo

foo

foo

foo bar

bar

bar

bar

sna

snasna

sna

Skip

18-5 20161017FooCafé.key - 28 October 2016

Contextualized Polymorphism

foo

foo

foo

foo bar

bar

bar

bar

sna

snasna

sna

“Just trust the objects to do

the right thing and everything will be fine.” —

Smalltalk

Skip

18-6 20161017FooCafé.key - 28 October 2016

Contextualized Polymorphism

foo

foo

foo

foo bar

bar

bar

bar

sna

snasna

sna

“You believe in things you don’t understand, you

may suffer.” — Stevie Wonder

Skip

18-7 20161017FooCafé.key - 28 October 2016

Contextualized Polymorphism

foo

foo

foo

foo bar

bar

bar

bar

sna

snasna

sna

Where is the use case?

Where is the use case?

Skip

18-8 20161017FooCafé.key - 28 October 2016

Contextualized PolymorphismRoles: A new

concept

19-1 20161017FooCafé.key - 28 October 2016

Contextualized PolymorphismContext:

Anothernew

concept

19-2 20161017FooCafé.key - 28 October 2016

Contextualized Polymorphism

go

Context: Another

new concept

19-3 20161017FooCafé.key - 28 October 2016

Contextualized Polymorphism

go

20-1 20161017FooCafé.key - 28 October 2016

Contextualized Polymorphism

bar sna

20-2 20161017FooCafé.key - 28 October 2016

Contextualized Polymorphism

bar sna

System Operations

20-3 20161017FooCafé.key - 28 October 2016

Contextualized Polymorphism

bar sna

Data

System Operations

20-4 20161017FooCafé.key - 28 October 2016

Contextualized Polymorphism

bar sna

Data

Cont

extSystem

Operations

20-5 20161017FooCafé.key - 28 October 2016

Contextualized Polymorphism

bar sna

Data

Cont

ext

Inte

ract

ion

System Operations

20-6 20161017FooCafé.key - 28 October 2016

Hoare’s Insight• “There are two ways of constructing a software

design: One way is to make it so simple that there are obviously no deficiencies, and the other way is to make it so complicated that there are no obvious deficiencies. The first method is far more difficult.” — Tony Hoare

• The primary goal of trygve is to make system operation code readable

• It is in many ways a language for 7-year-olds

21 20161017FooCafé.key - 28 October 2016

Smalltalk 80

Smalltalk 76

Smalltalk 72

Simula 67

C++

Java

trygve

DCI Squeak

Algol 68

C#

Marvin

self

Javascript

C

Garbage-collected, single-

hierarchy

Syntax (Worse is Better)

Object thinking over classthink

D

Perl

awk

22-1 20161017FooCafé.key - 28 October 2016

Smalltalk 80

Smalltalk 76

Smalltalk 72

Simula 67

C++

Java

trygve

DCI Squeak

Algol 68

C#

Marvin

self

Javascript

C

Garbage-collected, single-

hierarchy

Syntax (Worse is Better)

Object thinking over classthink

D

Class-oriented Programming

Perl

awk

22-2 20161017FooCafé.key - 28 October 2016

Smalltalk 80

Smalltalk 76

Smalltalk 72

Simula 67

C++

Java

trygve

DCI Squeak

Algol 68

C#

Marvin

self

Javascript

C

Garbage-collected, single-

hierarchy

Syntax (Worse is Better)

Object thinking over classthink

D

Class-oriented Programming

Object-Oriented Programming

Perl

awk

22-3 20161017FooCafé.key - 28 October 2016

The trygve language• Contexts: System use cases in code

• The goal: readable code

• System use case steps are demarcated along Role boundaries

• The Context chooses objects — “Role-players” — for each Role (one-time binding)

• Many forms of object can play each Role — duck-typed through a contract specification

• Role-players are dumb, and Role / instance contracts should be simple and primitive

23 20161017FooCafé.key - 28 October 2016

trygve building blocks• Declarations and expressions — and one value

• Parser swallows most naive Java syntax

• Contexts: use cases — mainly a set of Roles

• Classes: the “domain model” (dumb): actor DNA • Classify objects by how they are built

• Roles: scripts for the actors — stateless • Classify objects by how they act

24 20161017FooCafé.key - 28 October 2016

• So this works: int fact(int n) { int retval = 1; if (n > 1) retval = n * fact(n - 1); return retval }

• but this is orthodox: int fact(int n) { return if (n <= 1) 1 else n * fact(n-1) }

25 20161017FooCafé.key - 28 October 2016

Details• Semicolons optional

• Classes, but few class-oriented features (e.g., there is no protected)

• Strongly type-checked at run-time-typed; Roles are duck-typed

• Rudimentary templates

• No exceptions, RTTI, concurrency

26 20161017FooCafé.key - 28 October 2016

More going on here than meets the eye

• The trygve language is a stepping stone to side-effect free programming

• States make it difficult for a Role-player to play several Roles (the MI problem)

• Stateless computation transcends the problem

27 20161017FooCafé.key - 28 October 2016

Both class and Context instances can play Roles

• … in which case, we really don’t need classes any more

• They never were part of the OO vision

• The trygve language supports more or less arbitrary scope nesting (anything inside anything)

• Classes become truly operational models: exactly the Piagetian ideal that Kay strove for

28-1 20161017FooCafé.key - 28 October 2016

Both class and Context instances can play Roles

• … in which case, we really don’t need classes any more

• They never were part of the OO vision

• The trygve language supports more or less arbitrary scope nesting (anything inside anything)

• Classes become truly operational models: exactly the Piagetian ideal that Kay strove for

28-2 20161017FooCafé.key - 28 October 2016

On babies and bathwater• Classes are still part of the business vocabulary

• They are at least part of the learned business mental model

• They are certainly part of the programmer mental model — and programmers are people, too

• So the “classless movement” is really a fad

29 20161017FooCafé.key - 28 October 2016

Reflection• Even common inclusion polymorphism is overly

general — reflection takes it far outside human mental models

• trygve slices reflection with a precisely honed scimitar

• Reflection is the Turing Machine of types

• It shows a lack of design discipline in the articulation of a paradigm

• See “Reflections on Reflection,” SPLASH 2013 keynote

30 20161017FooCafé.key - 28 October 2016

Conclusion: Everybody Wins• Good for humans…

• Both cognitive & volitive models in code

• Organizes, rather than suppresses, complexity

• … and software engineering

• Incremental addition of new use cases

• Reduced discovery cost

• Separates rate-of-change shearing layers

31 20161017FooCafé.key - 28 October 2016

Postlog• trygve is an open-source community research

effort — join it (GitHub jcoplien / trygve)

• Also a binary download and documentation at fulloo.info.

• We’ve been stuck gilding the lily and making much ado about nothing for far too long

• trygve does not aspire to be king: it exists only to combat ignorance and stimulate thinking & dialog

32 20161017FooCafé.key - 28 October 2016

33 20161017FooCafé.key - 28 October 2016

Other assorted goodies

• Templates (very minimal — just enough so people can use familiar Java containers)

• Very basic Frames, Panels, Events, Colors

• Rudimentary InputStream & OutputStream I/O

• No exceptions (goal is readability)

34 20161017FooCafé.key - 28 October 2016

Look, Ma, no semicolonsinterface EventHandler { public void handleEvent(Event e) }

class MyPanel extends Panel { int XSIZE = 1000 int YSIZE = 600 public int xsize() { return XSIZE } public int ysize() { return YSIZE }

public MyPanel() { Panel() eventHandler_ = null frame_ = new Frame("Bouncy") frame_.add("Center", this) frame_.resize(XSIZE, YSIZE) frame_.setVisible(true) drawRect(0, 0, xsize(), ysize()) repaint() }

public boolean handleEvent(Event event) { boolean retval = true if (event.id == Event.MOUSE_MOVE) { if (eventHandler_ != null) { eventHandler_.handleEvent(event) } } return retval }

35 20161017FooCafé.key - 28 October 2016

Everything’s an expression

context SpellCheck { role Utilities { public boolean isDelim(String c) const { return switch (c) { case "ø": case "Ø": case "æ": case "Æ": case "å": case "Å": false; break default: (c < "a" || c > "z") && (c < "A" || c > "Z") } } } . . . .

36 20161017FooCafé.key - 28 October 2016

Duck-typed Role / Object Contracts

role ThePanel { public void drawCircle(int x, int y, int r) { fillOval(x+r, y+r, r, r) } public void drawPaddle(int xs, int ys, int h, int w) { drawRect(xs, ys, h, w) } public int maxX() { return xsize() } public int maxY() { return ysize() } public void setColor(Color c) { setForeground(c) } public void clearObjects() { removeAll() } public void clear() { setColor(new Color(227, 221, 240)); fillRect(0, 0, maxX() - 1, maxY() - 1 ) } } requires { void fillOval(int x, int y, int h, int w); void drawRect(int x, int y, int h, int w); void fillRect(int x, int y, int h, int w); int xsize(); int ysize(); void removeAll(); void setForeground(Color color) }

37 20161017FooCafé.key - 28 October 2016

A Puzzleclass ArrayDupTest { public void test() { int [] intArray = new int[5]; for (int i = 0; i < 5; i++) { intArray[i] = i }

for (int i = 0; i < 5; i++) { System.out.println(intArray[i]) } } }

new ArrayDupTest().test()

38 20161017FooCafé.key - 28 October 2016

Most class-oriented features have been removed

• protected

• super

• Class::

• ABCs

• static (though it exists internally)

39 20161017FooCafé.key - 28 October 2016

Can an object play more than one Role?

• In series, yes: that’s the whole idea • In parallel, no…

• One Context could instantiate another Context • That Context could share Role-players with the

original

• … unless it’s in the same Context so that there is no confusion

40 20161017FooCafé.key - 28 October 2016

The Object Machine• Classes are run-time objects (but not in the

language)

• Two scratch stacks: main, and event

• Two activation record stacks

• Uses Java GC + Context reference counting

• Like Smalltalk in that everything is an object

41 20161017FooCafé.key - 28 October 2016

42 20161017FooCafé.key - 28 October 2016

G&C Coplien — Lean Architecture

trygve Account Exampleclass Currency { public Currency(double amount) { amount_ = amount.clone } public Currency +(Currency amount) { assert(false) return this; } public Currency -(Currency amount) { assert(false) return this; } public String name() const { assert(false); return "" } public String sign() const { assert(false); return "" } public double amountInEuro() const { assert(false); return 0.0 } public double amount() const { return amount_ }

42

43 20161017FooCafé.key - 28 October 2016

G&C Coplien — Lean Architecture

trygve Account Example public String toString() const { return amountInEuro().toString() } public int compareTo(Currency other) { if (amount() > other.amount()) return 1 else if (amount() < other.amount()) return -1; return 0 }

private double amount_ }

class Euro extends Currency { public Euro(double amount) { Currency(amount) } public Euro -(Currency amount) { return new Euro(amount() - amount.amountInEuro()) } public Euro +(Currency amount) { return new Euro(amount() + amount.amountInEuro()) } public String name() const { return "Euro"; } public String sign() const { return "€"; }

43

44 20161017FooCafé.key - 28 October 2016

G&C Coplien — Lean Architecture

trygve Account Example public double amountInEuro() const { return amount() } public String toString() const { return amount().toString() } }

class Account { public Account() { acct_ = 1234 } public String accountID() const { return acct_.toString() } public Currency availableBalance() const { assert(false); return null } public void increaseBalance(Currency amount) { assert(false) } public void decreaseBalance(Currency amount) { assert(false) } public void updateLog(String message, Date date, Currency amount) { assert(false) } private int acct_ }

44

45 20161017FooCafé.key - 28 October 2016

G&C Coplien — Lean Architecture

trygve Account Exampleclass CheckingAccount extends Account { public CheckingAccount() { availableBalance_ = new Euro(100.00) } public Currency availableBalance() const { return availableBalance_ } public void decreaseBalance(Currency c) { availableBalance_ = availableBalance_ - c } public void updateLog(String message, Date t, Currency c) const { System.out.print("account: ").print(accountID()) .print(" CheckingAccount::updateLog(\"").print(message) .print("\", ").print(t.toString()).print(", ") .print(c.toString()).print(“)") .println() } public void increaseBalance(Currency c) { availableBalance_ = availableBalance_ + c }

private Currency availableBalance_ }

class SavingsAccount extends Account { public SavingsAccount() { availableBalance_ = new Euro(0.00) } public Currency availableBalance() const { return availableBalance_ }

45

46 20161017FooCafé.key - 28 October 2016

G&C Coplien — Lean Architecture

trygve Account Example public void decreaseBalance(Currency c) { assert(c > availableBalance_); availableBalance_ = availableBalance_ - c }

public void updateLog(String logMessage, Date timeOfTransaction, Currency amountForTransaction) const { assert(logMessage.length() > 0); assert(logMessage.length() < MAX_BUFFER_SIZE); // assert(new Date() < timeOfTransaction); System.out.print("account: ").print(accountID()) .print(" SavingsAccount::updateLog(\"").print(logMessage) .print("\", ").print(timeOfTransaction.toString()) .print(", ").print(amountForTransaction.toString()) .print(“)") .println() } public void increaseBalance(Currency c) { availableBalance_ = availableBalance_ + c }

private Currency availableBalance_; private int MAX_BUFFER_SIZE = 256 }

46

47 20161017FooCafé.key - 28 October 2016

G&C Coplien — Lean Architecture

trygve Account Exampleclass InvestmentAccount extends Account { public InvestmentAccount() { availableBalance_ = new Euro(0.00) } public Currency availableBalance() const { return availableBalance_ } public void increaseBalance(Currency c) { availableBalance_ = availableBalance_ + c } public void decreaseBalance(Currency c) { availableBalance_ = availableBalance_ - c; } public void updateLog(String s, Date t, Currency c) const { System.out.print("account: ").print(accountID()) .print(" InvestmentAccount::updateLog(\"") .print(s).print("\", ").print(t.toString()) .print(", ").print(c.toString()).print(")") .println() }

private Currency availableBalance_; }

47

48 20161017FooCafé.key - 28 October 2016

G&C Coplien — Lean Architecture

trygve Account Exampleclass Creditor { public Creditor(Account account) { account_ = account } public Account account() { return account_ } public Currency amountOwed() const { return new Currency(0.0) }

private Account account_ }

class ElectricCompany extends Creditor { public ElectricCompany() { Creditor(new CheckingAccount()) } public Currency amountOwed() const { return new Euro(15.0) } }

class GasCompany extends Creditor { public GasCompany() { Creditor( new SavingsAccount()); account().increaseBalance(new Euro(500.00)) // start off with a balance of 500 } public Currency amountOwed() const { return new Euro(18.76) } }

48

49 20161017FooCafé.key - 28 October 2016

G&C Coplien — Lean Architecture

trygve Account Examplecontext TransferMoneyContext { // Roles

role AMOUNT { public Currency(double amount); public Currency +(Currency amount); public Currency -(Currency amount); public String name() const; public String sign() const; public double amountInEuro() const; public double amount() const; public String toString() const; public int compareTo(Currency other) } requires { Currency(double amount); Currency +(Currency amount); Currency -(Currency amount); String name() const; String sign() const; double amountInEuro() const; double amount() const; String toString() const; int compareTo(Currency other) }

role GUI { public void displayScreen(int displayCode) } requires { void displayScreen(int displayCode) }

49

50 20161017FooCafé.key - 28 October 2016

G&C Coplien — Lean Architecture

trygve Account Example role SOURCE_ACCOUNT { public void transferTo() { // This code is reviewable and meaningfully testable with stubs! int SUCCESS_DEPOSIT_SCREEN = 10;

beginTransaction(); if (this.availableBalance() < AMOUNT) { endTransaction(); assert(false, "Unavailable balance") } else { this.decreaseBalance(AMOUNT); DESTINATION_ACCOUNT.increaseBalance(AMOUNT); this.updateLog("Transfer Out", new Date(), AMOUNT); DESTINATION_ACCOUNT.updateLog("Transfer In", new Date(), AMOUNT); } GUI.displayScreen(SUCCESS_DEPOSIT_SCREEN); endTransaction() } } requires { void decreaseBalance(Currency amount); Currency availableBalance() const; void updateLog(String msg, Date time, Currency amount) }

50

51 20161017FooCafé.key - 28 October 2016

G&C Coplien — Lean Architecture

trygve Account Example role DESTINATION_ACCOUNT { public void transferFrom() { this.increaseBalance(AMOUNT); this.updateLog("Transfer in", new Date(), AMOUNT); } public void increaseBalance(Currency amount); public void updateLog(String msg, Date time, Currency amount) } requires { void increaseBalance(Currency amount); void updateLog(String msg, Date time, Currency amount) }

public TransferMoneyContext(Currency amount, Account source, Account destination) { SOURCE_ACCOUNT = source; DESTINATION_ACCOUNT = destination; AMOUNT = amount } public TransferMoneyContext() { lookupBindings() } public void doit() { SOURCE_ACCOUNT.transferTo() }

51

52 20161017FooCafé.key - 28 October 2016

G&C Coplien — Lean Architecture

trygve Account Example private void lookupBindings() { // These are somewhat arbitrary and for illustrative // purposes. The simulate a database lookup InvestmentAccount investmentAccount = new InvestmentAccount(); investmentAccount.increaseBalance(new Euro(100.00)); // prime it with some money SOURCE_ACCOUNT = investmentAccount; DESTINATION_ACCOUNT = new SavingsAccount(); DESTINATION_ACCOUNT.increaseBalance(new Euro(500.00)); // start it off with money AMOUNT = new Euro(30.00) } }

52

53 20161017FooCafé.key - 28 October 2016

G&C Coplien — Lean Architecture

trygve Account Examplecontext PayBillsContext { public PayBillsContext() { lookupBindings } role [] CREDITORS { } requires { Currency amountOwed() } stageprop SOURCE_ACCOUNT { public String accountID() const; public Currency availableBalance() const; public void increaseBalance(Currency amount) unused; public void decreaseBalance(Currency amount) unused; public void updateLog(String message, Date date, Currency amount) unused } requires { String accountID() const; Currency availableBalance() const; void increaseBalance(Currency amount); void decreaseBalance(Currency amount); void updateLog(String message, Date date, Currency amount) }

public void doit() { for (Creditor credit : CREDITORS) { // Note that here we invoke another use case TransferMoneyContext xfer = new TransferMoneyContext( credit.amountOwed(), SOURCE_ACCOUNT, credit.account()); xfer.doit() } }

53

54 20161017FooCafé.key - 28 October 2016

G&C Coplien — Lean Architecture

trygve Account Example private void lookupBindings() { // These are somewhat arbitrary and for illustrative // purposes. The simulate a database lookup InvestmentAccount investmentAccount = new InvestmentAccount(); investmentAccount.increaseBalance(new Euro(100.00)); // prime it with some money SOURCE_ACCOUNT = investmentAccount;

Creditor [] creditors = new Creditor [2];

creditors[0] = new ElectricCompany(); creditors[1] = new GasCompany();

CREDITORS = creditors } }

{ // Main

TransferMoneyContext aNewUseCase = new TransferMoneyContext(); aNewUseCase.doit();

PayBillsContext anotherNewUseCase = new PayBillsContext(); anotherNewUseCase.doit() }

54

55 20161017FooCafé.key - 28 October 2016

G&C Coplien — Lean Architecture

C++ Account ExampleMany thanks to Felix Petriconi for bringing this up-to-date for C++14!

55

56 20161017FooCafé.key - 28 October 2016

G&C Coplien — Lean Architecture

Account Example: Currency/* * Currency.h * * Created by James Coplien on 7/31/09. * Copyright 2009 Gertrud & Cope. All rights reserved. */

#ifndef _CURRENCY_H #define _CURRENCY_H

#include <string>

class Currency;

class CurrencyBase { friend class Currency; public: CurrencyBase(); virtual ~CurrencyBase() = default; virtual CurrencyBase &operator+=(const Currency& amount) = 0; virtual CurrencyBase &operator-=(const Currency& amount) = 0; virtual CurrencyBase &operator=(const Currency& amount) = 0; virtual std::string name() const = 0; virtual std::string sign() const = 0; virtual double amountInEuro() const = 0; virtual std::string asString() const = 0; protected: unsigned referenceCount_; };

56

57 20161017FooCafé.key - 28 October 2016

G&C Coplien — Lean Architecture

Account Example: Currencyclass Currency { public: Currency(); Currency(const Currency& amount); virtual Currency& operator=(const Currency& amount); explicit Currency(CurrencyBase *derivedClassThis); virtual ~Currency(); virtual Currency& operator+=(const Currency& amount); virtual Currency& operator-=(const Currency& amount); virtual std::string name() const; virtual std::string sign() const; virtual double amountInEuro() const; virtual std::string asString() const; friend bool operator==(const Currency& x, const Currency& y); friend bool operator!=(const Currency& x, const Currency& y); friend bool operator<(const Currency& x, const Currency& y); friend bool operator>(const Currency& x, const Currency& y); friend bool operator<=(const Currency& x, const Currency& y); friend bool operator>=(const Currency& x, const Currency& y);

57

58 20161017FooCafé.key - 28 October 2016

G&C Coplien — Lean Architecture

Account Example: Currency friend std::ostream &operator<<(std::ostream& stream, const Currency& currency); private: CurrencyBase *actualCurrency_; };

class Euro: public CurrencyBase { friend class Currency; public: explicit Euro(double amount = 0.0); virtual ~Euro() = default; operator Currency(); CurrencyBase *copy() const; Euro &operator+=(const Currency& amount) override; Euro &operator-=(const Currency& amount) override; Euro &operator=(const Currency& amount) override; std::string name() const override; std::string sign() const override; double amountInEuro() const override; std::string asString() const override; private: double amount_; };

#endif

58

59 20161017FooCafé.key - 28 October 2016

G&C Coplien — Lean Architecture

Account Example: Currency/* * Currency.h * * Created by James Coplien on 7/31/09. * Copyright 2009 Gertrud & Cope. All rights reserved. */

#ifndef _CURRENCY_H #define _CURRENCY_H

#include <string>

class Currency;

class CurrencyBase { friend class Currency; public: CurrencyBase(); virtual ~CurrencyBase() = default; virtual CurrencyBase &operator+=(const Currency& amount) = 0; virtual CurrencyBase &operator-=(const Currency& amount) = 0;

59

60 20161017FooCafé.key - 28 October 2016

G&C Coplien — Lean Architecture

Account Example: Currency virtual CurrencyBase &operator=(const Currency& amount) = 0; virtual std::string name() const = 0; virtual std::string sign() const = 0; virtual double amountInEuro() const = 0; virtual std::string asString() const = 0; protected: unsigned referenceCount_; };

class Currency { public: Currency(); Currency(const Currency& amount); virtual Currency& operator=(const Currency& amount); explicit Currency(CurrencyBase *derivedClassThis); virtual ~Currency(); virtual Currency& operator+=(const Currency& amount); virtual Currency& operator-=(const Currency& amount); virtual std::string name() const; virtual std::string sign() const;

60

61 20161017FooCafé.key - 28 October 2016

G&C Coplien — Lean Architecture

Account Example: Currency virtual double amountInEuro() const; virtual std::string asString() const; friend bool operator==(const Currency& x, const Currency& y); friend bool operator!=(const Currency& x, const Currency& y); friend bool operator<(const Currency& x, const Currency& y); friend bool operator>(const Currency& x, const Currency& y); friend bool operator<=(const Currency& x, const Currency& y); friend bool operator>=(const Currency& x, const Currency& y); friend std::ostream &operator<<(std::ostream& stream, const Currency& currency); private: CurrencyBase *actualCurrency_; };

61

62 20161017FooCafé.key - 28 October 2016

G&C Coplien — Lean Architecture

Account Example: Currencyclass Euro: public CurrencyBase { friend class Currency; public: explicit Euro(double amount = 0.0); virtual ~Euro() = default; operator Currency(); CurrencyBase *copy() const; Euro &operator+=(const Currency& amount) override; Euro &operator-=(const Currency& amount) override; Euro &operator=(const Currency& amount) override; std::string name() const override; std::string sign() const override; double amountInEuro() const override; std::string asString() const override; private: double amount_; };

#endif

62

63 20161017FooCafé.key - 28 October 2016

G&C Coplien — Lean Architecture

Account Example: Currency/* * Currency.cpp * AgileBook * * Created by James Coplien on 7/31/09. * Copyright 2009 Gertrud & Cope. All rights reserved. * */

#include "Currency.h"

#include <sstream>

CurrencyBase::CurrencyBase() : referenceCount_(1) { }

Currency &Currency::operator+=(const Currency &amount) { *actualCurrency_ += amount; return *this; }

Currency &Currency::operator-=(const Currency &amount) { *actualCurrency_ -= amount; return *this; }

63

64 20161017FooCafé.key - 28 October 2016

G&C Coplien — Lean Architecture

Account Example: CurrencyCurrency &Currency::operator=(const Currency &amount) { amount.actualCurrency_->referenceCount_++; if (--actualCurrency_->referenceCount_ <= 0) delete actualCurrency_; actualCurrency_ = amount.actualCurrency_; return *this; }

Currency::Currency(const Currency &amount) { (actualCurrency_ = amount.actualCurrency_)->referenceCount_++; }

Currency::Currency() : actualCurrency_(new Euro) {}

Currency::~Currency() { if (--actualCurrency_->referenceCount_ <= 0) delete actualCurrency_; }

std::string Currency::name() const { return actualCurrency_->name(); }

std::string Currency::sign() const { return actualCurrency_->sign(); }

64

65 20161017FooCafé.key - 28 October 2016

G&C Coplien — Lean Architecture

Account Example: Currencybool operator<=(const Currency &x, const Currency &y) { return !(y < x); }

bool operator>=(const Currency &x, const Currency &y) { return !(x < y); }

Currency::Currency(CurrencyBase *derivedClassThis) : actualCurrency_(derivedClassThis) {}

Euro::operator Currency() { return Currency(this->copy()); }

CurrencyBase *Euro::copy() const { return new Euro(amount_); }

Euro &Euro::operator+=(const Currency &amount) { amount_ += amount.amountInEuro(); return *this; }

65

66 20161017FooCafé.key - 28 October 2016

G&C Coplien — Lean Architecture

Account Example: CurrencyEuro &Euro::operator-=(const Currency &amount) { amount_ -= amount.amountInEuro(); return *this; }

Euro &Euro::operator=(const Currency &amount) { amount_ = amount.amountInEuro(); return *this; }

Euro::Euro(double amount) : amount_(amount) {}

std::string Euro::name() const { return "Euro"; }

std::string Euro::sign() const { return "€"; }

double Euro::amountInEuro() const { return amount_; }

66

67 20161017FooCafé.key - 28 October 2016

G&C Coplien — Lean Architecture

Account Example: Currencystd::string Euro::asString() const { std::ostringstream stream; stream << amount_; return stream.str(); }

67

68 20161017FooCafé.key - 28 October 2016

G&C Coplien — Lean Architecture

Account Example: Currencybool operator<=(const Currency &x, const Currency &y) { return !(y < x); }

bool operator>=(const Currency &x, const Currency &y) { return !(x < y); }

Currency::Currency(CurrencyBase *derivedClassThis) : actualCurrency_(derivedClassThis) {}

Euro::operator Currency() { return Currency(this->copy()); }

CurrencyBase *Euro::copy() const { return new Euro(amount_); }

Euro &Euro::operator+=(const Currency &amount) { amount_ += amount.amountInEuro(); return *this; }

Euro &Euro::operator-=(const Currency &amount) { amount_ -= amount.amountInEuro(); return *this; }

Euro &Euro::operator=(const Currency &amount) { amount_ = amount.amountInEuro(); return *this; }

68

69 20161017FooCafé.key - 28 October 2016

G&C Coplien — Lean Architecture

Account Example: Account/* * Account.h * * Created by James Coplien on 9/2/08. * Copyright 2008 Gertrud & Cope. All rights reserved. * */

#ifndef _ACCOUNT_H #define _ACCOUNT_H

#include <string> #include "Currency.h"

class Account { public: Account(); std::string accountID() const; virtual void increaseBalance(const Currency&) = 0; virtual void decreaseBalance(const Currency&) = 0; private: int acct_; };

#endif

69

70 20161017FooCafé.key - 28 October 2016

G&C Coplien — Lean Architecture

Account Example: Account/* * Account.cpp * AgileBook * * Created by James Coplien on 9/2/08. * Copyright 2008 Gertrud & Cope. All rights reserved. * */

#include "Account.h" #include <sstream>

using namespace std;

namespace { int accountCounter = 0; }

Account::Account() { acct_ = accountCounter++; }

string Account::accountID() const { string retval; std::stringstream s(retval); s << acct_; return retval; }

70

71 20161017FooCafé.key - 28 October 2016

G&C Coplien — Lean Architecture

Account Example: CheckingAccount/* * CheckingAccount.h * * Created by James Coplien on 9/17/08. * Copyright 2008 Gertrud & Cope. All rights reserved. */

#ifndef _CHECKINGACCOUNT_H #define _CHECKINGACCOUNT_H

#include "Account.h" #include "Currency.h" #include "TransferMoneyContext.h" #include "MyTime.h" #include <string>

class CheckingAccount: public Account, public TransferMoneyContext::TransferMoneySink<CheckingAccount> { public: CheckingAccount(); virtual ~CheckingAccount() = default;

// These functions can be virtual if there are // specialisations of CheckingAccount Currency availableBalance() const; void decreaseBalance(const Currency&) override; void increaseBalance(const Currency&) override; void updateLog(const std::string&, const MyTime&, const Currency&) const override; private: Currency availableBalance_; };

#endif

71

72 20161017FooCafé.key - 28 October 2016

G&C Coplien — Lean Architecture

Account Example: CheckingAccount/* * CheckingAccount.cpp * * Created by James Coplien on 9/2/08. * Copyright 2008 Gertrud & Cope. All rights reserved. */

#include "CheckingAccount.h" #include "PayBillsContext.h" #include "Currency.h" #include "TransferMoneyContext.h" #include <iostream>

CheckingAccount::CheckingAccount() : availableBalance_(Euro(100.00)) { }

Currency CheckingAccount::availableBalance() const { std::cout << "CheckingAccount::availableBalance returns " << availableBalance_ << std::endl; return availableBalance_; }

void CheckingAccount::decreaseBalance(const Currency& c) { std::cout << "CheckingAccount::decreaseBalance(" << c << ")" << std::endl; availableBalance_ -= c; }

72

73 20161017FooCafé.key - 28 October 2016

G&C Coplien — Lean Architecture

void CheckingAccount::updateLog(const string& message, const MyTime& t, const Currency& c) const { std::cout << "account: " << accountID() << " CheckingAccount::updateLog(\"" << message << "\", MyTime, " << c << ")" << std::endl; }

void CheckingAccount::increaseBalance(const Currency& c) { std::cout << "CheckingAccount::increaseBalance(" << c << ")" << std::endl; availableBalance_ += c; }

Account Example: CheckingAccount

73

74 20161017FooCafé.key - 28 October 2016

G&C Coplien — Lean Architecture

Account Example: SavingsAccount/* * SavingsAccount.h * * Created by James Coplien on 9/2/08. * Copyright 2008 Gertrud & Cope. All rights reserved. */

#ifndef _SAVINGSACCOUNT_H #define _SAVINGSACCOUNT_H

#include "Account.h" #include "TransferMoneyContext.h" #include "MyTime.h" #include <string>

class SavingsAccount: public Account, public TransferMoneyContext::TransferMoneySink<SavingsAccount> { public: SavingsAccount(); SavingsAccount(Currency initialBalance): availableBalance_(initialBalance) { } private: // These functions can be virtual if there are // specialisations of SavingsAccount Currency availableBalance() const; void decreaseBalance(const Currency&) override; void increaseBalance(const Currency&) override; void updateLog(const std::string&, const MyTime&, const Currency&) const override; private: Currency availableBalance_; };

#endif

74

75 20161017FooCafé.key - 28 October 2016

G&C Coplien — Lean Architecture

Account Example: SavingsAccount/* * SavingsAccount.cpp * * Created by James Coplien on 9/2/08. * Copyright 2008 Gertrud & Cope. All rights reserved. */

#include "SavingsAccount.h" #include "PayBillsContext.h" #include "TransferMoneyContext.h"

#include <iostream> #include <cassert>

using namespace std;

SavingsAccount::SavingsAccount() : availableBalance_(Euro(0.00)) { // no application code assert(availableBalance_ == Euro(0.0)); }

Currency SavingsAccount::availableBalance() const { cout << "SavingsAccount::availableBalance returns " << availableBalance_ << std::endl; return availableBalance_; }

75

76 20161017FooCafé.key - 28 October 2016

G&C Coplien — Lean Architecture

Account Example: SavingsAccountvoid SavingsAccount::decreaseBalance(const Currency& c) { cout << "SavingsAccount::decreaseBalance(" << c << ")" << endl; assert(c > availableBalance_); availableBalance_ -= c; assert(availableBalance_ > Euro(0.0)); }

const unsigned MAX_BUFFER_SIZE = 256;

void SavingsAccount::updateLog(const string& logMessage, const MyTime& timeOfTransaction, const Currency& amountForTransaction) const { assert(logMessage.size() > 0); assert(logMessage.size() < MAX_BUFFER_SIZE); assert(MyTime("00:00:00.00 1970/1/1") < timeOfTransaction); cout << "account: " << accountID() << " SavingsAccount::updateLog(\"" << logMessage << "\", MyTime, " << amountForTransaction << ")" << endl; }

void SavingsAccount::increaseBalance(const Currency& c) { cout << "SavingsAccount::increaseBalance(" << c << ")" << endl; availableBalance_ += c; }

76

77 20161017FooCafé.key - 28 October 2016

G&C Coplien — Lean Architecture

Account Example: InvestmentAccount/* * InvestmentAccount.h * * Created by James Coplien on 9/2/08. * Copyright 2008 Gertrud & Cope. All rights reserved. */

#ifndef _INVESTMENTACCOUNT_H #define _INVESTMENTACCOUNT_H

#include "Account.h" #include "Currency.h" #include "TransferMoneyContext.h" #include "MyTime.h"

class InvestmentAccount: public TransferMoneyContext::TransferMoneySource<InvestmentAccount> { public: InvestmentAccount(); Currency availableBalance() const; void increaseBalance(const Currency&) override; void decreaseBalance(const Currency&) override; void updateLog(const std::string&, const MyTime&, const Currency&) const override; private: Currency availableBalance_; };

#endif

77

78 20161017FooCafé.key - 28 October 2016

G&C Coplien — Lean Architecture

Account Example: InvestmentAccount/* * InvestmentAccount.cpp * * Created by James Coplien on 9/2/08. * Copyright 2008 Gertrud & Cope. All rights reserved. */

#include "InvestmentAccount.h" #include "PayBillsContext.h" #include "TransferMoneyContext.h" #include <string> #include <iostream>

InvestmentAccount::InvestmentAccount() : availableBalance_(Euro(0.00)) {}

Currency InvestmentAccount::availableBalance() const { std::cout << "InvestmentAccount::availableBalance returns " << availableBalance_ << std::endl; return availableBalance_; }

void InvestmentAccount::increaseBalance(const Currency &c) { std::cout << "InvestmentAccount::increaseBalance(" << c << ")" << std::endl; availableBalance_ += c; }

78

79 20161017FooCafé.key - 28 October 2016

G&C Coplien — Lean Architecture

void InvestmentAccount::decreaseBalance(const Currency &c) { std::cout << "InvestmentAccount::decreaseBalance(" << c << ")" << std::endl; availableBalance_ -= c; }

void InvestmentAccount::updateLog(const std::string &s, const MyTime &, const Currency &c) const { std::cout << "account: " << accountID() << " InvestmentAccount::updateLog(\"" << s << "\", Time, " << c << ")" << std::endl; }

Account Example: InvestmentAccount

79

80 20161017FooCafé.key - 28 October 2016

G&C Coplien — Lean Architecture

Account Example: Creditors/* * Creditor.h * * Created by James Coplien on 9/17/08. * Copyright 2008 Gertrud & Cope. All rights reserved. */

#ifndef _CREDITOR_H #define _CREDITOR_H

#include "Currency.h" #include "MoneyPort.h" #include "TransferMoneyContext.h"

class Creditor { public: Creditor(TransferMoneyContext::MoneySink *account); virtual ~Creditor(); virtual TransferMoneyContext::MoneySink *account() { return account_; } virtual Currency amountOwed() const = 0; protected: TransferMoneyContext::MoneySink *account_; };

80

81 20161017FooCafé.key - 28 October 2016

G&C Coplien — Lean Architecture

Account Example: Creditors

class ElectricCompany: public Creditor { public: ElectricCompany(); virtual ~ElectricCompany() = default; Currency amountOwed() const override; };

class GasCompany: public Creditor { public: GasCompany(); virtual ~GasCompany() = default; Currency amountOwed() const override; };

#endif

81

82 20161017FooCafé.key - 28 October 2016

G&C Coplien — Lean Architecture

Account Example: Creditors/* * Creditor.cpp * * Created by James Coplien on 9/17/08. * Copyright 2008 Gertrud & Cope. All rights reserved. */

#include "Creditor.h" #include "CheckingAccount.h" #include "SavingsAccount.h"

Creditor::Creditor(TransferMoneyContext::MoneySink *account) : account_(account) { }

Creditor::~Creditor() { delete account_; }

ElectricCompany::ElectricCompany(): Creditor(new CheckingAccount()) { }

Currency ElectricCompany::amountOwed() const { return Euro(15.0); }

82

83 20161017FooCafé.key - 28 October 2016

G&C Coplien — Lean Architecture

Account Example: CreditorsGasCompany::GasCompany(): Creditor(new SavingsAccount(Euro(500.00))) // for the demo { }

Currency GasCompany::amountOwed() const { return Euro(18.76); // for the demo }

83

84 20161017FooCafé.key - 28 October 2016

G&C Coplien — Lean Architecture

Account Example: Context/**Context.h**CreatedbyJamesCoplienon1/14/09.UpdatedtoC++147/12/2016.*Copyright©2016Gertrud&Cope.Allrightsreserved.*/

#ifndef_CONTEXT_H#define_CONTEXT_H

classContext{public:Context();virtual~Context();public:staticContext*currentContext_;private:Context*parentContext_;};

#endif

84

85 20161017FooCafé.key - 28 October 2016

G&C Coplien — Lean Architecture

Account Example: Context/**Context.cpp**CreatedbyJamesCoplienon1/14/09.UpdatedtoC++147/12/2016.*Copyright©2016Gertrud&Cope.Allrightsreserved.*/

#include"Context.h"

Context*Context::currentContext_=nullptr;

Context::Context(){parentContext_=currentContext_;currentContext_=this;}

Context::~Context(){currentContext_=parentContext_;}

85

86 20161017FooCafé.key - 28 October 2016

G&C Coplien — Lean Architecture

Account Example: Transfer Money/* * TransferMoneyContext.h * * Created by James Coplien on 9/13/08. * Copyright 2008 Gertrud & Cope. All rights reserved. */

// TransferMoneyContext knows how to find the objects for a given // use case invocation. It associates those objects with // the roles they play in a use case of this type; and it // publishes those interface bindings for use by the // other Roles that participate in the use case (behind the // scenes).

#ifndef _XFERMONEYCONTEXT_H #define _XFERMONEYCONTEXT_H

#include "Account.h" #include "Context.h" #include "Currency.h" #include "MyExceptions.h" #include "Globals.h" #include "MoneyPort.h" #include <string>

class MyTime;

86

87 20161017FooCafé.key - 28 October 2016

G&C Coplien — Lean Architecture

class TransferMoneyContext: public Context { public: // Roles class MoneySource: public MoneyPort, public Account { public: virtual ~MoneySource() = default; virtual void transferTo() = 0; virtual void decreaseBalance(const Currency&) = 0; virtual void updateLog(const std::string&, const MyTime&, const Currency& amount) const = 0; };

Account Example: Transfer Money

87

88 20161017FooCafé.key - 28 October 2016

G&C Coplien — Lean Architecture

template <class RolePlayer> class TransferMoneySource: public MoneySource { public: TransferMoneySource() = default; virtual ~TransferMoneySource() = default; virtual void transferTo() override { // This code is reviewable and // meaningfully testable with stubs! beginTransaction(); if (SELF<RolePlayer>(this)->availableBalance() < AMOUNT<TransferMoneyContext>()) { endTransaction(); throw InsufficientFunds(); } else { SELF<RolePlayer>(this)->decreaseBalance(AMOUNT<TransferMoneyContext>()); RECIPIENT<TransferMoneyContext>()-> increaseBalance(AMOUNT<TransferMoneyContext>()); SELF<RolePlayer>(this)->updateLog("Transfer Out", DateTime(), AMOUNT<TransferMoneyContext>()); RECIPIENT<TransferMoneyContext>()->updateLog("Transfer In", DateTime(), AMOUNT<TransferMoneyContext>()); } GUI->displayScreen(SUCCESS_DEPOSIT_SCREEN); endTransaction(); } };

Account Example: Transfer Money

88

89 20161017FooCafé.key - 28 October 2016

G&C Coplien — Lean Architecture

class MoneySink: public MoneyPort { public: virtual ~MoneySink() = default; virtual void increaseBalance(const Currency& amount) = 0; virtual void updateLog(const std::string&, const MyTime&, const Currency& amount) const = 0; }; template <class RolePlayer> class TransferMoneySink: public MoneySink { public: TransferMoneySink() = default; virtual ~TransferMoneySink() = default; virtual void transferFrom(const Currency& amount) { SELF<RolePlayer>(this)->increaseBalance(amount); SELF<RolePlayer>(this)->updateLog("Transfer in", DateTime(), amount); } }; public: TransferMoneyContext(); TransferMoneyContext(const Currency& amount, MoneySource *src, MoneySink *destination); void doit(); TransferMoneyContext::MoneySource *sourceAccount() const; TransferMoneyContext::MoneySink *destinationAccount() const; Currency amount() const;

Account Example: Transfer Money

89

90 20161017FooCafé.key - 28 October 2016

G&C Coplien — Lean Architecture

private: void lookupBindings(); MoneySource *sourceAccount_; MoneySink *destinationAccount_; Currency amount_; };

#endif

Account Example: Transfer Money

90

91 20161017FooCafé.key - 28 October 2016

G&C Coplien — Lean Architecture

/* * TransferMoneyContext.cpp * * Created by James Coplien on 9/13/08. * Copyright 2008 Gertrud & Cope. All rights reserved. */

#include "TransferMoneyContext.h" #include "InvestmentAccount.h" #include "SavingsAccount.h"

TransferMoneyContext::TransferMoneyContext() : Context() { lookupBindings(); }

TransferMoneyContext::~TransferMoneyContext() { }

TransferMoneyContext::TransferMoneyContext(const Currency& amount, MoneySource *source, MoneySink *destination) : Context() { amount_ = amount; sourceAccount_ = source; destinationAccount_ = destination; }

Account Example: Transfer Money

91

92 20161017FooCafé.key - 28 October 2016

G&C Coplien — Lean Architecture

void TransferMoneyContext::doit() { sourceAccount()->transferTo(); }

void TransferMoneyContext::lookupBindings() { // These are somewhat arbitrary and for illustrative // purposes. The simulate a database lookup InvestmentAccount *investmentAccount = new InvestmentAccount; investmentAccount->increaseBalance(Euro(100.00)); // prime it with some money sourceAccount_ = investmentAccount; destinationAccount_ = new SavingsAccount; destinationAccount_->increaseBalance(Euro(500.00)); // start it off with money amount_ = Euro(30.00); }

TransferMoneyContext::MoneySource *TransferMoneyContext::sourceAccount() const { return sourceAccount_; }

TransferMoneyContext::MoneySink *TransferMoneyContext::destinationAccount() const { return destinationAccount_; }

Currency TransferMoneyContext::amount() const { return amount_; }

Account Example: Transfer Money

92

93 20161017FooCafé.key - 28 October 2016

G&C Coplien — Lean Architecture

Account Example: PayBills/* * PayBillsContext.h * * Created by James Coplien on 9/13/08. * Copyright 2008 Gertrud & Cope. All rights reserved. */

#ifndef _PAYBILLSCONTEXT_H #define _PAYBILLSCONTEXT_H

#include "TransferMoneyContext.h" #include "Creditor.h" #include <vector>

class Creditor;

class PayBillsContext: public Context { template <typename T> auto CREDITORS() { return static_cast<T*>(Context::currentContext_)->creditors(); } template <typename T> auto SOURCE_ACCOUNT() { return static_cast<T*>(Context::currentContext_)->sourceAccount(); }

93

94 20161017FooCafé.key - 28 October 2016

G&C Coplien — Lean Architecture

Account Example: PayBillspublic: PayBillsContext(); ~PayBillsContext(); TransferMoneyContext::MoneySource *sourceAccount() const; std::vector<Creditor*> creditors() const; // Role behaviours void doit() { // While object contexts are changing, we don't want to // have an open iterator on an external object. Make a // local copy. for (auto& credit : CREDITORS<PayBillsContext>()) { try { // Note that here we invoke another use case TransferMoneyContext transferTheFunds(credit->amountOwed(), SOURCE_ACCOUNT<PayBillsContext>(), credit->account()); transferTheFunds.doit(); } catch (const InsufficientFunds&) { throw; } } } private: void lookupBindings(); TransferMoneyContext::MoneySource *sourceAccount_; std::vector<Creditor *> creditors_; };

#endif

94

95 20161017FooCafé.key - 28 October 2016

G&C Coplien — Lean Architecture

Account Example: PayBills/* * PayBillsContext.cpp * * Created by James Coplien on 9/17/08. * Copyright 2008 Gertrud & Cope. All rights reserved. */

#include "PayBillsContext.h" #include "InvestmentAccount.h" #include "SavingsAccount.h" #include "Creditor.h"

PayBillsContext::PayBillsContext() : Context() { lookupBindings(); }

PayBillsContext::~PayBillsContext() { delete sourceAccount_; for (Creditor *creditor : creditors_) delete creditor; }

95

96 20161017FooCafé.key - 28 October 2016

G&C Coplien — Lean Architecture

Account Example: PayBillsvoid PayBillsContext::lookupBindings() { // These are somewhat arbitrary and for illustrative // purposes. The simulate a database lookup TransferMoneyContext::TransferMoneySource<InvestmentAccount> *investmentAccount = new InvestmentAccount; investmentAccount->increaseBalance(Euro(100.00)); // prime it with some money sourceAccount_ = investmentAccount; creditors_.push_back(new ElectricCompany); creditors_.push_back(new GasCompany); }

TransferMoneyContext::MoneySource *PayBillsContext::sourceAccount() const { return sourceAccount_; }

std::vector<Creditor *> PayBillsContext::creditors() const { return creditors_; }

96

97 20161017FooCafé.key - 28 October 2016

G&C Coplien — Lean Architecture

Account Example: main// // main.cpp // DCI Money Transfer // // Created by James Coplien on 12/07/16. // Copyright © 2016 Gertrud & Cope. All rights reserved. //

#include <iostream>

#include "TransferMoneyContext.h" #include "PayBillsContext.h" #include <memory>

int main() { auto aNewUseCase = std::unique_ptr<TransferMoneyContext>( new TransferMoneyContext()); aNewUseCase->doit(); auto anotherNewUseCase = std::unique_ptr<PayBillsContext>( new PayBillsContext()); anotherNewUseCase->doit();

return 0; }

97

98 20161017FooCafé.key - 28 October 2016

G&C Coplien — Lean Architecture

Account Example: Exceptions/**MyExceptions.h**CreatedbyJamesCoplienon9/2/08.UpdatedtoC++147/12/16.*Copyright©2016Gertrud&Cope.Allrightsreserved.*/

#ifndef_MYEXCEPTIONS_H#define_MYEXCEPTIONS_H

#include<exception>

classInsufficientFunds:publicstd::exception{public: InsufficientFunds();};

#endif

98

99 20161017FooCafé.key - 28 October 2016

G&C Coplien — Lean Architecture

Account Example: Exceptions/**MyExceptionsImplementation.cpp**CreatedbyJamesCoplienon9/2/08.UpdatedtoC++147/12/16.*Copyright©2016Gertrud&Cope.Allrightsreserved.*/

#include"MyExceptions.h"

InsufficientFunds::InsufficientFunds(){}

99

100 20161017FooCafé.key - 28 October 2016

G&C Coplien — Lean Architecture

Account Example: MyTime/**MyTime.h**CreatedbyJamesCoplienon9/2/08.UpdatedtoC++147/12/16.*Copyright©2016Gertrud&Cope.Allrightsreserved.*/

#ifndef_MYTIME_H#define_MYTIME_H

#include<string>

classMyTime{public:MyTime()=default;explicitMyTime(longlong);explicitMyTime(conststd::string&timeAsString);~MyTime();MyTime(constMyTime&t);MyTime&operator=(constMyTime&t);

friendbooloperator<(constMyTime&x,constMyTime&y);};

#endif

100

101 20161017FooCafé.key - 28 October 2016

G&C Coplien — Lean Architecture

Account Example: MyTime/**MyTimeImplementation.cpp**CreatedbyJamesCoplienon9/2/08.UpdatedtoC++147/12/16.*Copyright©2016Gertrud&Cope.Allrightsreserved.*/

#include"MyTime.h"

MyTime::MyTime(longlong){}

MyTime::MyTime(conststd::string&timeAsString){}

MyTime::~MyTime(){}

MyTime::MyTime(constMyTime&t){}

MyTime&MyTime::operator=(constMyTime&t){return*this;}

booloperator<(constMyTime&x,constMyTime&y){returntrue;}

101

102 20161017FooCafé.key - 28 October 2016

G&C Coplien — Lean Architecture

Account Example: Globals/**Globals.h**CreatedbyJamesCoplienon9/2/08.UpdatedtoC++147/12/16.*Copyright©2016Gertrud&Cope.Allrightsreserved.*/

#ifndef_GLOBALS_H#define_GLOBALS_H

#include"MyTime.h"

externvoidendTransaction();externvoidbeginTransaction();externMyTimeDateTime();

#endif

102

103 20161017FooCafé.key - 28 October 2016

G&C Coplien — Lean Architecture

Account Example: Globals/**GlobalsImplementation.cpp**CreatedbyJamesCoplienon9/2/08.UpdatedtoC++147/12/16.*Copyright©2016Gertrud&Cope.Allrightsreserved.*/

#include"Globals.h"#include"MyTime.h"#include<iostream>

voidendTransaction(){std::cout<<"::endTransaction()"<<std::endl;}

voidbeginTransaction(){std::cout<<"::beginTransaction()"<<std::endl;}

MyTimeDateTime(){returnMyTime(0);}

103

104 20161017FooCafé.key - 28 October 2016

G&C Coplien — Lean Architecture

Account Example: MoneyPort////MoneyPort.h//DCIMoneyTransfer////CreatedbyJamesCoplienon12/07/16.//Copyright©2016Gertrud&Cope.Allrightsreserved.//

#ifndefMoneyPort_h#defineMoneyPort_h

#include"Context.h"

classMoneyPort{//Commonprivateutilityfunctions

template<typenameT,typenameU>autoSELF(U*u){returnstatic_cast<T*>(u);}

template<typenameT>autoRECIPIENT(){autoresult=dynamic_cast<T*>(Context::currentContext_);if(result)returnresult->destinationAccount();throwstd::bad_cast();//("dynamiccastfailed");}

104

105 20161017FooCafé.key - 28 October 2016