Monday, August 25, 2014

Java Code Refactoring


I recently browsed again the excellent book Code Complete from Steve McConnell while in the middle of several Java code reviews. Although the book is nor specifically dedicated to Java code, I still found it quite useful and inspiring.

The chapter on refactoring in particular offers a very practical perspective that all programmer should have in mind when it comes to infuse a dose of evolution in the life cycle of their software.

What I found particularly valuable are the checklists that the author has put together: reasons to refactor, specific re-factorings (data level, statement level, routine-level, class-implementation, class-interface, system-level), refactoring safely, strategies, summary.

Since I do not have time to comment every item in these checklists, I decided to pick-up those that are not trivial or obvious and might bring the best return on your refactoring investment.

In a future post, I would like to illustrate some of these refactoring techniques with java code snippets, but that will be later :)


Checklist: Reasons to Refactor
  • Code is duplicate
  • A routine is too long
  • A loop is too long or too deeply nested
  • A class/interface/method has poor cohesion ⇐
  • A class interface does not provide a consistent level of abstraction ⇐
  • A parameter list has too many parameters ⇐
  • Changes within a class tend to be compartmentalized
  • Changes require parallel modifications to multiple classes ⇐
  • Inheritance hierarchies have to be modified in parallel
  • Related data items that are used together are not organized into classes ⇐
  • A routine uses more features of another class than of its own class
  • A primitive data type is overloaded
  • A class doesn't do very much
  • A chain of routines passes tramp data ⇐
  • A middle man object isn't doing anything
  • One class is overly intimate with another
  • A routine has a poor name
  • Data members are public
  • A subclass uses only a small percentage of its parents' routines
  • Comments are used to explain difficult code
  • Global variables are used
  • A routine uses setup code before a routine call or takedown code after a routine call
  • A program contains code that seems like it might be needed someday

Checklist: Summary of Refactorings
  • Data Level Refactoring
  • Replace a magic number with a named constant ⇐
  • Rename a variable with a clearer or more informative name
  • Move an expression inline
  • Replace an expression with a routine
  • Introduce an intermediate variable
  • Convert a multi-use variable to a multiple single-use variables ⇐
  • Use a local variable for local purposes rather than a parameter
  • Convert a data primitive to a class
  • Convert a set of type codes to a class
  • Convert a set of type codes to a class with subclasses
  • Change an array to an object
  • Encapsulate a collection ⇐
  • Replace a traditional record with a data class
  • Statement Level Refactorings
  • Decompose a boolean expression
  • Move a complex boolean expression into a well-named boolean function
  • Consolidate fragments that are duplicated within different parts of a conditional
  • Use break or return instead of a loop control variable
  • Return as soon as you know the answer instead of assigning a return value within nested if-then-else statements
  • Replace conditionals with polymorphism (especially repeated case statements) ⇐
  • Create and use null objects instead of testing for null values
  • Routine Level Refactorings
  • Extract a routine
  • Move a routine's code inline
  • Convert a long routine to a class
  • Substitute a simple algorithm for a complex algorithm
  • Add a parameter
  • Remove a parameter
  • Separate query operations from modification operations
  • Combine similar routines by parameterizing them
  • Separate routines whose behavior depends on parameters passed in ⇐
  • Pass a whole object rather than specific fields
  • Pass specific fields rather than a whole object
  • Encapsulate downcasting ⇐ 


Class Implementation Refactorings

  • Change value objects to reference objects
  • Change reference objects to value objects
  • Replace virtual routines with data initialization
  • Change member routine or data placement
  • Extract specialized code into a subclass ⇐
  • Combine similar code into a superclass
  • Class Interface Refactorings
  • Move a routine to another class
  • Convert one class to two
  • Eliminate a class
  • Hide a delegate ⇐
  • Replace inheritance with delegation
  • Replace delegation with inheritance
  • Remove a middle man ⇐
  • Introduce a foreign routine
  • Introduce a class extension
  • Encapsulate an exposed member variable
  • Remove Set() routines for fields that cannot be changed
  • Hide routines that are not intended to be used outside the class
  • Encapsulate unused routines ⇐
  • Collapse a superclass and subclass if their implementations are very similar
  • System Level Refactorings
  • Duplicate data you can't control ⇐
  • Change unidirectional class association to bidirectional class association
  • Change bidirectional class association to unidirectional class association
  • Provide a factory routine rather than a simple constructor
  • Replace error codes with exceptions or vice versa



Friday, July 18, 2014

Memory Settings on WebMethods - Windows Installation as Service

According to SoftwareAG, if you want to modify the memory settings of your WebMethods Installation (IS - Integration Server) you have to do it in one place:

setenv.bat
set JAVA_MIN_MEM=1024M
set JAVA_MAX_MEM=2048M
set JAVA_MAX_PERM_SIZE=512M

I'm not saying this is wrong, because is not if you start your IS using command line by invoking startup.bat (X:\SoftwareAG\IntegrationServer\bin)

However for us mortals (muggles) who have our installation configured as a Windows Service I found this that my service is started by executing an EXE file (which uses a config file named wrapper.conf):
X:\SoftwareAG\profiles\IS\configuration\wrapper.conf

Inside that file you'll find all sort of properties but no matter how many changes you perform in this file, you won't see any change reflected (no mater how many times you restart your service), unless you have checked at the end of this file where there is a commented line (leave it commented, no need to change anything) which actually includes an additional file custom_wrapper.conf (aha! That's the right spot!)

Feel free to modify this entries (those are the values I set to my DEV environment):
wrapper.java.additional.7=-Xms2048M
wrapper.java.additional.8=-Xmx2048M
wrapper.java.additional.9=-XX:MaxPermSize=512M 

If you want to add an additional property to your JVM (since the last property ends in 17), I added an additional property 18:
wrapper.java.additional.18=-Dcom.sun.management.jmxremote.port=7007 -Dcom.sun.management.jmxremote.ssl=false -Dcom.sun.management.jmxremote.authenticate=false

Restart your IS Windows Service and you'll see your changes reflected.