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 3.

[source,cpp,diff-id=1,diff-type=noncompliant]
----
void processEligibleUser(User user) {
  if ((user.isActive() && user.hasProfile()) // +1 (if) +1 (multiple conditions)
     || (user.getAge() > 18)) {              // +1 (mixing operators)
    // process the user
  }
}
----

==== 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 `processEligibleUser` function, which now only has a cognitive score of 1.

[source,cpp,diff-id=1,diff-type=compliant]
----
void processEligibleUser(User user) {
  if (isEligibleUser(user)) {  // +1 (if)
    // process the user
  }
}

bool isEligibleUser(User user) {
  return (user.isActive() && user.hasProfile()) // +1 (multiple conditions)
      || (user.getAge() > 18));                 // +1 (mixing operators)
}
----

**Break down large functions.**

==== Noncompliant code example

The code is simplified here to illustrate the purpose. Please imagine there is more happening in the process. +
The overall complexity of `processUser` is 8.

[source,cpp,diff-id=3,diff-type=noncompliant]
----
void processUser(User user) {
  if (user.isActive()) {      // +1 (if)
    if (user.hasProfile()) {  // +1 (if) +1 (nested)
      // process active user with profile
    } else {                  // +1 (else)
      // process active user without profile
    }
  } else {                    // +1 (else)
    if (user.hasProfile()) {  // +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 longer nested. +
The `processUser` now has a complexity score of two.

==== Compliant solution

[source,cpp,diff-id=3,diff-type=compliant]
----
void processUser(User user) {
  if (user.isActive()) {      // +1 (if)
    processActiveUser(user);
  } else {                    // +1 (else)
    processInactiveUser(user);
  }
}

void processActiveUser(User user) {
  if (user.hasProfile()) {    // +1 (if)
      // process active user with profile
  } else {                    // +1 (else)
      // process active user without profile
  }
}

void processInactiveUser(User user) {
  if (user.hasProfile()) {    // +1 (if)
    // 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 3.

[source,cpp,diff-id=4,diff-type=noncompliant]
----
void checkUser(User user) {
  if (user.isActive()) {     // +1 (if)
    if (user.hasProfile()) { // +1 (if) +1 (nested)
      // do something
    }
  }
}
----

==== Compliant solution

Checking for the edge case first flattens the `if` statements and reduces the cognitive complexity to 2.

[source,cpp,diff-id=4,diff-type=compliant]
----
void checkUser(User user) {
  if (!user.isActive()) {
    return;
  }
  if (!user.hasProfile()) {
    return;
  }
  // do something
}
----

=== Pitfalls

As this code is complex, ensure that you have unit tests that cover the code before refactoring.

include::../resources.adoc[]

ifdef::env-github,rspecator-view[]

'''
== Implementation Specification
(visible only on this page)

include::../message.adoc[]

=== Parameters

.maximumFunctionCognitiveComplexityThreshold
****

----
25
----

The maximum authorized complexity.
****


include::../highlighting.adoc[]

endif::env-github,rspecator-view[]
