CSC/ECE 517 Spring 2014/ch1a 1w1e rm: Difference between revisions
Line 43: | Line 43: | ||
==Getting Started with Refactoring in Ruby== | ==Getting Started with Refactoring in Ruby== | ||
===First step: Writing tests=== | |||
The first step in refactoring is writing solid set of tests for that section of code to avoid introducing bugs. In Ruby, this can be done using [http://www.ruby-doc.org/stdlib-2.1.0/libdoc/test/unit/rdoc/Test/Unit.html Test::Unit] or [http://rspec.info/ Rspec]. Next step is to make small changes, test again, make small changes and so on. <ref>http://www.amazon.com/Refactoring-Edition-Addison-Wesley-Professional-Series/dp/0321984137</ref> | The first step in refactoring is writing solid set of tests for that section of code to avoid introducing bugs. In Ruby, this can be done using [http://www.ruby-doc.org/stdlib-2.1.0/libdoc/test/unit/rdoc/Test/Unit.html Test::Unit] or [http://rspec.info/ Rspec]. Next step is to make small changes, test again, make small changes and so on. <ref>http://www.amazon.com/Refactoring-Edition-Addison-Wesley-Professional-Series/dp/0321984137</ref> | ||
===When to refactor=== | |||
It is always confusing when to start refactoring. If either one of the following conditions is true, it is a good time to start refactoring code: | It is always confusing when to start refactoring. If either one of the following conditions is true, it is a good time to start refactoring code: | ||
* The Rule of Three | * The Rule of Three | ||
Line 62: | Line 56: | ||
A [http://blog.codeclimate.com/blog/2014/01/09/when-is-it-time-to-refactor/ CodeClimate blog] also suggests some other conditions to identify the need to refactor code. | A [http://blog.codeclimate.com/blog/2014/01/09/when-is-it-time-to-refactor/ CodeClimate blog] also suggests some other conditions to identify the need to refactor code. | ||
===Refactoring fat models=== | |||
Fat models cause maintenance issues <ref>http://blog.codeclimate.com/blog/2012/10/17/7-ways-to-decompose-fat-activerecord-models/</ref>. This CodeClimate blog suggests using 7 patterns to refactor fat models: | |||
# Extract Value Objects | |||
# Extract Service Objects | |||
# Extract Form Objects | |||
# Extract Query Objects | |||
# Introduce View Objects | |||
# Extract Policy Objects | |||
# Extract Decorators | |||
==Metrics== | ==Metrics== |
Revision as of 23:59, 10 February 2014
This page discusses how to elegantly refactor code, including several common metrics used in determining the potential quality of refactoring code, as well as which refactoring techniques to use in coordination with such metrics.
Background
The practice of code refactoring deals with changing the content or structure of code without changing the code's function in its execution. Code refactoring has become a standard programming practice, as it potentially promotes readability, extensibility, and reusability of code.
Whether done through an IDE or by hand, large-scale code projects can prove tedious to refactor. If minimal non-functional benefits are achieved through refactoring, time is wasted. Furthermore, if not done properly, code refactoring can actually break the functionality of the code. In the extreme case, code could be structured so badly that starting over completely may be more viable than refactoring. As such, it is important to be able to know when and what to refactor.
Refactoring Techniques
Before a coder performs a refactor, they must, either formally or informally, identify their ‘code smells’. A code smell refers to a negative quality of a code base that either implements bad programming practices or slows down code development or runtime. These aren't typically bugs, but can increase the chance of bugs later on if not fixed. Based on the type of code smell, a different refactoring technique is used to fix it.
Duplicate Code
Duplicate code can be a tricky concept when refactoring. Large sections of duplicated code can be easy to find and fixed by pulling it out and creating a single centralized method to call, however it is usually not that easy. Sometimes it may only be one or two lines of code that are duplicated which calls for an assessment of whether or not it is in the best interest to create a new method for a couple lines of code. Other times, code is not duplicate, rather it is similar enough that a generic method could be created to serve various purposes. Some specific techniques to deal with this are:
- Extract Method / Pull-up Method
- If common code is used in multiple places, simply pull it out and make a method that can be called from all of the necessary places. Variables can be passed in if slight variations are needed between calls.
- If the code is used in various subclasses, put the common code in a method in the superclass, so that it can be seen and called by it’s children.
- Extract Method Example
- Form Template Method
- If two methods in subclasses perform similar steps in the same order, but the steps are different, then get the steps into methods with the same signature, so that the original methods become the same. Then pull them up. <ref>http://www.refactoring.com/catalog/formTemplateMethod.html</ref>
- Form Template Method Example
Large Method/Class
If a project is not planned out well enough in advance, it is easy for methods and classes to become populated with excess functionality. While the functionality may be necessary for the project, it might not be in the method or class.
- Extract Method
- This can be used when duplicate code occurs, as discussed above. But it can also be used when a method performs multiple functions that have the ability to be split up into various functions that serve a single purpose.
- Extract Class/Subclass/Superclass
- If there are class variables or methods that don’t directly pertain to a class, then it may be necessary to create a new class for those pieces.Example
- If there are pieces of a class that are only for a specific subset of instances, then a subclass can be constructed to contain these.Example
- If there are pieces that multiple classes use, then a superclass can be constructed to handle these generic functions, leaving the subclasses to deal with the remaining differences Example
Improving Readability and Clarity
Many times, refactoring can be used to do simple, yet necessary changes like renaming variables, methods, or classes. As features get added to a project, classes tend to get charged with more uses than originally planned, so sometimes, the original naming scheme no longer applies and a new one needs to be instilled.
Moving methods and parameters around to where they have the best accessibility also has its uses. Classes also tend to be promoted or demoted to super and sub classes after their ultimate functional purpose is determined.
More Techniques
There is an extensive list of coding smells that can be improved through refactoring.
A description of smells with their techniques exists here.
A list of techniques with examples in Ruby are listed here.
Getting Started with Refactoring in Ruby
First step: Writing tests
The first step in refactoring is writing solid set of tests for that section of code to avoid introducing bugs. In Ruby, this can be done using Test::Unit or Rspec. Next step is to make small changes, test again, make small changes and so on. <ref>http://www.amazon.com/Refactoring-Edition-Addison-Wesley-Professional-Series/dp/0321984137</ref>
When to refactor
It is always confusing when to start refactoring. If either one of the following conditions is true, it is a good time to start refactoring code:
- The Rule of Three
- When you add function
- When you need to fix a bug
- During code review,
- For greater understanding
A CodeClimate blog also suggests some other conditions to identify the need to refactor code.
Refactoring fat models
Fat models cause maintenance issues <ref>http://blog.codeclimate.com/blog/2012/10/17/7-ways-to-decompose-fat-activerecord-models/</ref>. This CodeClimate blog suggests using 7 patterns to refactor fat models:
- Extract Value Objects
- Extract Service Objects
- Extract Form Objects
- Extract Query Objects
- Introduce View Objects
- Extract Policy Objects
- Extract Decorators
Metrics
It can be hard to decide whether or not to refactor, especially when it’s for something that appears to be working fine with just a surface level smell. Program analysis tools are used to derive various types of code metrics, which allow coders to identify problem areas and future pitfalls of their code base. These tools look at the code in several different ways, including the number of times a source file has been edited to help determine if it is a possible target of [feature envy], duplicate code structure to identify replicated lines, and block depths to suggest possible complexity issues.
Open Source Ruby Tools
There are a variety of open source tools that can be employed specifically for Ruby programs. The Ruby Toolbox contains the most popular of these tools along with ratings.
Simple Cov is at the top of this list. It was developed specifically to be of use to anyone using any framework. It integrates itself with the project’s own test cases to check the coverage of them in addition to cucumber features.
Code Climate
Code Climate is a hosted code metrics tool that analyzes projects in a multitdue of ways. It produces three main metric ratings with grades from A-F that comprise of the methods and classes contained in each file and project.
Complexity Metric
This is based off of the Assignment, Branches, and Conditions (ABC) metric, where the number of assignments, branches, and conditions are counted and analyzed. However, because Code Climate is constructed for Ruby programs, it also takes into account certain types of Ruby constructs that may increase the metric score, but are actually beneficial to the project.
Duplication Metric
This looks at the syntax trees of the code in order to identify identical and similar code structures. Because the syntax trees are being analyzed, code formatting and different method and class names do not affect the score. <ref>https://codeclimate.com/docs#quality-metrics</ref>
Churn Method
This integrates with the Git repository to look at the change history of the project’s files. Files with excessively high change histories have a tendency to have a high complexity rating as well, as they can be the result of feature envy, where extra functions are added into a file instead of being added to a new file with it’s own functionality.
Automated Code Refactoring
RubyMine
- RubyMine has a built in refactoring menu.
- To perform refactoring, select a code fragment to refactor. Refactorings available for your selection appear under the Refactor Menu in RubyMine. <ref>http://www.jetbrains.com/ruby/webhelp/refactoring-source-code.html#common</ref>
RFactor
- RFactor is a Ruby gem, which aims to provide common and simple refactorings for Ruby code for text editors like TextMate
- The first release has only Extract method implemented while other refactorings are coming soon
- It is available on GitHub
Other IDEs
- Some other IDEs with built-in refactoring include Aptana Studio, Aptana RadRails and NetBeans 7 (which requires Ruby and Rails plugin)
- A StackOverflow post compares these tools ranking them as RubyMine being the best, followed by NetBeans, RadRails 2 and Aptana Studio 3
Further Reading
References
<references/>