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&C
5-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&C
5-4 20161017FooCafé.key - 28 October 2016
G&C
6 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 Models
public 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 Models
public 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 Qtr
2nd Qtr
3rd Qtr
4th Qtr
V0
10
20
30
40
50
60
70
80
90
1st Qtr 2nd Qtr 3rd Qtr 4th Qtr
East
West
North
ModelView
Controller
Skip
12-1 20161017FooCafé.key - 28 October 2016
G&C
Action Between Objects
1st Qtr
2nd Qtr
3rd Qtr
4th Qtr
V0
10
20
30
40
50
60
70
80
90
1st Qtr 2nd Qtr 3rd Qtr 4th Qtr
East
West
North
Skip
12-2 20161017FooCafé.key - 28 October 2016
G&C
Action Between Objects
1st Qtr
2nd Qtr
3rd Qtr
4th Qtr
V0
10
20
30
40
50
60
70
80
90
1st Qtr 2nd Qtr 3rd Qtr 4th Qtr
East
West
North
The programmer
must consider the
system:
action between
objects
Skip
12-3 20161017FooCafé.key - 28 October 2016
G&C
Action Between Objects
1st Qtr
2nd Qtr
3rd Qtr
4th Qtr
V0
10
20
30
40
50
60
70
80
90
1st Qtr 2nd Qtr 3rd Qtr 4th Qtr
East
West
North
13-1 20161017FooCafé.key - 28 October 2016
G&C
1st Qtr
2nd Qtr
3rd Qtr
4th Qtr
V0
10
20
30
40
50
60
70
80
90
1st Qtr 2nd Qtr 3rd Qtr 4th Qtr
East
West
North
Programmers’
objects interact
with objects previously
conceived by other
programmers
13-2 20161017FooCafé.key - 28 October 2016
G&C
14 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 Scripts
context 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 Scripts
context 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
sna
sna
sna
?
Skip
18-4 20161017FooCafé.key - 28 October 2016
Contextualized
Polymorphism
foo
foo
foo
foo bar
bar
bar
bar
sna
sna
sna
sna
Skip
18-5 20161017FooCafé.key - 28 October 2016
Contextualized
Polymorphism
foo
foo
foo
foo bar
bar
bar
bar
sna
sna
sna
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
sna
sna
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
sna
sna
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
Polymorphism
Context:
Another

new
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
Context
System
Operations
20-5 20161017FooCafé.key - 28 October 2016
Contextualized
Polymorphism
bar sna
Data
Context
Interaction
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 semicolons
interface 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 Puzzle
class 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 Example
class 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 Example
class 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 Example
class 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 Example
class 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 Example
context 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 Example
context 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 Example
Many 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: Currency
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;
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: Currency
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
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: Currency
Currency &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: Currency
bool 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: Currency
Euro &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: Currency
std::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: Currency
bool 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: SavingsAccount
void 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: Creditors
GasCompany::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	
	*	
	*		Created	by	James	Coplien	on	1/14/09.	Updated	to	C++14	7/12/2016.	
	*		Copyright	©2016	Gertrud	&	Cope.	All	rights	reserved.	
	*/	
#ifndef	_CONTEXT_H	
#define	_CONTEXT_H	
class	Context	{	
public:	
				Context();	
				virtual	~Context();	
public:	
				static	Context	*currentContext_;	
private:	
				Context	*parentContext_;	
};	
#endif
84
85 20161017FooCafé.key - 28 October 2016
G&C Coplien — Lean Architecture
Account Example: Context
/*	
	*		Context.cpp	
	*	
	*		Created	by	James	Coplien	on	1/14/09.	Updated	to	C++14	7/12/2016.	
	*		Copyright	©2016	Gertrud	&	Cope.	All	rights	reserved.	
	*/	
#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: PayBills
public:
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: PayBills
void 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	
	*	
	*		Created	by	James	Coplien	on	9/2/08.	Updated	to	C++14	7/12/16.	
	*		Copyright	©2016	Gertrud	&	Cope.	All	rights	reserved.	
	*/	
#ifndef	_MYEXCEPTIONS_H	
#define	_MYEXCEPTIONS_H	
#include	<exception>	
class	InsufficientFunds	:	public	std::exception	
{	
public:	
	 InsufficientFunds();	
};	
#endif	
98
99 20161017FooCafé.key - 28 October 2016
G&C Coplien — Lean Architecture
Account Example: Exceptions
/*	
	*		MyExceptionsImplementation.cpp	
	*	
	*		Created	by	James	Coplien	on	9/2/08.	Updated	to	C++14	7/12/16.	
	*		Copyright	©2016	Gertrud	&	Cope.	All	rights	reserved.	
	*/	
#include	"MyExceptions.h"	
InsufficientFunds::InsufficientFunds()	
{	
}	
99
100 20161017FooCafé.key - 28 October 2016
G&C Coplien — Lean Architecture
Account Example: MyTime
/*	
	*		MyTime.h	
	*	
	*		Created	by	James	Coplien	on	9/2/08.	Updated	to	C++14	7/12/16.	
	*		Copyright	©2016	Gertrud	&	Cope.	All	rights	reserved.	
	*/	
#ifndef	_MYTIME_H	
#define	_MYTIME_H	
#include	<string>	
class	MyTime	{	
public:	
				MyTime()	=	default;	
				explicit	MyTime(long	long);	
				explicit	MyTime(const	std::string&	timeAsString);	
				~MyTime();	
				MyTime(const	MyTime&	t);	
				MyTime&	operator=(const	MyTime	&t);	
				friend	
				bool	operator<(const	MyTime	&x,	const	MyTime	&y);	
};	
#endif	
100
101 20161017FooCafé.key - 28 October 2016
G&C Coplien — Lean Architecture
Account Example: MyTime
/*	
	*		MyTimeImplementation.cpp	
	*	
	*		Created	by	James	Coplien	on	9/2/08.	Updated	to	C++14	7/12/16.	
	*		Copyright	©2016	Gertrud	&	Cope.	All	rights	reserved.	
	*/	
#include	"MyTime.h"	
MyTime::MyTime(long	long)		
{	}	
MyTime::MyTime(const	std::string&	timeAsString)		
{	}	
MyTime::~MyTime()	{	}	
MyTime::MyTime(const	MyTime	&t)	{	}	
MyTime	&MyTime::operator=(const	MyTime	&t)	
{		
				return	*this;		
}	
bool	operator<(const	MyTime	&x,	const	MyTime	&y)	
{		
				return	true;		
}	
101
102 20161017FooCafé.key - 28 October 2016
G&C Coplien — Lean Architecture
Account Example: Globals
/*	
	*		Globals.h	
	*	
	*		Created	by	James	Coplien	on	9/2/08.	Updated	to	C++14	7/12/16.	
	*		Copyright	©2016	Gertrud	&	Cope.	All	rights	reserved.	
	*/	
#ifndef	_GLOBALS_H	
#define	_GLOBALS_H	
#include	"MyTime.h"	
extern	void	endTransaction();	
extern	void	beginTransaction();	
extern	MyTime	DateTime();	
#endif	
102
103 20161017FooCafé.key - 28 October 2016
G&C Coplien — Lean Architecture
Account Example: Globals
/*	
	*		GlobalsImplementation.cpp	
	*	
	*		Created	by	James	Coplien	on	9/2/08.	Updated	to	C++14	7/12/16.	
	*		Copyright	©2016	Gertrud	&	Cope.	All	rights	reserved.	
	*/	
#include	"Globals.h"	
#include	"MyTime.h"	
#include	<iostream>	
void	endTransaction()	{	
				std::cout	<<	"::endTransaction()"	<<	std::endl;	
}	
void	beginTransaction()	{	
				std::cout	<<	"::beginTransaction()"	<<	std::endl;	
}	
MyTime	DateTime()	{	
				return	MyTime(0);	
}	
103
104 20161017FooCafé.key - 28 October 2016
G&C Coplien — Lean Architecture
Account Example: MoneyPort
//	
//		MoneyPort.h	
//		DCI	Money	Transfer	
//	
//		Created	by	James	Coplien	on	12/07/16.	
//		Copyright	©	2016	Gertrud	&	Cope.	All	rights	reserved.	
//	
#ifndef	MoneyPort_h	
#define	MoneyPort_h	
#include	"Context.h"	
class	MoneyPort	{	
					
//	Common	private	utility	functions	
				template	<typename	T,	typename	U>	
				auto	SELF(U*	u)	
				{	
								return	static_cast<T*>(u);	
				}	
				template	<typename	T>	
				auto	RECIPIENT()	
				{	
								auto	result	=	dynamic_cast<T*>(Context::currentContext_);	
								if	(result)	
												return	result->destinationAccount();	
								throw	std::bad_cast();	//	("dynamic	cast	failed");	
				}	
104
105 20161017FooCafé.key - 28 October 2016

James Coplien: Trygve - Oct 17, 2016

  • 1.
    A taste oftrygve Jim Coplien Former C++ Programmer & Author Gertrud & Cope Helsingør, Danmark jcoplien@gmail 1 20161017FooCafé.key - 28 October 2016
  • 2.
    Pointers… • DCI documentation& downloads: • http://fulloo.info • trygve on GitHub: • https://github.com/jcoplien/trygve 2 20161017FooCafé.key - 28 October 2016
  • 3.
    My greatest contributionto computing is that I never invented a programming language. – Jerry Weinberg 3 20161017FooCafé.key - 28 October 2016
  • 4.
    In 1972, Kaycoined 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
  • 5.
  • 6.
    G&C We feel thata 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
  • 7.
    G&C We feel thata 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
  • 8.
  • 9.
  • 10.
    But we *do*design 7-1 20161017FooCafé.key - 28 October 2016
  • 11.
    But we *do*design • What kinds of tools / notations / models do you use? 7-2 20161017FooCafé.key - 28 October 2016
  • 12.
    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
  • 13.
    Java Programs asModels public 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
  • 14.
    Java Programs asModels public 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
  • 15.
    Class (domain) structure trygve Programs asModels 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
  • 16.
    Class (domain) structure trygve Programs asModels 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
  • 17.
    Research Results • FromHé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
  • 18.
    But couldn’t youjust… 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
  • 19.
    G&C Action Between Objects 1stQtr 2nd Qtr 3rd Qtr 4th Qtr V0 10 20 30 40 50 60 70 80 90 1st Qtr 2nd Qtr 3rd Qtr 4th Qtr East West North ModelView Controller Skip 12-1 20161017FooCafé.key - 28 October 2016
  • 20.
    G&C Action Between Objects 1stQtr 2nd Qtr 3rd Qtr 4th Qtr V0 10 20 30 40 50 60 70 80 90 1st Qtr 2nd Qtr 3rd Qtr 4th Qtr East West North Skip 12-2 20161017FooCafé.key - 28 October 2016
  • 21.
    G&C Action Between Objects 1stQtr 2nd Qtr 3rd Qtr 4th Qtr V0 10 20 30 40 50 60 70 80 90 1st Qtr 2nd Qtr 3rd Qtr 4th Qtr East West North The programmer must consider the system: action between objects Skip 12-3 20161017FooCafé.key - 28 October 2016
  • 22.
    G&C Action Between Objects 1stQtr 2nd Qtr 3rd Qtr 4th Qtr V0 10 20 30 40 50 60 70 80 90 1st Qtr 2nd Qtr 3rd Qtr 4th Qtr East West North 13-1 20161017FooCafé.key - 28 October 2016
  • 23.
    G&C 1st Qtr 2nd Qtr 3rdQtr 4th Qtr V0 10 20 30 40 50 60 70 80 90 1st Qtr 2nd Qtr 3rd Qtr 4th Qtr East West North Programmers’ objects interact with objects previously conceived by other programmers 13-2 20161017FooCafé.key - 28 October 2016
  • 24.
  • 25.
  • 26.
    G&C System Operations While thespecific interactions are emergent, the form of the interactions is designed. 15-2 20161017FooCafé.key - 28 October 2016
  • 27.
    G&C System Operations This formlives within no single object or class. 15-3 20161017FooCafé.key - 28 October 2016
  • 28.
    G&C System Operations Objects arean overly small concept, conceived for the revenge of the nerds, each owning their individual classes 15-4 20161017FooCafé.key - 28 October 2016
  • 29.
  • 30.
    G&C System Operations context TripReservation } { 16-220161017FooCafé.key - 28 October 2016
  • 31.
    G&C System Operations context TripReservation } { roleJourneyEnd { City city() { … } …. } role JourneyStart { City city() { … } …. } role RouteMap { Path pfinder() { … } …. } 16-3 20161017FooCafé.key - 28 October 2016
  • 32.
    G&C System Operations context TripReservation } { roleJourneyEnd { City city() { … } …. } role JourneyStart { City city() { … } …. } role RouteMap { Path pfinder() { … } …. } 16-4 20161017FooCafé.key - 28 October 2016
  • 33.
    Teaching Actors theirScripts context TripReservation { role JourneyStart { … } role JourneyEnd { … } public TripReservation(Object jStart, Object jEnd){ JourneyStart = jStart; JourneyEnd = jEnd } } 17-1 20161017FooCafé.key - 28 October 2016
  • 34.
    Teaching Actors theirScripts context TripReservation { role JourneyStart { … } role JourneyEnd { … } public TripReservation(Object jStart, Object jEnd){ JourneyStart = jStart; JourneyEnd = jEnd } } 17-2 20161017FooCafé.key - 28 October 2016
  • 35.
  • 36.
  • 37.
  • 38.
  • 39.
  • 40.
    Contextualized Polymorphism foo foo foo foo bar bar bar bar sna sna sna sna “Just trustthe objects to do the right thing and everything will be fine.” — Smalltalk Skip 18-6 20161017FooCafé.key - 28 October 2016
  • 41.
    Contextualized Polymorphism foo foo foo foo bar bar bar bar sna sna sna sna “You believein things you don’t understand, you may suffer.” — Stevie Wonder Skip 18-7 20161017FooCafé.key - 28 October 2016
  • 42.
    Contextualized Polymorphism foo foo foo foo bar bar bar bar sna sna sna sna Where is theuse case? Where is the use case? Skip 18-8 20161017FooCafé.key - 28 October 2016
  • 43.
    Contextualized PolymorphismRoles: A new concept 19-120161017FooCafé.key - 28 October 2016
  • 44.
  • 45.
  • 46.
  • 47.
  • 48.
  • 49.
  • 50.
  • 51.
  • 52.
    Hoare’s Insight • “Thereare 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
  • 53.
    Smalltalk 80 Smalltalk 76 Smalltalk72 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
  • 54.
    Smalltalk 80 Smalltalk 76 Smalltalk72 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
  • 55.
    Smalltalk 80 Smalltalk 76 Smalltalk72 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
  • 56.
    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
  • 57.
    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
  • 58.
    • So thisworks: 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
  • 59.
    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
  • 60.
    More going onhere 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
  • 61.
    Both class andContext 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
  • 62.
    Both class andContext 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
  • 63.
    On babies andbathwater • 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
  • 64.
    Reflection • Even commoninclusion 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
  • 65.
    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
  • 66.
    Postlog • trygve isan 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
  • 67.
  • 68.
    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
  • 69.
    Look, Ma, nosemicolons interface 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
  • 70.
    Everything’s an expression contextSpellCheck { 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
  • 71.
    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
  • 72.
    A Puzzle class 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
  • 73.
    Most class-oriented features havebeen removed • protected • super • Class:: • ABCs • static (though it exists internally) 39 20161017FooCafé.key - 28 October 2016
  • 74.
    Can an objectplay 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
  • 75.
    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
  • 76.
  • 77.
    G&C Coplien —Lean Architecture trygve Account Example class 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
  • 78.
    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
  • 79.
    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
  • 80.
    G&C Coplien —Lean Architecture trygve Account Example class 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
  • 81.
    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
  • 82.
    G&C Coplien —Lean Architecture trygve Account Example class 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
  • 83.
    G&C Coplien —Lean Architecture trygve Account Example class 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
  • 84.
    G&C Coplien —Lean Architecture trygve Account Example context 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
  • 85.
    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
  • 86.
    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
  • 87.
    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
  • 88.
    G&C Coplien —Lean Architecture trygve Account Example context 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
  • 89.
    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
  • 90.
    G&C Coplien —Lean Architecture C++ Account Example Many thanks to Felix Petriconi for bringing this up-to-date for C++14! 55 56 20161017FooCafé.key - 28 October 2016
  • 91.
    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
  • 92.
    G&C Coplien —Lean Architecture Account Example: Currency 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; 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
  • 93.
    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
  • 94.
    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
  • 95.
    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
  • 96.
    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
  • 97.
    G&C Coplien —Lean Architecture Account Example: Currency 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 62 63 20161017FooCafé.key - 28 October 2016
  • 98.
    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
  • 99.
    G&C Coplien —Lean Architecture Account Example: Currency Currency &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
  • 100.
    G&C Coplien —Lean Architecture Account Example: Currency bool 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
  • 101.
    G&C Coplien —Lean Architecture Account Example: Currency Euro &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
  • 102.
    G&C Coplien —Lean Architecture Account Example: Currency std::string Euro::asString() const { std::ostringstream stream; stream << amount_; return stream.str(); } 67 68 20161017FooCafé.key - 28 October 2016
  • 103.
    G&C Coplien —Lean Architecture Account Example: Currency bool 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
  • 104.
    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
  • 105.
    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
  • 106.
    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
  • 107.
    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
  • 108.
    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
  • 109.
    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
  • 110.
    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
  • 111.
    G&C Coplien —Lean Architecture Account Example: SavingsAccount void 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
  • 112.
    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
  • 113.
    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
  • 114.
    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
  • 115.
    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
  • 116.
    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
  • 117.
    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
  • 118.
    G&C Coplien —Lean Architecture Account Example: Creditors GasCompany::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
  • 119.
    G&C Coplien —Lean Architecture Account Example: Context /* * Context.h * * Created by James Coplien on 1/14/09. Updated to C++14 7/12/2016. * Copyright ©2016 Gertrud & Cope. All rights reserved. */ #ifndef _CONTEXT_H #define _CONTEXT_H class Context { public: Context(); virtual ~Context(); public: static Context *currentContext_; private: Context *parentContext_; }; #endif 84 85 20161017FooCafé.key - 28 October 2016
  • 120.
    G&C Coplien —Lean Architecture Account Example: Context /* * Context.cpp * * Created by James Coplien on 1/14/09. Updated to C++14 7/12/2016. * Copyright ©2016 Gertrud & Cope. All rights reserved. */ #include "Context.h" Context *Context::currentContext_ = nullptr; Context::Context() { parentContext_ = currentContext_; currentContext_ = this; } Context::~Context() { currentContext_ = parentContext_; } 85 86 20161017FooCafé.key - 28 October 2016
  • 121.
    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
  • 122.
    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
  • 123.
    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
  • 124.
    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
  • 125.
    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
  • 126.
    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
  • 127.
    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
  • 128.
    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
  • 129.
    G&C Coplien —Lean Architecture Account Example: PayBills public: 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
  • 130.
    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
  • 131.
    G&C Coplien —Lean Architecture Account Example: PayBills void 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
  • 132.
    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
  • 133.
    G&C Coplien —Lean Architecture Account Example: Exceptions /* * MyExceptions.h * * Created by James Coplien on 9/2/08. Updated to C++14 7/12/16. * Copyright ©2016 Gertrud & Cope. All rights reserved. */ #ifndef _MYEXCEPTIONS_H #define _MYEXCEPTIONS_H #include <exception> class InsufficientFunds : public std::exception { public: InsufficientFunds(); }; #endif 98 99 20161017FooCafé.key - 28 October 2016
  • 134.
    G&C Coplien —Lean Architecture Account Example: Exceptions /* * MyExceptionsImplementation.cpp * * Created by James Coplien on 9/2/08. Updated to C++14 7/12/16. * Copyright ©2016 Gertrud & Cope. All rights reserved. */ #include "MyExceptions.h" InsufficientFunds::InsufficientFunds() { } 99 100 20161017FooCafé.key - 28 October 2016
  • 135.
    G&C Coplien —Lean Architecture Account Example: MyTime /* * MyTime.h * * Created by James Coplien on 9/2/08. Updated to C++14 7/12/16. * Copyright ©2016 Gertrud & Cope. All rights reserved. */ #ifndef _MYTIME_H #define _MYTIME_H #include <string> class MyTime { public: MyTime() = default; explicit MyTime(long long); explicit MyTime(const std::string& timeAsString); ~MyTime(); MyTime(const MyTime& t); MyTime& operator=(const MyTime &t); friend bool operator<(const MyTime &x, const MyTime &y); }; #endif 100 101 20161017FooCafé.key - 28 October 2016
  • 136.
    G&C Coplien —Lean Architecture Account Example: MyTime /* * MyTimeImplementation.cpp * * Created by James Coplien on 9/2/08. Updated to C++14 7/12/16. * Copyright ©2016 Gertrud & Cope. All rights reserved. */ #include "MyTime.h" MyTime::MyTime(long long) { } MyTime::MyTime(const std::string& timeAsString) { } MyTime::~MyTime() { } MyTime::MyTime(const MyTime &t) { } MyTime &MyTime::operator=(const MyTime &t) { return *this; } bool operator<(const MyTime &x, const MyTime &y) { return true; } 101 102 20161017FooCafé.key - 28 October 2016
  • 137.
    G&C Coplien —Lean Architecture Account Example: Globals /* * Globals.h * * Created by James Coplien on 9/2/08. Updated to C++14 7/12/16. * Copyright ©2016 Gertrud & Cope. All rights reserved. */ #ifndef _GLOBALS_H #define _GLOBALS_H #include "MyTime.h" extern void endTransaction(); extern void beginTransaction(); extern MyTime DateTime(); #endif 102 103 20161017FooCafé.key - 28 October 2016
  • 138.
    G&C Coplien —Lean Architecture Account Example: Globals /* * GlobalsImplementation.cpp * * Created by James Coplien on 9/2/08. Updated to C++14 7/12/16. * Copyright ©2016 Gertrud & Cope. All rights reserved. */ #include "Globals.h" #include "MyTime.h" #include <iostream> void endTransaction() { std::cout << "::endTransaction()" << std::endl; } void beginTransaction() { std::cout << "::beginTransaction()" << std::endl; } MyTime DateTime() { return MyTime(0); } 103 104 20161017FooCafé.key - 28 October 2016
  • 139.
    G&C Coplien —Lean Architecture Account Example: MoneyPort // // MoneyPort.h // DCI Money Transfer // // Created by James Coplien on 12/07/16. // Copyright © 2016 Gertrud & Cope. All rights reserved. // #ifndef MoneyPort_h #define MoneyPort_h #include "Context.h" class MoneyPort { // Common private utility functions template <typename T, typename U> auto SELF(U* u) { return static_cast<T*>(u); } template <typename T> auto RECIPIENT() { auto result = dynamic_cast<T*>(Context::currentContext_); if (result) return result->destinationAccount(); throw std::bad_cast(); // ("dynamic cast failed"); } 104 105 20161017FooCafé.key - 28 October 2016