In dynamically and weakly-typed languages*, I often find myself with structures like the following pseudocode:
class Stateful:
# [ various datamembers / attributes / properties / fields / etc. ]
define constructor(arguments):
configureA(arguments)
# [ maybe set a variable or two here ]
configureB()
define configureA():
## configures the most important parts of Stateful state
## throws some exceptions if these basic changes cannot be made
# [ code goes here ]
define configureB():
## handles a little bit of bookkeeping. Usually called after configureA().
## expects the following variables to be set: <list of vars>
# [ code goes here ]
#
# ...
Though there may be a better way to do this such as providing a single block that describes the call-sequence and notes consequences all in once place, is it a good idea in general to document expected call-sequences? If it is a good idea to "just document" this sort of thing when it comes up, are there established best-practices? Or is doing so perhaps a sign of a deeper problem?
* Answers to this question suggest that configureA()
return a type which is required by configureB()
, then have configureB()
return a type which is required by configureC()
, etc. I'm asking here about languages which are weakly and/or dynamically typed, or in instances wherein adding extra classes for each configuration-step would just yield a bunch of smallish classes with low to no reusability and poor maintainability given a need for even more classes if config gains steps.
My mixed thoughts about this follow below the line:
Reasons to document expected call-sequences (in some form or other):
Such comments often help me track down would-be mysterious errors in my code, by leading me to re-examine call-sequences after periods of being focused on other implementation-details.
If code for stateful classes needs to be updated, this should help other programmers avoid such mysterious errors as well.
Especially for private functions, describing functions' "contracts" in comments allows me to focus on essential functionality in and less on
throw new DescriptiveErrorMessage("Let's talk for a while, shall me? ...")
. Even in the case where exceptions should ultimately be thrown, I find it easier to go back and examine exception-cases after I've been apart from the real "working" part of the code for a while.Not other all programmers will be using IDEs capable of generating information about standing call-sequences for them, and even if they did, an IDE may not be able to tell a programmer whether a certain sequence of initialization-calls is necessary or just a de-facto "it's in that order because that's how it was written"
Reasons not to do this:
Comments like these are implementation-specific and may not have a lot of usefulness after a class is stabilized.
Comments like these increase code's maintenance-burden because they need to be kept up-to-date in addition to the code itself.
The code should speak for itself and good programmers should use introspection instead of reading my drivel.
Comments specifying these kinds of sequential preconditions may just be a crutch for bad code.