Earlier quoted context omitted.
One approach that can help is to name things based on what the functions actually do. validateSortDisplayedItems { validation Logic ... sortDisplayedItems(); //Actually sorts items. } This can be harder to maintain, but really long names end up a useful code smell.
I find it a bit...incorrect. I mean, your above code LIES. If I call validateSortDisplayedItems, I don't validate, I validate AND sort. Plus, what do you do if you have "validateItems" and "sortItems", and then one function that calls them each in turn? call it "validateAndSortItems"? Yuck.
validateSortDisplayedItems
{
if(!DisplayedItemsValid())
{
CorrectDisplayedItems();
if(!DisplayedItemsValid())
{
DisplayValidationError();
return;
}
}
sortDisplayedItems(); //Actually sorts items.
}
AKA validate means try and make valid, not verify that data isValid. So, you can't just do if(isValid) sort; the bonus is unrecoverable errors end up at leaf nodes vs. the happy path.At the high level, your function might be sortClicked, which can then respond to that by calling a wide range of functions. (userCanSort,SortData,UpdateDisplay)
PS: I find the validate > correct loop is generally the important and error prone part of code, so I give it priority. The happy path where everything works is more or less an addendum.