Don't Do This! How Not To Write Java™ Technology-Based ... · >Mentor, Trainer, Consultant at...
Transcript of Don't Do This! How Not To Write Java™ Technology-Based ... · >Mentor, Trainer, Consultant at...
Don't Do This! How Not To Write Java™ Technology-Based SoftwareDean WamplerObject Mentor, [email protected] @deanwampler
Speaker logo centered below photo
Tuesday, June 2, 2009
> Mentor, Trainer, Consultant at Object Mentor, Inc.objectmentor.compolyglotprogramming.com
2
Tuesday, June 2, 2009
> September 2009oreilly.com/catalog/9780596157746/
> Read it now:programmingscala.com
3
Tuesday, June 2, 2009
4
Lessons fromthe trenches...
http://everystockphoto.com/photo.php?imageId=4027778http://everystockphoto.com/photo.php?imageId=4027778Tuesday, June 2, 2009
5
10 mistakes
http://everystockphoto.com/photo.php?imageId=4027778http://everystockphoto.com/photo.php?imageId=4027778
and how to avoid them.
Tuesday, June 2, 2009
Mistake #1: Comment everything!
6© Dean WamplerTuesday, June 2, 2009
7
public class Account { … /** * Withdraw money from account. * @param amount to withdraw (double) * @return new balance (double). */ public double withdraw(double amount) { balance -= amount; return balance; }}
Version 1
Tuesday, June 2, 2009
8
public class Account { … /** * Withdraw money from account. * @param amount to withdraw (double) * @return new balance (double). */ public double withdraw(double amount) { balance -= amount; return balance; }}
Version 1
Command-queryseparation?
Tuesday, June 2, 2009
9
public class Account { … /** * Withdraw money from account. * @param amount to withdraw (double) * @return new balance (double). */ public void withdraw(double amount) { balance -= amount; }}
Version 2
Tuesday, June 2, 2009
10
public class Account { … /** * Withdraw money from account. * @param amount to withdraw (double) * @return new balance (double). */ public void withdraw(double amount) { balance -= amount; }}
Version 2
What about overdrafts?
Tuesday, June 2, 2009
11
public class Account { … /** * Withdraw money from account. * @param amount to withdraw (double) * @return new balance (double). */ public void withdraw(double amount) throws OverdraftException { if (balance < amount) throw new OverdraftException( balance, amount); balance -= amount; }}
Version 3
Tuesday, June 2, 2009
12
public class Account { … /** * Withdraw money from account. * @param amount to withdraw (double) * @return new balance (double). */ public void withdraw(double amount) throws OverdraftException { if (balance < amount) throw new OverdraftException( balance, amount); balance -= amount; }}
Version 3
Tuesday, June 2, 2009
13
public class Account { … /** * Withdraw money from account. * @param amount to withdraw (double) * @return new balance (double). */ public void withdraw(double amount) throws OverdraftException { if (balance < amount) throw new OverdraftException( balance, amount); balance -= amount; }}
Version 3Doubles???
Tuesday, June 2, 2009
14
public class Account { … /** * Withdraw money from account. * @param amount to withdraw (double) * @return new balance (double). */ public void withdraw(Currency amount) throws OverdraftException { if (balance.lessThan(amount)) throw new OverdraftException( balance, amount); balance = balance.minus(amount); }}
Version 4
Tuesday, June 2, 2009
15
public class Account { … /** * Withdraw money from account. * @param amount to withdraw (double) * @return new balance (double). */ public void withdraw(Currency amount) throws OverdraftException { if (balance.lessThan(amount)) throw new OverdraftException( balance, amount); balance = balance.minus(amount); }}
Version 4
Tuesday, June 2, 2009
16
public class Account { … /** * Withdraw money from account. * @param amount to withdraw (double) * @return new balance (double). */ public void withdraw(Currency amount) throws OverdraftException { if (balance.lessThan(amount)) throw new OverdraftException( balance, amount); balance = balance.minus(amount); }}
Version 4
Still Accurate??
Tuesday, June 2, 2009
17
How do you test-drive
comments?
Tuesday, June 2, 2009
18
Why comments?
To communicate.
Tuesday, June 2, 2009
19
Communicatewith literate
code and tests.
Tuesday, June 2, 2009
20
class AccountTest { … @Test(expected=OverdraftException.class) public void overdraftThrowsException() { Currency c1 = new Currency(1000.00,…); Currency c2 = new Currency(1000.01,…); Account account = new Account(c1); account.withdraw(c2); }} Tests as
documentation
Tuesday, June 2, 2009
#2: Here, have an exception!
21http://www.damnit.org/2008-02/29osqid.jpg/viewTuesday, June 2, 2009
#2: Here, have an exception!
22http://www.damnit.org/2008-02/29osqid.jpg/view
“Use checked exceptions.”
Tuesday, June 2, 2009
23
import java.io.*public class FileFilter {
public static interface Filter { String filterLine(String line); } …
Tuesday, June 2, 2009
24
… public void filter(File src, File dest, Filter filter) { String lineSeparator = …; BufferedReader in = new BufferedReader( new FileReader(src)); BufferedWriter out= new BufferedWriter( new FileWriter(dest)); …
Tuesday, June 2, 2009
25
… public void filter(File src, File dest, Filter filter) { String lineSeparator = “…”; BufferedReader in = new BufferedReader( new FileReader(source)); BufferedWriter out= new BufferedWriter( new FileWriter(destination)); …
FileFilter.java:10: unreported exception java.io.FileNotFoundException; must be caught ... BufferedReader in = new BufferedReader(new …
Tuesday, June 2, 2009
26
… public void filter(File src, File dest, Filter filter) throws FileNotFoundException, IOException { String lineSeparator = “…”; BufferedReader in = new BufferedReader( new FileReader(source)); BufferedWriter out= new BufferedWriter( new FileWriter(destination)); …
Tuesday, June 2, 2009
27
How are the exceptionshandled?
Tuesday, June 2, 2009
28
… main(String[] args) { … workFlowProcess(…) { … stuffInTheMiddle(…) { … manipulateFiles(…) { FileFilter fileFilter = new …; fileFilter.filter(…); …
Who handles the FileNotFoundException
and IOException?
Tuesday, June 2, 2009
29
Could add throwsat every levelof the stack...
Namespace pollution
Tuesday, June 2, 2009
30
Could eatthe exception immediately...
Do you really know how to recover??
Tuesday, June 2, 2009
#2: Here, have an exception!
31http://www.damnit.org/2008-02/29osqid.jpg/view
“Handle every exception as soon
as you can.”
Tuesday, June 2, 2009
32
… main(String[] args) { … workFlowProcess(…) { … stuffInTheMiddle(…) { … manipulateFiles(…) { try { FileFilter fileFilter = new …; fileFilter.filter(…); } catch (Throwable th) { log(th); // Now what!! } …
Eat it…?
Tuesday, June 2, 2009
33
… main(String[] args) { … workFlowProcess(…) { … stuffInTheMiddle(…) { … manipulateFiles(…) { FileFilter fileFilter = new …; fileFilter.filter(…); …
One of these methodsknows what to do.
Tuesday, June 2, 2009
34
Useuncheckedexceptions.
Tuesday, June 2, 2009
35
Handleexceptions
strategically.
Tuesday, June 2, 2009
36
… main(String[] args) { … workFlowProcess(…) { … stuffInTheMiddle(…) { … manipulateFiles(…) { FileFilter fileFilter = new …; fileFilter.filter(…); …
Maybe you catch file IO exceptions and attempt
recovery...
Tuesday, June 2, 2009
#3: Just because youʼre paranoid doesnʼt mean you shouldnʼt check for nulls...
37http://www.flickr.com/photos/brewedfreshdaily89/2909152638/in/photostream/
Tuesday, June 2, 2009
38
… public void filter(File src, File dest, Filter filter) throws FileNotFoundException, IOException { if (src == null || dest == null || filter == null) panic(“…”); …
Tuesday, June 2, 2009
39
… public void filter(File src, File dest, Filter filter) throws FileNotFoundException, IOException { if (src == null || dest == null || filter == null) panic(“…”); …
Tuesday, June 2, 2009
40
Null checksobscurecode.
Tuesday, June 2, 2009
41
Null checkshave to betest driven.
Tuesday, June 2, 2009
42
But, isnʼtdefensive
programminggood?
Tuesday, June 2, 2009
43
Use strategicdata validation.
Tuesday, June 2, 2009
44
Check at module
boundaries.
Tuesday, June 2, 2009
45
Weed out nulls with
automated tests.
Tuesday, June 2, 2009
#4: We can build a better X in house.
46
http://picturethis.channel4.com/photo/9075
Tuesday, June 2, 2009
47
NIHsyndrome.
Tuesday, June 2, 2009
48
Examples:message queues.
Tuesday, June 2, 2009
49
Examples:rules engines.
Tuesday, June 2, 2009
50
Examples:web template
engines.
Tuesday, June 2, 2009
51
Whatʼs the cost of development?
Tuesday, June 2, 2009
52
Whatʼs the cost of long-term
maintenance?
Tuesday, June 2, 2009
53
In-house tools become a
maintenance burden.
Tuesday, June 2, 2009
54
Porting to a 3rd-party tool is
painful.
Tuesday, June 2, 2009
#5: Iʼll grab my own JDBC connection, thank you very much!
55© Dean WamplerTuesday, June 2, 2009
56
public void transfer( Account src, Account dest, Currency amount) { try { src.withdraw(amount); dest.deposit(amount); Class.forName("sun.jdbc..."); Connection con = DriverManager.getConnection(…); Statement stmt = con.createStatement(); …
Tuesday, June 2, 2009
57
public void transfer( Account src, Account dest, Currency amount) { try { src.withdraw(amount); dest.deposit(amount); Class.forName("sun.jdbc..."); Connection con = DriverManager.getConnection(…); Statement stmt = con.createStatement(); …
… or any other “hard” dependency.
Tuesday, June 2, 2009
58
How do you unit test transfer?
Tuesday, June 2, 2009
59
Hide dependencies
behind abstractions.
Tuesday, June 2, 2009
60
Inject dependencies:
inversion of control.
Tuesday, June 2, 2009
61
public void transfer( Account src, Account dest, Currency amount) { try { src.withdraw(amount); dest.deposit(amount); accountPersister.persist(src); accountPersister.persist(dest); …
Tuesday, June 2, 2009
62
public void transfer( Account src, Account dest, Currency amount) { try { src.withdraw(amount); dest.deposit(amount); accountPersister.persist(src); accountPersister.persist(dest); …
accountPersister set through constructor or setter.
Tuesday, June 2, 2009
63
For testing, set accountPersister to a test double.
Tuesday, June 2, 2009
64
For production, set accountPersister
using Spring.
Tuesday, June 2, 2009
65
You can remove the persistence
code completely...E.g., using Aspects.
Tuesday, June 2, 2009
#6: Why retest when you can copy and paste?
66© Dean WamplerTuesday, June 2, 2009
67
“Manual testing hurts.
Tuesday, June 2, 2009
68
So donʼt edit, retest and
redeploy code.
Tuesday, June 2, 2009
69
Copy, paste, and tweak it instead!”
Tuesday, June 2, 2009
70
⇒ Massive duplication!
Tuesday, June 2, 2009
71
Automated testing eliminates
the pain.
Tuesday, June 2, 2009
#7: This code doesnʼt need to be thread safe.
72http://www.flickr.com/photos/billward/359774589/Tuesday, June 2, 2009
73
Folk definition of insanity:Do the same thing over and over again and expect the
results to be different.
“The Problem with Threads”, IEEE Computer, May 2006Tuesday, June 2, 2009
74
Thatʼs multithreaded programming in a nutshell.
Tuesday, June 2, 2009
75
Code should tell its story.
Tuesday, June 2, 2009
76
public class Account { … public void withdraw(Currency amount) throws OverdraftException { if (balance.lessThan(amount)) throw new OverdraftException( balance, amount); balance = balance.minus(amount); }}
Tuesday, June 2, 2009
77
public class Account { … public void withdraw(Currency amount) throws OverdraftException { if (balance.lessThan(amount)) throw new OverdraftException( balance, amount); balance = balance.minus(amount); }} With threads, this code isnʼt
telling me the whole story.Tuesday, June 2, 2009
78
public class Account { … public void withdraw(Currency amount) throws OverdraftException { if (balance.lessThan(amount)) throw new OverdraftException( balance, amount); balance = balance.minus(amount); }} These two operations
must be atomic!Tuesday, June 2, 2009
79
2 ways to fix this code:
Tuesday, June 2, 2009
80
#1: Use thread synchronization
primitives.
Tuesday, June 2, 2009
81
Tuesday, June 2, 2009
82
#2: Write concurrent code without threads.
Tuesday, June 2, 2009
83
Use Actors.Go to Jonas Bonérʼs talk
tomorrow for other options...
Tuesday, June 2, 2009
84
ActorsMessage passing
between autonomous Actors.
Tuesday, June 2, 2009
85
ActorsNo shared, mutable state.
Tuesday, June 2, 2009
86
ActorsMade famous by Erlang.Also supported in Scala.
Google: Java actors
Tuesday, June 2, 2009
#8: Sophisticated code needs sophisticated APIʼs.
87http://www.flickr.com/photos/randomurl/440190706/Tuesday, June 2, 2009
88
“Enterprise appsrequire EJBs.”
Tuesday, June 2, 2009
89
Accidental vs.
essential complexity.
Tuesday, June 2, 2009
90
“Do the simplest thing
that could possibly work!”
Tuesday, June 2, 2009
91
2 ways to stay focused:
Tuesday, June 2, 2009
92
#1: Use Test-Driven
Development (TDD).
Tuesday, June 2, 2009
93
#2: Use Domain-Specific
Languages (DSLs).
Tuesday, June 2, 2009
94
Vacation vacation = vacation() .starting("10/09/2007") .ending("10/17/2007") .city("Paris") .hotel("Hilton") .airline("United") .flight("UA-6886");
http://www.infoq.com/articles/internal-dsls-javaTuesday, June 2, 2009
95
Vacation vacation = vacation() .starting("10/09/2007") .ending("10/17/2007") .city("Paris") .hotel("Hilton") .airline("United") .flight("UA-6886");
Expresses business logic.
http://www.infoq.com/articles/internal-dsls-javaTuesday, June 2, 2009
96
Vacation vacation = vacation() .starting("10/09/2007") .ending("10/17/2007") .city("Paris") .hotel("Hilton") .airline("United") .flight("UA-6886");
Hides implementation.
http://www.infoq.com/articles/internal-dsls-javaTuesday, June 2, 2009
97
What are the appropriate details
at this level of abstraction?
Tuesday, June 2, 2009
#9: Everything is an object.
98© Dean WamplerTuesday, June 2, 2009
99
Most appsare CRUD.
Tuesday, June 2, 2009
100
Do you really needORM and OO middleware?
Tuesday, June 2, 2009
101
Business rules:objects
or functions?
Tuesday, June 2, 2009
102
Why are map/reduce and key-value DBs
so hot?Tuesday, June 2, 2009
103
Embrace otherparadigms:
functional, aspects, logic, ...
Tuesday, June 2, 2009
#10: Java and XML are all we really need.
104http://www.flickr.com/photos/randomurl/440190706/Tuesday, June 2, 2009
105
Why did we enterXML Hell?
Tuesday, June 2, 2009
106
XML is for data,not scripting.
Tuesday, June 2, 2009
107
Application
Kernel of Components
Built-in Scripts User Scripts
(Java Components) + (Groovy/JRuby/Jython/... Scripts)
= Applications!Tuesday, June 2, 2009
108
Application
Kernel of Components
Built-in Scripts User Scripts
Components + Scripts = Applications
Tuesday, June 2, 2009
109
Why is Emacsstill relevant?
C + ELisp = Emacs
Tuesday, June 2, 2009
A Way Forward...
110© Dean WamplerTuesday, June 2, 2009
111
Communicate thrucode and tests.
#1: Comments
Tuesday, June 2, 2009
112
Handle themstrategically.
#2: Exceptions
Tuesday, June 2, 2009
113
Validate data at boundaries.
#3: Paranoid?
Tuesday, June 2, 2009
114
Use inversion of control.
#4: Dependencies
Tuesday, June 2, 2009
115
What is central to your business?
#5: NIH Syndrome
Tuesday, June 2, 2009
116
Avoid duplication.Automate testing.
#6: Copy & Paste
Tuesday, June 2, 2009
117
Avoid shared, mutable state.
#7: Thread Safety
Tuesday, June 2, 2009
118
Focus using TDD. Use DSLs.
#8: Complexity
Tuesday, June 2, 2009
119
Use FP, AOP, Relational, Logic...
#9: Objects Only?
Tuesday, June 2, 2009
120
Components + Scripts = Apps
#10: Java Only?
Tuesday, June 2, 2009
Dean WamplerObject Mentor, Inc.
[email protected]@deanwamplerblog.objectmentor.compolyglotprogramming.com/papersprogrammingscala.com
Tuesday, June 2, 2009