Slide 1

Slide 1 text

PROTECT PREPARE PRODUCE 3P PROTECT - PREPARE - PRODUCE Johan MARTINSSON

Slide 2

Slide 2 text

Options for refactoring a legacy project

Slide 3

Slide 3 text

@Johan_alps

Slide 4

Slide 4 text

@Johan_alps

Slide 5

Slide 5 text

@Johan_alps

Slide 6

Slide 6 text

The more of the Just In Time, the better the state of the project

Slide 7

Slide 7 text

Words enable thought

Slide 8

Slide 8 text

3P PROTECT PREPARE PRODUCE

Slide 9

Slide 9 text

Ex 1: Receipt printer We want a html receipt and we already have text and csv Total price and VAT calculus is mixed with formatting String makeReceipt(productNames, catalog, receiptType) productNames, catalog, receiptType makeReceipt() text csv Photo by Michael Walter on Unsplash

Slide 10

Slide 10 text

Protect Just call the function and assert the result String result = receiptService.makeReceipt(panier, catalog, new TextPrinter()); String expectedOutput = " JP Gothié créations, Paris \n" + "-----------------------\n" + " chemise deluxe 199.99 €\n" + " veste frimeur 520.50 €\n" + " chaussures cuir croco® 410.00 €\n" + "\n" + "Total: 1035.92 TTC\n" + "TVA: 172.65 \n" + "-----------------------\n" + " JP Gothié vous remercie pour votre visite"; assertThat(result).isEqualTo(expectedOutput);

Slide 11

Slide 11 text

Prepare Extract the calculations (total + vat) Move tests to logic of total and VAT Keep one test for csv, one for text

Slide 12

Slide 12 text

Produce TDD the html receipt

Slide 13

Slide 13 text

Value of Information 50 % chance of 1000 in value. Cost is 200
 50% * (1000 - 200) + 50% * (0-200) = 300 If you pay 50 to know : - 50 50% * (1000 - 200) + 50% * (0 - 0) = 350 Expected gain: Probability * Value - Cost of doing 70 % chance of 1000 in value, 30% 2000 in penalty. Cost is still 200 70% * (1000-200) + 30% * (-2000-200) = 100 If you pay 50 to know : - 50 70% * (1000-200) + 30% * (- 0 - 0) = 510

Slide 14

Slide 14 text

Cheap way of knowing? Wait

Slide 15

Slide 15 text

Types of refactorings Simpli fi cation Reduce illegal states Encode knowledge Make extensible (apply OCP) Which are good After?

Slide 16

Slide 16 text

@Johan_alps Test at end of story

Slide 17

Slide 17 text

@Johan_alps Test at start of story

Slide 18

Slide 18 text

Ef fi ciency? Learning? Test at start of story Test at end of story Replace with "micro increment” => TDD

Slide 19

Slide 19 text

Do the tests help? When we refactor? When we add new features? Learning

Slide 20

Slide 20 text

3P PROTECT PREPARE PRODUCE

Slide 21

Slide 21 text

Ex 2: Lift pass pricing (kata) github.com/martinsson/Refactoring-Kata-Lift-Pass-Pricing We want a rest-route that calculates price of several lift-passes We’ve got one for a single lift-pass!

Slide 22

Slide 22 text

@Johan_alps Rest-mapping DB request Sending response anonymous function

Slide 23

Slide 23 text

Protect Provide a database Hit the REST-API Assert the results

Slide 24

Slide 24 text

Prepare Extract the unit-cost function Adapt tests to the testable interfaces

Slide 25

Slide 25 text

@Johan_alps GetPriceUsecase PriceDao Price prices (rest) http domain infra

Slide 26

Slide 26 text

Produce TDD a new multiple-pass cost function and wrap it in a rest-route

Slide 27

Slide 27 text

ONE GOAL : MAKE IT SAFE TO REFACTOR - COVER ALL CASES - CAPTURE ALL BEHAVIOUR 3 P PROTECT POSSIBLE COMPROMISES - STABILITY - ISOLATION - WORKS ON MY MACHINE - READABILITY ! - …

Slide 28

Slide 28 text

Quick and dirty tests FTW 💩

Slide 29

Slide 29 text

Refactoring tests To protect a refactoring: what do we care about? Test quality Importance Coverage Vital Captures all side-e ff ects Vital Sub-second Nice to have Stability (not fl aky) Nice to have Stability (regarding external data changes) Nice to have Readability Who cares Runs on any machine (CI) Wildly useless Allows new features Wildly useless

Slide 30

Slide 30 text

Types of tests and qualities Nice place Nice place

Slide 31

Slide 31 text

Test transition PROTECT PREPARE PRODUCE

Slide 32

Slide 32 text

PREPARATORY REFACTORING MAKE IT "UNIT" TESTABLE => OFTEN SIMILAR 3 P PREPARE

Slide 33

Slide 33 text

JUST IMPLEMENT USING TDD… … NO MATTER THE ORIGINAL CODE 3 P PRODUCE

Slide 34

Slide 34 text

Diff - trackers A multi-stage processing accumulates multiple mongodb queries that are executed at the end We want to change the request that is made Pb : unit testing the syntax of mongodb ? •Brittle •TDD for new features would be ridiculous shopping_cart_tracker.update({ "$set": { “ware_house”: warehouse_id, “stock_status": VERIFIED, } }) shopping_cart_events.add_event( StockVerified(warehouse_id) )

Slide 35

Slide 35 text

Protect Start mongodb locally Insert data for testing Assert side-e ff ects by reading from db

Slide 36

Slide 36 text

Prepare Replace with Domain Events Separate code into 1. Loading 2. Computation of desired state 3. Saving Isolate tests - most tests concern computation

Slide 37

Slide 37 text

Produce TDD the new behaviour,
 simply emitting new Events 
 and calculating desired state

Slide 38

Slide 38 text

@Johan_alps From : CodeScene A fraction of the e ff ort

Slide 39

Slide 39 text

Tooling?

Slide 40

Slide 40 text

Protect Just call the function Approval tests to assert the full text String result = receiptService.makeReceipt(panier, catalog, new TextPrinter()); String expectedOutput = " JP Gothié créations, Paris \n" + "-----------------------\n" + " chemise deluxe 199.99 €\n" + " veste frimeur 520.50 €\n" + " chaussures cuir croco® 410.00 €\n" + "\n" + "Total: 1035.92 TTC\n" + "TVA: 172.65 \n" + "-----------------------\n" + " JP Gothié vous remercie pour votre visite"; assertThat(result).isEqualTo(expectedOutput); String result = receiptService.makeReceipt(panier, catalog, new TextPrinter()); Approvals.verify(result);

Slide 41

Slide 41 text

Approval testing • Automated assertion on strings (and bitmaps, …) • External di ff -tools to inspect di ff erences • convert complex data to strings or json • Scrubbers to normalize dates, uuids, etc String result = receiptService.makeReceipt(panier, catalog, new TextPrinter()); Approvals.verify(result);

Slide 42

Slide 42 text

WireMock • stubs: somewhat useful for changing data or costly requests • veri fi cation: assertions on fi re-and-forget side e ff ects. Also useful for not damaging data

Slide 43

Slide 43 text

Work fl ow comparison 3P TEST LAST IMPRESSION OF MAKING PROGRESS MAKING PROGRESS IMPRESSION OF NO PROGRESS

Slide 44

Slide 44 text

When to 3P ? • We want to improve the code, but tests are lacking • We want something progressive • The code is the only spec • We don’t want bugs It maximises ROI, in a progressive fashion, associating it with stories. So

Slide 45

Slide 45 text

When not to 3P ? • When it is convenient to replace with new code • Possibly when specs are Known • We can TDD a replacement (only it’s not progressive) • When the project has no (little) ambition • Not every improvement can be linked to a story

Slide 46

Slide 46 text

Smaller is more

Slide 47

Slide 47 text

The mikado method

Slide 48

Slide 48 text

Better ROI => more of it Test and refactoring JIT => better ROI Decide late 3P allows for massive, incremental refactoring 3P enables TDD in any project 3P is safe (but maybe not SAFe) Adopting TDD? => Feedback on viability in days Smaller batches Great relations with the business Recap Photo by Steven Wright on Unsplash

Slide 49

Slide 49 text

3P https://martinsson-johan.blogspot.com/ 2022/11/breaking-out-of-legacy-with-3p.html