By Michael Muller | Article Rating: |
|
November 16, 2012 11:44 AM EST | Reads: |
432 |

Technical Debt is worth nothing if no pragmatic action is taken into code, in order to control and tackle it. To ilustrate the Scertify's capability to automatically correct code defects that increase this unintended debt, we performed code refactoring on OpenKM, an Free/Libre document management system. The initial Technical Debt of the project has been reduced by 49.2% from 84 days to 42 days. Here, at Tocea, we call it the Debt Write-Off.
For this first Debt Write-Off, we have decided to perform the refactoring of OpenKM (6.2.1-DEV).
According to Wikipedia, OpenKM is a Free/Libre document management system that provides a web interface for managing arbitrary files. OpenKM is a great tool but an audit of the code revealed some technical debt problems. That was a good opportunity to use Scertify and to be useful to an open-source community. The application consists mainly in 200K lines of code of Java. There is also Javascript, JSP, CSS... but we focus here on the Java code.
Technical debt before refactoring
Scertify Refactoring Assessment allows us to estimate the technical debt of the application. As you can see on screenshot #1, it is estimated to 84 days. This is the time needed to correct manually each error. This number only includes the time needed to make the change on the code, it does not include things like finding the file, understanding the problem, etc.
Of this 84 days, 60 represent errors that can be automatically refactored, thus taking nearly zero effort to correct.
We can take a closer look on the possibilities of automation (screenshot #2). Not all rules are currently implemented in Scertify, but we are working on it. For this project, we chose 7 rules that seemed particularly interesting.
Rules used for the refactoring
Here's a presentation of the rules used to perform the refactoring of OpenKM.
- AvoidPrintStackTrace
This rule reports a violation when it finds a code that catch an expression and print its stack trace to the standard error output. A logging framework should be used instead, in order to improve application's maintainability.
The refactoring replace a call to print stack trace by a call to a logging framework. The rule can also declare the logger in the class and make the required imports. The rule can be configured to use the user's favorite framework.Here's the configuration used for OpenKM:
- The logger call to use: "log.error({0}.getMessage(), {0})" {0} is replaced by the exception.
- Do not refactor calls of printStackTrace to other IO (a file, a stream...)
- Make logger declaration when it's needed (ie: log is not already declared in class).
- The logger declaration to use : "private static Logger log = LoggerFactory.getLogger({0}.class);"
- The required imports : "org.slf4j.LoggerFactory,org.slf4j.Logger"
Original code :
view source print?1.
catch
(FileNotFoundExceptione){ e.printStackTrace(); }
-
Refactored code :
view source print?1.
catch
(FileNotFoundExceptione){ log.error(e.getMessage(),e); }
- AddEmptyStringToConvert
Using the concatenation of an empty string to convert a primitive type to a String is a bad practice. First of all, it makes the code less readable. It is also less efficient in most cases (the only case where the string concatenation is slightly better is when the primitive is final).
Original code:
view source print?1.
UserActivity.log(session.getUserID(),
"DELETE_PROCESS_DEFINITION"
,
""
+processDefinitionId,
null
,
null
);
Refactored code:
view source print?1.
UserActivity.log(session.getUserID(),
"DELETE_PROCESS_DEFINITION"
,
String
.valueOf(processDefinitionId),
null
,
null
);
- InefficientConstructorCall
Calling the constructor of a wrapper type, like Integer, to convert a primitive type is a bad practice. It is less efficient than calling the static method valueOf.
Original code:
view source print?1.
users.put(usersRead[i].getString(), newInteger(Permission.READ));
Refactored code:
view source print?1.
users.put(usersRead[i].getString(), newInteger(Permission.READ));
- IfElseStmtsMustUseBraces
This rule finds if statements that don't use braces. The refactoring adds required braces.
- PositionLiteralsFirstInComparisonsRefactor
This rule checks that literals are in the first position in comparisons. The following code is a violation :
Original code:
view source print?1.
if
(action.equals(
"ruleList"
))
Refactored code:
view source print?1.
if
(
"ruleList"
.equals(action))
The refactoring invert the literal and the variable. This ensures that the code cannot crash due to the variable being a null pointer.
- MethodArgumentCouldBeFinal
This method flags method's arguments that could be declared final and are not. The use of the final keyword is a useful information for future code readers.
- LocalVariableCouldBeFinal
The purpose is the same as the previous rule, except that it treats local variable and not arguments. These two rules are not critical, but since they have a huge number of violations, it is useful to get rid of them quickly with automatic refactoring.
We are now ready to perform the refactoring with Scertify.
- Configure a xml rule repository: The first step is crucial. As we have seen in previous section, some rules need to be configured to be useful. However, it shouldn't take more than half an hour.
- Run Scertify to perform the refactoring: The second step is just a command line invocation, where you specify the project to refactor and the rule repository to use.
The refactoring process
The refactoring process consists of two steps :
For this project of 200K lines of code, the refactoring took 2 minute. You can check the process on a smaller project in this video tutorial.
Technical debt after refactoring
Screenshot #3 is the analysis of the refactored project by Scertify Refactoring Assessment. As you can see, 24 days of technical debt have been erased.
Screenshot #4 and #5 show the difference of violations in Sonar between the original and the refactored project.
Here's the number of violations that have been corrected for each rule (*) :
- AddEmptyStringToConvert: 232
- AvoidPrintStackTrace: 70
- InefficientConstructorCall: 43
- IFElseStmtsMustUseBraces: 411
- PositionLiteralsFirstInComparisons: 358
- MethodArgumentCouldBeFinal: 8848
- LocalVariableCouldBeFinal : 7622
To sum up, with Scertify we've been able to correct quickly a huge number of errors. Some of them are not critical (like MethodArgumentCouldBeFinal) but we've also been able to refactor more evolved errors like AvoidPrintStackTrace, AddEmptyStringToConvert,...
Download the source files
- Original: OpenKM 6.2.1-DEV
- Refactored: OpenKM 6.2.1-DEV-Debt-Write-Off
(*) if you do the math, you'll see that more errors have been corrected. It's due to side effects of the refactoring (correcting a rule can remove violations of other rules) and also because we manually corrected few things in the code.
Submit your project for a Debt Write-Off
If you're interested in submitting your project to the next Debt Write-off, or just give some valuable feedback... Please contact us on Twitter: @Scertify
Published November 16, 2012 Reads 432
Copyright © 2012 SYS-CON Media, Inc. — All Rights Reserved.
Syndicated stories and blog feeds, all rights reserved by the author.
More Stories By Michael Muller
Michael Muller, a Marketing Manager at Tocea, has 10+ years of experience as a Marketing and Communication Manager. He specializes in technology and innovative companies. He is executive editor at http://dsisionnel.com, a French IT magazine and the creator of http://d8p.it, a cool URL shortener. Dad of two kids.
- Cloud People: A Who's Who of Cloud Computing
- Twelve New Programming Languages: Is Cloud Responsible?
- TOGAF Foundation Level Certification – Another Practice Test
- TOGAF Foundation Level Certification – Practice Test
- Day 2 Keynote at Cloud Expo Silicon Valley | An Open Cloud Discussion
- Rackspace Lets Go of OpenStack
- Day 1 Keynote at Cloud Expo Silicon Valley | Open Cloud – Place Your Bets!
- Cloud Expo Silicon Valley: APIs – The Wiring Behind the Cloud
- Cloud Expo Silicon Valley | Cloud Computing Adoption: Where Are We Really?
- Here Comes Rackspace & Amazon’s Latest Rival
- Dependencies Gone Wild: Testing Cloud Apps at Cloud Expo Silicon Valley
- How Many Degrees Separate You and Your Information?
- Cloud People: A Who's Who of Cloud Computing
- Twelve New Programming Languages: Is Cloud Responsible?
- Agile Adoption – Crossing the Chasm
- TOGAF Foundation Level Certification – Another Practice Test
- Examining the True Cost of Big Data
- TOGAF Foundation Level Certification – Practice Test
- Day 2 Keynote at Cloud Expo Silicon Valley | An Open Cloud Discussion
- What Makes Agile Agile?
- Thanks to Big Data, Analytics Will Be a $51B Business by 2016: IDC
- Rackspace Lets Go of OpenStack
- Day 1 Keynote at Cloud Expo Silicon Valley | Open Cloud – Place Your Bets!
- Cloud Expo Silicon Valley: APIs – The Wiring Behind the Cloud
- A Cup of AJAX? Nay, Just Regular Java Please
- Java Developer's Journal Exclusive: 2006 "JDJ Editors' Choice" Awards
- JavaServer Faces (JSF) vs Struts
- The i-Technology Right Stuff
- Rich Internet Applications with Adobe Flex 2 and Java
- Java vs C++ "Shootout" Revisited
- Bean-Managed Persistence Using a Proxy List
- Reporting Made Easy with JasperReports and Hibernate
- Creating a Pet Store Application with JavaServer Faces, Spring, and Hibernate
- Why Do 'Cool Kids' Choose Ruby or PHP to Build Websites Instead of Java?
- What's New in Eclipse?
- i-Technology Predictions for 2007: Where's It All Headed?
- ');
for(i = 0; i < google_ads.length; ++i)
{
document.write('
- ');
document.write('' + google_ads[i].line1 + '
'); document.write('' + google_ads[i].visible_url + '
'); document.write(google_ads[i].line2 + ' ' + google_ads[i].line3); document.write(' ');
}
document.write('