82
VANQUISHING THE FIRST DRAFT IN PRODUCTION CODE Refactoring Responsibly Drew Shefman @dshefman [email protected]

VANQUISHING THE FIRST DRAFT IN PRODUCTION CODE Refactoring Responsibly Drew Shefman @dshefman [email protected]

Embed Size (px)

Citation preview

Page 1: VANQUISHING THE FIRST DRAFT IN PRODUCTION CODE Refactoring Responsibly Drew Shefman @dshefman dshefman@squaredi.com

VANQUISHING T H E

F IRST DRAFTI N

PRODUCTION CODE

Refactoring Responsibly

Drew Shefman@dshefman

dshefman@squaredi .com

Page 2: VANQUISHING THE FIRST DRAFT IN PRODUCTION CODE Refactoring Responsibly Drew Shefman @dshefman dshefman@squaredi.com

Who am I?

Freelance Developer / Architect / Mentor 15+ years professional multimedia experience

Adobe Certified Flex Expert / InstructorProfessor @ University of HoustonConsultant @ Twin Technologies

Drew Shefman@dshefman

dshefman@squaredi .com

Page 3: VANQUISHING THE FIRST DRAFT IN PRODUCTION CODE Refactoring Responsibly Drew Shefman @dshefman dshefman@squaredi.com

Who are you?

Team member that

modifies or maintains

production level,

involved,

legacy code.

You touch the code

Significant financial cost if it breaks

Likely has appreciable code

smells

Code missing automated tests

Page 4: VANQUISHING THE FIRST DRAFT IN PRODUCTION CODE Refactoring Responsibly Drew Shefman @dshefman dshefman@squaredi.com

This presentation is NOT about

TheoriesTest Driven Development (TDD) guilt tripsYesterday’s feature additionContrived, convoluted code

Page 5: VANQUISHING THE FIRST DRAFT IN PRODUCTION CODE Refactoring Responsibly Drew Shefman @dshefman dshefman@squaredi.com

This presentation IS about

Practical answers for Why refactor? When to refactor? How to refactor?

Enabling real-world production code refactoring Extract & Override Characterization tests

Refactoring Observations

Page 6: VANQUISHING THE FIRST DRAFT IN PRODUCTION CODE Refactoring Responsibly Drew Shefman @dshefman dshefman@squaredi.com

Do NOT Wait

Page 7: VANQUISHING THE FIRST DRAFT IN PRODUCTION CODE Refactoring Responsibly Drew Shefman @dshefman dshefman@squaredi.com

WHAT IS IT?

WHY DO IT?

WHEN?

Refactoring?

Page 8: VANQUISHING THE FIRST DRAFT IN PRODUCTION CODE Refactoring Responsibly Drew Shefman @dshefman dshefman@squaredi.com

What is refactoring?

Definition

“A process of changing a

software system in such a

way that it DOES NOT alter

the external behavior of the

code yet improves its

internal structure”

-- Martin Fowler: Refactoring: Improving the Design of Existing Code

Page 9: VANQUISHING THE FIRST DRAFT IN PRODUCTION CODE Refactoring Responsibly Drew Shefman @dshefman dshefman@squaredi.com

What is refactoring?

Refactored code

VisualDefinition

Page 10: VANQUISHING THE FIRST DRAFT IN PRODUCTION CODE Refactoring Responsibly Drew Shefman @dshefman dshefman@squaredi.com

What refactoringis NOT

Adding functionality

Fixing bugs

Design enhancements

Discarding & rewriting

Substantial changes

Page 11: VANQUISHING THE FIRST DRAFT IN PRODUCTION CODE Refactoring Responsibly Drew Shefman @dshefman dshefman@squaredi.com

Ideally Before making functional changes

Realistically When the • smell • complexity• trepidation • fragility

exceeds personal thresholds

Specifically When all tests EXIST & PASS!

When to refactor?

Page 12: VANQUISHING THE FIRST DRAFT IN PRODUCTION CODE Refactoring Responsibly Drew Shefman @dshefman dshefman@squaredi.com

Increasing refactoring opportunities

When to refactor?

Page 13: VANQUISHING THE FIRST DRAFT IN PRODUCTION CODE Refactoring Responsibly Drew Shefman @dshefman dshefman@squaredi.com

When NOT to refactor

For the sake of refactoringToo many classes affectedPotentially momentarily

unusableWhile adding a featureWhile fixing a bugWhen you don’t have tests

to support your change

Page 14: VANQUISHING THE FIRST DRAFT IN PRODUCTION CODE Refactoring Responsibly Drew Shefman @dshefman dshefman@squaredi.com

When NOT to refactor

Supporting tests are missing

Page 15: VANQUISHING THE FIRST DRAFT IN PRODUCTION CODE Refactoring Responsibly Drew Shefman @dshefman dshefman@squaredi.com

Why is refactoring needed?

If it works the first time, why change it?

The majority of legacy code

is a first draft!

Page 16: VANQUISHING THE FIRST DRAFT IN PRODUCTION CODE Refactoring Responsibly Drew Shefman @dshefman dshefman@squaredi.com

Why not do it right the first time?

Anything important, deserves more than a first draft.

First Drafts*

40% not entirely hopeless, possibly reusable elements

5% GOLD

25% YAGNI

(You Ain’t Gonna Need It)

15%Random annoying inconsistencies

15%Code that

belongs elsewhere

* My personal non-empirical guess, based loosely on stats from copy

editors

Page 17: VANQUISHING THE FIRST DRAFT IN PRODUCTION CODE Refactoring Responsibly Drew Shefman @dshefman dshefman@squaredi.com

Why refactor?

We want to add value, not spend time searching for how it works

Page 18: VANQUISHING THE FIRST DRAFT IN PRODUCTION CODE Refactoring Responsibly Drew Shefman @dshefman dshefman@squaredi.com

Why stake holders dislike refactoring

Fear of breakingRefactoring =

uncontrolled && high riskNo ROI to “fix”

something that is “working”

Page 19: VANQUISHING THE FIRST DRAFT IN PRODUCTION CODE Refactoring Responsibly Drew Shefman @dshefman dshefman@squaredi.com

How proper refactoring placates stake holders

Fear of Breaking

Characterization tests

Uncontrolled / high risk

Small precision efforts, backed by automated tests

Low ROI, it is already working

What is there was “working”, but it won’t with the new feature.

no refactor = no feature || no bug

Page 20: VANQUISHING THE FIRST DRAFT IN PRODUCTION CODE Refactoring Responsibly Drew Shefman @dshefman dshefman@squaredi.com

How to refactor?

1. Define stopping point2. Identify class’s purpose3. Reorganize within class4. Characterization tests5. Extract & Override*6. All tests pass7. Modify the code8. Verify all tests pass

*optional

Page 21: VANQUISHING THE FIRST DRAFT IN PRODUCTION CODE Refactoring Responsibly Drew Shefman @dshefman dshefman@squaredi.com

How to refactor?

Resources

Page 22: VANQUISHING THE FIRST DRAFT IN PRODUCTION CODE Refactoring Responsibly Drew Shefman @dshefman dshefman@squaredi.com

How to refactor?

ToolsExtract Method

Extract InterfaceExtract VariableExtract Field…

Page 23: VANQUISHING THE FIRST DRAFT IN PRODUCTION CODE Refactoring Responsibly Drew Shefman @dshefman dshefman@squaredi.com

How to refactor?

Tools:Extract Method

PLUGIN: SourceMate by ElementRiver

IDE: IntelliJ by JetBrains

Page 24: VANQUISHING THE FIRST DRAFT IN PRODUCTION CODE Refactoring Responsibly Drew Shefman @dshefman dshefman@squaredi.com

Case Study:Order Presentation Model

• The Code• Define stopping point• Identify class purpose• Reorganize within class• Create characterization tests• Extract & Override• Verify all tests pass• Refactor

Page 25: VANQUISHING THE FIRST DRAFT IN PRODUCTION CODE Refactoring Responsibly Drew Shefman @dshefman dshefman@squaredi.com

Similar methods

openCreateNewOrderPopUp()

openQuickOrderPopup() openImportOrderPopup() exportOrder() showCancelNotEditableOrd

er() showModifyNotEditableOrd

er()

Original Class: Excessive Duplication

Page 26: VANQUISHING THE FIRST DRAFT IN PRODUCTION CODE Refactoring Responsibly Drew Shefman @dshefman dshefman@squaredi.com

Similar methodsDuplication Code Pattern

if (submittedOrder) {

alertUser(uniqueMessage)

}else{

showPopup(uniqueView)}

Original Class: Excessive Duplication

openCreateNewOrderPopUp()

openQuickOrderPopup() openImportOrderPopup() exportOrder() showCancelNotEditableOrd

er() showModifyNotEditableOrd

er()

Page 27: VANQUISHING THE FIRST DRAFT IN PRODUCTION CODE Refactoring Responsibly Drew Shefman @dshefman dshefman@squaredi.com

Original Code

public function openCreateNewOrderPopUp():void{

if (orderModel.inMSOState){

alertMSOToUser(RequestTypesBeforeSwitchingMSO.CREATE_NEW_ORDER)}else{

var createOrderPopup:CreateOrderView = new CreateOrderView() ;

new SM_PopupComponentEvent(createOrderPopup,true).dispatch()}

}

if (submittedOrder)alertUser(msg)

createPopup(instance)

Page 28: VANQUISHING THE FIRST DRAFT IN PRODUCTION CODE Refactoring Responsibly Drew Shefman @dshefman dshefman@squaredi.com

Before starting to refactor…

Predetermine specifically when

you are going to stop.

There is ALWAYS more to clean up.

Page 29: VANQUISHING THE FIRST DRAFT IN PRODUCTION CODE Refactoring Responsibly Drew Shefman @dshefman dshefman@squaredi.com

Determining when to stop

No changes to public interfacePopup & alert duplication eliminated100% test coverage on public interface

Page 30: VANQUISHING THE FIRST DRAFT IN PRODUCTION CODE Refactoring Responsibly Drew Shefman @dshefman dshefman@squaredi.com

Ideal Purpose Actual Purpose

Manage creating, reading, updating, & deleting*

orders by dispatchingbusiness events

Order CRUD eventsCreate alerts &

popupsHandle responses

from alerts & popupsPricing processingDate processingHolding order state

Indentifying Purpose

*CRUD

Page 31: VANQUISHING THE FIRST DRAFT IN PRODUCTION CODE Refactoring Responsibly Drew Shefman @dshefman dshefman@squaredi.com

Indentifying Purpose

Knowing

the purpose

helps determines

what stays in

and

what moves out.

Page 32: VANQUISHING THE FIRST DRAFT IN PRODUCTION CODE Refactoring Responsibly Drew Shefman @dshefman dshefman@squaredi.com

Intra-Class Organization

Rearrange / cluster related variables and methods

Organize imports

Remove disabled code (commented)

Remove UNUSED private variables / methods

Page 33: VANQUISHING THE FIRST DRAFT IN PRODUCTION CODE Refactoring Responsibly Drew Shefman @dshefman dshefman@squaredi.com

Use EXTREME CONFIDENCE while organizing

Page 34: VANQUISHING THE FIRST DRAFT IN PRODUCTION CODE Refactoring Responsibly Drew Shefman @dshefman dshefman@squaredi.com

Characterization Tests

Characterization test:

A means to describe (characterize) the actual behavior of an existing piece of software, and therefore protect existing behavior of legacy code against unintended changes via automated testing.

--Wikipedia

Page 35: VANQUISHING THE FIRST DRAFT IN PRODUCTION CODE Refactoring Responsibly Drew Shefman @dshefman dshefman@squaredi.com

Characterization Tests

One method at a timeExercise the ENTIRE method

Testing might not be easy.

Page 36: VANQUISHING THE FIRST DRAFT IN PRODUCTION CODE Refactoring Responsibly Drew Shefman @dshefman dshefman@squaredi.com

Testing Challenges

public function openCreateNewOrderPopUp():void{

if (orderModel.inMSOState){

alertMSOToUser(RequestTypesBeforeSwitchingMSO.CREATE_NEW_ORDER)

}else{

var createOrderPopup:CreateOrderView = new CreateOrderView() ;

new SM_PopupComponentEvent(createOrderPopup,true).dispatch()}

}

Dependency to OrderModel• Must exist• Must be in correct state

Page 37: VANQUISHING THE FIRST DRAFT IN PRODUCTION CODE Refactoring Responsibly Drew Shefman @dshefman dshefman@squaredi.com

Testing Challenges

public function openCreateNewOrderPopUp():void{

if (orderModel.inMSOState){

alertMSOToUser(RequestTypesBeforeSwitchingMSO.CREATE_NEW_ORDER)

}else{

var createOrderPopup:CreateOrderView = new CreateOrderView() ;

new SM_PopupComponentEvent(createOrderPopup,true).dispatch()}

}

Private method, calling Alert.show()

• Creates a visual element• Difficult to verify

Page 38: VANQUISHING THE FIRST DRAFT IN PRODUCTION CODE Refactoring Responsibly Drew Shefman @dshefman dshefman@squaredi.com

Testing Challenges

public function openCreateNewOrderPopUp():void{

if (orderModel.inMSOState){

alertMSOToUser(RequestTypesBeforeSwitchingMSO.CREATE_NEW_ORDER)

}else{

var createOrderPopup:CreateOrderView = new CreateOrderView() ;

new SM_PopupComponentEvent(createOrderPopup,true).dispatch()}

}

Cairngorm 2, static event dispatcher• Event doesn’t broadcast from this

class• Annoying to capture

Page 39: VANQUISHING THE FIRST DRAFT IN PRODUCTION CODE Refactoring Responsibly Drew Shefman @dshefman dshefman@squaredi.com

Testing Challenges

public function openCreateNewOrderPopUp():void{

if (orderModel.inMSOState){

alertMSOToUser(RequestTypesBeforeSwitchingMSO.CREATE_NEW_ORDER)

}else{

var createOrderPopup:CreateOrderView = new CreateOrderView() ;

new SM_PopupComponentEvent(createOrderPopup,true).dispatch()}

}

Dependency to orderModel

Private method, calling Alert.show

Cairngorm 2, static event dispatcher

Page 40: VANQUISHING THE FIRST DRAFT IN PRODUCTION CODE Refactoring Responsibly Drew Shefman @dshefman dshefman@squaredi.com

Ill-suited Suitable

OrderModel instance Many other

dependencies Not part of the testing

“unit”

Mocking Introducing an

unfamiliar framework was not an appropriate option at the time

Extract & Override Improves readability Enables dependency

breaking within tests Immediately

understandable

Challenges: Dependency to OrderModel

Page 41: VANQUISHING THE FIRST DRAFT IN PRODUCTION CODE Refactoring Responsibly Drew Shefman @dshefman dshefman@squaredi.com

Original Extracted Method

if (orderModel.inMSOState)…

if (modifyingSubmittedOrder())…

protected function modifyingSubmittedOrder():Boolean

{ return orderModel.inMSOState}

Extract Method

Potential for dependency elimination in subclass

Page 42: VANQUISHING THE FIRST DRAFT IN PRODUCTION CODE Refactoring Responsibly Drew Shefman @dshefman dshefman@squaredi.com

Subclass: OrderPresentationModelTester

public class OrderPresentationModelTester extends OrderPresentationModel

{public var isModifiyingSubmittedOrder:Boolean = false;

override protected function modifyingSubmittedOrder():Boolean{

return isModifiyingSubmittedOrder;}

}

Page 43: VANQUISHING THE FIRST DRAFT IN PRODUCTION CODE Refactoring Responsibly Drew Shefman @dshefman dshefman@squaredi.com

OrderPresentationModelTest

[Test]public function

openCreateNewOrderPopup_NotMSO_PopupEventWCreateOrderView():void

{var orderPresentationModel:OrderPresentationModel =

new OrderPresentationModelTester();

orderPresentationModel.openCreateNewOrderPopUp();fail(“The test compiles and fails… tests are working”);

}

Page 44: VANQUISHING THE FIRST DRAFT IN PRODUCTION CODE Refactoring Responsibly Drew Shefman @dshefman dshefman@squaredi.com

Test Fails – This is good

Page 45: VANQUISHING THE FIRST DRAFT IN PRODUCTION CODE Refactoring Responsibly Drew Shefman @dshefman dshefman@squaredi.com

What are we testing again?

public function openCreateNewOrderPopUp():void{

if (modifyingSubmittedOrder()){

alertMSOToUser(RequestTypesBeforeSwitchingMSO.CREATE_NEW_ORDER)}else{

var createOrderPopup:CreateOrderView = new CreateOrderView() ;

new SM_PopupComponentEvent(createOrderPopup,true).dispatch()}

}

Test that event is dispatched with a 2 item payload

Page 46: VANQUISHING THE FIRST DRAFT IN PRODUCTION CODE Refactoring Responsibly Drew Shefman @dshefman dshefman@squaredi.com

Reminder – not ideal environment

Unfortunately, we are not here.

We are here.

Page 47: VANQUISHING THE FIRST DRAFT IN PRODUCTION CODE Refactoring Responsibly Drew Shefman @dshefman dshefman@squaredi.com

CairngormEventRecorder

public class CairngormEventRecorder{

public static function create():CairngormEventRecorder{

var rtn:CairngormEventRecorder = new CairngormEventRecorder();CairngormEventDispatcher.addEventListener(

SM_PopupComponentEvent.EVENT, rtn.recordEvent,false,0,true);

return rtn;}

public static function destroy(inst:CairngormEventRecorder):void{

CairngormEventDispatcher.removeEventListener(SM_PopupComponentEvent.EVENT, inst.recordEvent);

}

}

Capture Cairngorm

events minimizing

memory leaks

Page 48: VANQUISHING THE FIRST DRAFT IN PRODUCTION CODE Refactoring Responsibly Drew Shefman @dshefman dshefman@squaredi.com

CairngormEventRecorder - Continued

public class CairngormEventRecorder{

public var storedEvents:Array = [];

public function recordEvent(e:Event):void{

storedEvents.push(e);}

public function getLastEvent():Event{

var len:int = storedEvents.length if (len >0){return Event(storedEvents[len]);}return null;

}

}

Save / retrieve

dispatchedCairngorm

events

Page 49: VANQUISHING THE FIRST DRAFT IN PRODUCTION CODE Refactoring Responsibly Drew Shefman @dshefman dshefman@squaredi.com

OrderPresentationModelTest

[Test] public function

openCreateNewOrderPopup_NotMSO_PopupEventWCreateOrderView():void{

var eventRecorder:CairngormEventRecorder = CairngormEventRecorder.create();

var orderPresentationModel:OrderPresentationModel = new OrderPresentationModelTester();orderPresentationModel.openCreateNewOrderPopUp();var lastEvent: SM_PopupComponentEvent = eventRecorder.getLastEvent() as SM_PopupComponentEvent ;

CairngormEventRecorder.destroy(eventRecorder);

assertNotNull(“Not Null”, lastEvent);assertTrue(“Popup Component”, lastEvent.component is CreateOrderView);assertTrue(“Modal”, lastEvent.modal);

}

Man

ag

e

Eve

nt

Cap

ture

Page 50: VANQUISHING THE FIRST DRAFT IN PRODUCTION CODE Refactoring Responsibly Drew Shefman @dshefman dshefman@squaredi.com

OrderPresentationModelTest

[Test] public function

openCreateNewOrderPopup_NotMSO_PopupEventWCreateOrderView():void{

var eventRecorder:CairngormEventRecorder = CairngormEventRecorder.create();

var orderPresentationModel:OrderPresentationModel = new OrderPresentationModelTester();orderPresentationModel.openCreateNewOrderPopUp();var lastEvent: SM_PopupComponentEvent = eventRecorder.getLastEvent() as SM_PopupComponentEvent ;

CairngormEventRecorder.destroy(eventRecorder);

assertNotNull(“Not Null”, lastEvent);assertTrue(“Popup Component”, lastEvent.component is CreateOrderView);assertTrue(“Modal”, lastEvent.modal);

}

SE

TU

P

Page 51: VANQUISHING THE FIRST DRAFT IN PRODUCTION CODE Refactoring Responsibly Drew Shefman @dshefman dshefman@squaredi.com

OrderPresentationModelTest

[Test] public function

openCreateNewOrderPopup_NotMSO_PopupEventWCreateOrderView():void{

var eventRecorder:CairngormEventRecorder = CairngormEventRecorder.create();

var orderPresentationModel:OrderPresentationModel = new OrderPresentationModelTester();orderPresentationModel.openCreateNewOrderPopUp();var lastEvent: SM_PopupComponentEvent = eventRecorder.getLastEvent() as SM_PopupComponentEvent ;

CairngormEventRecorder.destroy(eventRecorder);

assertNotNull(“Not Null”, lastEvent);assertTrue(“Popup Component”, lastEvent.component is CreateOrderView);assertTrue(“Modal”, lastEvent.modal);

}

TE

ST

S

Page 52: VANQUISHING THE FIRST DRAFT IN PRODUCTION CODE Refactoring Responsibly Drew Shefman @dshefman dshefman@squaredi.com

All Tests Pass

Page 53: VANQUISHING THE FIRST DRAFT IN PRODUCTION CODE Refactoring Responsibly Drew Shefman @dshefman dshefman@squaredi.com

Original Extracted Method

private function alertMSOToUser (requestType:String):

void{

… Alert.show(requestType)}

private function alertMSOToUser (requestType:String):

void{

… createAlert(requestType)}

protected function createAlert(msg:String):void

{Alert.show(msg)

}

Extract & Override: alertMSOToUser

* Other 7 arguments not

shown for simplicity

Page 54: VANQUISHING THE FIRST DRAFT IN PRODUCTION CODE Refactoring Responsibly Drew Shefman @dshefman dshefman@squaredi.com

Subclass: OrderPresentationModelTester

public class OrderPresentationModelTester extends OrderPresentationModel

{…

public var alertMsg:String = “”;

override protected function createAlert(msg:String):void{

alertMsg = msg;}

}

Page 55: VANQUISHING THE FIRST DRAFT IN PRODUCTION CODE Refactoring Responsibly Drew Shefman @dshefman dshefman@squaredi.com

SE

TU

P

OrderPresentationModelTest - 2nd Test

[Test]public function

openCreateNewOrderPopup_IsMSO_AlertResubmitModifiedSubmitedOrder():void

{ …

var expectedString:String …orderPresentationModel.isModifyingSubmittedOrder = true;orderPresentationModel.openCreateNewOrderPopUp();var alertMsg:String = orderPresentationModel.alertMsg;

assertEquals(expectedString, alertMsg);

}Using Extract & Override, isolate Alert.show into

its own method

Trap and record arguments and assert against those

Page 56: VANQUISHING THE FIRST DRAFT IN PRODUCTION CODE Refactoring Responsibly Drew Shefman @dshefman dshefman@squaredi.com

TE

ST

OrderPresentationModelTest - 2nd Test

[Test]public function

openCreateNewOrderPopup_IsMSO_AlertResubmitModifiedSubmitedOrder():void

{ …

var expectedString:String …orderPresentationModel.isModifyingSubmittedOrder = true;orderPresentationModel.openCreateNewOrderPopUp();var alertMsg:String = orderPresentationModel.alertMsg;

assertEquals(expectedString, alertMsg);

}

Page 57: VANQUISHING THE FIRST DRAFT IN PRODUCTION CODE Refactoring Responsibly Drew Shefman @dshefman dshefman@squaredi.com

All Tests Pass

Page 58: VANQUISHING THE FIRST DRAFT IN PRODUCTION CODE Refactoring Responsibly Drew Shefman @dshefman dshefman@squaredi.com

Review – Getting it under test

Extract methods (Use the tools)

Override methods to eliminate dependencies

Create helper objects if needed

Test everything that characterizes what is currently there.

Page 59: VANQUISHING THE FIRST DRAFT IN PRODUCTION CODE Refactoring Responsibly Drew Shefman @dshefman dshefman@squaredi.com

Add more tests

Our major smell was duplicationGet the duplicated methods under

test

Page 60: VANQUISHING THE FIRST DRAFT IN PRODUCTION CODE Refactoring Responsibly Drew Shefman @dshefman dshefman@squaredi.com

All Tests Pass

Page 61: VANQUISHING THE FIRST DRAFT IN PRODUCTION CODE Refactoring Responsibly Drew Shefman @dshefman dshefman@squaredi.com

Can we make REAL changes yet?!

Page 62: VANQUISHING THE FIRST DRAFT IN PRODUCTION CODE Refactoring Responsibly Drew Shefman @dshefman dshefman@squaredi.com

All Tests Pass – Refactoring Ready

Page 63: VANQUISHING THE FIRST DRAFT IN PRODUCTION CODE Refactoring Responsibly Drew Shefman @dshefman dshefman@squaredi.com

Reminder –NO (FUNCTIONAL) CHANGE

Committed to stabilityEliminated duplicationImproved

maintainabilityReduced complexityIdentified

inconsistencies

Page 64: VANQUISHING THE FIRST DRAFT IN PRODUCTION CODE Refactoring Responsibly Drew Shefman @dshefman dshefman@squaredi.com

Original Code

public function openCreateNewOrderPopUp():void{

if (orderModel.inMSOState){

alertMSOToUser(RequestTypesBeforeSwitchingMSO.CREATE_NEW_ORDER)}else{

var createOrderPopup:CreateOrderView = new CreateOrderView() ;

new SM_PopupComponentEvent(createOrderPopup,true).dispatch()}

}

Page 65: VANQUISHING THE FIRST DRAFT IN PRODUCTION CODE Refactoring Responsibly Drew Shefman @dshefman dshefman@squaredi.com

Refactored Code

public function openCreateNewOrderPopUp():void{

if (modifyingSubmittedOrder())){

createAlert_ModifySubmittedOrder_Confirmation();}else{

createPopup_CreateNewOrder();

}}

Page 66: VANQUISHING THE FIRST DRAFT IN PRODUCTION CODE Refactoring Responsibly Drew Shefman @dshefman dshefman@squaredi.com

if ( orderModel.inMSOState ) { alertMSOToUser(RequestTypesBeforeSwitchingMSO.CREATE_NEW_ORDER)} else {

var createOrderPopup:CreateOrderView = new CreateOrderView() ;

new SM_PopupComponentEvent(createOrderPopup,true).dispatch()}

if ( modifyingSubmittedOrder() ) { createAlert_ModifySubmittedOrder_Confirmation();} else {

createPopup_CreateNewOrder();}

Original & Refactored CodeO

RIG

INA

LR

EFA

CT

OR

ED

Page 67: VANQUISHING THE FIRST DRAFT IN PRODUCTION CODE Refactoring Responsibly Drew Shefman @dshefman dshefman@squaredi.com

That’s it?!

It looks nearly the same?

It *should*

It does the same thing

100% API test coverage

Duplication eliminated

Consistent method naming

Page 68: VANQUISHING THE FIRST DRAFT IN PRODUCTION CODE Refactoring Responsibly Drew Shefman @dshefman dshefman@squaredi.com

Refactored Consistent Protected Methods

createPopup_CreateNewOrder() createPopup_QuickOrderEntry() createPopup_ImportOrder() createPopup_ExportOrder() createPopup_CancelOrderWithNonEditableItems() createPopup_ModifyOrderWithNonEditableItems() createPopup(type)

  createAlert_OrderPastCutOff() createAlert_UnableToModifySubmittedOrder() createAlert_DeleteOrder_Confirmation() createAlert_CancelOrder_Confirmation() createAlert_ModifyOrder_Confirmation() createAlert_CancelSubmittedOrder_Confirmation() createAlert(msg)

Page 69: VANQUISHING THE FIRST DRAFT IN PRODUCTION CODE Refactoring Responsibly Drew Shefman @dshefman dshefman@squaredi.com

Moving out responsibilities

public function createPopup(type:String):void{ var popup:UIComponent = popupFactory.create(type); new SM_PopupComponentEvent(popup,true).dispatch();}

public function createAlert(msg:String):void{ alertFactory.create(msg)}

Externalized object

creation

Page 70: VANQUISHING THE FIRST DRAFT IN PRODUCTION CODE Refactoring Responsibly Drew Shefman @dshefman dshefman@squaredi.com

Other Refactoring Benefits

Alert inconsistencies identified & backlogged

mx.Alert.show()

spark.Alert.show()

CustomAlert.show()

Page 71: VANQUISHING THE FIRST DRAFT IN PRODUCTION CODE Refactoring Responsibly Drew Shefman @dshefman dshefman@squaredi.com

Metrics

Original Refactored

Public methods 58 58

Public variables 28 28

Non-public methods 18 57

PMD errors 23 4

PMD warnings 37 13

Import statements 157 99

Tested methods 0 58

Page 72: VANQUISHING THE FIRST DRAFT IN PRODUCTION CODE Refactoring Responsibly Drew Shefman @dshefman dshefman@squaredi.com

LESSONS LEARNEDAND

OTHER DISCOVERIES

Observations

Page 73: VANQUISHING THE FIRST DRAFT IN PRODUCTION CODE Refactoring Responsibly Drew Shefman @dshefman dshefman@squaredi.com

Make a 2nd Draft

Anything that is important deserves / demands more than a first draft.

Page 74: VANQUISHING THE FIRST DRAFT IN PRODUCTION CODE Refactoring Responsibly Drew Shefman @dshefman dshefman@squaredi.com

Be Responsible

Refactor responsiblyOnly modify once tests are in place

Page 75: VANQUISHING THE FIRST DRAFT IN PRODUCTION CODE Refactoring Responsibly Drew Shefman @dshefman dshefman@squaredi.com

Work small

Work in tiny increments

Refactoring is precision surgery

Refactoring != rewriting from scratch

Page 76: VANQUISHING THE FIRST DRAFT IN PRODUCTION CODE Refactoring Responsibly Drew Shefman @dshefman dshefman@squaredi.com

Extract & Override Dependencies

Isolate Creation code Evaluation code Control code UI Code

Page 77: VANQUISHING THE FIRST DRAFT IN PRODUCTION CODE Refactoring Responsibly Drew Shefman @dshefman dshefman@squaredi.com

Q&A

D r e w S h e f m a n@ d s h e f m a nd s h e f m a n @ s q u a r e d i . c o m

This presenta t ion* i s a t

h t tp : / /squared i .b logspot . com

* a n d s e v e r a l o t h e r r e f a c t o r i n g p o s t s

Page 78: VANQUISHING THE FIRST DRAFT IN PRODUCTION CODE Refactoring Responsibly Drew Shefman @dshefman dshefman@squaredi.com
Page 79: VANQUISHING THE FIRST DRAFT IN PRODUCTION CODE Refactoring Responsibly Drew Shefman @dshefman dshefman@squaredi.com
Page 80: VANQUISHING THE FIRST DRAFT IN PRODUCTION CODE Refactoring Responsibly Drew Shefman @dshefman dshefman@squaredi.com

Practice

Use code katas, like the Gilded Rose, to practice refactoring in a safe environment.

https://github.com/dshefman/GildedRoseAS3

AS3 + other language versions:http://craftsmanship.sv.cmu.edu/

posts/gilded-rose-kata

Page 81: VANQUISHING THE FIRST DRAFT IN PRODUCTION CODE Refactoring Responsibly Drew Shefman @dshefman dshefman@squaredi.com

Only add value

Refactor only if it adds value to the business

Page 82: VANQUISHING THE FIRST DRAFT IN PRODUCTION CODE Refactoring Responsibly Drew Shefman @dshefman dshefman@squaredi.com

Respect

“Regardless of what we discover, we understand and truly believe that everyone did the best job they could, given what they knew at the time, their skills and abilities, the resources available, and the situation at hand.”

-- Retrospective Prime Directive

http://www.retrospectives.com/pages/retroPrimeDirective.html