Jan 27

As a full time developer I spend a lot of time writing code. And I almost never get it right first time. I did once, a long time ago, and since then I’ve not had such luck so I’ve had to rely on a myriad of safety nets, such as unit tests and a keep it simple approach to design. Even then my code tends to grow somewhat organically leading to various code smells that a healthy wave of refactoring wafts away.

I thought I’d take this opportunity to share the ones I use the most often – in fact I couldn’t really live without them these days.

1) Rename and Change Method Signature

My personal favourites. Rename does just what it says on the tin. Initiate the refactoring, tell the IDE to apply it in all the right places and it just does it. When applied to fields in Java beans, the IDE will ask if sir would like those getters/setters renamed as well, and throughout the application, including JSPs. Yes, please, do that for me and save me a whole bunch of time.

Change Method Signature is even better because it includes Rename as a happy side effect. Want to change the order of those parameters and their types but don’t want to screw up all the myriad of calls into those methods? Why, yes, yes I do, Mr IDE. Just click in this box until you’re happy with the new order and let me do all the hard work. Don’t mind if I do (cracks open beer).

2) Extract Method

Especially useful when exploring a new code base. If you want to simplify a method that has clearly gotten out of hand, just select the area you feel should be a method in it’s own right and hit that refactor button. Suddenly all that complex code is whisked away and in it’s place is a simple method call. And if your IDE is really spiffy then you’ll find that all the other copy/pasted versions of that code have also been refactored into the method call. Marvellous.

3) Pull Up and Push Down

Have you suddenly discovered that a method or field is going to be duplicated in a bunch of subclasses? Use Pull Up to move the duplicated method or field into a super class. Done correctly, the IDE will automatically apply the refactoring to all subclasses with the duplication and substitute the super class reference in it’s place.

Push Down, as it’s name suggests, does the opposite. Your wonderful base class is now preventing subclasses from specialising as they should so you push the field or method down so that the subclasses can implement the method or not as they see fit.

4) Extract Base Class

Want to do a Pull Up but don’t have a super class in place? No problem, just use this and select the methods/fields that you want pulled up. Want that base class abstract? Not a problem, just tick the box, sir.

5) Introduce Parameter Object

If there’s one thing I really hate it’s a method with a long parameter list. And by long I mean 5 parameters maximum. Especially if they’re all named string1, string2, stringX and so on because a) it’s mental, 2) it’s confusing and iii) nobody will ever get the parameters in the correct order.

The solution to this debacle is, of course, to introduce a parameter object. A simple Value Object (read Java Bean) that abstracts all the parameters away behind a single reference. Want to add a new parameter but don’t want to have to go and change all the method signatures on your publicly available API? Just make sure they take a parameter object and the API will continue to work as you change the properties on the parameter object. If you were feeling really ambitious you could put validation code into the parameter object to provide a defensive layer, but that’s just silly, isn’t it? Isn’t it?

6) Introduce Constant

We’ve all done it: hard coded a string or number somewhere. Then used it again. And again. Then realised that, really, it should be defined properly somewhere up in the root of the class or ideally injected. And that is exactly what the Introduce Constant refactoring does. With a swift click of the mouse all the duplications are pulled up into a single, well named constant field destined to remain the single point of reference for that datum for all time. Very DRY.

7) Introduce Field

Method signatures getting a bit repetitive with that same reference getting passed around all over the place? It’s about time that parameter was converted into a fully fledged field.

The only problem with refactoring is that after you’ve done it a few times you kind of get addicted to it. Before long you’ll be spotting duplications and excessive parameter lists all over the place and applying refactorings to tidy them all up and what are you left with? Just well designed, clean code that is much easier to maintain.

Share
Tagged with:
Jan 09

How to be agile when all about you are not – part 3

In part 2 of this series, I explained how the DRY principle can be used in the build process and how the need for automated testing naturally arises from this. In this article, I go on to explain how to implement automated testing in Java using Ant and JUnit.

The subject of automated testing is vast, with many different philosophies and naming conventions springing up around it and a full explanation would take ages. [Include links to other sites]. However, it is well proven that the introduction of automated testing greatly improves the quality of a code base because of what is necessary to support it. There are 3 pre-requisites to successful automated testing:

1) an automatic build system
2) some kind of automated testing framework
3) an open design allowing small parts of the system to be tested in isolation

For the vast majority of projects, some kind of automated build system is already in place within the IDE. In the case of Java this is Ant, and typically the build script is automatically generated as a result of the various options that are selected within the IDE for the project.

Although it’s obvious, it still needs to be said that test code should not be mixed with production code, and that includes the supporting libraries. There are several ways to avoid this, but the best way is to introduce a new source tree that only contains test related classes and resources.

If you are a Java developer, the Maven convention is to define a sub-directory under the main source tree as follows: src/test/java, with production code going under src/main/java. I would strongly urge you to follow this convention as Maven is growing steadily as a replacement for Ant. Test classes then have the same package as the class under test.

The most widely used automated test framework in the Java world is JUnit (NUnit is used in the .Net world). At the time of writing version 4 is well-established and I would strongly urge you to use it. All that is required is the inclusion of a simple dependency into your project and you’re done. If you want to find out more about JUnit here is a good starting point.

The final step is modifying the existing code to support automated testing. This can be easy or hard depending on how well designed the legacy code is. If good programming practices have been followed, then automated testing is straightforward. There will be strong separation between classes, with each class performing a few well defined tasks that contribute to an overall cluster of functionality. Navigation around the cluster of objects will be straightforward since they will have clear naming conventions and follow some kind of established design pattern.

Time to refactor
For the rest of us, it’s time for some hard graft in the form of refactoring. This is the process by which code is rewritten to conform to a higher standard of design principles without changing it’s functionality. If done correctly the outside world is unaware of any change being made, while internally the code is much cleaner, succinct and therefore easier to maintain.

There are many references on the subject of refactoring (here is a good starting point), and your IDE will definitely support a wide variety of refactoring operations. Essentially your goal in refactoring is to break the code apart into smaller testable units that can be instantiated without reference to any of their surrounding classes. Or, if a reference must exist for a unit to work, that the reference is supplied from outside the class, i.e. the test class. This is known as Dependency Injection or Inversion of Control (IOC). A quick way to identify if you’re using IOC is to see if any of the dependency objects are created with the new operator, or are static references to utility classes. Either of these will mean some refactoring to introduce getters and setters so that external classes can pass in the instances for these dependencies.

So, instead of

private Worker worker = new Worker();

you have

private Worker worker = null;

public void setWorker(Worker worker) {
  this.worker=worker;
}

and now the test class can provide an alternative implementation of the Worker class which behaves in a predictable manner suitable for testing. The above can be achieved by means of the Encapsulate Fields refactoring (which is really for converting public fields into private ones with a setter, but never mind you can see what I’m trying to get across here).

The best approach to refactoring is to target a single change at a time. Your goal is to isolate each class as much as possible with the IOC pattern through a series of field conversions – pushing the external dependencies to the outer class that control the one you’re working with. At this point, the class is ready for automated testing.

Let’s get back to our fictional developer, Bob, and assume that he’s made these refactorings to his code to introduce the new credit card support (see part 2 for a fuller description of this). Instead of the inefficient and laborious process that he previously had to go through, the new approach is something like this:
1) Find the credit card payment system in the code and it’s associated automated tests
2) Modify the tests to include the new credit card and a wide range of test data that should induce failures
3) Run the tests and note any failures (the first time will definitely fail since there is no implementation code)
4) Fix the failures and repeat from step 3) until it’s all good
5) Perform an update from version control and re-run the tests
6) If it’s all OK, check it in

As you can see the cycle time between making a test and seeing the result of it is greatly reduced to a matter of seconds rather than minutes. Also, once the automated test has been written then every time the system is built then it will perform the same checks, over and over again forever. So now, if someone makes a change to that part of the system guarded by the test which causes the test to fail then there is a clear path to what went wrong and how to to fix it. The failure is caught early on in the development cycle and that is the cheapest point to fix it. Also, if the developer introducing the failure is regularly running a build that includes the test then they will remember what change they made that caused the failure in the first place and be quicker to debug and fix it.

In part 4 of this series I will explain what happens next to further improve the build process by introducing the idea of continuous integration.

Share
Tagged with:

You should follow me on TwitterYou should follow me on Twiiter here.

preload preload preload