Improving Your Application’s Design by Using Real Objects€¦ · Chris Richardson: Improving...
Transcript of Improving Your Application’s Design by Using Real Objects€¦ · Chris Richardson: Improving...
Slide 1
© Copyright 2007, Chris Richardson
Chris Richardson: Improving Your Application’s Design by Using Real Objects
Colorado Software Summit: October 21 – 26, 2007
Improving Your Application’sDesign by Using Real Objects
Chris RichardsonAuthor of POJOs in Action
Chris Richardson Consulting, Inc
http://www.chrisrichardson.net
© Copyright 2007, Chris Richardson
Chris Richardson: Improving Your Application’s Design by Using Real Objects Slide 2
Colorado Software Summit: October 21 – 26, 2007
About ChrisGrew up in EnglandLive in Oakland, CAOver twenty years ofsoftware developmentexperience
Building object-orientedsoftware since 1986Using Java since 1996Using J2EE since 1999
Author of POJOs in ActionSpeaker at JavaOne,JavaPolis, NFJS, JUGs, ….Chair of the eBIG Java SIGin Oakland (www.ebig.org)Run a consulting andtraining company that helpsorganizations build bettersoftware faster
© Copyright 2007, Chris Richardson
Chris Richardson: Improving Your Application’s Design by Using Real Objects Slide 3
Colorado Software Summit: October 21 – 26, 2007
Overall presentation goal
Learn how to improve applicationdesign with truly object-oriented
business logic
© Copyright 2007, Chris Richardson
Chris Richardson: Improving Your Application’s Design by Using Real Objects Slide 4
Colorado Software Summit: October 21 – 26, 2007
Agenda
Where are the real objects?
Overview of the Domain Model pattern
Domain model building blocks
Role of frameworks
Common code smells
Refactoring existing code
Obstacles to OO
© Copyright 2007, Chris Richardson
Chris Richardson: Improving Your Application’s Design by Using Real Objects Slide 5
Colorado Software Summit: October 21 – 26, 2007
Designing business logicSome enterprise frameworks (e.g.Spring) promote good design practices:
Dependency injection for loose couplingAOP for handling cross cutting concerns
But you must decide how to structureyour business logic:
Domain Model pattern – object-orientedTransaction Script pattern – procedural
Choice of pattern impacts ease of:Development, testing, maintainability, …
© Copyright 2007, Chris Richardson
Chris Richardson: Improving Your Application’s Design by Using Real Objects Slide 6
Colorado Software Summit: October 21 – 26, 2007
Lots of procedural Java code
Java is an object-oriented language
AND
Object-oriented design is a better way to tacklecomplexity
YET
Many complex enterprise Java applications are writtenin a procedural style
© Copyright 2007, Chris Richardson
Chris Richardson: Improving Your Application’s Design by Using Real Objects Slide 7
Colorado Software Summit: October 21 – 26, 2007
Example banking application
© Copyright 2007, Chris Richardson
Chris Richardson: Improving Your Application’s Design by Using Real Objects Slide 8
Colorado Software Summit: October 21 – 26, 2007
Example procedural design
BankingTransaction transfer (fromAccountId , toAccountId , amount )
MoneyTransferService
Account findAccount (accountId )
AccountRepository
txnId
date
BankingTransaction
addTransaction ()
BankingTransactionRepository
accountIdbalanceoverdraftType
Account
State
Behavior
Web Tier
Business Tier Transaction
script
An anemic
domain model
Missing classes
for key concepts
© Copyright 2007, Chris Richardson
Chris Richardson: Improving Your Application’s Design by Using Real Objects Slide 9
Colorado Software Summit: October 21 – 26, 2007
Example procedural codepublic class MoneyTransferServiceProceduralImpl implements MoneyTransferService {
public BankingTransaction transfer(String fromAccountId, String toAccountId, double amount) throws MoneyTransferException { Account fromAccount = accountDAO.findAccount(fromAccountId); Account toAccount = accountDAO.findAccount(toAccountId); assert amount > 0; double newBalance = fromAccount.getBalance() - amount; switch (fromAccount.getOverdraftPolicy()) { case Account.NEVER: if (newBalance < 0) throw new MoneyTransferException("In sufficient funds"); break; case Account.ALLOWED: Calendar then = Calendar.getInstance(); then.setTime(fromAccount.getDateOpened()); Calendar now = Calendar.getInstance();
double yearsOpened = now.get(Calendar.YEAR) - then.get(Calendar.YEAR); int monthsOpened = now.get(Calendar.MONTH) - then.get(Calendar.MONTH); if (monthsOpened < 0) { yearsOpened--; monthsOpened += 12; } yearsOpened = yearsOpened + (monthsOpened / 12.0); if (yearsOpened < fromAccount.getRequiredYearsOpen() || newBalance < fromAccount.getLimit()) throw new MoneyTransferException("Limit exceeded"); break; default: throw new MoneyTransferException("Unknown overdraft type: " + fromAccount.getOverdraftPolicy());
} fromAccount.setBalance(newBalance); toAccount.setBalance(toAccount.getBalance() + amount); TransferTransaction txn = new TransferTransaction(fromAccount, toAccount, amount, new Date()); bankingTransactionDAO.addTransaction(txn); return txn; }
public class Account {
public static final int NEVER = 1; public static final int ALLOWED = 2;
private int id;private double balance;private int overdraftPolicy;private String accountId;private Date dateOpened;private double requiredYearsOpen;private double limit;
Account() {}
public Account(String accountId, double balance, intoverdraftPolicy, Date dateOpened, double requiredYearsOpen,double limit) {….. }
public int getId() {return id;}
public String getAccountId() {return accountId;}
public void setBalance(double balance) { this.balance = balance; }
public double getBalance() { return balance; }
public int getOverdraftPolicy() { return overdraftPolicy; }
public Date getDateOpened() { return dateOpened; }
public double getRequiredYearsOpen() { return requiredYearsOpen; }
public double getLimit() {return limit; }}
© Copyright 2007, Chris Richardson
Chris Richardson: Improving Your Application’s Design by Using Real Objects Slide 10
Colorado Software Summit: October 21 – 26, 2007
A seductive programming style
Implementing new functionality is easy
Add a new transaction script
Add code to a new transaction script
No need to do any real design, e.g.
Create new classes
Determine responsibilities
© Copyright 2007, Chris Richardson
Chris Richardson: Improving Your Application’s Design by Using Real Objects Slide 11
Colorado Software Summit: October 21 – 26, 2007
Unable to handle complexity
Works well for simple business logice.g. the example wasn’t that bad
But with complex business logic:Large transaction scripts: 100s/1000s LOCDifficult/impossible to understand, test, and maintain
What’s worse: business logic has a habit ofgrowing
New requirements Add a few more lines to thetransaction scriptMany new requirements big messSoon or later you end up with unmaintainable code
© Copyright 2007, Chris Richardson
Chris Richardson: Improving Your Application’s Design by Using Real Objects Slide 12
Colorado Software Summit: October 21 – 26, 2007
Today – rich domain models aregrowing in popularity
POJOsPlain Old Java ObjectsLeverage OO features ofJava
O/R mapping frameworksfor persisting POJOs:
HibernateJava Persistence API…
Spring AOP and AspectJ forhandling cross-cuttingconcerns:
Transaction managementSecurityLoggingAuditing…
© Copyright 2007, Chris Richardson
Chris Richardson: Improving Your Application’s Design by Using Real Objects Slide 13
Colorado Software Summit: October 21 – 26, 2007
Agenda
Where are the real objects?
Overview of the Domain Model pattern
Domain model building blocks
Role of frameworks
Common code smells
Refactoring existing code
Obstacles to OO
© Copyright 2007, Chris Richardson
Chris Richardson: Improving Your Application’s Design by Using Real Objects Slide 14
Colorado Software Summit: October 21 – 26, 2007
Using the Domain Model Pattern
Business logic spread amongst a collectionof classes
Many classes correspond to real worldconcepts: Order, Customer, …
Many classes are true objects havingboth:
State – fields
Behavior – methods that act on the state
© Copyright 2007, Chris Richardson
Chris Richardson: Improving Your Application’s Design by Using Real Objects Slide 15
Colorado Software Summit: October 21 – 26, 2007
Procedural versus OO
Business Tier
Presentation Tier
Data Access Tier
TransactionScripts
(Session Beans)
Data Objects
Business Tier
Domain Model
Presentation Tier
Facade
Data Access Tier
© Copyright 2007, Chris Richardson
Chris Richardson: Improving Your Application’s Design by Using Real Objects Slide 16
Colorado Software Summit: October 21 – 26, 2007
An example domain model
debit(amount)credit(amount)
balance
Account
amountdate
BankingTransaction
BankingTransaction transfer(fromId, toId, amount)
MoneyTransferService
findAccount(id)
AccountRepository
<<interface>>OverdraftPolicy
NoOverdraftPolicy
limit
LimitedOverdraft
from
to
State + Behavior
Behavior
ExplicitRepresentation
of key concepts
Web Tier
Business Tier
addTransaction(…)
BankingTransactionRepository
Slide 17
© Copyright 2007, Chris Richardson
Chris Richardson: Improving Your Application’s Design by Using Real Objects
Colorado Software Summit: October 21 – 26, 2007
DEMO
Code Walkthrough
© Copyright 2007, Chris Richardson
Chris Richardson: Improving Your Application’s Design by Using Real Objects Slide 18
Colorado Software Summit: October 21 – 26, 2007
Benefits of the Domain ModelPattern
Improved maintainabilityThe design reflects realityKey domain classes are represented by classesThe design is more modular
Improved testabilitySmall classes that can be tested in isolation
Improved reusabilityClasses can be used in other applications
Building a domain modelCreates shared understandingDevelops an ubiquitous language
© Copyright 2007, Chris Richardson
Chris Richardson: Improving Your Application’s Design by Using Real Objects Slide 19
Colorado Software Summit: October 21 – 26, 2007
Quantifiably simpler code
Procedural – few, longer, morecomplex methods
Object-oriented – more, simpler,shorter methods
© Copyright 2007, Chris Richardson
Chris Richardson: Improving Your Application’s Design by Using Real Objects Slide 20
Colorado Software Summit: October 21 – 26, 2007
Drawbacks of the Domain Modelpattern
Requires object-oriented design skills
Requires domain model to betransparently “mappable” to the data
e.g. nice database schema
Ugly schemas and data stored in otherapplications is a challenge
© Copyright 2007, Chris Richardson
Chris Richardson: Improving Your Application’s Design by Using Real Objects Slide 21
Colorado Software Summit: October 21 – 26, 2007
When to use it
The business logic is reasonablycomplex or you anticipate that it will be
You have the skills to design one
You can use an ORM framework
© Copyright 2007, Chris Richardson
Chris Richardson: Improving Your Application’s Design by Using Real Objects Slide 22
Colorado Software Summit: October 21 – 26, 2007
Agenda
Where are the real objects?
Overview of the Domain Model pattern
Domain model building blocks
Role of frameworks
Common code smells
Refactoring existing code
Obstacles to OO
© Copyright 2007, Chris Richardson
Chris Richardson: Improving Your Application’s Design by Using Real Objects Slide 23
Colorado Software Summit: October 21 – 26, 2007
Domain model building blocks
Roles akastereotypes
Benefits of roles:
Guide design
Help name objects
Aid understanding
Roles (fromDomain-DrivenDesign)
Entity Value Object
Aggregate Service
RepositoryFactory
© Copyright 2007, Chris Richardson
Chris Richardson: Improving Your Application’s Design by Using Real Objects Slide 24
Colorado Software Summit: October 21 – 26, 2007
Entity
Objects with adistinct identity
Typicallycorrespond to realworld concepts
Almost alwayspersistent
public class Account {
private int id;
private double balance;
private OverdraftPolicy overdraftPolicy;
private String accountId;
private CalendarDate dateOpened;
Account() { }
public void debit(double amount) throws MoneyTransferException { assert amount > 0; double originalBalance = balance;
double newBalance = balance - amount; overdraftPolicy.beforeDebitCheck(this, originalBalance, newBalance); balance = newBalance; overdraftPolicy.afterDebitAction(this, originalBalance, newBalance);
}
public void credit(double amount) {
assert amount > 0; balance += amount; }
© Copyright 2007, Chris Richardson
Chris Richardson: Improving Your Application’s Design by Using Real Objects Slide 25
Colorado Software Summit: October 21 – 26, 2007
Value ObjectsObjects that aredefined by the valuesof their attributesTwo instances withidentical values canbe usedinterchangeablyPart of an entityUsually persistentIdeally immutableOften missing fromprocedural code
public class CalendarDate {
private Date date;
CalendarDate() { }
public CalendarDate(Date date) {
this.date = date; }
public Date getDate() { return date; }
public double getYearsOpen() { Calendar then = Calendar.getInstance(); then.setTime(date);
Calendar now = Calendar.getInstance();
int yearsOpened = now.get(Calendar.YEAR) – then.get(Calendar.YEAR);
int monthsOpened = now.get(Calendar.MONTH) - then.get(Calendar.MONTH); if (monthsOpened < 0) {
yearsOpened--; monthsOpened += 12; }
return yearsOpened + (monthsOpened/12.0);
}
}
© Copyright 2007, Chris Richardson
Chris Richardson: Improving Your Application’s Design by Using Real Objects Slide 26
Colorado Software Summit: October 21 – 26, 2007
Aggregates
NameserviceArea
Restaurant
updateDeliveryInfo()updateRestaurant()getTotal()...
Order
getExtendedPrice()
quantity
OrderLineItem
nameprice
MenuItem
Address
PaymentInformation
<<interface>>
Coupon
root boundary
A cluster of relatedentities and values
Behaves as a unit
Has a root
Has a boundary
Objects outside theaggregate can onlyreference the root
Deleting the rootremoves everything
© Copyright 2007, Chris Richardson
Chris Richardson: Improving Your Application’s Design by Using Real Objects Slide 27
Colorado Software Summit: October 21 – 26, 2007
RepositoriesManages a collection ofobjects
Provides methods for:Adding an object
Finding object or objects
Deleting objects
Consists of an interface andan implementation class
Encapsulates databaseaccess mechanism
Keeps the ORM frameworkout of the domain model
Similar to a DAO
public interface AccountRepository {
Account findAccount(String accountId);
void addAccount(Account account);
}
public class HibernateAccountRepository implements AccountRepository {
private HibernateTemplate hibernateTemplate;
public HibernateAccountRepository(HibernateTemplate template) { hibernateTemplate = template;
}
public void addAccount(Account account) {
hibernateTemplate.save(account); }
public Account findAccount(final String accountId) {
return (Account) DataAccessUtils.uniqueResult(hibernateTemplate .findByNamedQueryAndNamedParam( "Account.findAccountByAccountId", "accountId",
accountId)); }
}
© Copyright 2007, Chris Richardson
Chris Richardson: Improving Your Application’s Design by Using Real Objects Slide 28
Colorado Software Summit: October 21 – 26, 2007
ServicesImplements logic thatcannot be put in a singleentity
Not persistent
Consists of an interface andan implementation class
Service method usually:Invoked (indirectly) bypresentation tier
Invokes one or morerepositories
Invokes one or more entities
Keep them thin
public interface MoneyTransferService {
BankingTransaction transfer(String fromAccountId,
String toAccountId, double amount) throws MoneyTransferException;
}
public class MoneyTransferServiceImpl implements MoneyTransferService{
private final AccountRepository accountRepository;
private final BankingTransactionRepository
bankingTransactionRepository;
public MoneyTransferServiceImpl(AccountRepository accountRepository,
BankingTransactionRepository bankingTransactionRepository) { this.accountRepository = accountRepository; this.bankingTransactionRepository = bankingTransactionRepository; }
public BankingTransaction transfer(String fromAccountId, String toAccountId, double amount) {
… }
}
© Copyright 2007, Chris Richardson
Chris Richardson: Improving Your Application’s Design by Using Real Objects Slide 29
Colorado Software Summit: October 21 – 26, 2007
Factories
Use when a constructor is insufficientEncapsulates complex object creation logic
Handles varying products
Different kinds of factoriesFactory classes
Factory methods
Example: OrderFactoryCreates Order from a shopping cart
Adds line items
© Copyright 2007, Chris Richardson
Chris Richardson: Improving Your Application’s Design by Using Real Objects Slide 30
Colorado Software Summit: October 21 – 26, 2007
Agenda
Where are the real objects?
Overview of the Domain Model pattern
Domain model building blocks
Role of frameworks
Common code smells
Refactoring existing code
Obstacles to OO
© Copyright 2007, Chris Richardson
Chris Richardson: Improving Your Application’s Design by Using Real Objects Slide 31
Colorado Software Summit: October 21 – 26, 2007
Use the POJO programmingmodel
Your domain model might outliveinfrastructure frameworks Minimize
dependencies on them
POJO = Plain Old Java Object
Don't implement any infrastructureinterfaces
Don't call infrastructure APIs
No infrastructure framework annotations?
Slide 31
© Copyright 2007, Chris Richardson
Chris Richardson: Improving Your Application’s Design by Using Real Objects Slide 32
Colorado Software Summit: October 21 – 26, 2007
Use dependency injectionSpring instantiates and wires together
Services, factories and repositories
Dependency injection into entitiesOne option is @Configurable but it’s not POJOHibernate Interceptor+Manual injection is preferable
Benefits:Decouples components from one another and theinfrastructureImproves testability
Slide 32
public AccountServiceImpl(AccountDao accountDao,
BankingTransactionDao bankingTransactionDao) {
this.accountDAO = accountDao;
this.bankingTransactionDAO = bankingTransactionDao;
}
<beans>
<bean id="AccountService"
class="net.chris...domain.AccountServiceImpl">
<constructor-arg ref="accountDao"/>
<constructor-arg ref="bankingTransactionDao"/>
</bean>
…
</beans>
© Copyright 2007, Chris Richardson
Chris Richardson: Improving Your Application’s Design by Using Real Objects Slide 33
Colorado Software Summit: October 21 – 26, 2007
Use Aspect-OrientedProgramming
Spring AOP for service-levelcrosscutting concerns:
e.g. transactionmanagement, security,logging, etc.
AspectJ for entity and valueobject crosscutting concerns
e.g. tracking changes tofieldsBut AJC/Load-time weavinghas a cost
BenefitsDecouples code frominfrastructure
Improves modularity
© Copyright 2007, Chris Richardson
Chris Richardson: Improving Your Application’s Design by Using Real Objects Slide 34
Colorado Software Summit: October 21 – 26, 2007
Use object/relational mapping
Persisting objectswith JDBC is toomuch work
Implement DAOswith Spring ORM
BenefitsLess code
Simpler code
Improved testability
<class name="Account"
table="BANK_ACCOUNT" >
<id name="id" column="ACCOUNT_ID">
<generator class="native" />
</id>
<property name="balance" />
<property name="accountId" />
<property name="dateOpened" />
<many-to-one name="overdraftPolicy" />
</class>
public class HibernateAccountDao
implements AccountDao {
private HibernateTemplate hibernateTemplate;
public HibernateAccountDao(HibernateTemplate
template) {
this.hibernateTemplate = template;
}
public void addAccount(Account account) {
hibernateTemplate.save(account);
}
…
}
© Copyright 2007, Chris Richardson
Chris Richardson: Improving Your Application’s Design by Using Real Objects Slide 35
Colorado Software Summit: October 21 – 26, 2007
Agenda
Where are the real objects?
Overview of the Domain Model pattern
Domain model building blocks
Role of frameworks
Common code smells
Refactoring existing code
Obstacles to OO
© Copyright 2007, Chris Richardson
Chris Richardson: Improving Your Application’s Design by Using Real Objects Slide 36
Colorado Software Summit: October 21 – 26, 2007
Overview of code smells
Code smell = something about thecode that does not seem right
Impacts ease of development andtesting
Some are non-OOD
Some are the consequences of non-OOD
© Copyright 2007, Chris Richardson
Chris Richardson: Improving Your Application’s Design by Using Real Objects Slide 37
Colorado Software Summit: October 21 – 26, 2007
Long methodMethods should beshortBut business logic isconcentrated in theservices longmethodsLong methods aredifficult to:
Read and understandMaintainTest
Fix:Splitting into smallermethods
public class MoneyTransferServiceProceduralImpl implements MoneyTransferService {
public BankingTransaction transfer(String fromAccountId, String toAccountId, double amount) throws MoneyTransferException { Account fromAccount = accountDAO.findAccount(fromAccountId); Account toAccount = accountDAO.findAccount(toAccountId); assert amount > 0; double newBalance = fromAccount.getBalance() - amount; switch (fromAccount.getOverdraftPolicy()) { case Account.NEVER: if (newBalance < 0) throw new MoneyTransferException("In sufficient funds"); break; case Account.ALLOWED: Calendar then = Calendar.getInstance(); then.setTime(fromAccount.getDateOpened()); Calendar now = Calendar.getInstance();
double yearsOpened = now.get(Calendar.YEAR) - then.get(Calendar.YEAR); int monthsOpened = now.get(Calendar.MONTH) - then.get(Calendar.MONTH); if (monthsOpened < 0) { yearsOpened--; monthsOpened += 12; } yearsOpened = yearsOpened + (monthsOpened / 12.0); if (yearsOpened < fromAccount.getRequiredYearsOpen() || newBalance < fromAccount.getLimit()) throw new MoneyTransferException("Limit exceeded"); break; default: throw new MoneyTransferException("Unknown overdraft type: " + fromAccount.getOverdraftPolicy());
} fromAccount.setBalance(newBalance); toAccount.setBalance(toAccount.getBalance() + amount); TransferTransaction txn = new TransferTransaction(fromAccount, toAccount, amount, new Date()); bankingTransactionDAO.addTransaction(txn); return txn; }
© Copyright 2007, Chris Richardson
Chris Richardson: Improving Your Application’s Design by Using Real Objects Slide 38
Colorado Software Summit: October 21 – 26, 2007
Feature Envy
Methods that are fartoo interested indata belonging toother classes
Results in:Poor encapsulation
Long methods
Fix by movingmethods to the classthat has the data
public class MoneyTransferServiceProceduralImpl implements MoneyTransferService {
public BankingTransaction transfer(String fromAccountId, String toAccountId, double amount) throwsMoneyTransferException { Account fromAccount = accountDAO.findAccount(fromAccountId); Account toAccount = accountDAO.findAccount(toAccountId); assert amount > 0; double newBalance = fromAccount.getBalance() - amount; switch (fromAccount.getOverdraftPolicy()) { case Account.NEVER: if (newBalance < 0) throw new MoneyTransferException("In sufficient funds"); break; case Account.ALLOWED: Calendar then = Calendar.getInstance(); then.setTime(fromAccount.getDateOpened()); Calendar now = Calendar.getInstance();
double yearsOpened = now.get(Calendar.YEAR) - then.get(Calendar.YEAR); int monthsOpened = now.get(Calendar.MONTH) - then.get(Calendar.MONTH); if (monthsOpened < 0) { yearsOpened--; monthsOpened += 12; } yearsOpened = yearsOpened + (monthsOpened / 12.0); if (yearsOpened < fromAccount.getRequiredYearsOpen() || newBalance < fromAccount.getLimit()) throw new MoneyTransferException("Limit exceeded"); break; default: throw new MoneyTransferException("Unknown overdraft type: " + fromAccount.getOverdraftPolicy());
} fromAccount.setBalance(newBalance); toAccount.setBalance(toAccount.getBalance() + amount); TransferTransaction txn = new TransferTransaction(fromAccount, toAccount, amount, new Date()); bankingTransactionDAO.addTransaction(txn); return txn; }
© Copyright 2007, Chris Richardson
Chris Richardson: Improving Your Application’s Design by Using Real Objects Slide 39
Colorado Software Summit: October 21 – 26, 2007
Data class
Classes that are justgetters and setters
No business logic -it’s in the service
Leads to:
Feature envy
Fix by movingmethods that act ondata into class
public class Account {
public static final int NEVER = 1; public static final int ALLOWED = 2;
private int id;private double balance;private int overdraftPolicy;private String accountId;private Date dateOpened;private double requiredYearsOpen;private double limit;
Account() {}
public Account(String accountId, double balance, int overdraftPolicy, Date dateOpened, double requiredYearsOpen, double limit) {….. }
public int getId() {return id;}
public String getAccountId() {return accountId;}
public void setBalance(double balance) { this.balance = balance; }
public double getBalance() { return balance; }
public int getOverdraftPolicy() { return overdraftPolicy; }
public Date getDateOpened() { return dateOpened; }
public double getRequiredYearsOpen() { return requiredYearsOpen; }
public double getLimit() {return limit; }}
© Copyright 2007, Chris Richardson
Chris Richardson: Improving Your Application’s Design by Using Real Objects Slide 40
Colorado Software Summit: October 21 – 26, 2007
Primitive Obsession
Code uses built-intypes instead ofapplicationclassesConsequences:
ReducesunderstandabilityLong methodsCode duplicationAdded complexity
Fix by movingdata and codeinto new class
public class Account { private Date dateOpened;}
public class Account { private Date dateOpened;}
public class MoneyTransferServiceProceduralImpl implementsMoneyTransferService {
public BankingTransaction transfer(String fromAccountId, StringtoAccountId, double amount) throws MoneyTransferException {
Account fromAccount = accountDAO.findAccount(fromAccountId); Account toAccount = accountDAO.findAccount(toAccountId); … Calendar then = Calendar.getInstance();
then.setTime(fromAccount.getDateOpened()); Calendar now = Calendar.getInstance();
double yearsOpened = now.get(Calendar.YEAR) - then.get(Calendar.YEAR); int monthsOpened = now.get(Calendar.MONTH) –
then.get(Calendar.MONTH); if (monthsOpened < 0) { yearsOpened--; monthsOpened += 12;
} yearsOpened = yearsOpened + (monthsOpened / 12.0); if (yearsOpened < fromAccount.getRequiredYearsOpen()
|| newBalance < fromAccount.getLimit())…}
© Copyright 2007, Chris Richardson
Chris Richardson: Improving Your Application’s Design by Using Real Objects Slide 41
Colorado Software Summit: October 21 – 26, 2007
Switch StatementsUse of type codes andswitch statements insteadof polymorphism
Key concepts are notrepresented byclassesConsequences:
Longer methodsPoor maintainabilitycaused by code duplicationIncreased code complexity
Fix by introducing classhierarchy and movingeach part of switchstatement into aoverriding method
public class MoneyTransferServiceProceduralImplimplements MoneyTransferService {
public BankingTransaction transfer(StringfromAccountId, String toAccountId,
double amount) throws MoneyTransferException {… switch (fromAccount.getOverdraftPolicy()) { case Account.NEVER:
… break; case Account.ALLOWED: … default:
… } …}
public class Account {
public static final int NEVER = 1; public static final int ALLOWED = 2;…
© Copyright 2007, Chris Richardson
Chris Richardson: Improving Your Application’s Design by Using Real Objects Slide 42
Colorado Software Summit: October 21 – 26, 2007
Data clumps
Multiple fields ormethod parametersthat belong together
Consequences:Long methods
Duplication
Fix by:Moving fields intotheir own class
Eliminate resultingFeature Envy
public class Account {
public static final int NEVER = 1; public static final int ALLOWED = 2;
private int id;private double balance;private String accountId;private Date dateOpened;
private int overdraftPolicy;private double requiredYearsOpen;private double limit;
Account() {}
}
© Copyright 2007, Chris Richardson
Chris Richardson: Improving Your Application’s Design by Using Real Objects Slide 43
Colorado Software Summit: October 21 – 26, 2007
Agenda
Where are the real objects?
Overview of the Domain Model pattern
Domain model building blocks
Role of frameworks
Common code smells
Refactoring existing code
Obstacles to OO
© Copyright 2007, Chris Richardson
Chris Richardson: Improving Your Application’s Design by Using Real Objects Slide 44
Colorado Software Summit: October 21 – 26, 2007
Transforming procedural code
Inside every procedural design is adomain model just trying to get out
Incrementally transform a proceduraldesign into an OO design
Small, localized changes
Something to do on Monday morning!
© Copyright 2007, Chris Richardson
Chris Richardson: Improving Your Application’s Design by Using Real Objects Slide 45
Colorado Software Summit: October 21 – 26, 2007
Refactoring to an OO design
Transform aprocedural designto an OO design byapplyingrefactoringsRefactoring:
Restructure thecodeWithout changingbehavior
Essential cleanupsfor decaying code
© Copyright 2007, Chris Richardson
Chris Richardson: Improving Your Application’s Design by Using Real Objects Slide 46
Colorado Software Summit: October 21 – 26, 2007
Basic refactoringsExtract Method
Eliminates long methods
Move MethodMove a method to adifferent class (field orparameter)Moves method to wherethe data is
Push DownMove a method intosubclassesOptionally leave anabstract method behindPart of eliminatingconditional logic
…
© Copyright 2007, Chris Richardson
Chris Richardson: Improving Your Application’s Design by Using Real Objects Slide 47
Colorado Software Summit: October 21 – 26, 2007
Compound refactoringsA sequence of simpler refactoringsCompose method
Apply Extract Method repeatedlyUse to replace long method with more readable shortermethods
Replace Type Code With StrategyDefine GOF Strategy class for each type code
Replace Conditional With PolymorphismTurn into part of a switch statement into an overridingmethod in a subclass
Replace Data Value with ObjectMove field into its own classEliminates Primitive Obsession
Slide 48
© Copyright 2007, Chris Richardson
Chris Richardson: Improving Your Application’s Design by Using Real Objects
Colorado Software Summit: October 21 – 26, 2007
DEMO
Refactoring procedural code
© Copyright 2007, Chris Richardson
Chris Richardson: Improving Your Application’s Design by Using Real Objects Slide 49
Colorado Software Summit: October 21 – 26, 2007
Agenda
Where are the real objects?
Overview of the Domain Model pattern
Domain model building blocks
Role of frameworks
Common code smells
Refactoring existing code
Obstacles to good OO design
Slide 49
© Copyright 2007, Chris Richardson
Chris Richardson: Improving Your Application’s Design by Using Real Objects Slide 50
Colorado Software Summit: October 21 – 26, 2007
Performance tuning changes thedesign
Different web requests
display different objectgraphs
Display project details
Display project forapproval or rejection
Improve performanceby loading objectgraphs using optimizedqueries (e.g. fetch join)
Therefore we needmultiple Dao (andService) methods
Slide 50
getProject(projectId)
ProjectCoordinator
findProject(projectId)
ProjectRepository
getProjectDetails(projectId)
getProjectForReview(projectId)
ProjectCoordinator
findProjectDetails(projectId)
findProjectForReview(projectId)
ProjectRepository
hibernateTemplate.get()
from Project p
inner join fetch p.operations
from Project pinner join fetch p.operations
Inner join fetch p.createdBy
© Copyright 2007, Chris Richardson
Chris Richardson: Improving Your Application’s Design by Using Real Objects Slide 51
Colorado Software Summit: October 21 – 26, 2007
Untangling what to load fromthe code
Java Data Objects (JDO) has fetch groupsDeclarative specification the object graph thatneeds to be loaded
Flow:Web tier configures fetch groups
Calls ProjectCoordinator.get()
O/RM loads object graph specified by activefetch groups
Look for this feature in JPAimplementations that evolved from JDO
Slide 51
© Copyright 2007, Chris Richardson
Chris Richardson: Improving Your Application’s Design by Using Real Objects Slide 52
Colorado Software Summit: October 21 – 26, 2007
Web frameworks need JavaBeans
Web frameworks can bind request parametersdirectly to domain objectsEasy creation of domain objectsEasy editing of detached domain objects1. Load object graph from database2. Store object graph in HttpSession3. Bind Http parameters to object's properties4. Reattach object graph and update the database
A lot less codeBut domain objects must be JavaBeans:
Public default constructorJavaBean-style setters
Slide 52
© Copyright 2007, Chris Richardson
Chris Richardson: Improving Your Application’s Design by Using Real Objects Slide 53
Colorado Software Summit: October 21 – 26, 2007
The trouble with settersPoor encapsulation
Objects are now exposingtheir internal state
No immutable objectsIncreases code complexity
Makes it more error-prone
Developers might bypassbusiness method Bugs,poor design
Slide 53
public class Order {
private Address deliveryAddress;
public void updateDeliveryAddress( Address deliveryAddress) { // validate before changing …}
public Address getAddress() {…}…}
public class Address { private String street1;
private String street2;
public String getStreet1() {...}; public void setStreet1(String street1) {...} …
}
order.getAddress().setStreet1("Bad!");
© Copyright 2007, Chris Richardson
Chris Richardson: Improving Your Application’s Design by Using Real Objects Slide 54
Colorado Software Summit: October 21 – 26, 2007
How to cope
Live with it:It's often not that bad
Be vigilant for code bypassing businessmethods
Use DTOsHides domain objects from web tier
But you have to write more code
Encourage the development of betterframeworks
Slide 54
© Copyright 2007, Chris Richardson
Chris Richardson: Improving Your Application’s Design by Using Real Objects Slide 55
Colorado Software Summit: October 21 – 26, 2007
More on web binding
Web frameworks can bind to propertiesof nested objects, e.g.order.deliveryAddress.street1
But some frameworks require thatintermediate objects to be non-null
This can impact the domain model
Slide 55
© Copyright 2007, Chris Richardson
Chris Richardson: Improving Your Application’s Design by Using Real Objects Slide 56
Colorado Software Summit: October 21 – 26, 2007
Using ORM frameworksORM frameworks can access private fields
No setters (or getters) required
But require:Default constructorNon-final fieldsid fields
Subtle changes:Collection fields: null emptyEmbedded objects with null fields null reference
Proxy-based lazy loading:Don't access fields outside of instance affects equals()and hashCode()Can affect object identity: this != proxyToSameObjectAsThis
Slide 56
© Copyright 2007, Chris Richardson
Chris Richardson: Improving Your Application’s Design by Using Real Objects Slide 57
Colorado Software Summit: October 21 – 26, 2007
SummaryA rich domain model:
Organizes the business logic as classeswith state AND behavior
Improves maintainability and testability
Enabled by POJOs and non-invasiveframeworks (mostly)
Emerges from procedural code byincremental refactoring
Use It!
© Copyright 2007, Chris Richardson
Chris Richardson: Improving Your Application’s Design by Using Real Objects Slide 58
Colorado Software Summit: October 21 – 26, 2007
For more informationBuy my book
Send email:
Visit my website:
http://www.chrisrichardson.net
Talk to me about consultingand training