Imagine a game that needs to score words. A words needs to be scored immediately, in a list of words or even in a list of words from list of players.

I've created a scoring module which has the following public methods:

  • score_single_word(word) -> int
  • score_list_of_words(list) -> int
  • score_group_of_players(players) -> [int]

These methods obviously cascade, so score_group_of_players does some calculation and calls score_list_of_words eventually calls score_single_word.

Unfortunately, the every method requires clean up, such that the words are lowercase, stripped of white space and unique. Otherwise their respectives task would fail. I didn't see another way but doing that clean up multiple times, since neither method can be sure its assumptions are fulfilled earlier by one of the higher methods.

What can I do to remove those unnecessary clean ups while making sure that the assumptions are still correct?

2 Answers 2


I suspect you don't actually need to expose all of these functions. If, e.g. score_single_word is a private method, you can assume that it is called with valid input. (Though, adding assertions to guarantee this is probably worthwhile.)

If score_list_of_words also doesn't need to be public, then it may also assume it is given valid input, though I personally would likely define it to take any input and handle normalization.

score_group_of_players, as far as I can tell, doesn't need to do anything if score_list_of_words will take in arbitrary input. Alternatively, you could have a separate normalize function that will do all "clean up".

If you do need to expose score_single_word, I would define it in terms of score_list_of_words which normalizes its input. (I'd still likely factor out the "clean up" code into a normalize function, even if it is private and only used by score_list_of_words to make score_list_of_words be cleaner.) score_list_of_words can then call a private internal_score_single_word that doesn't validate the input.

At any rate, in general, you do what you normally do: factor out the commonality, find good location for abstraction barriers. For example, an alternative approach is to ask "why is 'messy' input even being given to any of these functions?" This might lead you to make a type for "words" and/or "lists of words" which guarantees the invariants and only presents "cleaned up" output. Often this is a better approach, but it may be overkill in this case.


Do you need to show the words back to the user? If not, then clean it on input. Likewise with lists - either don't insert words the list already contains, or if you're adding multiple words at once, immediately do a duplicate removal pass, and then only pass around cleaned up lists.

If you do need to keep the original string to show to the user again later, then instead of passing around raw strings, pass around an object (or struct, or whatever your language supports), that contains the original string and the cleaned up one. You can still keep lists clean before ever passing them on with this scenario, again, by either not inserting duplicates or doing a clean pass immediately after doing any additions.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.