Uxopian Software Blog

Coding Conventions

Written by David Toty | Apr 22, 2025 12:46:46 PM

In software development, adopting coding conventions is often seen as a needless constraint, allowing developers full flexibility beyond imposed style rules. However, this freedom can quickly become a source of disorganization and technical debt if left unchecked.

In many teams, a standard code style is defined and mandatory, ensuring visual consistency. However, without deeper rules, developers are free in their implementation choices, which can lead to inconsistencies, reduce code readability, and complicate maintenance.

 

Why Go Beyond Simple Code Style?

Relying solely on code style is not enough to ensure the quality and maintainability of a project. Here’s why it’s essential to adopt stricter development conventions:

  • Consistency and Uniformity: When each developer applies their own rules, the codebase quickly becomes heterogeneous. Establishing clear conventions ensures a unified architecture and better understanding across the team.
  • Easier Code Review: A structured codebase that adheres to clear principles facilitates peer review and accelerates validation of changes.
  • Improved Readability and Maintainability: Well-organized code, with explicit names and simplified structures, is easier to read and maintain—especially for new developers or during refactorings.
  • Fewer Errors and Lower Cognitive Load: By applying best practices like limiting method length or reducing condition nesting, we reduce mental strain and the risk of errors.
  • Standardization and Scalability: For large-scale projects, standardizing conventions supports scalability and smoother onboarding for new team members.

Going beyond basic style rules helps structure development effectively, promotes collaboration, and ensures long-term project sustainability. In the following sections, we’ll explore how to define effective coding conventions and manage cognitive complexity to produce cleaner, more maintainable code.

 

Cognitive Complexity

Cognitive complexity is a metric developed by SonarSource to measure how difficult code is to understand. Unlike metrics like cyclomatic complexity, it evaluates the mental effort required to read and analyze a code segment. Its goal is to encourage refactoring and enhance code readability to reduce developer cognitive load.

 

Working Memory and Its Limits

Working memory is a core cognitive function that allows us to temporarily store and manipulate information to complete a task. Unlike short-term memory, which only stores information for a few seconds, working memory processes data while performing other operations.
According to Miller’s Law (1956), the number of items that can be retained simultaneously in working memory is limited to 7 ± 2. However, more recent studies, such as Farrington (2011), suggest that the actual capacity is closer to 3 to 4 items.

Baddeley’s model (1992) illustrates this constraint:

  • People can typically retain around 7 words when presented as text.
  • When presented with icons or visual symbols, this drops to 4 items.
  • When both types are combined, memory recall is limited to 7 words and 4 icons.

This cognitive limit directly affects how we understand source code.
The more dense, nested, and condition-heavy code is, the more it burdens working memory, making comprehension harder.

This is where cognitive complexity comes in.
By limiting nesting depth, simplifying conditional logic, and organizing code modularly, we can ease the programmer’s mental load and improve readability.

 

How Is Cognitive Complexity Measured?

Cognitive complexity increases based on the following criteria:

  • +1 point for each control structure:
    • if, else, switch/case, for, while, do-while

  • +1 point for each code jump: 
    • continue, break, return (excluding simple function returns)

  • Logical operators:
    • Repeated use of the same logical operator (&& or ||) does not add complexity.
    • Changing logical operators (e.g., from && to ||) adds +1 per change.

The goal is to keep a method’s cognitive complexity below a critical threshold to ensure code clarity and maintainability. For example, SonarQube recommends not exceeding a score of 15 per method, with a good practice aiming for 10 or less.

Java Example:

if (A && B && C) {   // Score = 1 (for the if)
    process();
}

if (A && B && C || D || E && F) {  // Score = 4
    process();
}
    

Explanation:

  • In the first case, the repeated use of && adds no complexity, so the total score is just +1 for the if.
  • In the second case, changing from && to ||, and back to &&, adds two additional points, plus one for the if, for a total of 4.

Nesting Depth

Nesting control structures, such as loops and conditions, increases cognitive complexity. The more deeply nested a block is, the higher its complexity score.

  • Each nesting level adds points equal to its depth.
  • try blocks are excluded, but catch blocks count.

Code jumps like continue or break also add +1. They can make program flow more difficult to follow, especially when used inside nested loops.

Java Example:

 

for (int i = 0; i < 10; i++) {   // Score +1
    if (i % 2 == 0) {            // Score +2 (nesting depth 2)
        while (i < 5) {          // Score +3 (nesting depth 3)
            try {
                riskyMethod();
            } catch (Exception e) {  // Score +3 (nesting depth 3)
                System.out.println("Erreur");
            }
        }
    }
} // Cognitive complexity = 9
  
void myMethod() {
    Runnable r = () -> {   // +0 (but nesting depth increases)
        if (condition1) {  // +2            
            // Code...
        }
    };
}  // Cognitive complexity  = 2
  
String getOrderStatus(int status) {
    switch (status) {  // +1
        case 0:
            return "On hold";
        case 1:
            return "In processing";
        case 2:
            return "Shipped";
        case 3:
            return "Delivered";
        default:
            return "Unknown";
    }
} // Cognitive complexity = 1
  
int sumOfPrimesInArray(int[] numbers) {
    int total = 0;
    OUT: for (int i = 0; i < numbers.length; ++i) { // +1
        for (int j = 2; j < numbers[i]; ++j) {      // +2 (nesting depth 2)
            if (numbers[i] % j == 0) {              // +3 (nesting depth 3)
                continue OUT;                       // +1 (jump)
            }
        }
        total += numbers[i];
    }
    return total;
} // Cognitive complexity = 7
  

 

 

Solutions: Reducing Cognitive Complexity

High cognitive complexity hurts code readability, increases error risk, and makes maintenance harder.
To improve clarity and efficiency, it's important to adopt practices that simplify structure and organization.

Simplify logic

It is best to break down complex logic into several smaller functions or methods to improve code comprehension and readability.

Reduce nesting

Code with too many levels of nesting becomes difficult to follow and increases the mental load for developers. Therefore, strategies should be adopted to limit the depth of conditions and loops.

Extract methods
When a block of code becomes too large, it is recommended to move it into a separate method to improve modularity and facilitate program maintenance.

Simplify conditions

Long and complex conditions make code difficult to analyze. It is recommended to refactor these expressions to make them more readable and understandable.

Avoid unnecessary jumps (continue, break)

Flow breaks in loops make code difficult to read and execute. It's best to structure your program to minimize the use of these instructions whenever possible.`

Refactoring Example:

public void myMethod() throws IOException
{
    // code
    if (documentExists() || source != null && documentLayout != null
        && documentLayout instanceof DocumentContainer)
    {
        DFSDocumentAccessor accessor = new DFSDocumentAccessor
            (source.getDocumentId(), INITIAL, storageStrategy);
        accessor.setDocumentTitle(source.getDocumentTitle());
        accessor.setDocumentLayout(documentLayout);
        accessor.setRenditionState(DFSDocumentAccessor.RenditionState.CONVERTED);
        accessor.setMimeType(MimeTypes.APPLICATION_ARENDER_CONTAINER_DOCUMENT);
        accessor.setInputStream(new ByteArrayInputStream("empty".getBytes()));
        pushToCache(accessor);
    }
    else
    {
        // more code
    }
}
  

After:

public void myMethod() throws IOException
{
    // code
    if (shouldPushAccessor())
    {
        pushAccessor();
        return;
    }
    // more code
}

private void pushAccessor() throws IOException
{
    DFSDocumentAccessor accessor = new DFSDocumentAccessor
        (source.getDocumentId(), INITIAL, storageStrategy);
    accessor.setDocumentTitle(source.getDocumentTitle());
    accessor.setDocumentLayout(documentLayout);
    accessor.setRenditionState(DFSDocumentAccessor.RenditionState.CONVERTED);
    accessor.setMimeType(MimeTypes.APPLICATION_ARENDER_CONTAINER_DOCUMENT);
    accessor.setInputStream(new ByteArrayInputStream("empty".getBytes()));
    pushToCache(accessor);
}

private boolean shouldPushAccessor() {
    return documentExists() || (source != null && documentLayout != null 
        && documentLayout instanceof DocumentContainer);
}
  

 

Key Differences:

  1. Separation of concerns: Each function has a clear and unique responsibility.
  2. Encapsulation of decision logic: The condition is extracted into a method.
  3. Early return: Avoids unnecessary else blocks by exiting early.

Tip: Quickly Extract Methods with IntelliJ IDEA

To extract a block of code into a method in IntelliJ IDEA:

  1. Select the code block
  2. Right-click → Refactor → Extract Method…
  3. Or use the shortcut: Ctrl + Alt + M (Windows/Linux) or ⌘ + Option + M (Mac)

This generates a new method automatically, improving readability and reducing complexity in just a few seconds!

 

 

Sources :

  1. Wikipedia contributors. (n.d.). The magical number seven, plus or minus two. Wikipedia. Retrieved April 22, 2025, from https://en.wikipedia.org/wiki/The_Magical_Number_Seven,_Plus_or_Minus_Two

  2. SonarSource. (n.d.). Cognitive complexity. SonarSource. Retrieved April 22, 2025, from https://www.sonarsource.com/resources/cognitive-complexity/