include::../intro.adoc[] == Why is this an issue? include::../why.adoc[] === What is the potential impact? include::../impact.adoc[] == How to fix it include::../how.adoc[] === Code examples **Extraction of a complex condition in a new function.** ==== Noncompliant code example The code is using a complex condition and has a cognitive cost of 5. [source,python,diff-id=1,diff-type=noncompliant] ---- def process_eligible_users(users): for user in users: # +1 (for) if ((user.is_active and # +1 (if) +1 (nested) +1 (multiple conditions) user.has_profile) or # +1 (mixed operator) user.age > 18 ): user.process() ---- ==== Compliant solution Even if the cognitive complexity of the whole program did not change, it is easier for a reader to understand the code of the `process_eligible_users` function, which now only has a cognitive cost of 3. [source,python,diff-id=1,diff-type=compliant] ---- def process_eligible_users(users): for user in users: # +1 (for) if is_eligible_user(user): # +1 (if) +1 (nested) user.process() def is_eligible_user(user): return ((user.is_active and user.has_profile) or user.age > 18) # +1 (multiple conditions) +1 (mixed operators) ---- **Break down large functions.** ==== Noncompliant code example __Note:__ The code is simplified here, to illustrate the purpose. Please imagine there is more happening in the process. + The bellow code has a cognitive complexity score of 8. [source,python,diff-id=3,diff-type=noncompliant] ---- def process_user(user): if user.is_active(): # +1 (if) if user.has_profile(): # +1 (if) +1 (nested) ... # process active user with profile else: # +1 (else) ... # process active user without profile else: # +1 (else) if user.has_profile(): # +1 (if) +1 (nested) ... # process inactive user with profile else: # +1 (else) ... # process inactive user without profile ---- This function could be refactored into smaller functions: The complexity is spread over multiple functions and the breaks in flow are no more nested. + The `process_user` has now a complexity score of two. ==== Compliant solution [source,python,diff-id=3,diff-type=compliant] ---- def process_user(user): if user.is_active(): # +1 (if) process_active_user(user) else: # +1 (else) process_inactive_user(user) def process_active_user(user): if user.has_profile(): # +1 (if) +1 (nested) ... # process active user with profile else: # +1 (else) ... # process active user without profile def process_inactive_user(user): if user.has_profile(): # +1 (if) +1 (nested) ... # process inactive user with profile else: # +1 (else) ... # process inactive user without profile ---- **Avoid deep nesting by returning early.** ==== Noncompliant code example The below code has a cognitive complexity of 6. [source,python,diff-id=4,diff-type=noncompliant] ---- def calculate(data): if data is not None: # +1 (if) total = 0 for item in data: # +1 (for) +1 (nested) if item > 0: # +1 (if) +2 (nested) total += item * 2 return total ---- ==== Compliant solution Checking for the edge case first flattens the `if` statements and reduces the cognitive complexity to 4. [source,python,diff-id=4,diff-type=compliant] ---- def calculate(data): if data is None: # +1 (if) return None total = 0 for item in data: # +1 (for) if item > 0: # +1 (if) +1 (nested) total += item * 2 return total ---- === Pitfalls As this code is complex, ensure that you have unit tests that cover the code before refactoring. include::../resources.adoc[] include::../rspecator.adoc[]