http://qs321.pair.com?node_id=285355


in reply to Design Patterns Still Aren't

In defence of the Perl Design Patterns, I thought they were quite refreshing, and protrayed well how design patterns should be appropriately used in perl. There *is* a lot of hype around design patterns, and much of it *needs* to be deflated.

"Simple things should be simple" is the perl mindset, and the article does an excellent job of showing how to use them simply and effectively.

Design Patterns are a prime example of academic self-indulgence, where everything *must* be complex, because simple things are not publishable. Even the simplest pattern, Singleton, is an exercise in seeing how much complexity one can layer on top of a global variable, while providing zero benefits, and lingering problems. (Did anyone notice the note about timely and correct destruction being non-trivial--in the Knuth sense of the word?) In the end you have a Class in your global namespace instead of a variable, and a lot of useless, bloated code.

Patterns aren't Language Features. Maybe they aren't in java or C++, but if they *are* in perl or ruby, does that mean we still have to code it ourselves to make it a pattern? This is *exactly* the kind of artificial-complexity that turns design patterns into a tool of evil.

I'm not saying that patterns are always useless and bloated. (Well, maybe Singletons are.) They have their uses for solving complex problems, but not all problems are complex, and not all implementations need to be complex. Unfortunately, a culture of complexity has grown around design patterns, such that average programmers have a hard time applying or implementing them correctly. (I say that after having to fix applications by removing the design patterns from them.)

Patterns aren't Universally Applicable. and ... how a particular problem fits with a particular solution. Accepted patterns are too complex to be univerally applicable, but too many programmers try to apply them to everything anyway. You should be looking for solutions to your problems, not problems for your solution! It would help immensely if we could dispense with the complexity, and recognize iteration, repetition, and decision as valid patterns. Then patterns *would* be universally applicable, and it would be OK to apply simple solutions to one's problems.

Patterns aren't Platonic Ideals ... a ten-year-old collection of patterns from a different language. Um, well said. :) The problem with "distinctly named" patterns is that they become canonic: you should do it this way, even if perl has an easier and better way of doing it. Perl Design Patterns was trying to show the easier and better ways of doing it, instead of showing how to write 10-year-old C++ programs in perl. Is there something wrong with that?

Patterns aren't Total Solutions: ... The description of each pattern should review the context in which it is used, acknowledge the tradeoffs involved, and refer to other patterns that offer an alternative approach. First, I agree completely. Second, when was the last time you included comments like this in your code? (Oh wait, we only have to justify the pattern when we invent it, not when we use it, because any use of a pattern must be better than a non-pattern.) If people actually considered the tradeoffs involved (and documented them), complex patterns would only be used where the complexity is appropriate and necessary, or find a simpler way to do it.

Patterns aren't Generic Concepts. So looping is not a pattern because it is too generic? Why should I use a loop when an iterator will work just as well? It makes me feel elite, because I've written 10kLOC today.

Design Patterns provide solutions for problems, and standardize the names for those solutions. This is good.

Design Pattern Culture worships complexity to the point were any simple solution is rejected as a design pattern, and thus tacitly rejected as a solution. This is evil.

Replies are listed 'Best First'.
Re: Re: Design Patterns Still Aren't
by scrottie (Scribe) on Aug 22, 2003 at 13:37 UTC
    The only point I want to nitpick here is complexity. A large program becomes complex for one reason. Fredrick Brooks (of the infamous Mythical Man Month) termed Natural Complexity and Accidental Complexity. A friend of mine worked for a month at a place that needed some new features added to their program. The program is 10,000 lines, all in one file, and completely incomprehensable. This is one kind of complexity that doesn't need to exist. Further, the code had no apparent structure. It was peicemeal. No relationships between parts could be discerned, and in fact, it was hard to identify anything as being a part, seperate from the rest. And fittingly, this is the reputation Perl has.

    I don't advocate making programs more complex than they need to be, which is to say, they shouldn't be more complex than the problem they are meant to solve warrents. Patterns are meant to structure large programs - not small ones. Out of context, they look, well, dumb. This makes it hard to write examples and even harder to imagine what the example would look like in its native habitat. I have a copy of "Lions' Commentary on UNIX 6th Edition", ISBN 1-57398-013-7. This book rocks. It is half explanation, half source code listing (mostly C, very little assembly through in). The commentary on the code was done by a college professor for a class, and it points out idea behind the code, structure, how things were built, how the parts fit together - picking on things that students are likely to someday have benefited from learning. Patterns. Having structure to the code doesn't make it complex - quite the opposite. It makes it interesting and valuable and long lasting. Look - we're still using Unix, even though it had to fit into 128k on a PDP-11!

    My advice to people writing small one-off scripts and quick hacks is to ignore the whole patterns thing just like you ignore objects. The tool doesn't fit the job. And trying to make it will just warp the job - as you say, adding complexity. However, at the first hint that the code is starting to outgrow what little structure it has, future programmers doomed to work on the project will thank you if you start early trying to fit the code to some higher level idioms. You use low level idioms, why not higher level ones?

    Oh yeah. I forgot. Perl does that for you. Look. There are two kinds of programming tools in the world. 4GLs and things designed to make you not have to think about design or logic, and refactoring browsers and other things designed to augment the abilities of a human as they design. ASP fits the first category, along with dozens of failed graphical-builder tools. lint, yacc, c-tags, that postscript hack that makes a poster of the Linux kernel sources, Purify, Rational Rose and other UML or Use-Case modeling tools fit the second category. Things in the first category tend not to be any help at all to an expert - in fact, they are associated with amatures. Things in the latter category are associated with skilled professionals, who are highly effective at their job. These tools have stood the test of time and repeatedly proven themselves. Rather than trying to do a job for the programmer or make a job vanish, they augment what human can do. Think of humans augmented with computers rather than humans replaced with computers, if you want a mnenomic.

    To say that Perl has high level design built in so you don't have to think about it is to cast Perl as a member of the former group. I don't like that very much. To say that Perl is a language more than capable of accomodating the technical needs of design in a large project when skilled professionals employ the right tools - that I like. Does Perl do the job of thinking for you, or does it expand what you're capable of? Do design issues not exist in Perl like they do in Java, or do they exist more readily as Perl increases programmer productivity, allowing them to build more quickly? When you go to the book store, do you read just the Perl books, or do you wander over and actually peek into these computer sciency rags?

    Remember, at one time, no one would touch objects, and they were the fetish of a few colleges, never seen outside. It wasn't until the 1980's - 20 years after their invention - did they get foothold in global conciousness. Before that, no serious language would ever consider a lambda closure feature - people don't need that to do business reports in RPG or COBOL! Both of these things slowly seeped out. Lack of closure bit Java on the butt - inner classes are a horrible kludge, but absolutely needed the way Java makes you define objects of a certain class to be used as callbacks. Closures make code shorter, and to someone wise in their ways, more readable - they do great things to reduce the scope of variables, breaking the code down into obviously seperate, cleanly divided parts. Stupid CS stuff, trying to make our lives more complex! Tell yourself that patterns really aren't anything new, just a better way to learn objects - and I mean really learn objects - C++ shops have struggled something awful the last 15 years - objects didn't click into place for their programmers except for a very special few. None of the prophacies of objects making code reusable, modular, resistant to change came true for the ordinary man because they didn't grasp the single driving concept. They didn't have that "ahh" moment. Scheme and Lisp programmers never had any problem - they had "Structure and Interpretation of Computer Programs" to learn from. After an entire generation of doing it wrong, we have a generation of object programmers doing it right. So, to put it another way, the Perl global mindset is still stuck in last generations misused, misunderstood, ineffective object usage. If you need me, I'll be in the Java section.

    Whoops, I got pretty far afield here. I always do that. I meant to offer perspective on your comment on complexity - the rest has little or nothing to do with your note. Otherwise, I agree. I've focued on patterns that apply to Perl and Perl programmers, not direct Perl translations of C++ patterns - on perldesignpatterns.com. Patterns shouldn't be mindless sprinkled about - normal code should stay normal code, to paraphrase Larry Wall's "perl should stay perl". In a large system, you need glue between the normal code or you have an endless procession of code. Like a patent, a pattern should be interesting and non-obvious - otherwise, people won't want to read them. Most people don't like to be told the obvious. It is insulting. And so on. There are very good reasons why an iterator needs to be something more than a foreach statement - you're exposing the internals of one object to another object through a predefined interface. Returning an array is okey sometimes, but the internal datastructure may not jive with that. perldesignpatterns.com's example of an iterator - or one of the examples - exposes the contents of a network of objects. Rather than building a massive array, the natural recurssion is exposed through the interface. Tieing and overloading are also very powerful - Perl shouldn't lose its expressiveness because of other idioms - but sometimes the idiom of using an interface and objects packs more of a punch than that of an array. Sometimes. In large programs.

    -scott