The bottom is not a good place to be, even if you're capable of getting there.
Seth Godin's latest manifesto, Stop Stealing Dreams, calls for a change to the way we educate our children. I've written some about how changes in technology and culture will likely disrupt universities, but Godin bases his manifesto on a simpler premise: we have to change what we achieve through education because what we need has changed. Historically, he claims, our K-12 system has excelled at one task: "churning out kids who are stuck looking for jobs where the boss tells them exactly what to do".
As negatively as that is phrased, it may well have been a reasonable goal for a new universal system of compulsory education in the first half of the 1900s. But times have changed, technology has changed, our economy has changed, and our needs have changed. Besides, universal education is a reality now, not a dream, so perhaps we should set our sights higher.
I only began to read Godin's book this afternoon. I'm curious to see how well the ideas in it apply to university education. The role of our universities has changed over time, too, including rapid growth in the number of people continuing their education after high school. The number and variety of public universities grew through the 1960s and 1970s in part to meet the new demand.
Yet, at its root, undergraduate education is, for most students, a continuation of the same model they experienced K-12: follow a prescribed program of study, attend classes, do assignments, pass tests, and follow rules. A few students avail themselves of something better as undergrads, but it's really not until grad school that most people have a chance to participate fully in the exploration for and creation of knowledge. And that is the result of self-selection: those most interested in such an education seek it out. Alas, many undergrads seem hardly prepared to begin driving their own educations, let alone interested.
That is one of the challenges university professors face. From my experience as a student and a father of students, I know that many HS teachers are working hard to open their students' minds to bigger ideas, too -- when they have the chance, that is, amid the factory-style mass production system that dominates many high schools today.
As I sat down to write this, it occurred to me that learning to program is a great avenue toward becoming a creator and an innovator. Sadly, most CS programs seem satisfied to keep doing the same old thing: to churn out people who are good at doing what they are told. I think many university professors, myself included, could do better by keeping this risk in mind. Every day as I enter the classroom, I should ask myself what today's session will do for my students: kill a dream, or empower it?
While working out this morning, my iPod served up John Hiatt's song, "Everybody Went Low" (available on YouTube). The juxtaposition of "going low" in the song and Godin's warning about striving for the bottom created an interesting mash-up in my brain. As Hiatt sings, when you are at the bottom, there is:
Nothing there to live up to
There's nothing further down
Turn it off or turn around
Big systems with lots of moving parts are hard to turn around. I hope we can do it before we get too low.
It seems that I've been running across David Foster Wallace everywhere for the last few months. I am currently reading his collection A Supposedly Fun Thing I'll Never Do Again. I picked it up for a tennis-turned-philosophy essay titled, improbably, "Tennis Player Michael Joyce's Professional Artistry as a Paradigm of Certain Stuff about Choice, Freedom, Discipline, Joy, Grotesquerie, and Human Completeness". (You know I am a tennis fan.) On the way to reading that piece, I got hooked on the essay about filmmaker David Lynch. I am not a fan of Wallace's fiction, but his literary non-fiction arrests me.
This morning, I am listening to a lengthy uncut interview with Wallace from 2003, courtesy of fogus. In it, Wallace comes across just as he does in his written work: smart, well-read, and deeply thoughtful. He also seems so remarkably pleasant -- not the sort of thing I usually think of as a default trait in celebrities. His pleasantness feels very familiar to me as a fellow Midwesterner.
The video also offers occasional haunting images, both his mannerisms but especially his eyes. His obvious discomfort makes me uncomfortable as I watch. It occurs to me that I feel this way only because I know how his life ended, but I don't think that's true.
The interview contains many thought-provoking responses and interchanges. One particular phrase will stay with me for a while. Wallace mentions the fondness Americans have for the freedom to choice, the freedom to satisfy our desires. He reminds us that inherent in such freedom is a grave risk: a "peculiar kind of slavery", in which we feel we must satisfy our desires, we must act on our impulses. Where is the freedom in that prison?
There is also a simple line that appealed to the teacher in me: "It takes skill and education to get good enough at reading or listening to be able to derive pleasure from it." This is one of the challenges that faces teachers everywhere. Many things require skill and education -- and time -- in order for students to be able to derive satisfaction and even pleasure from them. Computer programming is one.
I recommend this interview to anyone interested in modern culture, especially American culture.
As I listened, I was reminded of this exchange from a short blog entry by Seth Godin from last year:
A guy asked his friend, the writer David Foster Wallace,
"Say, Dave, how'd y'get t'be so dang smart?"
"I did the reading."
Wallace clearly did the reading.
PHOTOGRAPH: David Foster Wallace at the Hammer Museum in Los Angeles, January 2006. Source: Wikimedia Commons.
Back at SIGCSE 2005, Joe Bergin and ran a workshop called The Polymorphism Challenge that I mentioned at the time but never elaborated on. It's been on my mind again for the last week. First I saw a link to an OOP challenge aimed at helping programmers move toward OO's ideal of small classes and short methods. Then Kent Beck tweeted about the Anti-IF Campaign, which, as its name suggests, wants to help programmers "avoid dangerous ifs and use objects to build a code that is flexible, changeable, and easily testable".
That was the goal of The Polymorphism Challenge. I decided it was time to write up the challenge and make our workshop materials available to everyone.
Beginning in the mid-1990s, Joe and I have been part of a cabal of CS educators trying to teach object-oriented programming style better. We saw dynamic polymorphism as one of the key advantages to be found in OOP. Getting procedural programmers to embrace it, including many university instructors, was a big challenge.
At ChiliPLoP 2003, our group was riffing on the idea of extreme refactoring, during which Joe and I created a couple of contrived examples eliminating if statements from a specific part of Karel the Robot that seemed to require them.
This led Joe to propose a programming exercise he called an étude, similar to what these days are called katas, which I summarized in Practice for Practice's Sake:
Write a particular program with a budget of n if-statements or fewer, for some small value of n. Forcing oneself to not use an if statement wherever it feels comfortable forces the programmer to confront how choices can be made at run-time, and how polymorphism in the program can do the job. The goal isn't necessarily to create an application to keep and use. Indeed, if n is small enough and the task challenging enough, the resulting program may well be stilted beyond all maintainability. But in writing it the programmer may learn something about polymorphism and when it should be used.
Motivated by the Three Bears pattern, Joe and I went a step further. Perhaps the best way to know that you don't need if-statements everywhere is not to use them anywhere. Turn the dials to 11 and make 'em all go away! Thus was born the challenge, as a workshop for CS educators at SIGCSE 2005. We think it is useful for all programmers. Below are the materials we used to run the workshop, with only light editing.
Working in pairs, you will write (or re-write) simple but complete programs that normally use if statements, to completely remove all selection structures in favor of polymorphism.
The purpose of this exercise is not to demonstrate that if statements are bad, but that they aren't necessary. Once you can program effectively this way, you have a better perspective from which to choose the right tool. It is directed at skilled procedural programmers, not at novices.
You should attempt to build the solutions to one of the challenge problems without using if statements or the equivalent.
You may use the libraries arbitrarily, even when you are pretty sure that they are implemented with if statements.
You may use exceptions only when really needed and not as a substitute for if statements. Similarly, while loops are not to be used to simulate if statements. Your problems should be solved with polymorphism: dynamic and parameterized.
Note that if you use (for example) a hash map and the program cannot control what is used as a key in a get (user input, for example). then it might return null. You are allowed to use an exception to handle this situation, or even an if. If you can't get all if statements out of your code, then see how few you really need to live with.
Participants worked in pairs. They had a choice of programming scenarios, some of which were adapted from work by others:
This pdf file contains the full descriptions given to participants, including some we did not try with workshop participants. If you come up with a good scenario for this challenge, or variations on ours, please let me know.
When participants hit a block and asked for pointers, we offered hints of various kinds, such as:
When you have two behaviors, put them into different objects. The objects can be created from the same class or from related classes. If they are from the same class, you may want to use parameterized polymorphism. When the classes are different, you can use dynamic polymorphism. This is the easy step. Java interfaces are your friend here.
When you have the behaviors in different objects, find a way to bring the right object into play at the right time. That way, you don't need to use ad hoc methods to distinguish among them. This is the hard part. Sometimes you can develop a state change diagram that makes it easier. Then you can replace one object with another at the well-defined state change points.
Note that you can eliminate a lot of if statements by capturing early decisions -- perhaps made using if statements -- in different objects. These objects can then act as "flags with behavior" when they are passed around the program. The flag object then encapsulates the earlier decision. Now try to capture those decisions without if statements.
(Note that this technique alone is a big win in improving the maintainability of code. You replace many if statements spread throughout a program with one, giving you a single point of change in future.)
Delegation from one object to another is a real help in this exercise. This leads you to the Strategy design pattern. An object M can carry with it another, S, that encapsulates the strategy M has for solving a problem. To perform the associated behavior, M delegates to S. By changing the strategy object, you can change the behavior of the object that carries it. M seems to behave polymorphically, but it is really S that does the work.
You can modify or enhance strategies using the Decorator design pattern. A decorator D implements the same interface as the thing it decorates, M. When sent a message, the decorator performs some action and also sends the same message to the object it decorates. Thus the behavior of M is executed, but also more. Note that D can provide additional functionality both before and after sending the message to M. A functional method can return quite a different result when sent through a decorated object.
You can often choose strategies or other objects that encapsulate decisions using the Factory design pattern. A hash map can be a simple factory.
You can sometimes use max and min to map a range of values onto a smaller set and then use an index into a collection to choose an object. max and min are library functions so we don't care here how they might be implemented.
At the end of the workshop, we gave one piece of general advice: Doing this exercise once is not enough. Like an étude, it can be practiced often, in order to develop and internalize the necessary skills and thought patterns.
I'll not give any answers or examples here, so that readers can take the challenge themselves and try their hand at writing code. In future posts, I'll write up examples of the techniques described in the hints, and perhaps a few others.
Joe wrote up his étude in Variations on a Polymorphic Theme. In it, he gives some advice and a short example.
Serge Demeyer, Stéphane Ducasse, and Oscar Nierstrasz wrote a wonderful paper that places if statements in the larger context of an OO system, Transform Conditionals: a Reengineering Pattern Language.
If you like the Polymorphism Challenge, you might want to try some other challenges that ask you to do without features of your preferred language or programming style that you consider essential. Check out these Programming Challenges.
Remember, constraints help us grow. Constraints are where creative solutions happen.
I'll close with the same advice we gave at the end of the workshop: Doing this exercise once is not enough, especially for OO novices. Practice it often, like an étude or kata. Repetition can help you develop the thought patterns of an OO programmer, internalize them, and build the skills you need to write good OO programs.
David Byrne's essay on collective-creation introduced me to a dandy little picture book by Bernard Rudofsky called Architecture Without Architects. I love a slim book, and I love architecture, so I didn't need much of a push to pick it up at the library.
For an agile software developer, the book's title evokes something visceral. I think software architecture often happens best when it happens organically, emerging as the programmer grows the program piecemeal, feature by feature. This is a pragmatic view, as expressed succinctly by Brian Marick in his recent The Aim of Architecture:
Architecture isn't true, it's useful.
In software, as Marick says, knowing a program's architecture helps us to navigate our way around the program and add new code. An agile developer is willing to let architecture describe the existing program, rather than prescribe its shape. A descriptive, emergent architecture will be more helpful in what we need it for than a prescribed, often inaccurate architecture created ahead of time.
That's the mindset I brought to Architecture Without Architects. I found, though, that it is about more than piecemeal growth and emergence; it talks about buildings and spaces created by regular people. Some people call this "vernacular" architecture, but Rudofsky uses a number of terms aimed at elevating the idea beyond the vulgar, among them "indigenous", "spontaneous", and "non-pedigreed". I think Rudofsky likes "non-pedigreed" best because it most accurately expresses the distinction between the creations he studies and "real" architecture: the only difference is the credential held by the builder.
He lays responsibility for this harmful distinction at the feat of historians, who emphasize "the parts played by architects and their patrons" at the expense of "the communal enterprise" of the built environment. But all of us share in the blame:
Part of our trouble results from the tendency to ascribe to architects -- or, for that matter, to all specialists -- exceptional insights into problems of living when, in truth, most of them are concerned with problems of business and prestige.
One of the goals of this book is to encourage the study of non-pedigreed architecture, to describe a typology and to document important examples. "There is much to learn," says Rudofsky, "from architecture before it became an expert's art".
So, it turns out that Architecture Without Architects is not about the same sense of "without architect" that we in the software world usually mean. Agile developers are, for the most part, professionals, not hobbyists or regular Joes cobbling together programs on the side. Part of that is cultural. People who would never think of writing a program for themselves think nothing about diddling around their houses. Part of it is technological. It's pretty easy to go to the nearest home improvement center and buy modular components that non-professionals can use to change the shape and decoration of their houses. Programming, not so much.
There are, of course, a few hobbyists tinkering around with programs in their spare time. More important, there are plenty of people with few or no credentials in computing or software engineering making a living by writing programs. Sometimes, they have switched careers out of necessity or choice. Other times, they have slowly drifted into software development over the course of a career.
In yet other cases, they retain their professional identity in another discipline and write code to help them do their jobs. Greg Wilson's Software Carpentry project is aimed at one such group of people: professional scientists who find themselves writing and maintaining software as an essential part of doing their science. Rudofsky may be right when he chides us for attributing exceptional insight to professional architects, and if so we are certainly right not to attribute exceptional insight to pedigreed software developers. But Wilson is building a brand by reminding us that, while it may not take exceptional insight to write programs, doing it well does require some skill and knowledge.
I think that Rudofsky's interest in vernacular architecture has other parallels in the software world. For example, technologies such as SourceForge and now GitHub have enabled developers to showcase, celebrate, and benefit from the communal enterprise of writing programs. Programmers may be sitting home working on their own, but they aren't really alone. They are sharing what they write, sharing in what others write, and otherwise participating in vibrant communities of developers.
Then there is the idea of credentials. While many programmers do have degrees in computer science or engineering, most professionals don't have advanced academic degrees or an academic bent. They write code in a world shaped by forces beyond those usually talked about in algorithms and data structures textbooks. The software patterns movement that grew up in the 1990s aimed to document valuable lessons learned programming "in the wild". Like Rudofsky's typology of indigenous architecture, catalogs of design patterns collected vernacular wisdom. As Rudofsky said about the creations of the anonymous builders of most of the world we actually live in,
The beauty of this architecture has long been dismissed as accidental, but today we should be able to recognize it as the result of rare good sense in the handling of practical problems.
Say whatever else you want about the Gang of Four book, it captured a lot of OO wisdom learned in the trenches, often from working with unforgiving building materials like C++.
I enjoyed Architecture Without Architects greatly. After an eight-page preface in which Rudofsky lays down most of the ideas I've summarized here, the book consists of 150 or so pages of pictures accompanied by explanatory paragraphs. There was a lot of interesting detail and even a little wisdom in those paragraphs. If you like architecture, whether housing or programming, you might enjoy spending a couple of hours with this book.
From The Heroes of Java: Ward Cunningham (emphasis added):
Making a new language is the ultimate power move. There are lots of ways to do it. Get to know them all. A switch statement inside a for loop makes an interpreter. When you write that, ask yourself: what language am I interpreting?
Those last two sentences distill a few weeks of a course on programming languages into an idea that spans all of computer science. Beautiful.
As in most conversations with Ward, this one is full of good sentences, including:
The shortest path to exceeding expectations rarely goes through meeting expectations.
When [pair programming] you can assume both people bring something to the collaboration. I'd rather find my colleague's strength or passion and learn from them as we go forward together.
Seth Godin's recent blog entry at the Domino Project talks about how changes in the book are changing the publishing industry. He doesn't use the word 'pattern' in his discussion, in the sense of an Alexandrian pattern, but that's how I see his discussion. The forces at play in our world are changing, which leads to changes in the forms that find equilibrium. In particular, Godin mentions:
Godin looks mostly at the forward implications of changes in the patterns of self-sufficiency, but I've been thinking about the backward implications of print publications having to stand on their own. As noted in a recent entry, I have begun to adapt a couple of my blog entries into articles for print media, such as newspaper and magazine opinion pieces. My blog entries link generously and regularly to my earlier writings, because much of what I write is part of an ongoing process of thinking out loud. I also link wherever I can to other peoples' works, whether blogs, journal articles, code, or other forms. That works reasonably well in a blog, because readers can see and following the context in which the current piece is written. It also means that I don't have to re-explain every idea that a given entry deals with; if it's been handled well in a previous entry, I link to it.
As I try to adapt individual blog entries, I find that they are missing so much context when we strip the links out. In some places, I can replace the link with a few sentences of summary. But how much should I explain? It's easy to find myself turning one- or two-page blog entry into four pages, or ten. The result is that the process of "converting an entry into an article" may become more like writing a new piece than like modifying an existing piece. That's okay, of course, but it's a different task and requires a different mindset.
For someone steeped in Alexander's patterns and the software patterns community, this sentence by Godin signals a shift in the writing and publishing patterns we are all used to:
As soon as paper goes away, so do the chokepoints that created scarcity.
Now, the force of abundance begins to dominate scarcity, and the forces of bits and links begin to dominate paper and bindings and the bookshelves of the neighborhood store.
It turns out that the world has for the last hundreds of years been operating within a small portion of the pattern language of writing and publishing books. As technology and people change, the equilibrium points in the publishing space have changed... and so we need to adopt a new set of patterns elsewhere in the pattern language. At first blush, this seems like unexplored territory, but in fact it is more. This part of the pattern language is, for the most part, unwritten. We have to discover these patterns for ourselves.
Thus, we have the Domino Project and others like it.
The same shifting of patterns is happening in my line of work, too. A lot of folks are beginning to explore the undiscovered country of university education in the age of the internet. This is an even greater challenge, I think, because people and how they learn are even more dominant factors in the education pattern language than in the publishing game.
Nathan Marz has written a nice article on what he calls suffering-oriented programming, a development style that places great value on "You Aren't Gonna Need It". It also has a guideline for when you should build something: you feel the pain of not having it. If it doesn't hurt yet, then you don't need it.
As you might imagine, Marz reports that the most important characteristic of this style is a relentless focus on refactoring. In refactoring, we often speak of code smells. Suffering-oriented programmers operate within a different metaphor. They are waiting for their code to make their lives difficult, such as when the queues and workers in Marz's stream processing system became unworkable at a larger scale. We need someone like Kent Beck to coin a catchy phrase for this -- code owies, perhaps.
I enjoyed the analogy Marz uses between refactoring and curve fitting:
"Making it beautiful" is where you use your design and abstraction skills to distill the problem space into simple abstractions that can be composed together. I view the development of beautiful abstractions as similar to statistical regression: you have a set of points on a graph (your use cases) and you're looking for the simplest curve that fits those points (a set of abstractions).
Do the simplest thing that would possibly work.
Marz presents a very practical instantiation of agile development without the hype that accompanies some usages of the term. It is worth a read.
Over the last couple of years, our university relations department has been trying to promote more actively the university's role in the public sphere. One element of this effort is pushing faculty work and professional commentary out into wider circulation. For example, before and after the recent presidential caucuses in Iowa, they helped connect local political science profs with media who were looking for professional commentary from in the trenches.
Well, they have now discovered my blog and are interested in shopping several pieces of general interest to more traditional media outlets, such as national newspapers and professional magazines. Their first effort involves a piece I wrote about liberal education last month, which builds on two related pieces, here and here. I'm in the process of putting it into a form suitable for standalone publication. This includes polishing up some of the language, as well as not relying on links to other articles -- one of the great wins of the networked world.
Another big win of the networked world is the ease with which we can get feedback and make our ideas and our writing better. If you have any suggestions for how I might improve the presentation of the ideas in these pieces, or even the ideas themselves, please let me know. As always, I appreciate your thoughts and willingness to discuss them with me.
When I mentioned this situation in passing on Twitter recently, a former student asked whether my blog's being on the university's radar would cause me to write differently. The fact is that I always tried to respect my university, my colleagues, and my students when I write, and to keep their privacy and integrity in mind. This naturally results in some level of self-censorship. Still, I have always tried to write openly and honestly about what I think and learn.
You can rest assured. This blog remains mine alone and will continue to speak in my voice. I will write as openly and honestly as ever. That is the only way that the things I write could ever be of much interest to readers such as you, let alone to me.
My recent post about teaching with authenticity and authority is about attitude. Some teaching behaviors happen in the moment. They are tactical decisions in response to specific events, but they, too, can have long-term effects on how our students see us and on how well a course proceeds.
A conversation with a colleague this week reminded me of a situation I've encountered several times over the years with faculty from across my university. Many have a lot of experience teaching yet seem to make a particular bad tactical decision.
Our university has a policy -- approved by the faculty -- that students are not to be penalized for missing class to participate in university-sanctioned events. These often involve representing the school in athletic and other extracurricular activities such as debate, but sometimes they relate important on-campus functions involving scholarships and the like.
Many faculty have attendance policies in their courses. For instance, they may take roll each day, and if a student misses more than four class meetings, then the student's grade in the course is reduced. These faculty genuinely believe that class participation is essential and want to encourage students to take attendance seriously. Because they have a large allowance for absences, many do not distinguish between "unexcused" absences and "excused" ones. That simplifies bookkeeping, and in the end it almost never matters to the student's final grade.
Still some students worry that they'll end up with unexpected reasons to miss the allotment of "free" days. When they have a university-sanctioned activity, they want the professor not to hold it against them. Don't worry, the prof tells them, it's unlikely to affect your grade, and if it does, I'll reconsider. Still the students worry, and point to the policy that they should not be penalized for the absence.
When I have talked to faculty in these situations, often in my roll as a faculty rep on my university's athletics advisory council but sometimes as department head, I am surprised by the faculty's responses when they learn of the faculty-approved policy.
"My attendance sheet is a record of fact. I cannot mark students present if they are absent."
Couldn't you treat the sheet as a record of unexcused absences?
"No. It also indicates that students have participated in class that day, and at what level. If they are absent, then they have not participated."
I am careful in these conversations to respect their autonomy and their control over the classroom, and the conversations go quite well. They understand the student's concern. They readily acknowledge that the absence is unlikely to have an effect on the student's grade and assure me that they have assured the student as much. They just don't want to mess with their systems. And they are baffled by the student's continued unhappiness with the result.
This baffles me. If attendance or absence on that one day is unlikely to have an effect on the student's grade, what is the advantage of falling on one's sword over such a small issue? And, metaphorically, falling on one's sword is what happens. The student is disenchanted at best, and unhappy enough to grieve the action at worst.
I have come to see such situations in this way: "unlikely to have an effect on the student's grade" creates an element of uncertainty. As teachers, we can bear the uncertainty, or we can leave our students to bear it. There may well be good reasons to leave uncertainty in our students' minds. We should ask ourselves, "Is this one of them?" If not, then we should bear it. Tell the student clearly, "This will not affect your grade", and make whatever change in our system of recording or grading needed to make it so.
The result of this approach is, most likely, a student with a positive outlook about us and about our course. The lack of fear or uncertainty frees them to learn better. The student may even think that the prof cares more about the student's learning than about his or her system.
Of course, all bets are off for repeated offenders, or for students who exhibit patterns of disengagement from the course. Students have to be invested in their own learning, too.
This scenario is but one of many in which instructors are required to make tactical decisions. The effects of bad decisions can accumulate, in a single student and in the class more generally. They then have negative effects on student attitude, on the atmosphere in the classroom, and on teaching and learning. The good professors I know seem to reliably make good tactical decisions in the moment, and when they err they are willing and able to make amends.
The decisions one makes in such situations is a direct result of one's general attitude, but I think that we can all learn to make better decisions. It is a skill that teachers can learn in the process of becoming better teachers.
You've got to learn your instrument.
Then, you practice, practice, practice.
And then, when you finally get up there on the bandstand,
forget all that and just wail. -- Charlie Parker
I signed up for an opportunity to read early releases of a book in progress, Bootstrapping Design. Chapter 4 contain a short passage that applies to beginning programmers, too:
Getting good at design means cultivating your taste. Right now, you don't have it. Eventually you will, but until then you cannot trust your creativity. Instead, focus on simplicity, clarity, and the cold, hard science of what works.
This is hard advice for people to follow. We like to use our brains, to create, to try out what we know. I see this desire in many beginning programming students. The danger grows as our skills grow. One of my greatest frustrations comes in my Programming Languages course. Many students in the course are reluctant to use straightforward design patterns such as mutual recursion.
At one level, I understand their mindset. They have started to become accomplished programmers in other languages, and they want to think, design, and program for themselves. Oftentimes, their ill-formed approaches work okay in the small, even if the code makes the prof cringe. As our programs grow, though, the disorder snowballs. Pretty soon, the code is out of the student's control. The prof's, too.
A good example of this phenomenon, in both its positive and negative forms, happened toward the end of last semester's course. A series of homework assignments had the students growing an interpreter for a small, Scheme-like language. It eventually became the largest functional program they had ever written. In the end. there was a big difference between code written by students who relied on "the cold, hard science" we covered in class and code written by students who had wondered off into the wilderness of their own creativity. Filled with common patterns, the former was relatively easy to read, search, and grade. The latter... not so much. Even some very strong students began to struggle with their own code. They had relied too much on their own approaches for decomposing the problem and organizing their programs, but those ideas weren't scaling well.
I think what happens is that, over time, small errors, missteps, and complexities accumulate. It's almost like the effect of rounding error when working with floating point numbers. I vividly remember experiencing that in mu undergrad Numerical Analysis courses. Sadly, few of our CS students these days take Numerical Analysis, so their understanding of the danger is mostly theoretical.
Perhaps the most interesting embodiment of trusting one's own creativity too much occurred on the final assignment of the term. After several weeks and several assignments, we had a decent sized program. Before assigning the last set of requirements, I gave everyone in the class a working solution that I had written, for reference. One student was having so much trouble getting his own program to work correctly, even with reference to my code, that he decided to use my code as the basis for his assignment.
Imagine my surprise when I saw his submission. He used my code, but he did not follow the example. The code he added to handle the new requirements didn't look anything like mine, or like what we had studied in class. It repeated many of the choices that had gotten him into hot water over the course of the earlier assignments. I could not help but chuckle. At least he is persistent.
It can be hard to trust new ideas, especially when we don't understand them fully yet. I know that. I do the same thing sometimes. We feel constrained by someone else's programming patterns and want to find our own way. But those patterns aren't just constraints; they are also a source of freedom. I try to let my students grow in freedom as they progress through the curriculum, but sometimes we encounter something new like functional programming and have to step back into the role of uncultivated programmer and grow again.
There is great value in learning the rules first and letting our tastes and design skill evolve slowly. Seniors taking project courses are ready, so we turn them loose to apply their own taste and creativity on Big Problems. Freshmen usually are not yet able to trust their own creativity. They need to take it slow.
To "think outside the box", you you have to start with a box. That is true of taste and creativity as much as it is of knowledge and skill.