SAD10 - Refactoring

23
+ The Dark Art of Refactoring Systems Analysis and Design Michael Heron

description

This is a lecture on Systems Analysis and design. It focuses on refactoring.

Transcript of SAD10 - Refactoring

Page 1: SAD10 - Refactoring

+

The Dark Art of RefactoringSystems Analysis and DesignMichael Heron

Page 2: SAD10 - Refactoring

+Introduction

Refactoring is sometimes thought of as a vaguely ‘black art’ of programming.

That stems from a basic misunderstanding of what refactoring is all about.

Part of this impression comes from a sense of the subjectivity that goes into refactoring.

While it’s easy to identify code that is wrong, it’s less easy to identify which is the ‘best’ out of bits of ‘good’ code.

The ease at which a system can be refactored is influenced by the way that system is designed.

Page 3: SAD10 - Refactoring

+Refactoring and the Impact of Change Refactoring is an ‘invisible’ action.

If you do it right, no-one should know you’ve done anything at all.

Refactoring is not about adding extra functionality. It may be a precursor to this.

Refactoring is not about fixing bugs. Bugs may be fixed as a consequence of it.

Refactoring is about fixing the problems caused by code you ‘would have done correctly’ given the opportunity.

Page 4: SAD10 - Refactoring

+Refactoring and the Impact of Change Refactoring is highly dependent on the impact of

change that goes with your modifications. In object orientation, this is predicted by the visibility of

your methods and attributes.

The benefit of techniques such as abstraction and encapsulation can readily be seen when it comes time to refactor code. Refactoring an abstracted, encapsulated method is easy. Refactoring a system with complex side-effects and

distributed processing is a nightmare.

Refactoring allows us to redesign architecture in running programs.

Page 5: SAD10 - Refactoring

+The Aim of Refactoring

When we refactor, we’re looking to improve the quality of the code. Remove dead code Make inefficient code more efficient Make code more readable

Self-describing code is the best documentation you can provide.

Make code more maintainable.

When we refactor, we try to get the code looking like it would have done, if we’d have written it properly the first time.

Page 6: SAD10 - Refactoring

+A Simple Example

Consider the following simple class:

public class Example {private int bing;

public int getValue() {return bing;

}

public void setValue (int b) {bing = b;

}}

Refactoring can be as simple as changing the name of a variable to be more meaningful.

Page 7: SAD10 - Refactoring

+A Simple (?) Example

public class Example {public int bing;

public int getValue() {return bing;

}

public void setValue (int b) {bing = b;

}}

Depending on the impact of change, even changing a variable name can be problematic.

Page 8: SAD10 - Refactoring

+Impact of Change

There’s a simple hierarchy we can follow when working out the impact of change of refactoring: Private variables and methods have low impact Protected variables and methods have medium impact Public variables and methods have high impact.

Impact of Change relates to the maintainability of your code. How much of your code do you have to change?

As developers, we strive to ensure minimum impact of change. You need to labour under the assumption that if someone has

access to a method or variable, they have taken advantage of that.

Page 9: SAD10 - Refactoring

+Impact of Change

Structural elements of a system usually carry with them a high impact of change. It’s usually safe to specialise, it’s usually not safe to

generalise.

In all cases, we want to refactor in such a way that our changes have no impact on anyone else. Fellow developers, mainly.

All of this relates to the code that we produce at the end of a systems development project. But as a direct consequence is relates to our design. We don’t stop designing or analysing just because a system

is ‘finished’

Page 10: SAD10 - Refactoring

+Another Example

Let’s say we have a method to which we need to add a parameter – say we need getValue to accept an integer parameter:

public class Example {private int bing;

public int getValue() {return bing;

}

public void setValue (int b) {bing = b;

}}

Page 11: SAD10 - Refactoring

+Another Example

How do we do this? There are two real choices: Add the parameter to the method definition.

High impact of change – every other class making use of getValue will need to change.

Add in an overloaded method. Low impact of change.

However, there’s a trade-off here: Adding a parameter may require lots of code to

change. Adding an overloaded method may reduce

internal consistency.

Page 12: SAD10 - Refactoring

+Remit of Refactoring

Where does your remit for refactoring lie? It depends on how much of the code for which

you are responsible. This may extend over a whole program. It may extend over a handful of classes.

You can unilaterally refactor only those elements of the program for which you have responsibility.

There are few things more frustrating than finding your programs no longer work because of someone else’s refactoring…

Page 13: SAD10 - Refactoring

+A Third Example

public class Example {

private int value;

public int makeDesposit (int value, int rate) {

if (value > 100) {return -1;

}else if (valid < 0) {

return -1;}else {

if (rate < 30) {value = value * rate;

}else {

value = value * rate;/2 }

}}

return value;}

}

Page 14: SAD10 - Refactoring

+Code Aesthetics

The aesthetics of your code are important. They are usually a hint at the maintainability.

However, it’s important not to just discard complicated code as needing total refactoring. Old code may not be ugly, it may be battle-scarred.

However, as you gain in experience and confidence as a developer, you can generally tell where the bits of code needing attention lie.

Everyone has their own way of doing this – you might investigate the Wodehouse Method of Refactoring for one interesting example.

Page 15: SAD10 - Refactoring

+Code Aesthetics

One way to improve the aesthetics is to break complicated functionality out into separate methods. This fulfils a general rule of object oriented programming, in

that each method should have one responsibility only.

Complicated and nested structures are usually a good warning sign of the need to refactor. Your activity diagrams will help you understand this. Look for lots of loops, lots of branches.

If you see complicated structures, seek to simplify them. Strive to reduce the cyclomatic complexity.

Page 16: SAD10 - Refactoring

+Cyclomatic Complexity

Cyclomatic complexity is a software metric, and is used to determine how complicated a piece of code is.

It’s computed using the flow of logic through the constituent paths of a unit. A function, a class, or a whole system.

The higher the complexity, the more complicated the code. The more complicated the code, the harder it is to modify.

Think of your complexity as ‘the number of decisions made in a piece of source code’ It’s more complicated than that, but that’s good enough for

now.

Page 17: SAD10 - Refactoring

+A Third Example

public class Example {public int value;

private boolean getValid (int value) {if (value > 100 || value < 0) {

return false;}

return true;}

private int getRate (int rate) {int rate;

if (rate > 20 && rate < 30) {rate = value;

}else {

rate = value / 2;}

return rate;}

public int makeDeposit (int value, int rate) {int rate;

if (getValid (value) == false) {return -1;

}

rate = getRate (rate);

value = value * rate;

return value;

}}

Page 18: SAD10 - Refactoring

+Some Common Structual Refactoring Tasks Generalising classes. Specialising classes. Improving encapsulation. Lowering impact of change Merging subclasses into fields Extracting fields into subclasses Implementing interfaces Adding abstract classes Making better use of polymorphism. Reduce inconsistency.

Page 19: SAD10 - Refactoring

+Some Common Internal Refactoring Tasks Simplifying internal structures.

Improving variable names.

Simplifying logical comparisons

Substituting one algorithm for another

Consolidating conditionals

Extracting functionality into separate methods.

Page 20: SAD10 - Refactoring

+Refactoring and Test Driven Development Refactoring introduces no new functionality.

You can thus use the tests you have put in place previously.

Having a comprehensive, full test-suite ensures that your refactored code behaves identically to the previous code. The importance of that in a multi-developer environment

cannot be stressed enough.

We’ve referred to test driven development in the past. We write the tests before we write the code, so that when we

make any change we can ensure the whole thing works.

Refactoring doesn’t violate this rule. If it does, you’re not refactoring at all.

Page 21: SAD10 - Refactoring

+When Do We Refactor?

Refactoring is an ongoing process we do all the time. Yeah, right.

The ideal case is that we refactor our code on a continual basis. The realities of life dictate that we must prioritise. Generally, we refactor code that is actively

getting in the way. There’s also often a ‘wish list’ we keep as

developers of code that we regret…

Page 22: SAD10 - Refactoring

+When Do We Refactor?

We refactor when code ‘smells bad’ Code is duplicated across locations. There are unjustifiable ‘god objects’ When cohesion is too low When coupling is too high When people have been ‘too clever’ for their

own good.

http://www.soberit.hut.fi/mmantyla/BadCodeSmellsTaxonomy.htm has a good list of ‘bad smells’

Page 23: SAD10 - Refactoring

+Conclusion

Refactoring is the process of looking back at old designs and fixing them before they become problems. Preventative maintenance, in other words.

You are going to make mistakes when you develop a system. Nobody is perfect.

The ease with which you can fix those mistakes is going to be based on the designs that you produce. Think of refactoring as ‘design band aids’.

Bearing this in mind at the design stage can save much heartache in the long run.