Extract conditions into descriptive functions
Break down complex expressions into well-named functions. Instead of a big, messy block, your code starts reading like sentences.
Pseudocode as expression of intent
if user is active and has permission to execute process request“Raw” C++
if (user.status == Status::Active && user.permissions.contains(Permission::Execute)) { process(request);}DSL-like C++
if (isActive(user) && hasPermissionToExecute(user)) { process(request);}Sometimes methods on objects can make your DSL cleaner, but be careful not to couple unrelated logic and dependencies into a class unnecessarily.
if (user.isActive() && user.hasPermission(Permission::Execute)) { process(request);}Consider taking it one step further:
if (user.canExecuteRequests()) { process(request);}When abstracting, there is always a trade-off. The reader now has to look elsewhere to see what “can execute requests” really means. Extracting the condition into a single function may or may not improve clarity. Judge based on the total length and complexity of the condition, and how well you are able to convey the meaning in a single name. A good function name describes its behavior such that the reader is not required to jump to the definition to understand it. Another good guideline is to avoid mixing levels of abstraction in the same scope.
Notice how the last step, canExecuteRequests() actually hides the originally expressed idea from the pseudocode snippet? This suggests that this might be one step of extracting too far.
By extension, prefer standard algorithms over raw loops. std::any_of, std::none_of, std::any_of are all essentially ‘extracted functions’ that are more expressive than using for loops to analyze the contents of a container.