Today’s subject is a well commented square root approximation method. Imagine that this method is buried deep in a very messy Java class. How can we make sure that this code is reusable and that our comments don’t become out of date as our code changes?
/**
* Approximate the square root of n, to within the specified tolerance,
* using the Newton-Raphson method. This method takes two arguments:
* @param Double n The number to be square-rooted
* @param Double tolerance the error tolerance
* @return Double result of square root operation
*/
public Double approximateSquareRoot(Double n, Double tolerance)
{
Double root = n / 2;
while (Math.abs(root - (n / root)) > tolerance)
{
root = 0.5 * (root + (n / root));
}
return root;
} |
/**
* Approximate the square root of n, to within the specified tolerance,
* using the Newton-Raphson method. This method takes two arguments:
* @param Double n The number to be square-rooted
* @param Double tolerance the error tolerance
* @return Double result of square root operation
*/
public Double approximateSquareRoot(Double n, Double tolerance)
{
Double root = n / 2;
while (Math.abs(root - (n / root)) > tolerance)
{
root = 0.5 * (root + (n / root));
}
return root;
}
It’s my philosophy that if you find yourself writing a comment that describes what a method does, either the method does too much, or you should use that comment AS the name of the method. Try something like this:
public Double newtonRaphsonSqRoot( Double number, Double tolerance ) |
public Double newtonRaphsonSqRoot( Double number, Double tolerance )
Method Delegation:
If you need to conform to a standard interface, then delegate!
Delegation is your best friend.
public Double approxSquareRoot( Double number )
{
return newtonRaphsonSqRootApprox( number, 0.0001 )
} |
public Double approxSquareRoot( Double number )
{
return newtonRaphsonSqRootApprox( number, 0.0001 )
}
Also… if you don’t want to add a private delegated method, then consider abstracting that behavior into an Operation class that performs the square root.
Object Delegation:
This strategy even lets you change behavior of your square root operations at runtime, at configuration time, and it lets you extend the behavior to use other algorithms without changing your client code. Just make sure that you only expose your interface, because as soon as your clients know about the implementing class, you defeated the purpose of delegating in the first place.
public interface SquareRoot
{
public Double perform(Double input);
}
/**
* Approximate the square root of n, to within the specified tolerance,
* using the Newton-Raphson method.
*/
public class NewtonRaphsonApproximation implements SquareRoot
{
private Double tolerance = 0.001;
public Double perform( Double input )
{
Double root = n / 2;
while (Math.abs(root - (n / root)) > tolerance)
{
root = 0.5 * (root + (n / root));
}
return root;
}
} |
public interface SquareRoot
{
public Double perform(Double input);
}
/**
* Approximate the square root of n, to within the specified tolerance,
* using the Newton-Raphson method.
*/
public class NewtonRaphsonApproximation implements SquareRoot
{
private Double tolerance = 0.001;
public Double perform( Double input )
{
Double root = n / 2;
while (Math.abs(root - (n / root)) > tolerance)
{
root = 0.5 * (root + (n / root));
}
return root;
}
}
See, we can even throw in a brief comment where it makes sense to store it.
The Factory:
Look! Now if you want to change the algorithm that calculates your square roots, all you have to do is create a new class that implements SquareRoot, and configure a
Factory to provide you with an instance of that class. The possibilities are limitless, really. You can select which type of square root you want to use via a configuration file, dynamic logic, anything:
//where OperationFactory decides which type of SquareRoot to provide.
SquareRoot squareRoot = OperationFactory.getSquareRoot();
Double result = squareRoot.perform( 123.2 ); |
//where OperationFactory decides which type of SquareRoot to provide.
SquareRoot squareRoot = OperationFactory.getSquareRoot();
Double result = squareRoot.perform( 123.2 );
Now it doesn’t matter that we are using
NewtonRaphson or
TaylorApproximation implementations of SquareRoot. And you still have clear understandable code under the covers.
Final Thoughts:
There are some who will say in response to this article, “you now have extra classes and methods that are making your code harder to understand,” and I say to them:
It all depends on the problem you are solving.
If you are using the newtonRaphsonSquareRoot() method in one place in your entire program, then you might be OK to leave it the way it is, sure. But as soon as you start using that method in other places, you might want to consider making a class to contain it anyway. Don’t just copy and paste your code. Cut and paste in a new class!
The next phase, the Factory, would come when you start using different types of SquareRoot approximations. Factories help hide the details of creation and implementation from the client. Hiding implementation is almost always good.
My article is a response to:
this blog. Comment away, so to speak.
i agree, if you need to write a comment to your code, its a smell. delegation and class/method names are the best way, and the moment you name a class right, which means you know what the job of the class is, you have reached a good object oriented design.
IMHO comments are more important for bugfixing than for reusability. In your comments you write down in your own words what your method is supposed to do. As a reviewer I can read the comment, understand the method and if I found a mismatch I found a bug.
So I clearly vote to do both. Commenting and writing easy to review code.
lincolnthree – my new theology is “don’t comment unless it’s weird” unless it’s something that is unconventional such as “we had to do this this way because of the payment table being wonky” or something of the sort commenting is only a crutch for non intuitive code.
I try to make my variable/method names and code structure so obvious that a non-developer could look at it and tell you what it does.Once you have reached that point coding is zen.
This is great info to know.
i know this thread is about commenting code, but thats not how you find the square root is it. It says Double root = n/2;
This is an implementation of the newton-raphson square root approximation algorithm, so yes.