Who thinks it would be great if the Drupal Coding Standards included checks for Cyclomatic Complexity and maximum nesting levels?

Cyclomatic complexity is a metric used to check the complexity of a function by checking the number of paths through it. There are those that think this should be limited at 10, any more and the function is too complex and should be refactored into a number of smaller, more easy to read, functions.

A good place this has highlighted faults is with people's use of the hook_form_alter() which ends up with a switching if of doom when they should really be using hook_form_FORM_ID_alter in most cases to just work on the form they actually want to change.

Nesting levels is the number of indentations caused by a new code block.

The PHPCS Generic CoderSniffer rules include the logic for this check already and I've supplied a patch to the coder module to include if it gets included in the DCS:
http://drupal.org/node/1934594#comment-7171972

Questions:

  1. Should this be included in the Drupal coding standards?
  2. What should the cyclomatic complexity limit be? - PHPCS sets this at 10 for a warning, 20 for an error
  3. What should the maximum nesting level be? - PHPCS sets this at 5 for a warning and 10 for an error (quite lenient)

For more details on this metric, see: http://en.wikipedia.org/wiki/Cyclomatic_complexity

Comments

skyredwang’s picture

I see measuring Cyclomatic Complexity in coder module is quite useful and educational as you have already proposed #1934594: Add checks for Cyclomatic Complexity. However, requiring a limit of Cyclomatic Complexity in coding standard might not be suitable at the moment for the 2 reasons below:

1. I tried to follow the wiki as well as "Structured Testing: A Testing Methodology Using the Cyclomatic Complexity Metric" (The link is point to a private file), I have not found any scientific or statistical evidence to suggest that the limit 10 (or any other number) is appropriate to apply in general.

2. In practice, there would be too many existing modules on Drupal.org that were not meeting the potential limit if introduced. If it got in coding standard now, we would be telling most people to re-do much of the our work over. But, we don't intend to send such message, do we?

johnennew’s picture

Hi @skyredwang, Thanks for your comments!

1. The limits would need to be set as appropriate by the community. Personally, I found the 10 (warning) 20 (error) limit that PHPCS highlights functions that do look like they need a refactor. As an example of a 15 - https://api.drupal.org/api/drupal/modules!comment!comment.module/functio...

2. The DCS are often more aspirational and setting the standard high gives developers a target to aim at. As a case in point, run the current coding standards on the Drupal 7 node module, you'll get 400+ violations of the current standards! Often I see attempts at getting web agencies to set some baseline metric of the separation of concerns or clean, supportable code, usually something along the lines of no function longer than 10 lines. This is quite a subjective measure but I think that Cyclomatic Complexity via coding standards is the best suggestion I've seen to date.

fuzzy76’s picture

In practice, there would be too many existing modules on Drupal.org that were not meeting the potential limit if introduced. If it got in coding standard now, we would be telling most people to re-do much of the our work over. But, we don't intend to send such message, do we?

Just my two cents: Most modules already break the existing code standards, so I doubt there would be many re-dos.

Angry Dan’s picture

I wasn't aware that there was a requirement to re-write code should the coding standards change? In this case you should be free to maintain existing code and failing functions, but new code should be aware of this measure. I don't think you can argue that it's not beneficial to have simpler code, and this is a good way of interpreting the readability and conciseness of code without setting difficult rules like "no function may be longer than 10 lines"

FWIW I'd like to see this in the standards in time for D8 contrib module developers.

Steve.C’s picture

Definitely agree with Cyclomatic Complexity being a better measure than lines of code. Only concern would be when to warn and when to error.. My understanding is that a comprehensive switch statement could easily burn a few of your paths and require a refactor, but this can be a very neat, readable way of laying out an Abstract Factory Pattern, for example. I'd be happy to take a slapped wrist and consider the design but should it be an error?

I understand switches are the easy way out, but occasionally Drupal pushes you down that way, and when writing with a view to various levels of developer being able to extend and support, they can be the "right" way. Perhaps the more OO nature of D8 will make the temptation less, but taking the boundaries down at all might stifle the flow of new, DCS compliant modules, when they're not going to break and make up for readability and support in other ways.

johnennew’s picture

@Steve.C - current codebase often fails Cyclomatic Complexity for the overuse of switch statements. In OO design, it's generally considered preferable to use different message types or classes that inherit from a common message class rather than trying to make choices within a function which makes the function more complex and means it behaves very differently depending on it's inputs. Clearly there are a number of different strategies to move away from switch statements (strategy and command patterns come to mind).

The point is that the Cyclomatic Complexity warning highlights that there is an issue and forces you to consider an alternative solution (if you want to be compliant). Perhaps it should remain as a warning and errors set much higher. I'm not sure DCS differentiates between warnings and errors - are warnings allowable but errors a definite no?

damien tournoud’s picture

Using the cyclomatic complexity as a metric for code quality is really far from being a silver bullet.

The main drawback in the case of PHP code is that the only available tools evaluate the cyclomatic complexity by static analysis at the function/method level, which has two really nasty implications:

  • The overall cyclomatic complexity is not measured, and the easiest way to reduce the cyclomatic complexity of a function/method is to break it into two; obviously this operation doesn't reduce the overall cyclomatic complexity;
  • The complexity of any dynamic branching (observer patterns, trampolines, etc.) is just completely hidden under the carpet.

A common fallacy is to think that by breaking up a function/method into smaller chunks (and hence reducing its cyclomatic complexity) you reduce the complexity of its tests. That's really never true, and is just an effect of the above.

I fear that in the current situation, having cyclomatic complexity as code quality metric would just increase the overall complexity of Drupal, making the code paths less obvious and at the end of the day making the whole thing less maintainable.

johnennew’s picture

@Damien Tournoud - what you say is of course true. However, we must remember the purpose of the DCS is to improve quality and provide some standard for compliance - it is not a provable metric for the software actually working, nor does compliance anywhere near guarantee a non-complex end product. This suggestion is for another tool to help capture compliancy issues where they can be captured. I do not think it makes the current situation worse but provides a mechanism to help make contrib authors think a bit deeper about the code they produce.

sun’s picture

I wanted to comment, but @Damien Tournoud literally covered all aspects in #7 already.

Statistical tools like this may help you to locate and identify some offending code, but they are not sufficient and suitable as a silver bullet and as a hard/enforced coding standard.

Crell’s picture

I agree that we can't/shouldn't enforce a "if you have a CC higher than X you get an error" rule in coding standards or in coder module. However, simply reporting on CC may help to point people toward the concept of complexity, and thereby become a learning experience. So +1 on calculating and reporting it, -1 for "enforcing" it.

johnennew’s picture

The PHPCS "Coder Sniffer" plugin for coder allows problems to be reported as either warning or errors. The Drupal Coding Standards, as I understand them, does not set these two thresholds; it's either in the standard (and therefore enforceable?) or not in the standard (and therefore ignored?). From @Crell's comments - is there a middle ground where DCS makes some recommendations, including CC, which are not part of the enforceable standard but used to point to potential code issues?

johnennew’s picture

Issue summary: View changes

Added li elements to questions list

jhedstrom’s picture

Status: Needs review » Postponed

I'm marking this postponed.

Since it won't be enforceable, it doesn't really make sense to add a limit to the DCS. Once patches are automatically tested for coding standards, this could be unpostponed to also report on CC. Alternatively, this could be moved into the coder queue as a feature request.

Version: 8.0.x-dev » 8.1.x-dev

Drupal 8.0.6 was released on April 6 and is the final bugfix release for the Drupal 8.0.x series. Drupal 8.0.x will not receive any further development aside from security fixes. Drupal 8.1.0-rc1 is now available and sites should prepare to update to 8.1.0.

Bug reports should be targeted against the 8.1.x-dev branch from now on, and new development or disruptive changes should be targeted against the 8.2.x-dev branch. For more information see the Drupal 8 minor version schedule and the Allowed changes during the Drupal 8 release cycle.

Version: 8.1.x-dev » 8.2.x-dev

Drupal 8.1.9 was released on September 7 and is the final bugfix release for the Drupal 8.1.x series. Drupal 8.1.x will not receive any further development aside from security fixes. Drupal 8.2.0-rc1 is now available and sites should prepare to upgrade to 8.2.0.

Bug reports should be targeted against the 8.2.x-dev branch from now on, and new development or disruptive changes should be targeted against the 8.3.x-dev branch. For more information see the Drupal 8 minor version schedule and the Allowed changes during the Drupal 8 release cycle.

Version: 8.2.x-dev » 8.3.x-dev

Drupal 8.2.6 was released on February 1, 2017 and is the final full bugfix release for the Drupal 8.2.x series. Drupal 8.2.x will not receive any further development aside from critical and security fixes. Sites should prepare to update to 8.3.0 on April 5, 2017. (Drupal 8.3.0-alpha1 is available for testing.)

Bug reports should be targeted against the 8.3.x-dev branch from now on, and new development or disruptive changes should be targeted against the 8.4.x-dev branch. For more information see the Drupal 8 minor version schedule and the Allowed changes during the Drupal 8 release cycle.

Version: 8.3.x-dev » 8.4.x-dev

Drupal 8.3.6 was released on August 2, 2017 and is the final full bugfix release for the Drupal 8.3.x series. Drupal 8.3.x will not receive any further development aside from critical and security fixes. Sites should prepare to update to 8.4.0 on October 4, 2017. (Drupal 8.4.0-alpha1 is available for testing.)

Bug reports should be targeted against the 8.4.x-dev branch from now on, and new development or disruptive changes should be targeted against the 8.5.x-dev branch. For more information see the Drupal 8 minor version schedule and the Allowed changes during the Drupal 8 release cycle.

Version: 8.4.x-dev » 8.5.x-dev

Drupal 8.4.4 was released on January 3, 2018 and is the final full bugfix release for the Drupal 8.4.x series. Drupal 8.4.x will not receive any further development aside from critical and security fixes. Sites should prepare to update to 8.5.0 on March 7, 2018. (Drupal 8.5.0-alpha1 is available for testing.)

Bug reports should be targeted against the 8.5.x-dev branch from now on, and new development or disruptive changes should be targeted against the 8.6.x-dev branch. For more information see the Drupal 8 minor version schedule and the Allowed changes during the Drupal 8 release cycle.

Version: 8.5.x-dev » 8.6.x-dev

Drupal 8.5.6 was released on August 1, 2018 and is the final bugfix release for the Drupal 8.5.x series. Drupal 8.5.x will not receive any further development aside from security fixes. Sites should prepare to update to 8.6.0 on September 5, 2018. (Drupal 8.6.0-rc1 is available for testing.)

Bug reports should be targeted against the 8.6.x-dev branch from now on, and new development or disruptive changes should be targeted against the 8.7.x-dev branch. For more information see the Drupal 8 minor version schedule and the Allowed changes during the Drupal 8 release cycle.

Version: 8.6.x-dev » 8.8.x-dev

Drupal 8.6.x will not receive any further development aside from security fixes. Bug reports should be targeted against the 8.8.x-dev branch from now on, and new development or disruptive changes should be targeted against the 8.9.x-dev branch. For more information see the Drupal 8 and 9 minor version schedule and the Allowed changes during the Drupal 8 and 9 release cycles.

Version: 8.8.x-dev » 8.9.x-dev

Drupal 8.8.7 was released on June 3, 2020 and is the final full bugfix release for the Drupal 8.8.x series. Drupal 8.8.x will not receive any further development aside from security fixes. Sites should prepare to update to Drupal 8.9.0 or Drupal 9.0.0 for ongoing support.

Bug reports should be targeted against the 8.9.x-dev branch from now on, and new development or disruptive changes should be targeted against the 9.1.x-dev branch. For more information see the Drupal 8 and 9 minor version schedule and the Allowed changes during the Drupal 8 and 9 release cycles.

Version: 8.9.x-dev » 9.2.x-dev

Drupal 8 is end-of-life as of November 17, 2021. There will not be further changes made to Drupal 8. Bugfixes are now made to the 9.3.x and higher branches only. For more information see the Drupal core minor version schedule and the Allowed changes during the Drupal core release cycle.

Version: 9.2.x-dev » 9.3.x-dev

Version: 9.3.x-dev » 9.4.x-dev

Drupal 9.3.15 was released on June 1st, 2022 and is the final full bugfix release for the Drupal 9.3.x series. Drupal 9.3.x will not receive any further development aside from security fixes. Drupal 9 bug reports should be targeted for the 9.4.x-dev branch from now on, and new development or disruptive changes should be targeted for the 9.5.x-dev branch. For more information see the Drupal core minor version schedule and the Allowed changes during the Drupal core release cycle.

Version: 9.4.x-dev » 9.5.x-dev

Drupal 9.4.9 was released on December 7, 2022 and is the final full bugfix release for the Drupal 9.4.x series. Drupal 9.4.x will not receive any further development aside from security fixes. Drupal 9 bug reports should be targeted for the 9.5.x-dev branch from now on, and new development or disruptive changes should be targeted for the 10.1.x-dev branch. For more information see the Drupal core minor version schedule and the Allowed changes during the Drupal core release cycle.

Version: 9.5.x-dev » 11.x-dev

Drupal core is moving towards using a “main” branch. As an interim step, a new 11.x branch has been opened, as Drupal.org infrastructure cannot currently fully support a branch named main. New developments and disruptive changes should now be targeted for the 11.x branch. For more information, see the Drupal core minor version schedule and the Allowed changes during the Drupal core release cycle.

quietone’s picture

Status: Postponed » Closed (won't fix)

There hasn't been interest in pursuing this in 10 years. And the related issue in the Coder project was closed as won't fix 9 years ago with no further discussion. #1934594: Add checks for Cyclomatic Complexity. Due to the lack of interest I am closing this as won't fix. If anyone disagrees, re-open adding an explanatory comment.