104
A taste of trygve Jim Coplien Former C++ Programmer & Author Gertrud & Cope Helsingør, Danmark jcoplien@gmail

James Coplien - Trygve - October 17, 2016

Embed Size (px)

Citation preview

Page 1: James Coplien - Trygve - October 17, 2016

A taste of trygveJim Coplien

Former C++ Programmer & AuthorGertrud & Cope

Helsingør, Danmarkjcoplien@gmail

Page 2: James Coplien - Trygve - October 17, 2016

Pointers…

• DCI documentation & downloads:• http://fulloo.info

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

Page 3: James Coplien - Trygve - October 17, 2016

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

– Jerry Weinberg

Page 4: James Coplien - Trygve - October 17, 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

Page 5: James Coplien - Trygve - October 17, 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

Page 6: James Coplien - Trygve - October 17, 2016

G&C

Page 7: James Coplien - Trygve - October 17, 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

Page 8: James Coplien - Trygve - October 17, 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 (applicati

on)

Page 9: James Coplien - Trygve - October 17, 2016

Class (domain) structure

trygve Programs as Models

Use case structure

Roles (applicati

on)

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) { … } … }}

Page 10: James Coplien - Trygve - October 17, 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.“

Page 11: James Coplien - Trygve - October 17, 2016

But couldn’t you just…

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

Use aspectsThe joinpoints are still dictated by the class structure

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

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

Use multi-paradigm designUndesired decoupling and lack of cohesion

Page 12: James Coplien - Trygve - October 17, 2016

G&C

Action Between Objects

View

The programmer must consider the system:action

between objects

ModelView

Controller

Skip

Page 13: James Coplien - Trygve - October 17, 2016

G&C

Action Between Objects

View

Programmers’ objects interactwith objects previously conceived by other programmers

Page 14: James Coplien - Trygve - October 17, 2016

G&C

System Operations

While the specific interactions are emergent, the

form of the interactions is

designed.

This form lives within no single object or class.

Objects are an overly small

concept, conceived for the revenge of the nerds, each

owning their individual classes

Page 15: James Coplien - Trygve - October 17, 2016

G&C

System Operations

context TripReservation

}

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

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

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

Page 16: James Coplien - Trygve - October 17, 2016

Teaching Actors their Scripts

context TripReservation { role JourneyStart { … } role JourneyEnd { … } public TripReservation(Object jStart, Object jEnd){ JourneyStart = jStart; JourneyEnd = jEnd }}

Page 17: James Coplien - Trygve - October 17, 2016

Contextualized Polymorphism

foo

foofoo

foo

foo

?

bar

bar

barbar

bar

?

sna

sna

snasna

sna

?

“Just trust the objects to do

the right thing and everything

will be fine.” — Smalltalk

“You believe in things you don’t understand, you may suffer.”

— Stevie Wonder

Where is the use case?

Where is the use case?

Skip

Page 18: James Coplien - Trygve - October 17, 2016

Contextualized Polymorphism

go

Roles: A new concept

Context: Another

new concept

Page 19: James Coplien - Trygve - October 17, 2016

Contextualized Polymorphism

bar sna

go

Data

Cont

ext

Inte

ract

ion

System Operation

s

Page 20: James Coplien - Trygve - October 17, 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

Page 21: James Coplien - Trygve - October 17, 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-orientedProgramming

Object-OrientedProgramming

Perl

awk

Page 22: James Coplien - Trygve - October 17, 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

Page 23: James Coplien - Trygve - October 17, 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

Page 24: James Coplien - Trygve - October 17, 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)}

Page 25: James Coplien - Trygve - October 17, 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

Page 26: James Coplien - Trygve - October 17, 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

Page 27: James Coplien - Trygve - October 17, 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

Page 28: James Coplien - Trygve - October 17, 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

Page 29: James Coplien - Trygve - October 17, 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

Page 30: James Coplien - Trygve - October 17, 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

Page 31: James Coplien - Trygve - October 17, 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

Page 32: James Coplien - Trygve - October 17, 2016
Page 33: James Coplien - Trygve - October 17, 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)

Page 34: James Coplien - Trygve - October 17, 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 }

Page 35: James Coplien - Trygve - October 17, 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") } } } . . . .

Page 36: James Coplien - Trygve - October 17, 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) }

Page 37: James Coplien - Trygve - October 17, 2016

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

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

new ArrayDupTest().test()

Page 38: James Coplien - Trygve - October 17, 2016

Most class-oriented features have been

removed• protected

• super

• Class::

• ABCs• static (though it exists internally)

Page 39: James Coplien - Trygve - October 17, 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

Page 40: James Coplien - Trygve - October 17, 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

Page 41: James Coplien - Trygve - October 17, 2016
Page 42: James Coplien - Trygve - October 17, 2016

G&C Coplien — Lean Architecture

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

Page 43: James Coplien - Trygve - October 17, 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 "€"; }

Page 44: James Coplien - Trygve - October 17, 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_}

Page 45: James Coplien - Trygve - October 17, 2016

G&C Coplien — Lean Architecture

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

private Currency availableBalance_}

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

Page 46: James Coplien - Trygve - October 17, 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}

Page 47: James Coplien - Trygve - October 17, 2016

G&C Coplien — Lean Architecture

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

private Currency availableBalance_;}

Page 48: James Coplien - Trygve - October 17, 2016

G&C Coplien — Lean Architecture

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

private Account account_}

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

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

Page 49: James Coplien - Trygve - October 17, 2016

G&C Coplien — Lean Architecture

trygve Account Examplecontext TransferMoneyContext{ // Roles

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

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

Page 50: James Coplien - Trygve - October 17, 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) }

Page 51: James Coplien - Trygve - October 17, 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() }

Page 52: James Coplien - Trygve - October 17, 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) }}

Page 53: James Coplien - Trygve - October 17, 2016

G&C Coplien — Lean Architecture

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

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

Page 54: James Coplien - Trygve - October 17, 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()}

Page 55: James Coplien - Trygve - October 17, 2016

G&C Coplien — Lean Architecture

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

Page 56: James Coplien - Trygve - October 17, 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_;};

Page 57: James Coplien - Trygve - October 17, 2016

G&C Coplien — Lean Architecture

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

Page 58: James Coplien - Trygve - October 17, 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

Page 59: James Coplien - Trygve - October 17, 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;

Page 60: James Coplien - Trygve - October 17, 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;

Page 61: James Coplien - Trygve - October 17, 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_;};

Page 62: James Coplien - Trygve - October 17, 2016

G&C Coplien — Lean Architecture

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

#endif

Page 63: James Coplien - Trygve - October 17, 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;}

Page 64: James Coplien - Trygve - October 17, 2016

G&C Coplien — Lean Architecture

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

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

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

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

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

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

Page 65: James Coplien - Trygve - October 17, 2016

G&C Coplien — Lean Architecture

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

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

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

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

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

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

Page 66: James Coplien - Trygve - October 17, 2016

G&C Coplien — Lean Architecture

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

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

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

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

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

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

Page 67: James Coplien - Trygve - October 17, 2016

G&C Coplien — Lean Architecture

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

Page 68: James Coplien - Trygve - October 17, 2016

G&C Coplien — Lean Architecture

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

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

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

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

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

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

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

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

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_;}

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

Page 69: James Coplien - Trygve - October 17, 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

Page 70: James Coplien - Trygve - October 17, 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;}

Page 71: James Coplien - Trygve - October 17, 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

Page 72: James Coplien - Trygve - October 17, 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;}

Page 73: James Coplien - Trygve - October 17, 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

Page 74: James Coplien - Trygve - October 17, 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

Page 75: James Coplien - Trygve - October 17, 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_;}

Page 76: James Coplien - Trygve - October 17, 2016

G&C Coplien — Lean Architecture

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

const unsigned MAX_BUFFER_SIZE = 256;

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

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

Page 77: James Coplien - Trygve - October 17, 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

Page 78: James Coplien - Trygve - October 17, 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;}

Page 79: James Coplien - Trygve - October 17, 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

Page 80: James Coplien - Trygve - October 17, 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_;};

Page 81: James Coplien - Trygve - October 17, 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

Page 82: James Coplien - Trygve - October 17, 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);}

Page 83: James Coplien - Trygve - October 17, 2016

G&C Coplien — Lean Architecture

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

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

Page 84: James Coplien - Trygve - October 17, 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

Page 85: James Coplien - Trygve - October 17, 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_;}

Page 86: James Coplien - Trygve - October 17, 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;

Page 87: James Coplien - Trygve - October 17, 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

Page 88: James Coplien - Trygve - October 17, 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

Page 89: James Coplien - Trygve - October 17, 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

Page 90: James Coplien - Trygve - October 17, 2016

G&C Coplien — Lean Architecture

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

#endif

Account Example: Transfer Money

Page 91: James Coplien - Trygve - October 17, 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

Page 92: James Coplien - Trygve - October 17, 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

Page 93: James Coplien - Trygve - October 17, 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(); }

Page 94: James Coplien - Trygve - October 17, 2016

G&C Coplien — Lean Architecture

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

#endif

Page 95: James Coplien - Trygve - October 17, 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;}

Page 96: James Coplien - Trygve - October 17, 2016

G&C Coplien — Lean Architecture

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

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

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

Page 97: James Coplien - Trygve - October 17, 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;}

Page 98: James Coplien - Trygve - October 17, 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

Page 99: James Coplien - Trygve - October 17, 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(){}

Page 100: James Coplien - Trygve - October 17, 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

Page 101: James Coplien - Trygve - October 17, 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; }

Page 102: James Coplien - Trygve - October 17, 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

Page 103: James Coplien - Trygve - October 17, 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);}

Page 104: James Coplien - Trygve - October 17, 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"); }