Part 3 of Softwerkskammer Dortmund's Racing Car Kata series. Katas are by Emily Bache and teach how to work with legacy code using SOLID principles an dependency breaking techniques by Michael Feathers.
2. static cling?
• think of cling wrap (🇩🇪 "Frischhaltefolie")
• static stuff (classes, methods) kind of sticks to your code
• they're almost inside their caller
• they destroy OOP's prime characteristic: dynamic dispatch
• called code determined at runtime
• allows for swapping implementations
• base for all test doubles
• global state should be at the edges of your system
• big problem in legacy code
3. your task
• Ticket Dispenser exercise
• https://github.com/emilybache/Racing-Car-Katas
• work in pairs + introduce yourselves
• git clone https://github.com/emilybache/Racing-Car-Katas.git
• choose your language
• get TicketDispenser under test
• en passant: which SOLID principles were violated?
4. approaches
• choose one dependency breaking technique:
• "introduce instance delegator"
• "introduce static setter"
• "replace global reference with getter"
• "encapsulate global references"
• use Google if you don't know them yet
• finish the task using that technique
• present the technique and your approach
• retrospective
cf.: Michael Feathers – "Working effectively with legacy code" (WELC)
6. "introduce instance delegator"
• undesirable static method from your SUT
• create instance method with same signature
• in class with static method
• make instance method delegate to static method
• replace static method calls with instance method calls
• also hand in an instance somehow
• e.g. "parameterize method" refactoring
7. "introduce static setter"
• when you still want to call the static method
• but you want to control its behavior
• introduce static setter
• breaks encapsulation
• also useful for breaking Singletons
• decrease access restrictions on constructor
• add setter for singleton field
• maybe create subclass and call setter using subclass
• use in setup() and teardown() methods to set internal state
8. "replace global reference with getter"
• a.k.a. "extract and override"
• a.k.a. "subclass for testing"
• the most basic dependency breaking technique
• create instance method that returns static instance
• in calling class
• override the instance method to return your mock
• extract interface if necessary
9. "encapsulate global references" (1)
• identify globals you want to encapsulate
• create a class with a good name
• copy the globals over
• if necessary move initializers to new class
• comment out the original declarations
• create global instance of new class
• lean on the compiler
• find all places where compilation breaks and use the new class name there
10. "encapsulate global references" (2)
• now use one of:
• "introduce static setter"
• "parameterize constructor"
• "parameterize method"
• "replace global reference with getter"
• does not look like much, but
• classes attract methods
• we have separation of global and local
• because we can use dependency breaking techniques