refactoring agile development project. lecture roadmap refactoring some issues to address when...
DESCRIPTION
Refactoring “… the process of changing a software system in such a way that it does not alter the external behaviour of the code, yet it improves the internal structure” -- Martin Fowler, RefactoringTRANSCRIPT
Refactoring
Agile Development Project
Lecture roadmap Refactoring Some issues to address when coding
Refactoring “… the process of changing a software system in such a
way that it does not alter the external behaviour of the code, yet it improves the internal structure”
-- Martin Fowler, Refactoring
In the nature of a software module… All software modules have three functions:
To perform its intended function while executing (Correct) To allow itself to be changed (Structured) To communicate to its readers (Appropriately Documented)
Any software module that violates one of the above three functions can be classified as ‘defective’ and needs to be fixed
Refactoring steps Build a set of test cases for the code that you want to
refactor (change) Changes made without the support of test cases are risky
Make changes in small/incremental steps It is easier to check if things do not work as expected this
way
Write code for humans Use known techniques for reference
Why refactor? We refactor to,
improve the design of software make the software easier to read/understand
Side effects of refactoring Helps find defects/bugs Helps communicate the design choices better, improving
overall productivity (this claim has not yet been proven, but is accepted by some)
When to refactor The following are suggested options:
Refactoring when you add a function (not the same as a method)
Refactor when you need to fix a defect Refactor as you perform a code review Refactor to remove ‘code smells’ or ‘bad design choices’
Refactoring helps To reuse code To explain intention and implementation separately To isolate change
Refactoring - Challenges Database schema changes and data migration issues Changing interfaces – this is tied to how test cases work Some architectural/design decisions are not always
easy to refactor and express in code What if you know the existing design is poor, but cannot
express it better?
Refactoring Vs re-engineering Vs re-building Refactoring may impact performance (but most of the
time it has no impact) Must be attempted only with support of proper tools
When writing code…. Intentionally consider the following issues:
Design of fields What type of method am I adding?
Utility/Mutator or Accessor?
Ensure that you consider the Cohesion and Coupling issues
Designing Fields and Methods
Good Code has the following attributes, Minimises Coupling Maximises Cohesion Avoids Special Data Values Uses Constants Wisely Is easy to maintain and understand Wisely commented
Designing Fields
Avoid using one variable to represent multiple attributes of a single class.
Common violation of this rule is by using Special Values within a variable with its own special meaning.
This Special Meaning is often documented too - however it does not make it anymore maintainable.
Designing Fields - Example
Attempting to determine if we can use Coffee Cup
class CoffeeCup // BAD - AVOID THIS WAY
{
private int innerCoffee;
public boolean isReadyForNextUse()
{ // If coffee cup isn't washed, then it's not ready
if (innerCoffee == 500) { return false; }
return true;
Designing Fields - Example
The aim of the previous example was to show code where a number denoted how full the cup was and therefore this was used to determine if the cup could be washed or not.
And the correct solution would be ……..
Designing Fields - Constants
Avoid magic numbers (like you would a plague) Depending on the required visibility,
Public - Used outside the class Private - Used internally only Protected – Avoid if possible
Take care when using Public Constants. Good Example: PI in a Math class.
Designing Methods
All methods can be classified into 3 categories, Utility Methods - Does NOT use or modify the
state of a class. State-View Methods - View only, no modification
of the state. State-Change Methods - Modifies the state of the
class or Object.
Utility Methods
Cosine function inside the Math Class is an excellent example of an Utility Method.
Utility Methods are normally defined as static and public.
Utility Methods should return a Value. Similar Utility Methods should be clubbed
together into a class.
State-View Methods
Get Methods in almost all Classes are State-View Methods.
They may or may not perform computation to determine the state.
Computations performed should NEVER change the state of the object.
State-Change Methods
Well any method that changes the state of the class or the instance of a class.
Invocation of these methods normally represent an “Event” to a class or object.
The code of the method “handles” the event, potentially changing the state of the class or the object.
Minimizing Method Coupling
The goal of a good design for a class is to minimize coupling. The degree of interdependence between a
method and its environment (other methods, objects, and classes).
The lesser the coupling, the more independent the method is and the more flexible the design.
Minimally Coupled Utility Methods
Takes input only from its parameters. Expresses its output only through its
parameters or its return value (or by throwing an exception)
Accepts as input only data that is actually needed by the method.
Returns as output only data that is actually produced by the method.
Minimally Coupled View Methods
Uses as input only parameters and the class variables of the class that declares method, plus (if an instance method) the instance variables of the object upon which the method is invoked.
Expresses its output only through its return value or by throwing an exception.
Minimally Coupled Change Methods
Uses as input only parameters and the class variables of the class that declare the method
If an instance method, the instance variables of the object upon which the method is invoked.
Minimally Coupled Change Methods
Expresses its output only through its return value, parameters, by throwing an exception, through the class variables of the class that declares the method, or (if an instance method) through the instance variables of the object upon which the method is invoked.
Method Cohesion
What do Method’s Do? Low Level: Accept Input Data, Operate on the
data and deliver data as output (although not always the case)
High Level: Concerned with responsibilities (Add Element to Vector, Convert to String)
Method Cohesion (cont.)
Minimizing Coupling needs one to look at the low level (as discussed before)
Cohesion should ideally be increased Cohesion looks at the degree to which a
method accomplishes one conceptual task Methods should aim to accomplish one single
conceptual task
Why Maximise Cohesion?
The more cohesive the methods, the more flexible the code
Cohesive methods increase flexibility by, Focussing on a single Conceptual Task Changing the behavior of a class will be easier
When is a method NOT cohesive?
Method signature is misleading!! Method includes tasks that are conceptually
quite different. Passes Control Down into Methods.
Control?: When a method uses a piece of input data not for processing, but for deciding how to process, then it is said that the input data is being used for control.
How About Exceptions?
Exceptions are good. Exceptions should be thought out well before coding. Exceptions pass control back up the chain, this is
considered a good design and coding practice.
Reduce Assumptions
Functionally Cohesive Code increase flexibility because they make fewer assumptions about the order in which actions are performed.
References Refactoring, Improving the design of existing code,
Martin Fowler, Addison Wesley Agile Software Development, Principles, Patterns and
Practices, Robert. C. Martin, Prentice Hall Object-Oriented Design Heuristics, Arthur J. Riel,
Addison Wesley