I have to write API validation functions where the rules can get hairy and have many outputs depending on the branch taken.
These validation functions end up being a nesting of lots of IF conditions here and there (I try to stick to simple condition IF for simplicity), where I have lots of comments to help what's happening, but it's a big spaghetti.
Also, as I validate, I do little steps towards constructing the object/result I'm interested on, so I have two problems with this code:
It's a huge spaghetti with lots of exit branches, which... does reflect the complicated real life situation.
Validation and result construction happen together, tricky to split validation separately, because if done then I end up with this complex tree twice, once in a validation function and another to build my result.
Are there strategies/patterns to look for these scenarios?
PS: I'm using Python in case any library or pattern helps with that.
-
take a look at the composite design pattern sourcemaking.com/design_patterns/composite and dzone.com/articles/composite-design-pattern-java-0 and sourcemaking.com/design_patterns/composite/python/1 and code.activestate.com/recipes/…Richard Chambers– Richard Chambers2017年11月03日 05:28:06 +00:00Commented Nov 3, 2017 at 5:28
-
1@RichardChambers: That seems like overkill unless you're building a compiler or a rules engine.Robert Harvey– Robert Harvey2017年11月03日 15:58:00 +00:00Commented Nov 3, 2017 at 15:58
-
@RobertHarvey whether it is over kill or not is really up to the OP since there is insufficient information provided to determine if it is over kill or not. From what I gather a rules engine with validation and creating some kind of object or result while performing the validation is what he is doing.Richard Chambers– Richard Chambers2017年11月03日 19:24:14 +00:00Commented Nov 3, 2017 at 19:24
2 Answers 2
Write simple boolean functions and combine them.
bool ContainsUpperCase(string s) { } bool ContainsNumbers(string s) { } bool ContainsLowerCase(string s) { } bool ContainsSpecialCharacters(string s) { } bool IsValidPassword = ContainsUpperCase(password) && ContainsNumbers(password) ...etc
Use Early Exit
if (parameter == null) return (or throw); if (!IsValidPassword) return (or throw);
Use default values to avoid null checks
int parameter = 0;
Rewrite the logic so it requires less conditions.
Use a validation library
Write a Rules Engine
..etc
Here's some snippet as suggestion.
class MyComplexObject:
def __init__(self):
#lots of properties in your complex object
def build_complex_result(complex_input):
complex_object = MyComplexObject()
#Validate person info
assert(complex_input.age > 10 \
and complex_input.age < 50 \
and 'brazil' not in complex_input.country)
add_person_info(complex_object, complex_input)
#Validating address
assert(complex_input.address is not None) #...and lots of other conditions...
add_address_info(complex_object, complex_input)
#... and so on ...
#Also, you could place these assertions and 'add_xxxx_info' to other classes
#if necessary
return complex_object