''From SelfDocumentingCode...'' '''''A narrow interface is a better interface.''''' This is partially related to OnceAndOnlyOnce. '''Rationale:''' A system with much duplication is more complex than one without duplication. The reasons are simple: * Duplication implies unnecessary code. Unnecessary code is code that can be removed. * Unnecessary code has to be maintained. Maintenance is a nonlinear function of code length as the more code in the system, the more likely it interlinks. Since we already know the code is duplicated, there exists at least one part of the code with links to more than one location. Thus, maintenance is at least geometrically increased (if not exponentially). The best thing to do then is to RefactorMercilessly and combine the two (or more) cases into one. Also, by combining the two cases into one, where you had to change two code snippets, now you only have to change one. Furthermore, it is frequently found that systems with narrower interfaces are a) more flexible as one doesn't have to do as much work in order to change it, b) faster to adapt to change, c) more elegant, d) simpler as there is less code to read. Narrow interfaces also foster code reuse as you now have simple, elemental functions to work with instead of monstrous spaghetti. This is an application of the KissPrinciple. NOTE: The interface is not limited to class interfaces, methods, functions. Any part of the code that can be simplified into one case should likely be reduced. '''Arguments.''' ''"I have to change all this code? That's too much work."'' It's hard to believe it's less work maintaining all that code. ''"I may introduce defects from refactoring."'' True, but you can use UnitTest''''''s to make sure your refactoring is valid. Moreover, it is easier to understand and remove defects in the system as you know exactly where to look. Plus, the interactions between the two code segments are removed, thus you've automatically removed one source of bugs. ''"I don't really know what the best way to narrow the interface is."'' This is a toughy. With more experience, this is likely easier. Or, you can just follow your gut instinct. ZenProgramming works. '''Exceptions:''' The AdapterPattern and the ProxyPattern may be construed as code duplication. That's far fetched though because they are necessary. Sometimes when you are given a shoddy implementation, you have to write your own. However, legacy code requires that you can't change the existing codebase. You could always RefactorMercilessly, but this can be a headache. Also, sometimes you want to implement the same interface in different ways. This is a valid practice (e.g. AbstractDataType''''''s). However, you're not really expanding the interface because you've only got the one. '''Examples:''' The most common examples programmers encounter are certain groups of statements that are repeatedly used. These are then typically shoved off into their own methods/functions. In fact, code reuse is one of the top mentioned reasons for creating new functions. ''[even though, in my opinion, abstraction is a better reason.]'' (see MethodsVsCodeFragments) In fact, see also MethodsVsCodeFragments for an example of how to create simple quantized code snippets that can be reused instead of CopyAndPasteProgramming. ''[CopyAndPasteProgramming is an example of what '''not''' to do!]'' Another good example is the iostream library in C++. The iostream class itself is pretty simple. All the work is done using streambuf implementations. Instead of creating entirely separate stream objects for each stream type, the library designers chose to NarrowTheInterfaceThroughAbstraction. Also, SingleDispatch logging unifies the input vectors to a web application to simplify event handling, logging, authentication & access control, and input taint checking in powerful ways. ---- WhatsaNarrowInterface? And what does it have to do with code duplication? I thought a narrow interface was one with a small number of methods in it. ---- The interface being narrowed isn't just the interface to a class but the interface to the problem. For example, in object-oriented programming a given problem may be solved uniquely in many different classes, but it is still the same, singular problem. When you NarrowTheInterface, you pull all these classes into one, so the same problem only gets solved OnceAndOnlyOnce, in one place. The goal is to get the narrowest possible interface for the entire problem. As if you considered the problem a volume in space and the ''interface'' is the surface that encloses the problem (like a cell membrane to a cell), you'd want the surface area to be as small as possible... -- SunirShah ---- I think the more you NarrowTheInterface the easier it is to treat all objects with this interface the same, the easier it is to CollectionAndLoopVsSelectionIdiom. ''Definitely!'' ---- From above: : The most common examples programmers encounter are certain groups of statements that are repeatedly used. These are then typically shoved off into their own methods/functions. In fact, code reuse is one of the top mentioned reasons for creating new functions. ''[even though, in my opinion, abstraction is a better reason.]'' (see MethodsVsCodeFragments) Why is abstraction a better reason than reuse to create new functions? I'm assuming here that "reuse" in this context really means OnceAndOnlyOnce. Because you can replace a large number of code lines by simple calls. This help to understand code structure, helps "separating" problems, etc. ---- One of the things that leads to a wide interface is a large number of AccessorFunctions. See TellDontAsk and LawOfDemeter. Of course, direct variable access is no better than accessors in this respect; what you want, is to make client objects only able to access the attributes they really, really, '''really''' need. ----- This topic strikes me as a little vague. It needs examples or something in my opinion. Example 1: a graphism that could NarrowTheInterface. Charles Saunders Peirce invented an iconic notation which makes it possible to represent each one of an entire set of formulas of a sentential logic which are logically equivalent, in one graph. These are logically equivalent. *P-->Q *-(P&-Q) *-PvQ The iconic logical representation (in English) is Q inside a closed loop, and the Q-loop is inside another closed loop which itself contains P----loop, P, loop, Q. (P(Q)). The graph contains all of the information in the list of three formulas. The trick is to be able to correctly read the graph in the three possible ways that it can be read. Then you can narrow the interface without loosing anything. Example 2: a LowKeystrokeNotation. (LowKeystrokeFormalLanguages ?) (ConservationOfKeystrokes ?) ---- See InterfaceSegregationPrinciple