How do you teach simple vs complex solutions? ("Duh, Alistair, don't teach complex solutions!" I hear you cry.) Here's my problem - a few great programmers in my classes come up with elaborate solutions. I can tell they are protecting themselves every which way against future problems, using the ShieldPattern with a vengeance. We are trained to show people when the solution is too simplistic - we come up with a situation (test case) that breaks it. But how to show that the solution is overly complex? I have not encountered anything in the literature or even anecdotal to help them learn their solution is too complex.
Here is my current approach, tried exactly once so far (this last quarter (spring 98)), on the final. I first asked for a 2-class solution. It was the video store, and I gave a small set of user stories, said I would provide librarian classes to locate individual instances of their classes, and please draw a solution with only two kinds of objects. I thought the problem was a giveaway (how naive I am!)
Several people wrote that they were sure I didn't really mean only 2 classes, but that is what I requested, so more or less under protest they gave a 2-class solution. One person was sure I had made a mistake, so after he gave a 2-class solution, he argued for what he really would have put down if only I hadn't asked for only 2 classes. A few people couldn't read or couldn't count, and put down 3, 4 or 5 class solutions.
Next I asked them to describe the limitations of that 2-class design. Then, over the next several questions, I added use cases, until there was finally a really large requirement that they could not more than sketch a solution to. In each case, I asked what was the limitation of the design. Not surprisingly, they had real trouble with describing the limits of their own design, even though we had spent quite some energy on that during the semester.
Anyway, that was my attempt. I am content that it works as part of the story. But I don't know what to say in class when someone describes a RococoSolution to a problem. The industry does not yet know how to critique overly complex designs.
-- Alistair Cockburn
My seat-of-the-pants response would be "And how long will it take you to implement that?" The problem is that college students are unlikely to have enough experience to be able to give truthful answers to that question.
One useful exercise might be to play "telephone": have each student tell another student about his design in 5 minutes, then have the interlocutor describe the design to the class. This might help the overengineers realize that if it's hard to describe, it's hard to use.
VisualDisplayOfQuantitativeInformation? has the eraser exercise. Start with any graph. Erase anything you can without losing any information. When you can't erase anymore, you're done.
You can do the same thing with a design. You have some test cases. Erase (by inlining, for example) everything you can without violating the following rules:
It would be nice if you could clarify the first rule: "Say everything once - you can't erase the last expression of some interesting or useful thought ". I mean,
Bloodied but unbowed after recent discussions of YAGNI, I hear echoes of programmers crying "But my design is so much more general!?!?".
How do we show them that's not [necessarily] good? -- RonJeffries
Give programmers a hairy framework, then describe a simple app they should make. See how long it takes for them to get it right. Next, take away the framework and ask them to make a functionally-equivalent app. Let them count all the hooks in the framework that they had to glance at and purposefully ignore once they discovered that they weren't needed. Ask them to multiply out how many times they would forget what the hooks were for and relearn them only to discover they were still not needed. Most programmers will concede the point, but many actually prefer believing that it is worth going through the jungle every time you want to take a walk. -- MichaelFeathers
This argument is flawed. The part that was meant to be rather general, in your example, is the framework. But there's nothing wrong with the framework, the big mistake is using it for a task for which it's totally unsuitable. In principle, you try to convince the poor programmer by purposefully making him do something stupid, then telling him how stupid he is. Big, general frameworks aren't bad. For example, I used to hate CommonObjectRequestBrokerArchitecture, because someone made me learn CORBA by using it for tiny toy projects. Later I came across a quote saying, "We don't consider CORBA bloated because we use every feature. Something you use can't be bloat." (If someone knows the source, please add it ... I believe the project is some sort of window manager.) -- NeKs
You're remembering something someone said about the FrescoFramework: http://fresco.org/introduction.html
Here's Michael's task in a simple assignment using MicrosoftFoundationClasses. Write a program that automatically creates two views on one document. Make it so that the same docname auto-opens (a la quicken) each time.
It doesn't help to teach simple without teaching how to go from simple to more complex when you need to. I put in extra complexity when I am afraid I can't put it in later. So, I think teaching simplicity has to go hand in hand with teaching refactoring and testing. -- KentBeck
The solution is to take each student's source code and introduce 3 simple bugs in 3 different locations in their code. Then have everyone swap their code with another person. Time how long it takes for their classmate to understand and debug their code. Then illustrate complexity by saying that the other person took too long to digest the code (since it was complex) and that debugging was much harder (since when you step through the code it jumps all over 15 classes instead of 2). Alternatively, skip the debugging and just time how long it takes another student to understand the code well enough to describe it in front of the class.
I am reminded of a probably apocryphal story about early Japanese TV manufacturing. The engineers would take a competitor's TV and start clipping components off of the circuit board until the TV failed to work. They used this approach to find the minimal set of components actually needed for the TV to operate.
A similar approach could be used to identify a simple solution. Are all of the methods necessary to support the requirements or acceptance criteria? For each method, are all of the conditional branches or overloads necessary?
This would serve as a definition of "functional simplicity". I suspect there is also an "implementation simplicity", meaning that it is easy to understand, and that deserves an independent definition.
See http://CommunityWiki.org/PlainTalk