Part of the Well Formed Errors Initiative
Problem/Motivation
"Be polite, Never Assert
Avoid the assert() mechanism, because it could turn a three-day debug fest into a ten minute one."
-- How to Write Unmaintainable Code, Roedy Green.
Even the experienced developers can be stumped or stalled when a large program they are working with throws a cryptic error or exception from an unfamiliar section of the code, especially when the actual failure is much further up the stack.
To prevent these sorts of headaches and make developing for Drupal 8 easier than ever before this issue ticket introduces the use of PHP's assert mechanism, optimizing the cache system as a case study and usage scenario. New traits are provided to allow unit tests to be written in an assertion aware manner so that the assert statements can be verified to fail when they should fail.
What are Assertions? What's the difference between Assertion, Exception and Error?
Assertions get confused with exceptions by novice and even some experienced programmers, so here is a summary of what they are, what they do, and what makes them distinct and useful.
- Assertions document the code and openly state conditions that are impossible given error free code and module configuration.
- Unlike errors and exceptions, assertions can be disabled, and in this state they have no more effect on the runtime than the comment text (so long as they are passed as strings to be evaluated, not as output from functions or expressions).
- Because they can be disabled, assertions cannot be used as control structures.
- Assertions are not a replacement for Test Driven Design - they are a supplement to it. PHP Unit Tests allow a block of code to be tested for its internal consistency, and more elaborate tests can be written to test interactions with other known blocks of code. Assertions can guard the code against mistakes in code and configuration files yet to be written.
- Exceptions deal with user input mistakes, other programs malfunctioning, hardware failures, network outages, etc. If a situation can arise from outside the program, no matter how rare it is in practice, it should be handled by an Exception. Exceptions can be catch by code further up the stack using try/catch blocks. Neither assertions nor errors have this ability.
- Errors either
- Deal with situations which are by nature irresolvable (such as a parse error) and will require system shutdown - hence no opportunity should be given to catch them at all.
- Log circumstances that may be important but do not leave the program in an unstable state - such as the calling of a function scheduled for deprecation.
Keep in mind the following: All bugs are errors, but not all errors are bugs. Assertions catch bugs -- errors in the program code and its developer configuration files (not the config files the final system admin writes themselves though). They are never to be used to catch errors which can arise from the user or environment as these aren't bugs (though failure to properly handle them is often called such).
Proposed resolution
The usefulness of the assert mechanism is demonstrated using the cache contexts system. During development it is necessary to validate both the cache tags and cache contexts since an invalid entry in either can invalidate the cache and lock up the site. During production new cache tags and cache contexts are not being created so such validation becomes redundant and expensive - profiling tests have shown a slowdown of the whole system of about 2% on just a basic page with around 50 cache tokens, nevermind a complicated view with hundreds or thousands of such tokens.
Assertions will replace calls to these verifications so that they only occur during development when assertions are turned on. Since PHP ships with assertions turned on by default assertions will be turned off using .htaccess.
User interface changes
None.
API changes
No changes, minor additional options opened for developers writing tests.
Beta phase evaluation
Issue category | Task because this is an enhancement and developer's aid only. |
---|---|
Issue priority | Major |
Prioritized changes | Using assert has been verified to give performance gains in #2454643: Optimize cacheability bubbling (Cache::mergeTags(), ::mergeContexts(), BubbleableMetadata), so this minimal complexity version is being built for 8.0.x |
Disruption | Adding assertions will expose additional existing bugs, and already has during testing #2465749: Widespread HTML validation issue - The ID attribute MUST be unique on the page.. Priority will need to be assigned on those bugs. It is hoped that at least a few of these turn out to be the culprits behind the remaining critical bugbears. Note though the code itself isn't creating new bugs, simply exposing them. |