I have to work out a result which depends on many models obtained from asynchronous calls. Those asynchronous calls performs network calls or UI interruptions (prompts for the user requiring him/her to choose something).
My first attempt has been just to invoke, recursively, to an ugly if/else nest, that looks like this:
public void getResult() {
if(mModelA == null) {
getModelA();
} else if(mModelB == null) {
getModelB(mModelA.someData);
} else if(mModelB.value == -1) {
askUserAboutValue();
} else if(mModelB.value == 5) {
getModelC();
} else if(mModelB.value == 3) {
getModelD();
} else if(...) {
....
}
}
The methods getModelX and askUserAboutValue perform asynchronous tasks and when they finish, they write some global variable and call getResult() in its callback.
I wonder if there is a pattern that could simplify this spaghetti code and what is more, to simplyfy its unit testing.
I think that isolating every check in simpler methods (like: checkModelA()) could help, but it might exist something better.
By the way, this is executed in the Activity of an Android application, so I'm constrained to have all this code in only one class.
Perhaps a switch would work better for this? Or just use a custom method that takes the Integer returned by mModelB.value? Notice the "Integer" not int to check for that null.
Another suggestion would be to use polymorphism, maybe create a method called "getModel(mModelB.value)".
Switch Case / If-Else problems are generally solution for bad design situation.
It looks like you should SubClass your ModelB so that Value of 5, -1 and 3 are different ChildClass which all relates to a Parent Class which would be a ModelB.
But from the function called in every If clause, it seems like -1 is not a SubClass but an error. It feels like in one single function you try to identify the right class that should be use and manage 1 case of error. Error case should be treated inside of the function called.
So in resume, this is a mess? I would gladly help you more but you will have to give me more info on what are those "value" and those "model" and how they interact with each other or their use so that I can try and come up with a better design. Your problem does not sit only on this If/Else function, it's bigger.
Related
Can anyone assist me with an alternative to if then else statements for control flow? Or advise on a good article?
From what I've seen, some use mapping or enums. Trouble I'm having is that I have multiple conditions i.e. if (condition1 && condition2 && condition3)... and I need to do this for several permutations and all 3 variables need to be validated.
Please can someone point me in the right direction?
else if (String.Utils.isNotEmpty(payload.getKeyChange2TokenNumber()) && String.Utils.isEmpty(payload.getKeyChange1TokenNumber()) && String.Utils.isEmpty(payload.getKeyChange3TokenNumber()){
String.format(return value dependant on outcome of validation)
}
So no if then else statements, how can I implement a hashmap to determine what to return in place of the if then else statements return
Thank you.
So, a lot of people end up trying to avoid using if statements because they feel "there must be an easier and more cleaner way of doing this". However think fundamentally, code is just a bunch of if statements at the basic level.
So I wouldn't be too worried about using them, because by trying to use HashMaps or whatever, then you may be just using a nuclear bomb to kill a mosquito.
One thing to keep in mind is that you don't want nested if/else statements, it does become hard to check.
For your example, you mention that you have to do this check on the variables multiple times. So what's wrong with checking that they aren't empty at the start of the flow. If they are then exit or return with the corresponding result. You then don't need to do the checks again.
Additionally, it is useful to use short functions that describe what you're trying to do.
Instead of:
else if (String.Utils.isNotEmpty(payload.getKeyChange2TokenNumber())
&& String.Utils.isEmpty(payload.getKeyChange1TokenNumber())
&& String.Utils.isEmpty(payload.getKeyChange3TokenNumber()) {
String.format(return value dependant on outcome of validation)
}
Try:
if (notEmpty(payload.getKeyChange2TokenNumber())
&& notEmpty(payload.getKeyChange1TokenNumber())
&& notEmpty(payload.getKeyChange3TokenNumber())) {
String.format(return value dependant on outcome of validation)
}
private boolean notEmpty(String string) {
return StringUtils.isNotEmpty(string);
}
Additionally, if the above check is actually related to a domain related response then use that instead. For example, let's say getKeyChange1TokenNumber, getKeyChange2TokenNumber, getKeyChange3TokenNumber are all checked to determine whether the mandatory key change token numbers are provided and you cannot proceed if it isn't true. You're code would look like this:
public void main() {
if (mandatoryKeyChangeTokensNotProvided(payload)) {
return "Mandatory Key Change Tokens not provided";
}
...
}
private boolean mandatoryKeyChangeTokensNotProvided(Payload payload) {
return isEmpty(payload.getKeyChange2TokenNumber())
&& isEmpty(payload.getKeyChange1TokenNumber())
&& isEmpty(payload.getKeyChange3TokenNumber());
}
private boolean isEmpty(String string) {
return StringUtils.isEmpty(string);
}
Try to use the domain language in your code so it makes more sense to the dev. So a dev reading this would read the mandatoryKeyChangeTokensProvided method and know what it does. If they want to know how it does it, then just go into the method and see that its doing string empty checks against it. Hopefully this clears things up for you.
There are multiple ways you can do this, but it all depends on your domain. For example, you say this is validation? Whats wrong with having a Validator Class that does all these checks for you? But remember the KISS principle. Try not to overcomplicate things.
I have 2 questions:
1) In JUnit you shouldn't test or mock private methods. But how do I deal with, when they are getting called inside a public method. Let's assume I have following setup:
public void method(String value){
if(value.contains("something")){
doSomethingToString(value);
}
else{
//do something else
}
}
private void doSomethingToString(String value){
Object obj = service.getObject(); //service is mocked in my test-class
//do something with the obj and value
}
I am doing a whitebox test, so I know the methods and what's going on. Now I want to test the public method method(String value). When I now only consider what happens in there, I would get into trouble, since I need to influence what service.getObject() in my private method returns. Is it OK, when I just go on, like I would, meaning using doReturn(objectICreatedInMyTestClass).when(service.getObject()) or do I need to find another way?
2) Methods which have more than one conditions. For example:
public void method(String value){
if(value.contains("something")){
Object obj = service.getObj(value);
}
else{
//do something else
}
if(obj.getAddress == null){
//do something
}
else{
//do something else
}
if (obj.getName == "Name") {
// do something
}
else
{
// do something else
}
}
How many times do I need to test this method? Only twice, where once all conditions return true, and second, where they all return false? Or is it advised to test every possible scenario? This would mean test with condition 1 = true, condition 2 = false, condition 3=false, and then condition 1 = true, condition 2 = true, condition 3 = false and so on (= 8 possibilites).
1) Should I test private methods on their own, outside of the public methods that call them?
Typically I've always followed the assumption that if the only way your code will access that method is by going through another, then that's how you should test it. My experience with testing systems has lead me to believe that this is generally the way it's done in 'the real world' as well.
If we take your example, we can assume that our first step is to write tests to thoroughly test our main method. As part of this we should be testing scenarios that include properly exercising all the conditions we could expect it to face. This will include at least a subset of the scenarios that your private method will face.
Your private method may be used by multiple (possibly wildly different) methods, so its space of possible inputs and outputs may be greater than any single public method that uses it. If you thoroughly test the public methods that use them however, you should be in the situation where you are testing all of the possible scenarios that that private method will encounter.
Because of this you shouldn't need to write tests specifically for the private method. There may be other scenarios where it is unavoidable to try and test private methods, or private classes. Usually I would argue this is because the code is simply written in a way that makes it hard/impossible and could be rewritten to make it friendlier to tests (And therefore friendlier to being updated/refactored at a later date).
2) Should all of those combinations be tested?
This depends on what is happening in the example. There are two different scenarios to consider
a) Neither of these branches have anything to do with each other. That is, what ever happens in the first set of branches will have no way of impacting the logic of what happens in the second branch.
b) Some possible implications of running any logic in either of the first set of branches would result in a different result in the logic of the code in one or more of the second branches.
This will be down to your reading and understanding what is happening in the code, so your example isn't enough to point to one or the other way of doing things.
Keeping stacktrace out of it, lets say that the idea of 'error' is a problem that you didn't want to occur, but did.
If I were to use a boolean system to check if the action successfully completed, it would look something like this:
String[] array = new String[10];
int i = 0;
public boolean accessValue(int id) {
if(id < array.length) {
//do something
return true;
}
return false;
}
while(true) {
if(!accessValue(i++)) {
//tend to situation
}
}
If I were to use Exceptions, it would look like this:
class InvalidAccessException extends Throwable {
}
public boolean accessValue(int id) throws InvalidAccessException {
if(!id < array.length || !id >= 0)
throw new InvalidAccessException();
//do something
}
while(true) {
try {
accessValue(i++);
}catch(InvalidAccessException e) {
//tend to situation
}
}
The only thing that matters to me is that when a problem occurs, I'm notified in some way, and I will have an option to handle the situation. Which way is more practiced? Does it just depend on the situation, or are there reasons for picking one over the other?
The first approach you mention, is more C oriented, in which you have functions yielding various integers to denote how did the function fair during its execution.
Although this worked it (in my opinion) introduced extra problems where the developer would need to go through other documentation or other developer code to understand why was the particular value returned.
In Java, as far as I know the way to go is always to throw exceptions when something goes wrong (even when you expect it to go wrong). The obvious advantage of using exceptions is that the code is more readable, just by seeing your method signature I know what potential issues could your method cause. This would allow me to code quicker since I do not need to dig through your own documentation or code just to see what the behaviour of your method is (although I could potentially need to dig through documentation/code to see if I can find a solution to why is your code throwing exceptions).
Also, since Java does not have an implementation of a tuple to return error codes and values you would need to create your own which could affect code re usability and readability, which in my opinion is always something you should avoid.
EDIT:
What if my intention isn't to go back into my code and find where the
error was thrown to fix it. just wanted to be notified that an error
happened, in a way I can easily handle the situation in some way.
Rather than me going into the code and fixing it manually, I want to
be able to trigger another set of code (like a handleError() method),
which has an algorithm that will even things out. (whichever algorithm
I may choose). Will handling with Exceptions give me any advantage in
this case?
Yes it should since exception handling will allow you handle exceptional events, so in your code, you could have this:
while(true) {
try {
accessValue(i++);
}catch(InvalidAccessException e) {
//Execute algorithms here
}
}
Having a stack trace is helpful when, as you are saying, you are debugging a problem since it provides information of which methods where called when your program crashed. That being said, they are not the only benefit of using exceptions (as mentioned above).
Another potential problem I see with using return values is when different developers work on the same function. So you could have something like so designed by one developer:
function int doSomething()
{
//if it worked, yield 0
//else yield some number between 1 and 10
}
Then another developer comes along which believes that errors should have negative numbers and extends the above method,
function int doSomething()
{
//if it worked, yield 0
//else yield some number between 1 and 10
//something else went wrong, return -1
}
The above would mean that you would need to go through all other functions calling doSomething() and see that they now handle the case where the return value is negative. This is cumbersome and is also error prone.
EDIT 2:
I hope I am getting your point. I see this issue when you return true/false:
Assume this:
public boolean foo(arg1, arg2)
{
if(arg1 is invalid) return false;
if(arg2 is invalid) return false;
}
In the above example, what does false mean? Does it mean arg1 is invalid or arg2? What if you need to trigger different algorithms for different parameter validity?
I have found myself using the following practice, but something inside me kind of cringes every time i use it. Basically, it's a precondition test on the parameters to determine if the actual work should be done.
public static void doSomething(List<String> things)
{
if(things == null || things.size() <= 0)
return;
//...snip... do actual work
}
It is good practice to return at the earliest opportunity.
That way the least amount of code gets executed and evaluated.
Code that does not run cannot be in error.
Furthermore it makes the function easier to read, because you do not have to deal with all the cases that do not apply anymore.
Compare the following code
private Date someMethod(Boolean test) {
Date result;
if (null == test) {
result = null
} else {
result = test ? something : other;
}
return result;
}
vs
private Date someMethod(Boolean test) {
if (null == test) {
return null
}
return test ? something : other;
}
The second one is shorter, does not need an else and does not need the temp variable.
Note that in Java the return statement exits the function right away; in other languages (e.g. Pascal) the almost equivalent code result:= something; does not return.
Because of this fact it is customary to return at many points in Java methods.
Calling this bad practice is ignoring the fact that that particular train has long since left the station in Java.
If you are going to exit a function at many points in a function anyway, it's best to exit at the earliest opportunity
It's a matter of style and personal preference. There's nothing wrong with it.
To the best of my understanding - no.
For the sake of easier debugging there should be only one return/exit point in a subroutine, method or function.
With such approach your program may become longer and less readable, but while debugging you can put a break point at the exit and always see the state of what you return. For example you can log the state of all local variables - it may be really helpful for troubleshooting.
It looks like there a two "schools" - one says "return as early as possible", whereas another one says "there should be only one return/exit point in a program".
I am a proponent of the first one, though in practice sometimes follow the second one, just to save time.
Also, do not forget about exceptions. Very often the fact that you have to return from a method early means that you are in an exceptional situation. In your example I think throwing an exception is more appropriate.
PMD seems to think so, and that you should always let your methods run to the end, however, for certain quick sanity checks, I still use premature return statements.
It does impair the readability of the method a little, but in some cases that can be better than adding yet another if statement or other means by which to run the method to the end for all cases.
There's nothing inherently wrong with it, but if it makes you cringe, you could throw an IllegalArgumentException instead. In some cases, that's more accurate. It could, however, result in a bunch of code that look this whenever you call doSomething:
try {
doSomething(myList);
} catch (IllegalArgumentException e) {}
There is no correct answer to this question, it is a matter of taste.
In the specific example above there may be better ways of enforcing a pre-condition, but I view the general pattern of multiple early returns as akin to guards in functional programming.
I personally have no issue with this style - I think it can result in cleaner code. Trying contort everything to have a single exit point can increase verbosity and reduce readability.
It's good practice. So continue with your good work.
There is nothing wrong with it. Personally, I would use else statement to execute the rest of the function, and let it return naturally.
If you want to avoid the "return" in your method : maybe you could use a subClass of Exception of your own and handle it in your method's call ?
For example :
public static void doSomething(List<String> things) throws MyExceptionIfThingsIsEmpty {
if(things == null || things.size() <= 0)
throw new MyExceptionIfThingsIsEmpty(1, "Error, the list is empty !");
//...snip... do actual work
}
Edit :
If you don't want to use the "return" statement, you could do the opposite in the if() :
if(things != null && things.size() > 0)
// do your things
If function is long (say, 20 lines or more), then, it is good to return for few error conditions in the beginning so that reader of code can focus on logic when reading rest of the function. If function is small (say 5 lines or less), then return statements in the beginning can be distracting for reader.
So, decision should be based on primarily on whether the function becomes more readable or less readable.
Java good practices say that, as often as possible, return statements should be unique and written at the end of the method. To control what you return, use a variable. However, for returning from a void method, like the example you use, what I'd do would be perform the check in a middle method used only for such purpose. Anyway, don't take this too serious - keywords like continue should never be used according to Java good practices, but they're there, inside your scope.
I am no newb on OO programming, but I am faced with a puzzling situation. I have been given a program to work on and extend, but the previous developers didn't seem that comfortable with OO, it seems they either had a C background or an unclear understanding of OO. Now, I don't suggest I am a better developer, I just think that I can spot some common OO errors. The difficult task is how to amend them.
In my case, I see a lot of this:
if (ret == 1) {
out.print("yadda yadda");
} else if (ret == 2) {
out.print("yadda yadda");
} else if (ret == 3) {
out.print("yadda yadda");
} else if (ret == 0) {
out.print("yadda yadda");
} else if (ret == 5) {
out.print("yadda yadda");
} else if (ret == 6) {
out.print("yadda yadda");
} else if (ret == 7) {
out.print("yadda yadda");
}
ret is a value returned by a function, in which all Exceptions are swallowed, and in the catch blocks, the above values are returned explicitly. Oftentimes, the Exceptions are simply swallowed, with empty catch blocks.
It's obvious that swalllowing exceptions is wrong OO design. My question concerns the use of return values. I believe that too is wrong, however I think that using Exceptions for control flow is equally wrong, and I can't think of anything to replace the above in a correct, OO manner.
Your input, please?
These are IMHO two completely different things:
OO-vs.-non-OO design
and
exception-based-vs.-return-value-based design.
You can combine them in any way (although most developers would say that a non-OO design is only good for special tasks like algorithms.
With regard to your code base: I would recommend a holistic analysis of the whole software, and then some careful thinking whether doing away with the return codes is a good idea. Will the software be expanded in the future? Or is it just some dead wood lying somewhere to do one specific task?
I would recommend reading up on "refactoring" and "legacy code". People around me say "Working Effectively with Legacy Code" by Michael Feathers is a very solid and recommended book. So this could help you a lot.
Good luck!
But this is Java (not C++). So if you work with `codes' like that you ought to work with Enums. And using Enums (or integers, incidentally) you can use the switch() statement to improve code like that a lot.
public abstract class Example {
protected abstract ErrorCode test();
public void run() {
ErrorCode code=test();
switch(code) {
case OK:
System.out.println("All ok");
break;
case OOPS:
System.out.println("Oops, an error occurred.");
break;
case OTHER_ERROR:
System.out.println("A different error occurred");
break;
case UNKNOWN_ERROR:
System.out.println("Yet another, unknown error occurred.");
break;
}
}
public static enum ErrorCode {
OK, OOPS, OTHER_ERROR, UNKNOWN_ERROR;
}
}
This can be extended to give it some more Continuation Passing Style flavour; by defining a callback method for ErrorCode and calling that method instead of doing the switch() statement.
Of course using exceptions for control flow is not the right thing to do. They need to be handled separated from your actual program control flow.
The fact that an exception occurred means that there was an exceptional event in you application and swallowing it or turn it into a return value doesn't change that (meaning that as soon as you turned it into a return value you kind of used it for the control flow). Usually it is possible to avoid return values that indicate both success states and exceptional states (first step: by using enums and then gradually improving the OO design).
According to if-else approach, I'll bring just a hint if you'd like to go more OO here.
You definitely could use state pattern.
Class State{
public:
virtual void showInfo()=0;
}
class Iddle:public State{
public:
void showInfo(){
std.cout<<"I've just initialized"<<std.endl;
};
}
class Wrong:public State{
public:
void showInfo(){
std.cout<<"Something goes wrong"<<std.endl;
};
}
main()
{
boost::scoped_ptr<State> mystate = new Iddle();
mystate->showInfo();
.....
mystate.reset(new Wrong());
....
mystate->showInfo();
}
You can implement anything you want in desired states.
This way you will throw out if-elses.
This is the way your generic "catch" function could set the states.
This could be of course used by regular system tasks, so any main component would know what is the state, and what action should be proceeded.
Simplifies:
if you'll have an exception, set a state to Wrong, then kill the thread, stop the action or whatever object responsible for the failure.
You'll still have the state, you handled the exception in proper manner, but still have some states, which could be a basis for taking appropriate actions in another thread.
Generally consensus is that exceptions shouldn't be used for control flow. However, the Python community seems to think differently.
However, I think the fundamental issue that you have is one of clarity; catching exceptions in one method and converting each condition to some arbitrary numeric value make it very unclear what the code is trying to do.
Without seeing the called code that you mention it's difficult to suggest how to improve it. If it is dealing with genuine exceptional conditions then I would consider allowing those to be handled by the calling code and possibly rethrowing as whatever exception fits the purpose of the method.