Sunday 22 April 2012

Parameterize Method

Introduction

Whether cooking up a new class and its methods or adding a new method to an existing class, you should keep one eye on the bigger picture to minimize duplication. Code duplication can, at times, be blatantly present and other times not as such. The key is identifying duplicate code no matter how subtle or in however big a class may be. When adding or updating a method, it’s essential to be aware of the other methods available in the class. With an understanding of the class’s motivation, identifying opportunities to refactor out duplicate code becomes an easier task.

1. Obvious code duplication

Some methods have values or behaviours included in their method names and when an additional method is needed that would ‘naturally’ fit as being very similar with a slight change of the mentioned method name value. That’s if you encounter a well-named method name. The method name does not always guarantee the critical aspects of its functionality, so reading into the details of a ‘similar’ method might be worth the effort. Note: One might be discouraged if encountered with a long method that seems to go on and on that might best be suited for a procedural programming language. That’s covered in another post.

Once such a method is identified, add a parameter to the method, rename the method and make the changes to the code that use the newly added parameter. Use other refactoring techniques to ensure no manual work is incurred.

2. Subtle code duplication

Code duplication identification may not always be at the method name level. Within the method’s implementation is a good place to look for opportunities to eliminate duplicate code. We’ll go over an example of such a scenario however be suspicious of methods that do ‘too much’ and do not rely on private methods to make themselves more concise. This task is easier undertaken with classes that exhibit high cohesion and that are loosely coupled. The more muddled the class in what it does the more of a refactoring effort will be needed not only to remote duplication but to align it more with best practices.

So, if two method implementations are doing similar work, consider extracting a new parameterized method or updating an existing method to serve both methods.

To a certain extent, identifying subtle code duplication can be a journey in itself, an acquired  skill or even down to an art.

Sunday 15 April 2012

Parameter Object

Introduction
  • Make methods parameters more cohesive through the introduction of a parameter object

Consider encapsulating multiple parameters into a parameter object to keep the method signature concise.

1. More expressive method signature

A method containing multiple parameters can lead to confusion with understanding how to satisfy the method and with its implementation details having to trace the order of parameters and relying on poorly named parameter names to track values. Try to group some parameters (if not all) into parameter objects that make sense. This will reduce the parameter list and result in a more expressive method signature.

2. Less validation

The basic parameter validation can be moved from the method to the parameter object by introducing a parameter object. This makes the method’s implementation more concise since it can trust the parameter object to be well constructed. Constructor validation enforced when extracting parameter objects introduces a parameter trusting philosophy rather than a paranoid check for null/empty in every method implementation.

3. Aggregate object

It’s worth reflecting on the domain model to ensure whether the parameters can fit in an existing domain object rather than introducing a parameter object. If one does not exist, the parameter object that needs creation could indeed be missing from the domain model. Consider introducing an aggregate object that will fit within the domain model rather than a parameter object. Do this only if it makes sense and gives me insight into the domain model.


Manual refactoring (REPEAT from Update method name lesson)

Now, let’s see how to become a refactorKing using Eclipse
todo....

Remove Parameter

Introduction
  • Caution when removing a parameter

Unlike adding method parameters, removing method parameters is not as popular. While adding parameters carries certain risks (see add parameter entry), removing parameters should also be carried out with equal concern.

1. Is the parameter simply not used?

Don’t overlook that unused method, if it’s not being used in the implementation then get rid of it. This leads to the a diluted method signature and potentially superfluous client processing to retrieve the parameter to satisfy the method signature. Unless null is passed in (see number 2 in this list) which doesn’t do anyone any favours. If it’s not being used, trash it!

2. Can certain method invocation combinations tolerate null values?

Calling a method with a null parameter is something that should be avoided. Such practice is risky as the method consumer know of the method’s implementation details. This introduces a risk when the implementation changes and a null value is no longer tolerated, the result will be potential null pointer exceptions. No one likes null pointer exceptions. This proves even more so when developing in an IOC environment where the consumers are only aware of interfaces not implementations. And even more so when you don’t have access to the implementation details and the tolerating of null values was somewhat of a ‘discovery’.

Make sure to introduce overloaded method signatures when developing an implementation that tolerates null values with certain parameter combinations.

3. Parameters belong in a single class?

Sometimes a group of different parameters that make up a method signature can indeed form part of an existing class or motivate you to create a new class to encapsulate them. The creation of a new class (if indeed it makes sense) will make the method signature more concise and potentially reduce parameter validation for each parameter with the method. The validation can be moved to the newly created class. The original method becomes less cluttered with parameter validation and more cohesive just focusing on what it should be doing.

4. Would the method benefit from using a parameter object or an aggregate object?

At times a methods require the same data from many different sources, data that does not make sense to exist in a single class. In such a case, a parameter object (typically a simple bean) is used instead of methods with multiple parameters which can lead to client consumption confusion. Another approach is to create an aggregate class that is constructed using multiple class that contain the data needed. The aggregate class is responsible for not exposing containing objects but rather only exposing their relevant data through its own methods. The aggregate approach should only be adopted if the class and the data it exposes make sense to be contained within an aggregate class.

5. Is the type expressive of the parameter data?

Okay, so this isn’t exactly removing a parameter but it does carry a similar amount of refactoring. When an existing parameter type does not concisely represent the actual data then it’s worth removing and adding (effectively replacing) a parameter to help callers consume the method with more confidence. Typically, parameters represented as primitives or String types are potentially candidates for further investigation. A case I come across is that of id where the id is represented as a String. The consumer can easily consume the method with any old string value and will probably encounter runtime exceptions if the string value does not adhere to the expected id format. In this case, it would be more helpful to consumers to change the type from String to URI, UUID or some custom id class. With this approach there’s no guessing from the consumer as to what format the id should be in.


Manual refactoring (REPEAT from Update method name lesson)

Now, let’s see how to become a refactorKing using Eclipse
todo....

Add Parameter

Introduction
  • Caution when adding a parameter

Although it’s something that happens quite often during a developer’s day, but some questions need to be answered before adding a new parameter to a method.

1. Will the new parameter dilute the method’s cohesion?

A method should do one thing and do it well. At times when additional functionality is needed it’s easiest added to an existing method. Doing so might be in-line with the method’s original intention, which is fine, however it might also just be convenient to add a parameter and additional functionality to the method. In the latter case, it’s best to review the method and perhaps separate additional functionality to its own class/method.

2. Can the new parameter value be found is existing parameter?

When a method’s parameter starts to grow, it’s worth reviewing the existing parameters to consider using a value that they provide to be used directly or used to resolve a value instead of adding an additional parameter. It might be worth to consider adding a the desired value to an existing object only if it makes sense; a natural fit.

3. Would the method benefit from using a parameter object or an aggregate object?

At times a methods require the same data from many different sources, data that does not make sense to exist in a single class. In such a case, a parameter object (typically a simple bean) is used instead of methods with multiple parameters which can lead to client consumption confusion. Another approach is to create an aggregate class that is constructed using multiple class that contain the data needed. The aggregate class is responsible for not exposing containing objects but rather only exposing their relevant data through its own methods. The aggregate approach should only be adopted if the class and the data it exposes make sense to be contained within an aggregate class.

Manual refactoring (REPEAT from Update method name lesson)

Now, let’s see how to become a refactorKing using Eclipse
todo....

Rename Method

Introduction
  • Good to rename methods so they’re more expressive
  • Define developer translation


Issues of impact (show impact in Eclipse)

#1 Clients and test cases
Changing a method’s name impacts clients and test cases.

#2 Interface
Changing a method name on an interface impacts not only the implementing classes but their clients and test cases as well.

#3 Subclass / Superclass
Changing a method name of a subclass or superclass (overriding) impacts all the implementations, their test cases and clients. This can be of a significantly larger impact which results in an ever bigger overhead to give the method a more appropriate name.

Manual refactoring techniques

1. Follow the red dots
Rename the method and see the compilation errors show up in Eclipse or a compilation errors if you’re not using an IDE. That there is the impact annotated by those lovely red markers. Go through each red marker and correct the compilation error (update to use the new method name).

The overhead of changing the method name as you resolve compilation errors depends on the number of clients and test cases calling the updated method.

2. Finding references and implementations
Another technique is to create a new method with the new name, then copy the old method’s implementation to the newly created method. Update the old method to call the new method and then find all references to the old method and update them to use the new method. This technique is used when an incremental refactoring strategy is adopted. So, only certain clients will use the new method name.

Problems with manual refactoring
Developers are sometimes discouraged to go through with the renaming of a method when the renaming effort results in a huge impact for which the overhead of resolving referencing code outweighs the benefits of renaming to a more aptly named method. In the case a partial rename refactoring (only some clients are updated to use the new method name) the developer will not be discouraged by a huge impact overhead, since it can be controlled, but what you’re left with is a code base potentially littered with partial refactorings; methods calling other (renamed) methods pollutes the API.

Not refactoring due to the impact on the code-base is not healthy and will lead to code entropy; “oh don’t change that method”. The code will become stale and not evolve. Developer translation will still be needed, something we want to minimize.

Now, let’s see how to become a refactorKing using Eclipse
todo....