I'm working on a class which sends a RequestDTO to a Web Service. I need to validate the request before it is sent.
The request can be sent from 3 different places and there are different validation rules for each "requesttype", e.g. request1 must have name and phonenumber, request2 must have address, etc)
I have a DTO which contains a long list of fields (name, address, city, phonenumber, etc.) and it is the same DTO sent no matter which type of request it is.
I have created 3 different validation methods and based on the type the appropriate method is called.
In each of these methods I have a long list of if-else's to check for the fields that are necessary for each request type.
private void validateRequest1(Request request) { StringBuilder sb = new StringBuilder(); if (null == request) { throw new IllegalArgumentException("Request is null"); } if (isFieldEmpty(request.getName())) { *see below sb.append("name,")); } if (isFieldEmpty(request.getStreet())) { sb.append("street,")); } ...
isFieldEmpty()
checks the string for null and isEmpty()
and returns a boolean
This gives me a cyclomatic complexity of 28 in one of those methods so my question is.. is it possible to reduce this complexity? - if so, how would I go about doing so?
Ultimately I need to check a lot of fields and I cannot see how this can be done without lots of checks :/
Cyclomatic complexity refers to the number of possible execution paths inside a given piece of code—for instance, a function. The more decision structures you use, the more possible branches there are for your code. Cyclomatic complexity is especially important when it comes to testing.
Avoid use of switch/case statements in your code. Use Factory or Strategy design patterns instead. Complexity of 8 (1 for each CASE and 1 for method itself). Refactoring using Factory design pattern and complexity changed to 1.
Consequences: A high cyclomatic complexity for a particular function means that the function will be difficult to understand, and more difficult to test. That in turn means functions with a cyclomatic complexity above 10 or 15 can be reasonably expected to have more undetected defects than simpler functions.
An easy way is to promote the check into a separate method:
private String getAppendString(String value, String appendString) { if (value == null || value.isEmpty()) { return ""; } return appendString; }
And then you can use this method instead of the if
blocks:
sb.append(getAppendString(request.getStreet(), "street,");
This will reduce complexity from 28 down to 3. Always remember: high complexity counts are an indication that a method is trying to do too much. Complexity can be dealt with by dividing the problem into smaller pieces, like we did here.
Another approach would be to enforce that contract in the Request object itself. If a field is required or can't be null, say so when the Request is created.
Create the Request in such a way that it's 100% valid and ready to go when the constructor exists.
I'd also create that String version in the Request toString() method. It should know how to render itself.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With