Don't Do This! How Not To Write Java™ Technology-Based ... · >Mentor, Trainer, Consultant at...

Post on 25-May-2020

2 views 0 download

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, Inc.dean@objectmentor.com @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

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.

dean@objectmentor.com@deanwamplerblog.objectmentor.compolyglotprogramming.com/papersprogrammingscala.com

Tuesday, June 2, 2009