4 ms·
copy/paste is one of the cancers of our profession
by djKianoosh 15y ago
copy/paste is one of the cancers of our profession
- kstenerud 15y agoCorrection: BAD copy/paste is one of the cancers of our profession. Like all tools, it has its place, and there are people who tend to misuse it. Just because it's misused by bad programmers is no reason to deprive GOOD programmers of its benefits. You might as well ban screwdriver heads in power drills because lots of clumsy, inattentive people tend to strip screw heads with them. Similar misguided calls-to-arms have been raised over other useful tools such as preprocessor macros and goto.
- loup-vaillant 15y agoCould you give your estimate of the properly used/badly used ration of copy/paste, preprocessor macros, and goto? Mine would be "too low for me to worry about". Okay, there are some (corner) cases where they really are a good idea. But "never ever use this Chtulu Abomination" still is a damn good heuristic.
- kstenerud 15y agoGood copy/paste: Anything boilerplate such as manually initialized structures/arrays of stuff, language-specific boilerplate (Java comes to mind here) that is essentially the same repeated shit but you gotta do it anyway, unrolling loops, setting up switch statements. Anything unavoidable (or too expensive to refactor) that's repetitive. Preprocessor macros: Code generators, compile-time switchable code (such as logging) without filling your source files with #ifdefs Goto: Managing complex resource allocation/deallocation within a function: bool success = false; int fd = -1; char* memory = NULL; fd = open(filename, "rb"); if(fd == -1) { LOG_ERROR("Could not open %s: %s", filename, strerror(errno)); goto done; } memory = malloc(BUFF_SIZE); if(memory == NULL) { LOG_ERROR("Out of memory"); goto done; } for(blah blah blah) { if(failed to read or whatever) { LOG_ERROR("It's borked"); goto done; } } ... success = true; done: if(memory != NULL) { free(memory); } if(fd != -1) { close(fd); } return success; I disagree that dismissing a tool out of hand as an "abomination" is a commendable approach. If you take that attitude (or instill it in others), you'll probably never learn the proper use of such a specialized tool, leaving you ill-equipped to deal with the situations those tools handle well.
- loup-vaillant 15y agoBoilerplate: your language is bad. Switch to a better one, or modify the front-end of your compiler (they probably won't let you, though, and that sucks). I mean it, the cost of boilerplate is really high. Unrolling loops: I never saw an instance where that was necessary. Plus, the compiler can often do it for you. I know we often use high performance applications (video decoders, 3D games…), but very, very few of us write ones. Switch statement: the syntax of the construct is heavy, we should lighten it. The rest is hardly boilerplate any more: light_switch (expr) { 1 : i11; i12; // "break;" is implicit 42 : i21; : i_default; // "default" is implicit } Preprocessor macros: I agree (I mean, I back-pedal), they are more useful than the rest. However, I still avoid them by default, as they make really good foot-guns. Goto: your example shows exceptions (try…catch finally here). Goto makes much less sense when you have them. Now my point isn't to never do those things at all. Only to think of them as last resorts. The "Chtulu Abomination" metaphor helps me do that.
- kstenerud 15y ago"your language is bad. Switch to a better one" All languages have boilerplate somewhere. It's unavoidable. Switching languages just because there are pain points is not a solution, because you'll simply be exchanging one problem for another. "or modify the front-end of your compiler" This is most definitely pie-in-the-sky. In the real world of real business, you can't do this. "I mean it, the cost of boilerplate is really high." Oh, I agree wholeheartedly. But you need to work in the languages that programmers understand today. I'm not going to have nearly as much success hiring smalltalk programmers as I would have hiring Python programmers, for example. "Unrolling loops: I never saw an instance where that was necessary." I have, but then again I've been at this for 20 years. "Plus, the compiler can often do it for you." You can't be sure until you look at the disassembly. Often, it does it wrong. "Switch statement: the syntax of the construct is heavy, we should lighten it." That's not going to happen within the next decade. Meanwhile cut & paste is my tool of choice to cut through the boilerplate. "Goto: your example shows exceptions (try…catch finally here). Goto makes much less sense when you have them." But it makes LOTS of sense when you don't have them. And it's still useful in C++ and Objective-C, where you still end up interfacing with C libraries. If you don't know about the goto "poor man's exception", you'll either end up with repeated and buggy deallocation code, or a monstrosity of nested scopes, or a bunch of check-return-and-throw constructs, which in the case of Objective-C will slow your program way down because it implements try/catch using longjmp. Goto is also useful for breaking out of inner loops when the language doesn't support that (some languages support "break [label], to make it seem less like a goto). I don't consider these to be last resorts; I consider them specialized tools. Much like design patterns, they're for mitigating some deficiencies in a programming language, but they're only effective if you know how to use them.