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

3P (Protect-Prepare-Produce) to get out of Lega...

3P (Protect-Prepare-Produce) to get out of Legacy - BreizCamp

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

June 29, 2023
Tweet

More Decks by martinsson

Other Decks in Programming

Transcript

  1. 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
  2. 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);
  3. Prepare Extract the calculations (total + vat) Move tests to

    logic of total and VAT Keep one test for csv, one for text
  4. 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
  5. Types of refactorings Simpli fi cation Reduce illegal states Encode

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

    at end of story Replace with "micro increment” => TDD
  7. 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!
  8. 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 ! - …
  9. 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
  10. 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) )
  11. Prepare Replace with Domain Events Separate code into 1. Loading

    2. Computation of desired state 3. Saving Isolate tests - most tests concern computation
  12. 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);
  13. 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);
  14. 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
  15. Work fl ow comparison 3P TEST LAST IMPRESSION OF MAKING

    PROGRESS MAKING PROGRESS IMPRESSION OF NO PROGRESS
  16. 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
  17. 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
  18. 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