Do you prefer to limit the number of parameters accepted by a single
function/method, and if so, how do you handle situations where more data
is needed?
TLDR; specific questions at the end of this msg
Along with one of our list-colleagues (a fellow graduate?survivor from
the time of mainframe computers, monolithic programs, when "structured
programming" was 'the latest new idea', and OOP[s] was one's exclamation
upon making a mistake) we have been re-reading and discussing "Code
Complete". It is 'an oldie, but a goodie', and Python progs may feel
so-superior by happily looking-past various C*/Java-based ideas.
The chapter on "High-Quality Routines" covers a lot of (hopefully, to
you) familiar ground, eg structural-decomposition, descriptive names,
manageability, readability, reliability, changeability, isolating
complexity, SRP, strong-cohesion, loose-coupling (and all the fun of the
fair...).
A particular focus is "Parameter passing issues" - that the list as an
whole presents a "consistent interface abstraction", that the parameters
are in a sensible sequence (that it matches any other similar function
signatures), and that assumptions are documented. The recommendation is
that the list be <= seven parameters. [I have a recollection that
someone else (?'Uncle Bob Martin') recommends <= three]
What should one do when a routine requires numbers of input values? Does
Python's lack of "interfaces" let us down?
If we were going to be pedantic, then the quick-and-dirty way to reduce
the parameter-count might be to use a collection, eg put a physical
address into a named-tuple or list called "address" instead of passing
"street", "town", "city", "postal_code", etc.
We shouldn't be childish when it comes to style-guides. If the data is
as cohesive as the components of an address, we should define a class.
Now we can pass a single instantiated-object, with style and flair!
However, the criticism of that idea is that it 'breaks' encapsulation -
the parameter's routine now needs to know which data-attributes exist
within the passed object - which is an example of close-coupling. Also,
if instead of creating a new object, eg "address", we passed across a
containing object, eg "person"; we might save ourselves some effort!
Sadly, we would (likely) be passing loads of unnecessary data, possibly
even in an insecure fashion.
Time for some compromise? How about we add a method to the "address"
example-object, which is then passed to the routine? It can be called,
and deliver the object's necessary attributes per the interface's spec.
NB we can do this in Python because a function/method is a "first-class
object"! Now our parameter list is shortened (hopefully to the
recommended degree) - thus also the degree of "coupling" between the
call-ing and call-ed routines, the data passed is minimised, and the
communication across the interface clarified. That said, haven't we now
built what other languages might call an "interface"?
Questions:
Is the idea of limiting the number of parameters passed across an
interface a real concern or somewhat an affectation?
Is three, five, seven, ... a valid limit (or warning-signal)?
Do you have a personal or corporate style or 'standard' to limit
parameter lists to seven parameters, or some other number?
Given that Python enables labeled arguments ("keyword arguments"), does
the concern really only apply to 'us' in terms of numbers of "positional
arguments"?
Why not simply create and pass a collection (to suit the 'standards
committee') and be done. What's the big deal, don't have time to waste,
bureaucracy (!)...
What about the similar Q+D solution using a class? After all, we could
just as easily build an extraction-routine into the calling-class, which
reaches into the passed-class for the data it needs - then we don't have
to go to the other team to ask their 'permission'/agreement/cooperation
or wait for them to build the requisite method!
Is passing a function as an argument a safe and valid way to do
business, or is it 'showing off'?
Does the pass-a-function idea making testing easier (of both the call-ed
and the call-ing routines) and might it make a change (eg adding another
field) easier to manage in-future?
What do you do?
Refs:
Steve McConnell, "Code Complete", Microsoft Press, 2004.
--
Regards,
=dn
--
https://mail.python.org/mailman/listinfo/python-list