Slide 1

Slide 1 text

THOUGHT DRIVEN DEVELOPMENT by @AlexeyBuzdin

Slide 2

Slide 2 text

@AlexeyBuzdin Developer / Trainer at

Slide 3

Slide 3 text

DOES THIS CODE WORK? def trySend (Mail mail) { try { mailService.send mail } catch (ServerTimeOutException e) { /* TODO: Handle error here */ } }

Slide 4

Slide 4 text

NO IDEA TO BE HONEST…

Slide 5

Slide 5 text

HOW TO MAKE SURE?

Slide 6

Slide 6 text

RUN THE THING!

Slide 7

Slide 7 text

ZE CODE AGAIN def trySend (Mail mail) { try { mailService.send mail } catch (ServerTimeOutException e) { /* TODO: Handle error here */ } }

Slide 8

Slide 8 text

ZE CODE AGAIN def trySend (Mail mail) { try { mailService.send mail } catch (ServerTimeOutException e) { /* TODO: Handle error here */ } } HOW MANY PATHS?

Slide 9

Slide 9 text

3+ HOW MANY PATHS?

Slide 10

Slide 10 text

3+ HOW MANY PATHS? HAPPY PATH SERVER TIMEOUT ?

Slide 11

Slide 11 text

3+ HOW MANY PATHS? HAPPY PATH SERVER TIMEOUT ?

Slide 12

Slide 12 text

3+ HOW MANY PATHS? HAPPY PATH SERVER TIMEOUT ?

Slide 13

Slide 13 text

ZE CODE AGAIN def trySend (Mail mail) { try { mailService.send mail } catch (ServerTimeOutException e) { /* TODO: Handle error here */ } }

Slide 14

Slide 14 text

3+ HOW MANY PATHS? HAPPY PATH SERVER TIMEOUT NULL POINTER

Slide 15

Slide 15 text

RUN THE THING 1!

Slide 16

Slide 16 text

RUN THE THING 1! RUN THE THING 2!

Slide 17

Slide 17 text

RUN THE THING 1! RUN THE THING 2! RUN THE THING 3!

Slide 18

Slide 18 text

No content

Slide 19

Slide 19 text

WHO HAS DONE THIS?

Slide 20

Slide 20 text

DEBUGGING CODE TO UNDERSTAND WHERE IS THE FAILURE

Slide 21

Slide 21 text

IN 99% THIS IS WRONG!

Slide 22

Slide 22 text

TESTS

Slide 23

Slide 23 text

TESTS ARE MADE TO MAKE YOU FEEL SECURE!

Slide 24

Slide 24 text

LIKE A LOVELY HUG ♥

Slide 25

Slide 25 text

YOU NEED TO ADD SOMETHING TO THIS CODE

Slide 26

Slide 26 text

public byte[] scaleImage(InputStream is, int maxWidth, int maxHeight, ImageType type) throws IOException { if (is == null) throw new IOException(String.format("Input stream is unavailable for image type %s", type.getMime())); BufferedImage source = ImageIO.read(is); int width = source.getWidth(); int height = source.getHeight(); int scaledWidth = width; int scaledHeight = height; if (width > maxWidth) { scaledWidth = maxWidth; scaledHeight = (int) Math.ceil((scaledWidth * height * 1.0) / width); } if (scaledHeight > maxHeight) { scaledHeight = maxHeight; scaledWidth = (int) Math.ceil((scaledHeight * width * 1.0) / height); } source = (width < maxWidth || height < maxHeight) ? subImage(source, width, height, maxWidth, maxHeight) : scale(source, width, height, scaledWidth, scaledHeight); ByteArrayOutputStream stream = new ByteArrayOutputStream(); ImageIO.write(source, type.getMime(), stream); return stream.toByteArray(); }

Slide 27

Slide 27 text

NO TESTS…

Slide 28

Slide 28 text

NO TESTS… DO YOU FEEL SECURE?

Slide 29

Slide 29 text

TESTS ARE AWESOME!

Slide 30

Slide 30 text

THUS…

Slide 31

Slide 31 text

LETS SELL THEM!

Slide 32

Slide 32 text

LETS SELL THEM! EVANGELIZE

Slide 33

Slide 33 text

(TDD) TEST-DRIVEN DEVELOPMENT

Slide 34

Slide 34 text

CLASSIC TDD 1. ADD A TEST 2. RUN ALL TESTS 3. WRITE SOME CODE 4. RUN TESTS 5. REFACTOR CODE 6. REPEAT

Slide 35

Slide 35 text

CONFIDENCE MEANS STRICT RULES?

Slide 36

Slide 36 text

I WANT TO BE A BADASS!

Slide 37

Slide 37 text

AWESOME AND CONFIDENT

Slide 38

Slide 38 text

No content

Slide 39

Slide 39 text

EATING ELEPHANT PIECE BY PIECE

Slide 40

Slide 40 text

EATING ELEPHANT PIECE BY PIECE AND KEEPING HIM ALIVE IN THE PROCESS!

Slide 41

Slide 41 text

ATOMIC COMMITS?

Slide 42

Slide 42 text

SINGLE COMMIT OR SINGLE TEST DOES NOT BRING ANY VALUE

Slide 43

Slide 43 text

SINGLE TEST DOES NOT BRING ANY VALUE MERGE WITH MASTER DOES SINGLE COMMIT OR

Slide 44

Slide 44 text

SINGLE TEST DOES NOT BRING ANY VALUE TESTED USER STORY DOES SINGLE COMMIT OR

Slide 45

Slide 45 text

SO WHY EXTRA EFFORT?

Slide 46

Slide 46 text

SO WHY EXTRA EFFORT? BECAUSE IT’S COOL!

Slide 47

Slide 47 text

Test-Driven Development

Slide 48

Slide 48 text

Kent Beck stated that TDD: - encourages simple designs - inspires confidence Test-Driven Development

Slide 49

Slide 49 text

TOOLS ARE MEANT TO HELP

Slide 50

Slide 50 text

Kent Beck stated that TDD: - encourages simple designs - inspires confidence TDD acts as a self-documenting code Test-Driven Development

Slide 51

Slide 51 text

Kent Beck stated that TDD: - encourages simple designs - inspires confidence TDD acts as a self-documenting code Test-Driven Development but on which level?

Slide 52

Slide 52 text

Kent Beck stated that TDD: - encourages simple designs - inspires confidence TDD acts as a self-documenting code Test-Driven Development but on which level? LETS THINK!

Slide 53

Slide 53 text

THOUGHT DRIVEN DEVELOPMENT

Slide 54

Slide 54 text

AS A USER I WANT TO POST A TWEET

Slide 55

Slide 55 text

ARE YOU CONFIDENT ABOUT THIS?

Slide 56

Slide 56 text

NO? THEN TEST IT!

Slide 57

Slide 57 text

BUT WHAT IF CONNECTION FAILS?

Slide 58

Slide 58 text

UNSURE? THEN TEST IT!

Slide 59

Slide 59 text

FEATURES ARE NOT LIKELY TO BE REMOVED

Slide 60

Slide 60 text

FEATURES ARE LIKELY TO EVOLVE

Slide 61

Slide 61 text

FEATURES ARE LIKELY TO EXPAND

Slide 62

Slide 62 text

def join(List tokens, String separator) HOW MANY TEST WOULD YOU WRITE?

Slide 63

Slide 63 text

def join(List tokens, String separator) {
 def sb = new StringBuilder()
 boolean first = true
 for (String item : tokens)
 {
 if (first) first = false
 else sb.append separator
 sb.append item
 }
 return sb.toString
 } HOW MANY TEST WOULD YOU WRITE?

Slide 64

Slide 64 text

def join(List tokens, String separator) {
 def sb = new StringBuilder()
 boolean first = true
 for (String item : tokens)
 {
 if (first) first = false
 else sb.append separator
 sb.append item
 }
 return sb.toString
 } HOW MANY TEST WOULD MAKE YOU CONFIDENT?

Slide 65

Slide 65 text

@Test def joinsStrings() { def actual = util.join(Arrays.asList("hello", "world"), ";") assertThat(actual, equalTo "hello;world") } IS ONE ENOUGH?

Slide 66

Slide 66 text

TECHNICAL BOILERPLATE WILL LIKELY TO BE CHANGED

Slide 67

Slide 67 text

TECHNICAL BOILERPLATE AND IT’S TESTS WILL LIKELY TO DIE

Slide 68

Slide 68 text

GOOD TEST IS LIKELY TO BE #BROKEN

Slide 69

Slide 69 text

TEST BEHAVIOR, NOT CODE!

Slide 70

Slide 70 text

BUT TEST AS LOW AS IT MAKES SENSE

Slide 71

Slide 71 text

IDENTIFY INDEPENDENT MODULES/LAYERS

Slide 72

Slide 72 text

MAKE END-TO-END TESTS FOR CORE FUNCTIONALITY

Slide 73

Slide 73 text

ALWAYS TEST PUBLIC API EXTENSIVELY!

Slide 74

Slide 74 text

SOMETIMES LET CLIENTS TEST YOUR APP!

Slide 75

Slide 75 text

Scenario: New Customer is retrieved by ID Given request body from file json/newCustomer.json When the client performs POST request on /customers Then status code is 201 And header Location end with customers/(.+) And assign variable "{(location)}" to header "Location" value When the client performs GET request on {(location)} Then status code is 200 And response body contains properties from file json/newCustomer.json Acceptance Test-Driven Development (ATDD)

Slide 76

Slide 76 text

ALWAYS TEST POINTS OF INTEGRATIONS FOR TRICKY CASES!

Slide 77

Slide 77 text

ALWAYS TEST INPUT

Slide 78

Slide 78 text

ALWAYS EXTENSIVELY TEST CODE, THAT MAKES YOU MONEY!

Slide 79

Slide 79 text

CODE COVERAGE

Slide 80

Slide 80 text

CODE COVERAGE IS YOUR SIDEKICK

Slide 81

Slide 81 text

CODE COVERAGE IS YOUR SIDEKICK NOT A COMPETITOR

Slide 82

Slide 82 text

TAKE AWAYS

Slide 83

Slide 83 text

TAKE AWAYS LET TESTS GUIDE YOUR HAND

Slide 84

Slide 84 text

TAKE AWAYS LET TESTS GUIDE YOUR HAND TEST FOR EACH FAILURE ACCOUTERED

Slide 85

Slide 85 text

TAKE AWAYS LET TESTS GUIDE YOUR HAND TEST FOR EACH FAILURE ACCOUTERED TEST MEANINGFUL CODE

Slide 86

Slide 86 text

TAKE AWAYS LET TESTS GUIDE YOUR HAND TEST FOR EACH FAILURE ACCOUTERED TEST MEANINGFUL CODE TEST-DOCUMENT PUBLIC API

Slide 87

Slide 87 text

BUT SOMETIMES HEAR OUT YOUR GUTS!

Slide 88

Slide 88 text

Q&A @AlexeyBuzdin #bycraft