Checking "rules" in Java without lots of if statements - java

I'm creating a springboot banking API and in order to create a transaction a bunch of "rules" have to be checked.
e.g:
Current logged in user can't withdraw money from another user's savings account
Amount can't be higher/lower than certain number
etc.
This causes my createTransaction method to contain a lot of if statements (12!). This is what my code looks like in pseudo:
public ResponseEntity<String> createTransaction(Transaction body) {
if (check rule 1) {
return ResponseEntity.status(HttpStatus.BAD_REQUEST).body("...");
}
if (check rule 2) {
return ResponseEntity.status(HttpStatus.BAD_REQUEST).body("...");
}
// etc...
// Transaction complies to set rules
return ResponseEntity.status(HttpStatus.CREATED).body("Transaction successful!");
}
I can post my actual code if necessary but I think this paints the picture without having anyone to read 100 lines of code.
Because I have around 12 if statements checking these rules, my function is quite lengthy and difficult to read/maintain.
Googling for a solution didn't bring up results I was looking for. I've tried implementing exceptions but this didn't remove the amount of if statements. Maybe a switch could improve a bit, but I'm wondering if there's a clean OOP solution.
My question is: How can I clean this code up (OOP style)?
Thanks in advance.

You should create a TransactionRule interface that allows you to implement specific transaction rules, and then use a stream to get the final result:
public interface TransactionRule {
public boolean isAllowed(Transaction someTransaction);
}
Example implementation 1:
public class SufficientBudgetTransactionRule implements TransactionRule {
public boolean isAllowed(Transaction someTransaction) {
// Custom logic e.g.
return someTransaction.wallet.value >= someTransaction.transaction.value;
}
}
Example implementation 2:
public class NotInFutureTransactionRule implements TransactionRule {
public boolean isAllowed(Transaction someTransaction) {
// Custom logic e.g.
return someTransaction.transaction.datetime.isBefore(OffsetDateTime.now());
}
}
Then, you can store all the TransactionRules in a List and check whether they all validate like so:
private final List<TransactionRule> transactionRules; // Fill these of course
public boolean allTransactionRulesMatch(Transaction someTransaction) {
return transactionRules.stream()
.map(transactionRule -> transactionRule.isAllowed(someTransaction))
.allMatch(result => result);
}

Related

How to deal with history-sensitivity?

So I have written a Java program that has a function handInExam() that may not be called twice in a row, thus the program is history-sensitive. The problem that then occurs is that I need a variable canHandInExam to check whether this method has already been called and update this variable in each method, which leads to very poor maintainability. Below is a code snippet to show the problem.
public class NotAllowedException extends Exception {
public NotAllowedException(String message) {
super(message);
}
}
import java.util.Scanner;
public class Exam {
String[] exam;
String[] answers;
boolean canHandInExam;
public Exam(String[] questions) {
exam = questions;
answers = new String[exam.length];
canHandInExam = false;
}
// This method may only be called once in a row
public void handInExam throws NotAllowedException() {
if (canHandInExam) {
// Send exam to teacher
canHandInExam = false;
} else {
throw new NotAllowedException("You may not hand in this exam!");
}
}
public void otherMethod() {
// Do something
canHandInExam = true;
}
}
In this small example it is feasible to slightly adapt each method, however if you would have lots of methods you would need to adapt all of them. Since after all these methods you may again call handInExam() thus the variable canHandInExam would need to be set to true.
Is there a way to solve this problem in a way that is more maintainable? I am open to other possible programming languages that are not OO, but at this point I am unsure of what would be suitable.
I have considered using functional programming (e.g. Haskell) as those languages are not history-sensitive, however I did not know how to limit that you may only call a function once in a row. I tried searching for how to limit a function call to n times in a row both in Java and Haskell, but this ended up with only references to how to call a function n times.
If you speak about handing in an exam, than this doesn't mean that something is done with that exam, but that there is some entity to which the exam is given. So instead of storing within the exam whether it was handed in or can be handed in, something like this would be more appropriate:
//or whatever you call this
public interface Institution {
void handInExam(Exam exam) throws DuplicateExamException;
boolean isHandedIn(Exam exam);
}
Implementations of Institution store the exams that were handed in (possibly using a Set).

What is the best way to handle code with if/switch statements having high cyclomatic complexity?

I have a method that takes an input called capability id. Based on the capability id, I execute the business implementations put forward in form of a switch case. I have my functionality working, But came across a problem where the sonar report is showing high cyclomatic complexity around 12-14. The company I work for, uses a standard of 10 as the max cyclomatic complexity. My considerations is that, If I happen to break the code into too many block, the code readability is getting affected.
Note:-
I don't have permissions to change sonar rules.
Unfortunately, I can't share the code. The code would be in the following way though,
// Dependency Injected
private someService;
public void processCapability(..., String capabilityId) {
switch (capabilityId) {
case ORDER_DISPENSED_WITH_SOURCE1:
someService.doDispense1();
case ORDER_DISPENSED_WITH_SOURCE2:
someService.doDispense2();
case ORDER_REJECTED:
someService.doReject();
case ORDER_CANCEL:
someService.doCancel();
case ORDER_PURGE:
someService.doPurge();
...
default: throw exception
}
}
Update: I was able to resolve my problem, with a solution I posted in below answers.
There are multiple ways to avoid large if-else statements.
Maybe the most common patterns are the template method pattern and the strategy pattern.
As you haven't provided any code, it's hard to help you to lower the cyclomatic complexity, but I'm absolutely sure, there's a way to avoid those if-else-s.
I'd suggest you to read a bit about the topic; I'll provide you some sources I've found useful:
Using strategy to replace if else
Using command pattern to replace conditional logic
I'd encourage you to use enums, they are more usable in conditional logic than you'd think: using enums instead of switch
Also it's good to know about various design patterns, maybe you can find a suitable one here
Also a readable code means it's easy to understand. I agree with #Erwin Bolwidt's comment, if you create more methods with good names, it will be easier to read. To read more about the topic, check the book "Clean Code" by Robert C. Martin.
I suggest that you refactor this switch statement (which is a code smell) using polymorphism. A possible way to do it is something like that:
public interface Order {
void processCapability(...);
}
public final class RejectedOrder implements Order {
private final SomeService someService;
public RejectedOrder(SomeService someService) {
this.someService = someService;
}
#Override
public void processCapability(...) {
someService.doReject();
}
}
public final class CancelledOrder implements Order {
private final SomeService someService;
public RejectedOrder(SomeService someService) {
this.someService = someService;
}
#Override
public void processCapability(...) {
someService.doCancel();
}
}
More useful resources talking about the 'switch smell':
http://refactoring.com/catalog/replaceConditionalWithPolymorphism.html
http://c2.com/cgi/wiki?SwitchStatementsSmell
If there is nothing wrong with your code, why make it more complex only to avoid SonarQube warnings? You might not be allowed to change SonarQube rules, but you certainly can suppress the warning by annotating your method with the following:
#SuppressWarnings("squid:MethodCyclomaticComplexity")
I have figured one way to handle the big if/switch statements. Based on the ideas, I got from everyone of you. I compiled into a simple solution that is easy to understand and modify, also handles the complexity part. Please find my solution below,
// Dependency Injected
private someService;
public void processCapability(..., String capabilityId) {
Boolean isCapabilityProcessed = processDispenseCapabilities(...) || processUpdateCapabilities(..);
if(isCapabilityProcessed) {
throw exception("Invalid Capability");
}
}
private Boolean processDispenseCapabilities(..,String capabilityId) {
Boolean result = false;
switch (capabilityId) {
case ORDER_DISPENSED_WITH_SOURCE1:
someService.doDispense1();
result = true;
case ORDER_DISPENSED_WITH_SOURCE2:
someService.doDispense2();
result = true;
case ORDER_REJECTED:
someService.doReject();
result = true;
...
default: //do nothing
}
return result;
}
private Boolean processUpdateCapabilities(..,String capabilityId) {
Boolean result = false;
switch (capabilityId) {
case ORDER_CANCEL:
someService.doCancel();
result = true;
case ORDER_PURGE:
someService.doPurge();
result = true;
...
default: //do nothing
}
return result;
}

Business logic validation patterns & advices

I have two layers of validation in my application. First is entity validation performed by bean validation API (e.g. required fields).
The second level is business logic validation. For example, user has a post. User can delete a post only if he is a creator of this post and post rating < 50. So I have to do something like this:
if (post.getCreator().equals(session.getUser())) {
if (post.getRating() < 50) {
postRepository.delete(post);
} else errors.add(400, "Cant delete post with rating 50 or higher")
} else errors add (400, "You should be owner of the post")
I don't like this way as this conditionals are reused and I have to duplicate code. Moreover, if number of conditionals is greater than 5 or so it becomes unreal to read and understand the code.
Moreover, standard Spring Validator won't be very helpful as I have to maker different validation for one entity on different actions (delete and update for example)
So I'm looking for a way to do this in a smarter way (pattern maybe) and I would be very grateful if someone could give me a hint.
Thank in advance!
You can use the strategy pattern.
Each condition can be modelled as a function that takes a post and a session context and might return an error:
Post -> Session -> Optional<String>
You could represent this with an interface:
#FunctionalInterface
public interface ValidationCondition {
Optional<String> validate(final Post post, final Session session);
}
So for example:
public class CreatorValidation implements ValidationCondition {
public Optional<String> validate(final Post post, final Session session) {
if (post.getCreator().equals(session.getUser()) {
return Optional.empty();
}
return Optional.of("You should be the owner of the post");
}
}
You can then store every validation in a list:
final List<ValidationCondition> conditions = new ArrayList<>();
conditions.add(new CreatorValidation());
conditions.add(new ScoreValidation());
// etc.
Using the list, validations can be applied in bulk:
final List<String> errors = new ArrayList<>();
for (final ValidationCondition condition : conditions) {
final Optional<String> error = condition.validate(post, session);
if (error.isPresent()) {
errors.add(error.get());
}
}
Using Java 8 lambdas, you could declare these inline:
final ValidationCondition condition = (post, session) -> {
// Custom logic
});
Strategy pattern is the solution in my opinion.
I will give you a very simple example. Lets say we have two kinds of credit cards, Visa and Mastercard. The logic to perform payment operation is the same for both cards, but card number validation is different. So, by passing VisaStrategy object through a workflow does the same logic and operations as we would pass MastercardStrategy, except one thing - card number validation, which is done inside each defined Strategy class, so you do not have any "if else" stuff in your code at all. Each Strategy class is now responsible for one and only one type of card validation.
If you look for flexible and easy to maintain code structure - use Strategy design pattern.

Index Service Design - Sync / Async

I have a requirement to index items. This service should run Sync or Async.
I started designing an Interface
public interface IndexService{
public void index();
}
And two implementation, one for a Async Index:
public class AsyncIndex implements IndexService {
public void index(){
//... Creates a Thread and index the items
}
}
And the other one to the Sync Index
public class SyncIndex implements IndexService {
public void index(){
//... Creates a Thread and index the items
}
}
But now there is another design that is having a IndexService, who has a flag to execute as a async service or as a sync service:
public interface IndexService{
public void index(int mode);
}
So now the implementation will know how to run base on that flag.
I know that the first design is better, but I need pros and cons to explain why.
I go for first approach because
1- code is cleaner AsyncInex class only has codes related to async call and syncIndex would has its own code.
2- you can avoid else if
...
public void runService(IndexService service) {
service.index()
}
// some where in your code
runService(new AsyncIndex());
// or
runService(new SyncIndex());
as you are working with interface "IndexService" you can always change implementation without changing clients code.
specially if you are using DI frameworks you can have the kick of it ;).
this is so important to not allowing client code know about the implementation. suppose situation where you are indexing, for instance, a database.
you want to do async index when data is huge or sync index when data is small.
caller should has no knowledge about the way Index is called. this way you can have different strategy in different situations without changing callers code. if you take the second approach you have to do some extra work.
I say both.
Assume, you plan to use the second approach. Your implmentation may look like:
public SyncOrAsyncIndex implements IndexService {
public void index(int mode) {
if(mode == 0) {
//sync processing code
} else if (mode == 1) {
//async procesisng code
}
}
That said, are you going to write all the implementation within this index method or SyncOrAsyncIndex class. That will possibly end up being unmanageable.
So, the index method may end up like this:
public void index(int mode) {
if(mode == 0) {
new SyncIndex().index(); //for example
} else if (mode == ) {
new AsyncIndex().index(); //for example
}
}
Assume, you decide on supporting a third mode. Imagine the plight of the index method or SyncOrAsyncIndex class. So, the first approach is needed.
So, as per "code to the interface" strategy the first approach is suggested. If the invoker is aware of the type of indexing, they can just instantiate the particular type and use it.
Else, along with the first approach the second one may be required as a factory or strategy to calculate which type of indexing to use based on the passed parameter. The invoker would then use the SyncIndex or AsyncIndex via SyncOrAsyncIndex.

How to remove large if-else-if chain [duplicate]

This question already has answers here:
Closed 11 years ago.
Possible Duplicate:
Long list of if statements in Java
I was tasked to work with some code, and there is a giant if-else-if chain (100+ else-ifs) that checks Strings.
What are some good techniques to update this code as to where the if-else-if chain can be shrunken down to something much more manageable.
The chain looks something like this:
if(name.equals("abc")){
do something
} else if(name.equals("xyz")){
do something different
} else if(name.equals("mno")){
do something different
} ......
.....
else{
error
}
You can extract the code in each branch to a separate method, then turn the methods into implementations of a common base interface (let's call it Handler). After that, you can fill a Map<String, Handler> and just look up and execute the right handler for given string.
Unfortunately the implementation of 100+ subclasses for the interface requires quite a lot of boilerplate code, but currently there is no simpler way in Java to achieve this. Implementing the cases as elements of an Enum may help somewhat - here is an example. The ideal solution would be using closures / lambdas, but alas we have to wait till Java 8 for that...
Some options / ideas:
Leave it as it is - it's not fundamentally broken, and is reasonably clear and simple to maintain
Use a switch statement (if you are using Java 7) - not sure if this gains you much though
Create a HashMap of String to FunctionObjects where the function objects implement the required behaviour as a method. Then your calling code is just: hashMap.get(name).doSomething();
Break it into a heirarchy of function calls by sub-grouping the strings. You could do this by taking each letter in turn, so one branch handles all the names starting with 'a' etc.
Refactor so that you don't pass the name as a String but instead pass a named object. Then you can just do namedObject.doSomething()
With Enums, you can have a method per instance.
public enum ActionEnum {
ABC {
#Override
void doSomething() {
System.out.println("Doing something for ABC");
}
},
XYZ {
#Override
void doSomething() {
System.out.println("Doing something for XYZ");
}
};
abstract void doSomething();
}
public class MyActionClass {
public void myMethod(String name) {
ActionEnum.valueOf("ABC").doSomething();
}
}
It is still kinda messy (big enum with 100+ entries, even it all it does is dispatching), but may avoid the HashMap initialization code (100+ puts is also messy in my opinion).
And yet another option (for documentation purposes) would be reflection:
public interface Action {
void doSomething();
}
public class ABCAction implements Action {
#Override
public void doSomething() {
System.out.println("Doing something for ABC");
}
}
public class MyActionClass {
void doSomethingWithReflection(String name) {
try {
Class<? extends Action> actionClass = Class.
forName("actpck."+ name + "Action").asSubclass(Action.class);
Action a = actionClass.newInstance();
a.doSomething();
} catch (Exception e) {
// TODO Catch exceptions individually and do something useful.
e.printStackTrace();
}
}
}
Each approach has it's trade offs:
HashMap = Fast + Kinda messy ("set-up" code with hundred of puts)
Enum = Fast + Kinda messy 2 (huge file).
Reflection = Slower + runtime error prone, but provides clean separation without resorting to clunky big HashMap.
Like Matt Ball said in his comment, you can use a command pattern. Define a collection of Runnable classes:
Runnable task1 = new Runnable() {
public void run() { /* do something */ }
};
Runnable task2 = // etc.
Then you can use a map from your keys to runnables:
Map<String,Runnable> taskMap = new HashMap<String,Runnable>();
taskMap.put("abc", task1);
taskMap.put("xyz", task2);
// etc.
Finally, replace the if-else chain with:
Runnable task = taskMap.get(name);
if (task != null) {
task.run();
} else {
// default else action from your original chain
}
you can use the switch statement , but Switch statements with String cases have been implemented in Java SE 7
the best solution is to use the command pattern
This is a popular Arrow Anti-Pattern and Jeff discusses some approaches to handle this very nicely in his post here.

Categories

Resources