Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Getting out of Legacy with 3P (Protect-Prepare-...

Getting out of Legacy with 3P (Protect-Prepare-Produce) - TechExcellence meetup

See the presentation : https://www.youtube.com/watch?v=E2d2BYxOiME

Summary
When you write tests or refactor at the end of a story, or worse in a separate story, who gets the benefits? And when?

Unfortunately it's the next person who touches the code ... sometime in the future ... if we're lucky. Given that the tests remain relevant. And given that the refactoring actually helps with the new functionality, that we don't know yet ... 🤔

That means our efforts in refactoring and tests are primarily for other people, sometime in the future and of uncertain value to them. Is it surprising if we don't do much of it and let the code rot?

An alternative, that maximizes the ROI of the tests and the refactoring, would be the Protect-Prepare-Produce method 🧐.

Protect
Write quick and dirty(!) tests to protect refactoring in the next step. Beware this can hurt some sensitive viewers.

Prepare
Refactor in depth to make the new functionality easier. Also make the code testable and improve the tests written in the previous step.

Produce
Code the new functionality in TDD. Should be a piece of cake given the Prepare phase.

Being the primary beneficiaries of the testing and refactoring we do ourselves means more happiness. With a much better ROI on testing and refactoring, we're likely to have a lot more of it.

Let's make this clear with a few examples. Not the least what I mean by QUICK and DIRTY tests.

ABOUT JOHAN

Johan Martinsson is a freelance dev coach, passionate about code and software design.

A serial kata-creator and co-creator of conferences SnowCamp and AlpesCraft, facilitator of regular meetups since 2009, he often finds (good) excuses for showing code at conferences.

LinkedIn: https://www.linkedin.com/in/jomartinsson/
Twitter: https://twitter.com/johan_alps
GitHub: https://github.com/martinsson
Blog: http://martinsson-johan.blogspot.com

martinsson

April 05, 2023
Tweet

More Decks by martinsson

Other Decks in Technology

Transcript

  1. 3P

  2. 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
  3. Protect Just call the function Approval tests to assert the

    full text String result = receiptService.makeReceipt(panier, catalog, new TextPrinter()); Approvals.verify(result);
  4. 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);
  5. Prepare Extract the calculations (total + vat) Normal assertions for

    the total and VAT Keep one approval test for csv, one for text
  6. 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);
  7. 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
  8. Value of Information 50 % chance of 1000 in value.

    Cost is 200
 50% * (1000 - 200) + 50% * (0-200) = 300 Expected gain: Probability * Value - Cost of doing
  9. 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
  10. 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
  11. 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
  12. Value of Information Expected gain: Probability * Value - Cost

    of doing -250 -125 0 125 250 375 500 Useful Not useful Useful Not useful 300 350 Paying to know Paying to know 510
  13. Value of Information Expected gain: Probability * Value - Cost

    of doing -250 -125 0 125 250 375 500 Useful Not useful Useful Not useful 300 350 Paying to know Paying to know 510
  14. Value of Information Expected gain: Probability * Value - Cost

    of doing -250 -125 0 125 250 375 500 Useful Not useful Useful Not useful -700 -525 -350 -175 0 175 350 525 700 Useful Not useful Useful Not useful 300 350 Paying to know Paying to know 100 510
  15. Value of Information Expected gain: Probability * Value - Cost

    of doing -250 -125 0 125 250 375 500 Useful Not useful Useful Not useful -700 -525 -350 -175 0 175 350 525 700 Useful Not useful Useful Not useful 300 350 Paying to know Paying to know 100 510
  16. Types of refactorings Simpli fi cation Reduce illegal states Encode

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

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

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

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

    knowledge Make extensible (apply OCP) Which are good After?
  21. Ef fi ciency? Test at start of story Test at

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

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

    at end of story Replace with "micro increment” => TDD
  24. 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!
  25. ONE GOAL : MAKE IT SAFE TO REFACTOR - COVER

    ALL CASES - CAPTURE ALL BEHAVIOUR 3 P PROTECT
  26. 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 ! - …
  27. 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
  28. 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, } })
  29. 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) )
  30. Prepare Replace with Domain Events Separate code into 1. Loading

    2. Computation of desired state 3. Saving Isolate tests - most tests concern computation
  31. 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
  32. Work fl ow comparison 3P TEST LAST IMPRESSION OF MAKING

    PROGRESS MAKING PROGRESS IMPRESSION OF NO PROGRESS
  33. 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
  34. 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
  35. 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 Recap Photo by Steven Wright on Unsplash
  36. 3P