How to refactor a big function with many if constructs? - java

We have App A as main app. Now we build from it App B which uses a subset of App A's functionality.
App A stays like it is whereas app B only uses a subset of A
So I want to refactor the function without or with as little dublication as possible and with maximum readability.
So the function looks like this (it is actually longer, this is an excerpt):
class SomeClass {
Data prepareData() {
if (this.bothId==1 || this.appAid=2 /*or only relevant for appA*/) {
if(this.data==null) { /*appA*/
appAdoSmth(); /*appA*/
}
boolean merge=false; /*appA*/
if (this.data==null) { /*appA*/
merge=appAanalyze(data); /*appA*/
}
bothPrepare(merge);
} else if (bothIsRelevant()) {
if(appArelevant()) { /*appA*/
data=appAprepare(); /*appA*/
} else {
data=prepareBoth();
}
bothUpdateSomeValue();
}
}
How would you do it?

Other Answers address the general question of how to refactor code. They offer good advice, but I don't think it is what you are asking.
I think you are asking about possible refactorings of the code in your question.
It is hard to give an answer that is generally applicable, or even specifically applicable. (The sample code isn't your real code, and it is a little difficult to understand what it actually "means").
AndreasD gives one approach: break the big complicated nested if into separate methods.
Another approach is to use the Stragegy design pattern. Separate the code that is specific to each app into strategy classes. For example:
interface Strategy {
Data prepareData();
}
class GeneralStrategy implements Strategy {
Data prepareData() {
// do general preparation
}
}
class App1Strategy extends GeneralStrategy {
Data prepareData() {
// do app1-specific preparation
super.prepareData();
// do more app1-specific preparation
}
}
and so on.

I ideal world develop unit test that validates that existing implementation of your function works.
Then start changing code incrementally and run your test after every change.
It is hard to give your formal recommendation without knowing your code structure. But generally try to find duplicate code fragments, write methods that implement this logic with parameters and replace the duplicate fragments to your new method. Etc, etc.
Good luck.

Readbility can be improved by extracting some logic in separate methods. That is a refactoring method.
Data prepareData() {
if (this.bothId==1 || this.appAid=2 ) {
handleCase1(); // <- you'll find better names for the methods
} else if (bothIsRelevant()) {
handleCase2();
}
}
private void handleCase1() {
if(this.data==null) {
appAdoSmth();
}
boolean merge=false;
if (this.data==null) {
merge=appAanalyze(data);
}
bothPrepare(merge);
}
private handleCase2() {
if(appArelevant()) {
data=appAprepare();
} else {
data=prepareBoth();
}
bothUpdateSomeValue();
}
This doesn't reduce the number of if/else, of course, but it keeps the "main" method simple.

If I were you I would run a coverage report on this class. (e.g. http://ecobertura.johoop.de/ or http://www.eclemma.org/) This way Eclipse can show covered lines green and this helps you to identify the cases. With this aid it's much easier to separate green lines and pull them into methods.

Related

Is an adapter the right pattern for external SOAP clients?

My software is a Java EE application which talks to another service via SOAP. I want to create a layer that is better testable and use an ideal solution for that. I am not sure which pattern is the right one for this issue.
I have an internal data class which is called InputData. It uses locically correct data types. The SOAP interface on the other hand needs most of the data in strings, like dates in "dd.MM.yyyy", boolean as "0" and "1" and some other weird rules. I cannot change that.
So I need a layer between that. First I thought the best way was to use pure functions because they are easier to test without any side effects. My idea was to create a class with static methods of which one is public. I should return a ValueObject which holds all the data in the correct format.
I had trouble finding a name, so I started with "Adapter". But having something like this:
public class SoapDataAdapter {
public static SoapData getSoapData(InputData input) {
SoapData data = new SoapData();
data.setDate = getDate(input.getDate());
data.isCustomer = isCustomer(input.isCustomer());
// and many more
return data;
}
private static String getDate(LocalDate date) {
return DateHelper.toSoapDate(date);
}
private static String isCustomer(boolean isCustomer) {
return isCustomer ? "0" : "1";
}
}
But this is not an Adapter according to the known patterns. But it is not a Factory -- if I go with the definition of the Gang of Four -- either.
Then I was not sure how to call it or if a "real" Adapter would be a better option. So I tried this:
public class SoapDataAdapter {
private InputData input;
public SoapData getSoapData(InputData input) {
this.input = input;
}
public String getDate() {
return DateHelper.toSoapDate(input.getDate());
}
public String isCustomer() {
return input.isCustomer ? "0" : "1";
}
}
The GoF design patterns gather around OOP which is probably not always the best solution. Having just those pure functions makes a lot of sense to me instead of having the overhead of creating an instance and holding the state. Also, my goal is to make it easier to understand and much easier to test.
What do you think is the best solution for the problem? The first, the second or even another solution? (Adapter seems to be the pattern that fits for exactly that problem, if I understood it correctly.)
What would you call the first one? Is Factory here acceptable?

Refactoring If Statements For Better Readability

I'm currently working on a project that will diminish a class that being used by other several classes.
if(condition_A)
{
doSomething();
}
else if(condition_B)
{
classToBeRemoved();
}
else
{
doAnother();
}
The first solution that came up to me is to negate the condition of the if-else statement that will be modified.
if(condition_A)
{
doSomething();
}
else if(!condition_B)
{
doAnother();
}
This method of refactoring do not affect the functionality of the code but sometimes if the condition is too long, it affects the readability of the code.
Is there another way that will maintain the readability of the code other than negating the condition?
Maybe with functions, vaguely like:
List<BooleanSupplier> actions = new ArrayList<>();
actions.add(() -> {
if (!condition_A) {
return false;
}
doSomething();
return true;
});
actions.add(this::canDoSomething);
if (!actions.stream().anyMatch(p::get)) {
doAnother();
}
I took the liberty to abstract condition+action into a predicate, instead of using a Pair or such.
This is uglier, but could decouple things, as now the add's can come from outside the class, defining a public void addAction(BooleanSupplier action).
Though probably a parameter is needed to provide a data context (Predicate<?>).

Listing all unimplemented methods called from within a method

We have a huge project where many methods have been declared upfront and implementations are in progress. All declared methods have a body which simply throws an exception, say, UnimplException.
Now since the methods have been declared and a valid (compilable) body has been provided, they can be called from within other methods.
Now the question is that is there any way to list all such unimplemented (having just a compilable body throwing a particular exception) methods given a particular method?
To illustrate more(the code is to convey the idea and not strictly compiler friendly):
class A {
methA () {
throw new UnimplException();
}
}
class B {
methB () {
// proper body
// and calls methA
A.methA();
// does something else
// and returns.
}
}
class C {
methC () {
// proper body
// calls methB
B.methB();
}
}
So, if we start from, say, methC, then we want to travel all the way down the method tree to reach to methA because methC calls methB (which is properly implemented and we are not interested) which in turn calls methA which is not properly implemented and that is what we want to find.
We want to search for all such unimplemented methods starting from a method and going few levels deep until we cover all such unimplemented methods.
We thought of JavaAssist but we aren't sure how to go down all the levels because it seems to be giving us all methods called from within a method but not recursively.
Any help is greatly appreciated :)
Have you seen this project: https://github.com/gousiosg/java-callgraph? This appears to do the Java introspection part, listing every method call from every method in a jar file. I'd try using that to do the heavy lifting of parsing your code, then just recurse through the results.
Something like:
Use the callgraph code to build a list of all method calls.
Save that data somewhere.
Recursively parse that structure to find matching methods.
So from your example, step 1 would give something like the following:
A:methA -> UnimplException:<init>
B:methB -> A:methA
C:methC -> B:methB
Then shove those in a Multimap and do a fairly straightforward recursive search:
// this is populated from the output of the callgraph code
com.google.common.collect.Multimap<String, String> methodMap;
void checkAllMethods() {
for (String method : methodMap.keySet()) {
List<String> callStack = new ArrayList<>();
if (doesMethodThrowUnimplException(method, callStack)) {
System.out.println(method);
// can print callStack too if interested
}
}
}
boolean doesMethodThrowUnimplException(String method, List<String> callStack) {
for (String child : methodMap.get(method)) {
// have to check the exact method name from callgraph
if (child.equals("UnimplException:<init>")) {
return true;
}
// recurse into child if not already seen
if (!callStack.contains(child)) {
callStack.add(child);
if (doesMethodThrowUnimplException(child, callStack)) {
return true;
}
callStack.remove(callStack.size() - 1);
}
}
return false;
}
Doesn't strictly satisfy your requirements as this will report any method which throws the UnimplException, not those who only throw the exception, but not sure if that matters.
Standard disclaimer - just typed this in - haven't compiled / run it, so may well be typos, but hopefully the idea helps.

Is it ok to handle a class metadata through reflection to ensure a DRY approach?

The title might seem unsettling, but let me explain.
I'm facing an interesting challenge, where I have a hierarchy of classes that have associated an object that stores metadata related to each one of its attributes (an int-valued enum with edit flags like UPDATED or NO_UPDATE).
The problem comes when merging two objects, because I dont want to check EVERY field on a class to see if it was updated and skip or apply the changes.
My idea: Reflection.
All the objects are behind an interface, so I could use IObject.class.getMethods() and iterate over that array in this fashion:
IClass class = //Instance of the first class;
IAnotherClass anotherClass = //Instance of the second class;
for(Method m : IObject.class.getMethods()) {
if(m.getName().startsWith("get")) {
try {
//Under this method (which is a getter) I cast it on
//both classes who implement interfaces that extend an
//interface that defines the getters to make them
//consistent and ensure I'll invoke the same methods.
String propertyClass = (String)m.invoke(class);
String propertyAnotherClass = (String)m.invoke(anotherClass);
if(propertyClass != propertyAnotherClass) {
//Update attribute and attribute status.
}
} catch (Exception e) {
}
}
}
Is there another way to implement this or should I stick to lengthy methods invoking attribute per attribute and doing the checks like that?. The objects are not going to change that much and the architecture is quite modular, so there is not much update involved if the fields change but having to change a method like that worries me a little.
EDIT 1: I'm posting a working code of what I have got so far. This code is a solution for me but, tough it works, I'm using it as a last resource not because I have time to spend but because I don't want to rediscover the wheel. If I use it, I'll make a static list with the methods so I only have to fetch that list once, considering the fact that AlexR pointed out.
private static void merge(IClazz from, IClazz to) {
Method methods[] = from.getClass().getDeclaredMethods();
for(Method m : methods) {
if(m.getName().startsWith("get") && !m.getName().equals("getMetadata")) {
try {
String commonMethodAnchor = m.getName().split("get")[1];
if(!m.getReturnType().cast(m.invoke(from)).equals(m.getReturnType().cast(m.invoke(to)))) {
String setterMethodName = "set" + commonMethodAnchor;
Method setter = IClazz.class.getDeclaredMethod(setterMethodName, m.getReturnType());
setter.invoke(to, m.getReturnType().cast(m.invoke(from)));
//Updating metadata
String metadataMethodName = "set" + commonMethodAnchor + "Status";
Method metadataUpdater = IClazzMetadata.class.getDeclaredMethod(metadataMethodName, int.class);
metadataUpdater.invoke(to.getMetadata(), 1);
}
} catch (Exception e) {
}
}
}
}
metadataUpdater sets the value to 1 just to simulate the "UPDATED" flag I'm using on the real case scenario.
EDIT 3: Thanks Juan, David and AlexR for your suggestions and directions! They really pointed me to consider things I did not consider at first (I'm upvoting all your answers because all of them helped me).
After adding what AlexR sugegsted and checking jDTO and Apache Commons (finding out that in the end the general concepts are quite similar) I've decided to stick to my code instead of using other tools, since it is working given the object hierarchy and metadata structure of the solution and there are no exceptions popping up so far. The code is the one on the 2nd edit and I've placed it on a helper class that did the trick in the end.
Apache Commons Bean Utils may resolve your problem: http://commons.apache.org/beanutils/
If you want to copy all properties, try to use copyProperties: http://commons.apache.org/beanutils/v1.8.3/apidocs/src-html/org/apache/commons/beanutils/BeanUtils.html#line.134
Look an example from: http://www.avajava.com/tutorials/lessons/how-do-i-copy-properties-from-one-bean-to-another.html
FromBean fromBean = new FromBean("fromBean", "fromBeanAProp", "fromBeanBProp");
ToBean toBean = new ToBean("toBean", "toBeanBProp", "toBeanCProp");
System.out.println(ToStringBuilder.reflectionToString(fromBean));
System.out.println(ToStringBuilder.reflectionToString(toBean));
try {
System.out.println("Copying properties from fromBean to toBean");
BeanUtils.copyProperties(toBean, fromBean);
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
}
System.out.println(ToStringBuilder.reflectionToString(fromBean));
System.out.println(ToStringBuilder.reflectionToString(toBean));
I think the best approach would be using proxy objects, either dynamic proxies or cglib enhancers or something like it, so you decorate the getters and setters and you can keep track of the changes there.
Hope it helps.
Your approach is OK, but keep in mind that getMethod() is much slower than invoke(), so if your code is performance critical you will probably want to cache the Method objects.

Java code PMD Complains about Cyclomatic Complexity , of 20

When i ran PMD on my Java Code , one of the Error Message it is showing is
"The class STWeb has a Cyclomatic Complexity , of 20 " .
Typically my java class is of this way
public class STWeb implements STWebService {
public String getData(RequestData request)
{
validate(request);
}
public boolean validate(Data[] formdata)
{
if(formdata.length==1)
//do this
else if(formdata.length==3)
//do this
else if(formdata.length==4)
//do this
else if(formdata.length>4)
//do this
else if(formdata.length==2)
{
if(formdata[0].getName.equals("OIY"))
{
}
/ And many more if else here
}
}
}
As you can see , as per my business requirements , i need to code the class
with many if's and if else so the reason the cyclocomplexity has ncreased , please tell me
what is feasible approach as per the standard for this ??
Cyclomatic Complexity measurements shouldn't be used for quality control, but rather as an indicator/warning for bad code. You should focus more on the code behind it rather than the value of the CC itself.
Although you can reduce the complexity of the validate method by splitting it into smaller methods through refactoring, the class as a whole will still have the same CC.
As long as the code is readable and makes sense to the next person that has to look at it, then having a higher CC shouldn't matter so much.
It helps if you have something like this:
if (a) {
return true;
} else if (b) {
return true;
} else if (c) {
return true;
} else {
return false;
}
then, you replace it with this:
return a || b || c;
Just wanted to add, that sometimes it's possible to resolve such problems with object- or structure-building. You could declare a "Wrapper-Class" for your data that is supposed to be returned. But there are always cases when you can't apply this without bloating the code with tons of objects, which in return also results in unreadable code ^^"
EDIT: this SO-post is a [nice example with ENUMS]
Cyclomatic complexity seems to indicate the amount of code paths that exist. So if your requirements say you must use many ifs and if elses, then you can ignore that message.
If this is mandatory - yes this happens despite it's futil - you can often reduce the class cyclomatic complexity by introducing base classes and move distribute the functions into the base classes until the per class cyclomatic complexity is ok.
Or simpler: add // NOPMD to your class:
public class VeryComplexStuff { // NOPMD
...

Categories