Subj : Re: What the bleep is Coupling? (was: Polymorphism sucks) To : comp.programming,comp.object From : rem642b Date : Wed Jul 27 2005 01:43 am > From: Chris Sonnack > C'n'P is a terrible form of coding IF ITS PURPOSE IS THE DUPLICATION > OF LINKED CODE. In other words, if you know you have to do the same > thing in two places, and you do it by duplicating code, that's a > mistake. A big mistake. Well of course, if you want to do *exactly* the same thing in two places, and if you in fact know that ahead of time, then it's stupid to copy the text, it's better to move the first copy out to a separate function definition and then simply call that function from two places. The question arises when you don't want to do exactly the same thing, but only similar things, and you don't know in advance which factors will be in common and which factors will be different, so it's nigh impossible to decide ahead of time how to parameterize a function from the start so you can just call it with different parameters in both places. In that case, it's best to simply copy the code, amend it as needed to make it work for the new application, and after it's working correctly in both places *then* if it's worth the effort re-factor the two copies into a single parameterized subroutine. Sometimes it's just not worth the effort to refactor into a parameterized subroutine. > In *my* world, and I can well imagine in the worlds of most other > programmers, hierarchical organization has a proven track record. For some collections of subroutines and data structures, it does make sense to spend the effort to fit them into a neat hierarchy, and for other collections it would be wrong to try that, and for some collections it's best to pull part out to a hierarchy and leave the rest unorganized. In many cases, the best organization is simply to collect all the tools specific to a partcular kind of data structure into a single module, but not try to fit that module into any larger hierarchy except in a very loose sense. > Coupling is: I have a class "Foo" and a class "Bar" (separate units), > and Foo needs to know stuff about Bar. Therefore, Foo is coupled to > Bar. This can be disasterous if someone else controls Bar's design. If Bar is free to change the public interface from day to day, then don't use Bar at all, it's a crock of shit. If the public interface for Bar is stable, then it's perfectly fine for Foo to depend on knowledge of Bar's public interface. For debugging, the programmer for Foo might happen to know some of the innerds of Bar, and that might aid debugging, but none of this knowledge should be incorporated into permanent code inside Foo. (In some cases Bar's public documentation may be poorly written, to where Foo's author must look inside Bar to see what's really going in order to correctly re-intereprest Bar's documentation, in order to effectively use Bar. But at that point it's best if Foo's author tells Bar's author about the problem, and if then Bar's author either fixes the code to match the documentation, or fixes the documentation to match what the code really does. By the way, I've found lots of mistakes in Java's API documentation, but I'm powerless to get Sun Microsystems to fix it.) > In most languages, if you have a function Snork(int x, int y), all > calls to Snork() are coupled in that they need to pass a pair of > appropriate ints in the right order. But the public interface documentation should say clearly what the respective roles of first int and second int are, like which is the row number and which is the column number, just as it tells whether numbering starts from top or bottom of rectangle, etc., so what's the problem?? RTFM before trying to use the FC (*), right? * (C denotes "code" as in "implementation of an interface", and you all know the F word, thanks to George Carlin, right?) > (Some languages help decouple by providing the ability to pass > arguments by name. Thus, you can at least avoid the ordering > coupling.) You still need to RTFM to learn the names of the parameters and their semantics. The one place where keyword parameters is a big win is when you have a whole class of functions that use similar keyword arguments consistently, such as in Common Lisp sequence functions: [FUNCTION: find, position, fill, replace, remove, remove-if, remove-if-not, delete, delete-if, delete-if-not, remove-duplicates, delete-duplicates, substitute, substitute-if, substitute-if-not, nsubstitute, ... count...] [&KEY :test :test-not :start :end :start1 :end1 :start2 :end2 :from-end :key :count] Not all keywords apply to all those functions, and you have to be careful about the ones that take two sequences and use :start[12] and :end[12] vs those that take only one and just use :start and :end, but once you get accustomed to those keyword parameters they are really nice. Java hasn't done anywhere near as nice in this area due to lack of keyword parameters. > Functions coupling is *controlled* by publishing to the compiler > information about Snork(). That way, if a caller changes, or if > Snork() changes, the compiler screams. IMO If you purchase a Snork module, and later somebody reverses the sequences of parameters out from under your application, that's an unpardonable offense, and you deserve double your money back. > The reason coupling is "bad" is because it introduces dependancies > that must be managed. The higher the management cost, the worse > the coupling. Every time you call a function with more than one parameter, you have such "coupling". Most of the time the right thing to do is pass a single object that encapsulates all the various bindings needed. But you can't always do that, because you really do have to take input from different sources and bring them together to be correlated, so at some point you have to take two such binding-environments and pass them both to the same function which performs the correlation between them, or which merely merges the two binding environments into a single b.e. which can then be passed to a single-parameter function that does the actual correlation work. > cross-references can give you an index to certain forms of coupling. > You need to do more than just list them to determine if they are > under control, unavoidable or worth refactoring. One thing you might do is simply draw a structure diagram, showing at the top your main program, under it anything it directly calls, all the way to low-level utilities at the bottom. If you can automate the layout of that diagram so it's nicely factored into groups of related subroutines and not too crowded and not too haywired, that would be nice, but I don't know if anybody has been able to solve the "nice layout" A.I./SmartSystem problem. Without any objective measure of "niceness" of a diagram, there's no way to train a neural network or genetic algorithm to produce optimal niceness. It's not like automatic layout of a PC or IC whereby you try to minimize path length and cross-talk and layer-crossings. .