A Very Common Series of Techniques Refactoring A Very Common Series of Techniques Copyright © 2016 Curt Hill
Introduction Refactoring is the process of restructuring code It should retain the same behavior It has a different and better structure The structure is the form and number of classes, methods and functions It should only change non-functional attributes Renaming an entity is the simplest form Most are much more complicated Copyright © 2016 Curt Hill
Once More Refactoring is a disciplined technique for restructuring an existing body of code Altering its internal structure without changing its external behavior A series of small behavior preserving transformations Each transformation does little Since each refactoring is small, it’s less likely to go wrong The system is kept fully working after each small refactoring, reducing the chances that a system can get seriously broken during the restructuring www.Refactoring.com Copyright © 2016 Curt Hill
Why Increases maintainability Increase extensibility We refactor to improve design We refactor when the code smells Copyright © 2016 Curt Hill
Code Smell Poor design that will impede future enhancements or modifications Typically loaded with technical debt Smells are certain structures in the code that indicate violation of fundamental design principles and negatively impact design quality Martin Fowler: a code smell is a surface indication that usually corresponds to a deeper problem in the system Code may smell and still work Copyright © 2016 Curt Hill
Renaming Example In languages with complex namespaces (such Java and C++) even a simple rename of a variable may be exciting Suppose the variable has the same name as a function that is called Simple string replace yields syntax errors Thus, code analysis is required Copyright © 2016 Curt Hill
Transformations Extraction Extract Base Class Extract Component Class Pull up Push down Copyright © 2016 Curt Hill
Extraction This process is taking a function that has grown too large and segment it into smaller pieces Grown? Good design suggests that functions should be of modest size – they are more understandable Typically what happens is that more responsibilities were given the function or the simple algorithm was replaced by a more complex one Copyright © 2016 Curt Hill
Function Extraction What we are looking for are pieces of the large function that are: Universal – that is can be reused What we are looking for is a function that could be used in other contexts Self contained This will make it easier to extract Copyright © 2016 Curt Hill
Example 1 Consider a C++ function that inputs a line and counts the number of a certain character that is in it void count_char_input(char c,int & count){ char str[MAX]; cin.getline(str, MAX); int len = strlen(str); count = 0; for(int i=0;i<len;i++) if(str[i]==c) count++; } Copyright © 2016 Curt Hill
Commentary Although this is not a “large” function it is a candidate for refactoring It has two separate purposes Read in a line Count the number of a particular character that exists in the line These could be two separate functions called by a third It would be good to at least remove the counter function Copyright © 2016 Curt Hill
Example 2 Consider the refactored functions int count_char_string(char * str, char c){ count = 0; int len = strlen(str); for(int i=0;i<len;i++) if(str[i]==c) count++; } void count_char_input(char c,int & count){ char str[MAX]; cin.getline(str, MAX); count = count_char_string(str,c); Copyright © 2016 Curt Hill
Commentary The functionality of the code is the same The structure is different There exists the possibility that count_char_string could be used by a function that does not delete the string that has been read in Copyright © 2016 Curt Hill
Self Contained Sometimes we need to reduce the size of a function There is no “universal” code it it We just do so to make the function a better size Copyright © 2016 Curt Hill
Extraction Process Select a block for extraction Block must be complete from a syntax point of view We get entire loops, entire decisions Cut this out and plant into a new function Convert all of the variables of the code into one of: Parameters (by value or reference) Local variables Global variables Copyright © 2016 Curt Hill
Variables again A local variable must be set before used Global variable in original will continue as a global variable Value parameters are preferred Its value must not be used later in the original If not use a reference parameter Copyright © 2016 Curt Hill
Extract Base Class Used when we want to add new functionality to class without much change to it Classes may grow too large just like functions Happens when the original design put too much in a single class Often becomes obvious when there is a need for new functionality Consider the matrix example Copyright © 2016 Curt Hill
Matrix Example class Matrix { double values[100][100]; int columns, rows; public: Matrix(); void inverse(); void multiply(Matrix &); double get(int,int); void put(double, int, int); }; Copyright © 2016 Curt Hill
Continued Simple 100 by 100 matrix of doubles suitable for linear algebra usage Now suppose we get a request: Allow the possibility of a either a sparse or dense matrix A sparse matrix has the majority of its values as zero They are frequently used and frequently larger than 100 by 100 so may use excessive memory Now what? Copyright © 2016 Curt Hill
Discussion We do not want to store both a dense and sparse matrix in the same class We need an additional class With the exception of the constructors the public method signatures would be exactly the same Only the implementations would be different We need an abstract base class! Copyright © 2016 Curt Hill
An Abstract Base Class class AbstractMatrix { int columns, rows; public: AbstractMatrix(); void inverse(); void multiply(AbstractMatrix &); double get(int,int)=0; void put(double, int, int)=0; }; Copyright © 2016 Curt Hill
Commentary Get and put are implementation specific Inverse and multiply are not as long as they use get and put Thus AbstractMatrix will implement them The other two will use them Copyright © 2016 Curt Hill
Dense class DenseMatrix: public AbstractMatrix { double values[100][100]; public: DenseMatrix(); double get(int,int); void put(double, int, int); }; Copyright © 2016 Curt Hill
Sparse class SparseMatrix: public AbstractMatrix { list <Row> values; public: SparseMatrix(); double get(int,int); void put(double, int, int); }; Row is a list of position and value pairs. Items not specifically accounted for must be zero. Copyright © 2016 Curt Hill
New Hierarchy We should have the same functionality as before We also have enhanced functionality We have a sparse matrix class for those problems needing it Inverse and Multiply should work with any combination of Dense and Sparse matrices Copyright © 2016 Curt Hill
Extract Component Class Somewhat similar to extracting a function out of another function Except we are extracting pieces of a class out of a class to form a new class We replace simple assignment with setters and getters Then we may enhance the class as needed Sometimes called Encapsulation Copyright © 2016 Curt Hill
Example We had a class that represents a retail item It has: An inventory number A name (string) Price (a double) Etc. We now remove price as a double and replace it with a class named price Copyright © 2016 Curt Hill
Example Continued In the original class where there were things like: price = price * 1.1; we replace this with: price.set(price.get()*1.1); Same functionality but different form This example is a little too simple, but now we can enhance the price class Copyright © 2016 Curt Hill
Up and Down Pull up is moving something from a class to its super-class Push down is moving something from a class to its sub-class Copyright © 2016 Curt Hill
Tools A number of IDE have support for semi-automatic refactoring These include: Eclipse Visual Studio Embarcadero Delphi Most object oriented languages have one or more such tools Copyright © 2016 Curt Hill
Finally Refactoring is a common task of developers It is a non-functional improvement The same behavior is still present However, it does enable certain efficiencies in code It is a technique where the design of the code improves Agile techniques strongly believe in and use refactoring since they seldom get design right the first time Copyright © 2016 Curt Hill