Legacy Code
Quit Complaining, Start Fixing

Saturday, February 15, 14
What Is Legacy Code?

Saturday, February 15, 14
34.                                         }
35.  
36.                                 } else if (!data.getIsOffshore()) ...
What Is Legacy Code?

Code where the tests are an impediment,
not a benefit

Saturday, February 15, 14
Steps
Vent
But get it out of your system
Get it in a Harness
Verify the code around your new code
Add your Code

Saturday,...
Seams
A place where you can change existing
behavior without editing code
Objects, Linker, Preprocessor
Enabling Point

Sa...
var ParseRecurrenceDate = function (recurrencedata) {
var StartTime = DTSTART.exec(recurrencedata)[1];
var EndTime = DTEND...
     (will-mount [_]

        (let [{:keys [id-key filter tag-fn]} opts
              kill-chan (om/get-state owner :kill-...
e void paintBackgroundDisabledAndWindowMaximized(Graphics2D g) {
    roundRect = decodeRoundRect1();
    g.setPaint(decode...
Adapt Parameter
Create New Interface That you can fake
Wrap Hard to instantiate class
Move to interfaces that communicate
...
e void paintBackgroundDisabledAndWindowMaximized(GraphicsAdapter g) {
    roundRect = decodeRoundRect1();
    g.setPaint(d...
public class StubGraphicsAdapter implements GraphicsAdapter {
 
public void setPaint(java.awt.Color color) {
}
...
}
 
pub...
UIAlertView *alert = [[UIAlertView alloc] initWithTitle:@"Signup Unsuccessful"
message:reason
delegate:NULL
cancelButtonTi...
Extract and Override
Identify the call you want to extract
Create a new method on the current class
Override in test

Satu...
UIAlertView *alert =[[[[self class] alertViewClass] alloc] initWithTitle:@"Signup
message:reason
delegate:NULL
cancelButto...
+(Class) alertViewClass
{
return [UIAlertView class];
}
 
// In test file
@interface LoginViewControllerWithTestAlert : Lo...
Static Setter
Allow Subclassing a Singleton
Add a Static Setter
Add a Clear or Reset to avoid Test
Pollution

Saturday, Fe...
void MessageRouter::route(Message *message) {
Dispatcher *dispatcher =
ExternalRouter::instance()->getDispatcher();
if (di...
class ExternalRouter
{
private:
static ExternalRouter *_instance;

ExternalRouter();
public:
static ExternalRouter *instan...
class ExternalRouter
{
private:
static ExternalRouter *_instance;
protected:
ExternalRouter();
public:
static ExternalRout...
Higher Level Tests

Characterization Tests
In case of emergency break glass.

Saturday, February 15, 14
Resources
Working Effectively With Legacy Code
- Michael Feathers
http://www.reddit.com/r/badcode
@paytonrules (that’s me)...
Upcoming SlideShare
Loading in …5
×

Legacy codesmalltalk

396 views

Published on

0 Comments
0 Likes
Statistics
Notes
  • Be the first to comment

  • Be the first to like this

No Downloads
Views
Total views
396
On SlideShare
0
From Embeds
0
Number of Embeds
2
Actions
Shares
0
Downloads
2
Comments
0
Likes
0
Embeds 0
No embeds

No notes for slide

Legacy codesmalltalk

  1. 1. Legacy Code Quit Complaining, Start Fixing Saturday, February 15, 14
  2. 2. What Is Legacy Code? Saturday, February 15, 14
  3. 3. 34.                                         } 35.   36.                                 } else if (!data.getIsOffshore()) { // local 37.   38.                                         cash = data.getCashBalance(); 39.   40.                                         investment = data.getInvestmentBalance(); 41.   What Is Legacy Code? 42.                                 } 43.   44.                                 if (<hidden>.getmCurrentExchangeRate().getRate().compareTo(newBigDecimal("0.0000")) == 1) { 45.                                         // convert to current rate 46.                                         cash = cash.divide(<hidden>.getmCurrentExchangeRate().getRate(),BigDecimal.ROUND_UP); 47.                                         investment =investment.divide(<hidden>.getmCurrentExchangeRate().getRate(), BigDecimal.ROUND_UP); 48.                                 } 49.   50.                                 // investment slice 51.                                 item = new PieChartItem(); 52.                                 item.mLabel = res.getString(R.string.pcs_investment); 53.                                 item.mSliceValue = investment; 54.                                 item.mValue = investment.floatValue(); 55.                                 item.mColor = res.getColor(R.color.pcs_teal); 56.                                 slices.add(item); 57.   58.                                 // cash slice 59.                                 item = new PieChartItem(); 60.                                 item.mLabel = res.getString(R.string.pcs_cash); 61.                                 item.mSliceValue = cash; 62.                                 item.mValue = cash.floatValue(); 63.                                 item.mColor = res.getColor(R.color.pcs_biscuit); 64.                                 slices.add(item); 65.   66.                                 mPieChartList.add(slices); 67.                         } 68.   69.                 } 70.   Saturday, February 15, 14
  4. 4. What Is Legacy Code? Code where the tests are an impediment, not a benefit Saturday, February 15, 14
  5. 5. Steps Vent But get it out of your system Get it in a Harness Verify the code around your new code Add your Code Saturday, February 15, 14
  6. 6. Seams A place where you can change existing behavior without editing code Objects, Linker, Preprocessor Enabling Point Saturday, February 15, 14
  7. 7. var ParseRecurrenceDate = function (recurrencedata) { var StartTime = DTSTART.exec(recurrencedata)[1]; var EndTime = DTEND.exec(recurrencedata)[1]; if (StartTime.indexOf("T") > 0) { ... } var EndDate = RRULE.exec(recurrencedata)[1]; EndDate = new Date(parseInt(EndDate.substr(0, 4), 10), parseInt(EndDate.substr(4, 2), 10) - 1, parseInt(EndDate.substr(6, 2 10)); Saturday, February 15, 14
  8. 8.      (will-mount [_]         (let [{:keys [id-key filter tag-fn]} opts               kill-chan (om/get-state owner :kill-chan)               tx-chan (om/get-shared owner :tx-chan)               txs (chan)]           (assert (not (nil? tx-chan))             "om-sync requires shared :tx-chan pub channel with :txs topic")           (async/sub tx-chan :txs txs)           (om/set-state! owner :txs txs)           (go (loop []                 (let [dpath (om/path coll)                       [{:keys [path new-value new-state] :as tx-data} _] (<! txs)                       ppath (popn (- (count path) (inc (count dpath))) path)]                   (when (and (subpath? dpath path)                              (or (nil? filter) (filter tx-data)))                     (let [tag (if-not (nil? tag-fn) Saturday, February 15, 14
  9. 9. e void paintBackgroundDisabledAndWindowMaximized(Graphics2D g) {     roundRect = decodeRoundRect1();     g.setPaint(decodeGradient1(roundRect));     g.fill(roundRect);     roundRect = decodeRoundRect2();     g.setPaint(decodeGradient2(roundRect));     g.fill(roundRect);     rect = decodeRect1();     g.setPaint(color4);     g.fill(rect);     rect = decodeRect2();     g.setPaint(color5);     g.fill(rect);     rect = decodeRect3(); Saturday, February 15, 14
  10. 10. Adapt Parameter Create New Interface That you can fake Wrap Hard to instantiate class Move to interfaces that communicate responsibilities not implementation - to avoid over-mocking Saturday, February 15, 14
  11. 11. e void paintBackgroundDisabledAndWindowMaximized(GraphicsAdapter g) {     roundRect = decodeRoundRect1();     g.setPaint(decodeGradient1(roundRect));     g.fill(roundRect);     roundRect = decodeRoundRect2();     g.setPaint(decodeGradient2(roundRect));     g.fill(roundRect);     rect = decodeRect1();     g.setPaint(color4);     g.fill(rect);     rect = decodeRect2();     g.setPaint(color5);     g.fill(rect);     rect = decodeRect3(); Saturday, February 15, 14
  12. 12. public class StubGraphicsAdapter implements GraphicsAdapter {   public void setPaint(java.awt.Color color) { } ... }   public class JavaAwtGraphicsAdapter implements GraphicsAdapter { private Graphics2D g; public JavaAwtGraphicsAdapter(Graphics2D g) { this.g = g; } public void setPaint(java.awt.Color color) { this.g.setPaint(color); } Saturday, February 15, 14
  13. 13. UIAlertView *alert = [[UIAlertView alloc] initWithTitle:@"Signup Unsuccessful" message:reason delegate:NULL cancelButtonTitle:@"OK" otherButtonTitles:NULL]; Saturday, February 15, 14
  14. 14. Extract and Override Identify the call you want to extract Create a new method on the current class Override in test Saturday, February 15, 14
  15. 15. UIAlertView *alert =[[[[self class] alertViewClass] alloc] initWithTitle:@"Signup message:reason delegate:NULL cancelButtonTitle:@"OK" otherButtonTitles:NULL]; Saturday, February 15, 14
  16. 16. +(Class) alertViewClass { return [UIAlertView class]; }   // In test file @interface LoginViewControllerWithTestAlert : LoginViewController @end   @implementation LoginViewControllerWithTestAlert   +(Class) alertViewClass { return [TestAlert class]; }   @end Saturday, February 15, 14
  17. 17. Static Setter Allow Subclassing a Singleton Add a Static Setter Add a Clear or Reset to avoid Test Pollution Saturday, February 15, 14
  18. 18. void MessageRouter::route(Message *message) { Dispatcher *dispatcher = ExternalRouter::instance()->getDispatcher(); if (dispatcher != NULL) dispatcher->sendMessage(message; } Saturday, February 15, 14
  19. 19. class ExternalRouter { private: static ExternalRouter *_instance; ExternalRouter(); public: static ExternalRouter *instance(); }   ExternalRouter *ExternalRouter::_instance = 0;   ExternalRouter *ExternalRouter::instance() { if (_instance == 0) { _instance = new ExternalRouter(); } return _instance; } Saturday, February 15, 14
  20. 20. class ExternalRouter { private: static ExternalRouter *_instance; protected: ExternalRouter(); public: static ExternalRouter *instance(); static void setTestingInstance(ExternalRouter *newInstance); }   void ExternalRouter::setTestingInstance(ExternalRouter *newInstance) { delete _instance; _instance = newInstance; }   class TestingExternalRouter : public ExternalRouter { public: virtual void Dispatcher *getDispatcher() const { return new FakeDispatcher(); } } Saturday, February 15, 14
  21. 21. Higher Level Tests Characterization Tests In case of emergency break glass. Saturday, February 15, 14
  22. 22. Resources Working Effectively With Legacy Code - Michael Feathers http://www.reddit.com/r/badcode @paytonrules (that’s me) Bullets suck Saturday, February 15, 14

×