Simple Programming/Design Tidbits
Banking application
Customer, Accounts, Transactions, ATM,
All transactions at an ATM
class AccountService {
List<Transaction> transactionsAt(int accountId, ATM atm) {
List<Transaction> transactionList = new List<Transaction>();
for (Transaction txn : transactions)
if (transaction.wasAtLocation(atm.getLocationId()))
transactionList.add(txn);
return transactionList;
}
}
class Transaction {
ATM atm;
boolean wasAtLocation(int locationId) {
return atm.getLocationId() == locationId;
}
}
All transactions at an ATMAll transactions at an ATM
class AccountService {
List<Transaction> transactionsAt(int accountId, ATM atm) {
List<Transaction> transactionList = new List<Transaction>();
for (Transaction txn : transactions)
if (transaction.wasAt(atm))if (transaction.wasAt(atm))
transactionList.add(txn);
return transactionList;
}
}
class Transaction {
ATM atm;
boolean wasAt(ATM atm) {boolean wasAt(ATM atm) {
return this.atm.equals(locationId);return this.atm.equals(locationId);
}
}
Pass object not its data
Encasulation can be broken across methods
class Customer {
static double eligibilityForHomeLoan = 500000;
static double eligibilityForPersonalLoan = 10000;
double salary;
boolean targetForHomeLoan() {
return salary > eligibilityForHomeLoan;
}
boolean targetForPersonalLoan() {
return salary > eligibilityForPersonalLoan;
}
}
Should target a customer for loan?
Should target a customer for loan?Should target a customer for loan?
class Customer {
Salary salary;Salary salary;
boolean targetForHomeLoan() {
return salary.isEligibleForHomeLoan();return salary.isEligibleForHomeLoan();
}
}
class Salary {class Salary {
double amount;double amount;
static double eligibilityForHomeLoan = 500000;static double eligibilityForHomeLoan = 500000;
Salary(double amount) {Salary(double amount) {
this.amount = amount;this.amount = amount;
}}
boolean isEligibleForLoan() {boolean isEligibleForLoan() {
return amount > eligibilityForHomeLoan.amount;return amount > eligibilityForHomeLoan.amount;
}}
}}
Avoid primitives in your domain
Primitives not only language but can be domain
primitives e.g. Money/Date/Currency
class Customer {
Set<Account> accounts;
Set<Account> getAccounts() {
return accounts;
}
}
class CustomerService {
void addAccount(Customer customer) {
Account account = new Account();
customer.getAccounts().add(account);
}
}
Open new account for a customer
class Customer {
Set<Account> accounts;
Account[] getAccounts() {Account[] getAccounts() {
return accounts.toArray();return accounts.toArray();
}}
void addNewAccount() {void addNewAccount() {
Account account = new Account();Account account = new Account();
accounts.add(account);accounts.add(account);
}}
}
class CustomerService {
void addAccount(Customer customer) {
customer.addNewAccount();customer.addNewAccount();
}
}
Open new account for a customerOpen new account for a customer
Collections are mutable, donot expose them
class Customer {
Set<Account> accounts;
Money balance() {
Money total = Money.Zero();
for (Account account : accounts) {
total += account.getBalance();
}
return total;
}
Money inactiveAccounts() {
for (Account account : accounts) {
if (account.isInactive())
inactiveAccounts.add(account);
}
}
}
Customer's accounts
class Customer {
Accounts accounts;Accounts accounts;
}
class Accountsclass Accounts {
Set<Account> accounts;Set<Account> accounts;
Money total = Money.Zero();
Money balance() {
for (Account account : accounts) {
total += account.getBalance();
}
return total;
}
Money inactiveAccounts() {
for (Account account : accounts) {
if (account.isInactive())
inactiveAccounts.add(account);
}
}
}
Customer's accounts
Collections are primitives
Create domain specific collections
class Account {
InterestPlan interestPlan;
Money bal;
Money applyInterest() {
switch (interestPlan) {
case Simple: interest = new SICalc().calculate(bal);
case Compound: interest = new CICalc().calculate(bal);
......
}
bal += interest;
}
}
enum InterestPlan {
Simple, Compound, InflationAdjusted,
DurationDependent
}
Apply interest
class Account {
InterestPlan interestPlan;
Money bal;
static Map calculators = {static Map calculators = {
Simple => new SICalc(),Simple => new SICalc(),
Compound => new CICalc();Compound => new CICalc();
..........
}}
Money applyInterest() {
interest = calculators[interestPlan].calculate();interest = calculators[interestPlan].calculate();
}
}
Apply interestApply interest
Externalize if conditions
Can use for functions as value in map as well
class Account {
State state;
boolean transactionsAllowed() {
return state == State.Approved || state == State.Active;
}
boolean onlineTransactionAllowed() {
return state == State.Active || state == State.Locked;
}
}
enum State {
PendingApproval, Approved, Locked, Active, Closed
}
Account Security
class Account {
State state;
List transactionsAllowed = {State.Approved, State.Active};List transactionsAllowed = {State.Approved, State.Active};
List onlineTransactionsAllowed = {State.Locked, State.Active};List onlineTransactionsAllowed = {State.Locked, State.Active};
boolean transactionsAllowed() {
return transactionsAllowed.contains(state)transactionsAllowed.contains(state);
}
boolean onlineTransactionAllowed() {
return onlineTransactionsAllowed.contains(state)onlineTransactionsAllowed.contains(state);
}
}
enum State {
PendingApproval, Approved, Locked, Active, Closed
}
Account SecurityAccount Security
void monthlyReport() {
TransactionRepository repo = new TransactionRepository(...);
var list = repo.getBiggerTransactionsNotTransferredToSelf();
......
}
class TransactionRepository {
Transactions getBiggerTransactionsNotTransferredToSelf() {
Transactions transactions = loadTransactions(customerId);
....logic...
}
}
Suspicious Transactions
void monthlyReport() {
TransactionRepository repo = new TransactionRepository(...);
var list = repo.suspiciousTransactions()repo.suspiciousTransactions();
......
}
class TransactionRepository {
Transactions suspiciousTransactions()suspiciousTransactions() {
Transactions transactions = loadTransactions(customerId);
....logic...
}
}
Suspicious TransactionsSuspicious Transactions
Tell what not how
Keep implementation encapsulation
Seen more when doing TDD
class Customer {
String name;
Date dateOfBirth;
Accounts accounts;
Money salaryForLoanCalculations;
boolean targetForHomeLoan() {
return salaryForLoanCalculations.isEligibleForHomeLoan();
}
boolean targetForPersonalLoan() {
return salaryForLoanCalculations.isEligibileForPersLoan();
}
}
Customer
class Customer {
String name;
Date dateOfBirth;
Accounts accounts;
Money salary;Money salary;
boolean targetForHomeLoan() {
return salary.isEligibleForHomeLoan();return salary.isEligibleForHomeLoan();
}
boolean targetForPersonalLoan() {
return salary.isEligibileForPersonalLoan();return salary.isEligibileForPersonalLoan();
}
}
CustomerCustomer
Store what not what for
Seen more when doing TDD
class Customer {
String name;
Accounts accounts;
Money salary;
boolean isLoyal() {
if (salary > 20000 && accounts.balance() > 100000) {
return true;
}
return false;
}
}
Is Loyal Customer?
class Customer {
String name;
Accounts accounts;
Money salary;
boolean isLoyal() {
return salary > 20000 && accounts.balance() > 100000);return salary > 20000 && accounts.balance() > 100000);
}
}
Is Loyal Customer?Is Loyal Customer?
class Customer {
Accounts accounts;
boolean isLoyal() {
....
}
void issueCard(String accountNumber) {
Account account = accounts.get(accountNumber);
if (isLoyal() == true)
account.issuePlatinum();
else
account.issueOfLastType();
}
}
Issue platinum card?
class Customer {
Accounts accounts;
boolean isLoyal() {
....
}
void issueCard(String accountNumber) {
Account account = accounts.get(accountNumber);
if (isLoyal())if (isLoyal())
account.issuePlatinum();
else
account.issueOfLastType();
}
}
Issue platinum card?Issue platinum card?
class Customer {
String name;
Date dateOfBirth;
public void validateForNew() throws ValidationException {
ValidationException exception = new ValidationException();
if (name == null || name.isEmpty())
exception.add(“Name not specified”);
if (dateOfBirth == null)
exception.add(“Date of birth not specified”);
else if (dateOfBirth.isBefore(1990))
exception.add(“below 20 years are not eligible”);
if (exception.hasErrors()) {
throw exception;
}
}
}
New Customer
class Customer {
String name;
Date dateOfBirth;
public ValidationError validateForNew() {public ValidationError validateForNew() {
ValidationError error = new ValidationError();ValidationError error = new ValidationError();
if (name == null || name.isEmpty())
error.add(“Name not specified”);
if (dateOfBirth == null)
error.add(“Date of birth not specified”);
else if (dateOfBirth.isBefore(1990))
error.add(“below 20 years are not eligible”);
return error;return error;
}
}
New CustomerNew Customer
Error during validation is not exceptional scenario
public class Customer {
public void gotMarried() {
title = "Mrs";
}
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
Customer customer = (Customer) o;
if (!firstName.equals(customer.firstName)) return false;
if (!lastName.equals(customer.lastName)) return false;
if (!title.equals(customer.title)) return false;
return true;
}
public int hashCode() {
int result = firstName.hashCode();
result = 31 * result + lastName.hashCode();
result = 31 * result + title.hashCode();
return result;
}
}
Customer got married
public void test() {
Customer customer = new Customer("foo", "bar", "Miss");
Map map = new HashMap();
map.put(customer, "rich");
assertTrue(map.get(customer) != null);
customer.gotMarried();
assertTrue(map.get(customer) != null); <-- FailsassertTrue(map.get(customer) != null); <-- Fails
}
Customer got married
Don't use mutable fields for hashcode
Account account = AccountRepository.load(1);
....
cleanUp(account);
public static void cleanUp(Account account) {
if (null != account) {
deleteAccount(account, null);
account = null;
}
}
Get rid of large object from memory
Objects references are always passed by value
Thats why C# has explicit pass by ref (not
recommending essentially)
Class Customer {
Name name;
Date dateOfBirth;
Accounts accounts;
Name getName() {
if (name == null) name = new Name();
return name;
}
}
Get customer's name
Do not change data in getter, it deceives
ToString() is object's user interface
Reserve it and use for debugging only
public class Customer {
List<Account> accounts = new ArrayList<Account>();
public void isAccountInactive(String accountNumber, int
maxInactivityAllowed) {
int i = accounts.indexOf(new Account(accountNumber));
Account account = accounts.get(i);
inactive(account, maxInactivityAllowed);
}
private static boolean inactive(Account account, int
maxInactivityAllowed) {
return account.getLastActivity().within(maxInactivityAllowed);
}
}
What can we do here?
public class Customer {
List<Account> accounts = new ArrayList<Account>();
public void isAccountInactive(String accountNumber, int
maxInactivityAllowed) {
int i = accounts.indexOf(new Account(accountNumber));
Account account = accounts.get(i);
account.inactive(maxInactivityAllowed);account.inactive(maxInactivityAllowed);
}
}
Look for staticsLook for statics
Look out for static methods and hints (by IDE) to
make methods static
Use the suggestion by not accepting it
class Account {
Transactions transactions;
Customer customer;
boolean suggestLinkingOfAccounts() {
if (transactions != null) {
Transactions customerXAs = transactions.with(customer);
return customerXAs.totalAmount() > 10000;
}
return false;
}
}
Suggest linking of accounts?
class Account {
Transactions transactions;
Customer customer;
boolean suggestLinkingOfAccounts() {
if (transactions != null) {
return transactions.withAndInExcessOf(customer, 10000);return transactions.withAndInExcessOf(customer, 10000);
}
return false;
}
}
Suggest linking of accounts?Suggest linking of accounts?
Tell don't ask at second level
(unless for performance reasons)
class Customer {
Transactions todaysTransactions;
Accounts accounts;
public Customer(Accounts account, Date date) {
this.accounts = accounts;
todaysTransactions = accounts.TransactionDoneOn(date);
}
Transactions todaysTransaction() {
Return todaysTransactions;
}
}
Today's transactions
class Customer {
Accounts accounts;
public Customer(Accounts account)public Customer(Accounts account) {
this.accounts = accounts;
}
Transactions allTransactionsOn(Date date) {Transactions allTransactionsOn(Date date) {
Return accounts.TransactionDoneOn(date);Return accounts.TransactionDoneOn(date);
}}
}
Today's transactions
Model state based on domain
State shouldn't be based on object's usage,
methods are for that
Suggestions might not always apply

Simple design/programming nuggets

  • 1.
    Simple Programming/Design Tidbits Bankingapplication Customer, Accounts, Transactions, ATM,
  • 2.
    All transactions atan ATM class AccountService { List<Transaction> transactionsAt(int accountId, ATM atm) { List<Transaction> transactionList = new List<Transaction>(); for (Transaction txn : transactions) if (transaction.wasAtLocation(atm.getLocationId())) transactionList.add(txn); return transactionList; } } class Transaction { ATM atm; boolean wasAtLocation(int locationId) { return atm.getLocationId() == locationId; } }
  • 3.
    All transactions atan ATMAll transactions at an ATM class AccountService { List<Transaction> transactionsAt(int accountId, ATM atm) { List<Transaction> transactionList = new List<Transaction>(); for (Transaction txn : transactions) if (transaction.wasAt(atm))if (transaction.wasAt(atm)) transactionList.add(txn); return transactionList; } } class Transaction { ATM atm; boolean wasAt(ATM atm) {boolean wasAt(ATM atm) { return this.atm.equals(locationId);return this.atm.equals(locationId); } }
  • 4.
    Pass object notits data Encasulation can be broken across methods
  • 5.
    class Customer { staticdouble eligibilityForHomeLoan = 500000; static double eligibilityForPersonalLoan = 10000; double salary; boolean targetForHomeLoan() { return salary > eligibilityForHomeLoan; } boolean targetForPersonalLoan() { return salary > eligibilityForPersonalLoan; } } Should target a customer for loan?
  • 6.
    Should target acustomer for loan?Should target a customer for loan? class Customer { Salary salary;Salary salary; boolean targetForHomeLoan() { return salary.isEligibleForHomeLoan();return salary.isEligibleForHomeLoan(); } } class Salary {class Salary { double amount;double amount; static double eligibilityForHomeLoan = 500000;static double eligibilityForHomeLoan = 500000; Salary(double amount) {Salary(double amount) { this.amount = amount;this.amount = amount; }} boolean isEligibleForLoan() {boolean isEligibleForLoan() { return amount > eligibilityForHomeLoan.amount;return amount > eligibilityForHomeLoan.amount; }} }}
  • 7.
    Avoid primitives inyour domain Primitives not only language but can be domain primitives e.g. Money/Date/Currency
  • 8.
    class Customer { Set<Account>accounts; Set<Account> getAccounts() { return accounts; } } class CustomerService { void addAccount(Customer customer) { Account account = new Account(); customer.getAccounts().add(account); } } Open new account for a customer
  • 9.
    class Customer { Set<Account>accounts; Account[] getAccounts() {Account[] getAccounts() { return accounts.toArray();return accounts.toArray(); }} void addNewAccount() {void addNewAccount() { Account account = new Account();Account account = new Account(); accounts.add(account);accounts.add(account); }} } class CustomerService { void addAccount(Customer customer) { customer.addNewAccount();customer.addNewAccount(); } } Open new account for a customerOpen new account for a customer
  • 10.
    Collections are mutable,donot expose them
  • 11.
    class Customer { Set<Account>accounts; Money balance() { Money total = Money.Zero(); for (Account account : accounts) { total += account.getBalance(); } return total; } Money inactiveAccounts() { for (Account account : accounts) { if (account.isInactive()) inactiveAccounts.add(account); } } } Customer's accounts
  • 12.
    class Customer { Accountsaccounts;Accounts accounts; } class Accountsclass Accounts { Set<Account> accounts;Set<Account> accounts; Money total = Money.Zero(); Money balance() { for (Account account : accounts) { total += account.getBalance(); } return total; } Money inactiveAccounts() { for (Account account : accounts) { if (account.isInactive()) inactiveAccounts.add(account); } } } Customer's accounts
  • 13.
    Collections are primitives Createdomain specific collections
  • 14.
    class Account { InterestPlaninterestPlan; Money bal; Money applyInterest() { switch (interestPlan) { case Simple: interest = new SICalc().calculate(bal); case Compound: interest = new CICalc().calculate(bal); ...... } bal += interest; } } enum InterestPlan { Simple, Compound, InflationAdjusted, DurationDependent } Apply interest
  • 15.
    class Account { InterestPlaninterestPlan; Money bal; static Map calculators = {static Map calculators = { Simple => new SICalc(),Simple => new SICalc(), Compound => new CICalc();Compound => new CICalc(); .......... }} Money applyInterest() { interest = calculators[interestPlan].calculate();interest = calculators[interestPlan].calculate(); } } Apply interestApply interest
  • 16.
    Externalize if conditions Canuse for functions as value in map as well
  • 17.
    class Account { Statestate; boolean transactionsAllowed() { return state == State.Approved || state == State.Active; } boolean onlineTransactionAllowed() { return state == State.Active || state == State.Locked; } } enum State { PendingApproval, Approved, Locked, Active, Closed } Account Security
  • 18.
    class Account { Statestate; List transactionsAllowed = {State.Approved, State.Active};List transactionsAllowed = {State.Approved, State.Active}; List onlineTransactionsAllowed = {State.Locked, State.Active};List onlineTransactionsAllowed = {State.Locked, State.Active}; boolean transactionsAllowed() { return transactionsAllowed.contains(state)transactionsAllowed.contains(state); } boolean onlineTransactionAllowed() { return onlineTransactionsAllowed.contains(state)onlineTransactionsAllowed.contains(state); } } enum State { PendingApproval, Approved, Locked, Active, Closed } Account SecurityAccount Security
  • 19.
    void monthlyReport() { TransactionRepositoryrepo = new TransactionRepository(...); var list = repo.getBiggerTransactionsNotTransferredToSelf(); ...... } class TransactionRepository { Transactions getBiggerTransactionsNotTransferredToSelf() { Transactions transactions = loadTransactions(customerId); ....logic... } } Suspicious Transactions
  • 20.
    void monthlyReport() { TransactionRepositoryrepo = new TransactionRepository(...); var list = repo.suspiciousTransactions()repo.suspiciousTransactions(); ...... } class TransactionRepository { Transactions suspiciousTransactions()suspiciousTransactions() { Transactions transactions = loadTransactions(customerId); ....logic... } } Suspicious TransactionsSuspicious Transactions
  • 21.
    Tell what nothow Keep implementation encapsulation Seen more when doing TDD
  • 22.
    class Customer { Stringname; Date dateOfBirth; Accounts accounts; Money salaryForLoanCalculations; boolean targetForHomeLoan() { return salaryForLoanCalculations.isEligibleForHomeLoan(); } boolean targetForPersonalLoan() { return salaryForLoanCalculations.isEligibileForPersLoan(); } } Customer
  • 23.
    class Customer { Stringname; Date dateOfBirth; Accounts accounts; Money salary;Money salary; boolean targetForHomeLoan() { return salary.isEligibleForHomeLoan();return salary.isEligibleForHomeLoan(); } boolean targetForPersonalLoan() { return salary.isEligibileForPersonalLoan();return salary.isEligibileForPersonalLoan(); } } CustomerCustomer
  • 24.
    Store what notwhat for Seen more when doing TDD
  • 25.
    class Customer { Stringname; Accounts accounts; Money salary; boolean isLoyal() { if (salary > 20000 && accounts.balance() > 100000) { return true; } return false; } } Is Loyal Customer?
  • 26.
    class Customer { Stringname; Accounts accounts; Money salary; boolean isLoyal() { return salary > 20000 && accounts.balance() > 100000);return salary > 20000 && accounts.balance() > 100000); } } Is Loyal Customer?Is Loyal Customer?
  • 27.
    class Customer { Accountsaccounts; boolean isLoyal() { .... } void issueCard(String accountNumber) { Account account = accounts.get(accountNumber); if (isLoyal() == true) account.issuePlatinum(); else account.issueOfLastType(); } } Issue platinum card?
  • 28.
    class Customer { Accountsaccounts; boolean isLoyal() { .... } void issueCard(String accountNumber) { Account account = accounts.get(accountNumber); if (isLoyal())if (isLoyal()) account.issuePlatinum(); else account.issueOfLastType(); } } Issue platinum card?Issue platinum card?
  • 29.
    class Customer { Stringname; Date dateOfBirth; public void validateForNew() throws ValidationException { ValidationException exception = new ValidationException(); if (name == null || name.isEmpty()) exception.add(“Name not specified”); if (dateOfBirth == null) exception.add(“Date of birth not specified”); else if (dateOfBirth.isBefore(1990)) exception.add(“below 20 years are not eligible”); if (exception.hasErrors()) { throw exception; } } } New Customer
  • 30.
    class Customer { Stringname; Date dateOfBirth; public ValidationError validateForNew() {public ValidationError validateForNew() { ValidationError error = new ValidationError();ValidationError error = new ValidationError(); if (name == null || name.isEmpty()) error.add(“Name not specified”); if (dateOfBirth == null) error.add(“Date of birth not specified”); else if (dateOfBirth.isBefore(1990)) error.add(“below 20 years are not eligible”); return error;return error; } } New CustomerNew Customer
  • 31.
    Error during validationis not exceptional scenario
  • 32.
    public class Customer{ public void gotMarried() { title = "Mrs"; } public boolean equals(Object o) { if (this == o) return true; if (o == null || getClass() != o.getClass()) return false; Customer customer = (Customer) o; if (!firstName.equals(customer.firstName)) return false; if (!lastName.equals(customer.lastName)) return false; if (!title.equals(customer.title)) return false; return true; } public int hashCode() { int result = firstName.hashCode(); result = 31 * result + lastName.hashCode(); result = 31 * result + title.hashCode(); return result; } } Customer got married
  • 33.
    public void test(){ Customer customer = new Customer("foo", "bar", "Miss"); Map map = new HashMap(); map.put(customer, "rich"); assertTrue(map.get(customer) != null); customer.gotMarried(); assertTrue(map.get(customer) != null); <-- FailsassertTrue(map.get(customer) != null); <-- Fails } Customer got married
  • 34.
    Don't use mutablefields for hashcode
  • 35.
    Account account =AccountRepository.load(1); .... cleanUp(account); public static void cleanUp(Account account) { if (null != account) { deleteAccount(account, null); account = null; } } Get rid of large object from memory
  • 36.
    Objects references arealways passed by value Thats why C# has explicit pass by ref (not recommending essentially)
  • 37.
    Class Customer { Namename; Date dateOfBirth; Accounts accounts; Name getName() { if (name == null) name = new Name(); return name; } } Get customer's name
  • 38.
    Do not changedata in getter, it deceives
  • 39.
    ToString() is object'suser interface Reserve it and use for debugging only
  • 40.
    public class Customer{ List<Account> accounts = new ArrayList<Account>(); public void isAccountInactive(String accountNumber, int maxInactivityAllowed) { int i = accounts.indexOf(new Account(accountNumber)); Account account = accounts.get(i); inactive(account, maxInactivityAllowed); } private static boolean inactive(Account account, int maxInactivityAllowed) { return account.getLastActivity().within(maxInactivityAllowed); } } What can we do here?
  • 41.
    public class Customer{ List<Account> accounts = new ArrayList<Account>(); public void isAccountInactive(String accountNumber, int maxInactivityAllowed) { int i = accounts.indexOf(new Account(accountNumber)); Account account = accounts.get(i); account.inactive(maxInactivityAllowed);account.inactive(maxInactivityAllowed); } } Look for staticsLook for statics
  • 42.
    Look out forstatic methods and hints (by IDE) to make methods static Use the suggestion by not accepting it
  • 43.
    class Account { Transactionstransactions; Customer customer; boolean suggestLinkingOfAccounts() { if (transactions != null) { Transactions customerXAs = transactions.with(customer); return customerXAs.totalAmount() > 10000; } return false; } } Suggest linking of accounts?
  • 44.
    class Account { Transactionstransactions; Customer customer; boolean suggestLinkingOfAccounts() { if (transactions != null) { return transactions.withAndInExcessOf(customer, 10000);return transactions.withAndInExcessOf(customer, 10000); } return false; } } Suggest linking of accounts?Suggest linking of accounts?
  • 45.
    Tell don't askat second level (unless for performance reasons)
  • 46.
    class Customer { TransactionstodaysTransactions; Accounts accounts; public Customer(Accounts account, Date date) { this.accounts = accounts; todaysTransactions = accounts.TransactionDoneOn(date); } Transactions todaysTransaction() { Return todaysTransactions; } } Today's transactions
  • 47.
    class Customer { Accountsaccounts; public Customer(Accounts account)public Customer(Accounts account) { this.accounts = accounts; } Transactions allTransactionsOn(Date date) {Transactions allTransactionsOn(Date date) { Return accounts.TransactionDoneOn(date);Return accounts.TransactionDoneOn(date); }} } Today's transactions
  • 48.
    Model state basedon domain State shouldn't be based on object's usage, methods are for that
  • 49.