Teaching and Learning

There are no mistakes only lessons; a lesson is repeated until learned; tuition varies

image from www.drcherie.comOne of my principal sources of wisdom is Cherie Carter Scott's book, If Life is a Game, These are the Rules, an elaboration of her Ten Rules for Being Human, which initially appeared (inadvertently unattributed) in Jack Canfield's book, Chicken Soup for the Soul.

My two favorite life rules are:

3. There are no mistakes, only lessons

4. A lesson is repeated until learned

I regularly quote these rules - online and offline - and over the years have recognized an important addendum to rule 4:

4b. Tuition varies

In Dr. Cherie's book, each rule is elaborated in a separate chapter that begins with an introduction and is followed by a few sections presenting themes (or perhaps lesson plans) relating to the rule. For Rule 3 - There are no mistakes, only lessons - the themes are compassion, forgiveness, ethics and humor. Here is an excerpt from the introduction for this chapter:

Rather than viewing your own mistakes as failures and others' mistakes as slights, you can view them as opportunities to learn. As Emerson said, "Every calamity is a spur and a valuable hint." Every situation in which you do not live up to your own expectations is an opportunity to learn something about your own thoughts and behaviors. Every situation in which you feel "wronged" by another person is a chance to learn something about your reactions. Whether it is your own wrongdoing or someone else's, a mistake is simply an opportunity to evolve further along your spiritual path.

The chapter on Rule 4 - Lessons are repeated as needed - includes elaborations on awareness, willingness, causality and patience. It begins with an introduction that articulates the following insight:

You will continually attract the same lessons into your life. You will also draw to you teachers to teach you that lesson until you get it right. The only way you can free yourself of difficult patterns and issues you tend to repeat is by shifting your perspective so that you can recognize the patterns and learn the lessons that they offer. You may try to avoid the situations, but they will eventually catch up with you.

I regularly experience the wisdom of these rules, with varying degrees of awareness. It often seems to be the case that I recognize their relevance retroactively. Over time, I have also learned that the lessons have variable costs, which exhibit a general upward trend. The costs can take different forms - money, opportunities, friends - but the most common currency appears to be emotional pain. In a 12-step group I used to attend, we often light-heartedly referred to the repetition of an emotionally painful lesson as another f***ing growth opportunity, or AFGO for short. 

Emotional pain experienced during lessons is often magnified by my unwillingness to practice self-forgiveness - for which two specific lesson plans are highlighted in the chapters on rules 3 and 4 - and my tendency to add a layer of self-criticism when I recognize that I've unwittingly and unintentionally repeated a mistake lesson yet again. But when the lessons involve other people - in either a cooperative or adversarial learning opportunity - the emotional pain also arises from my guilt over the tuition they pay ... fees that, in many cases, my co-learners never explicitly signed up for.

The highest student debt accumulated for my repeated lessons involve my wife and children. The costs in terms of the emotional pain I experience when I fail to live up to my own expectations of being an attentive and effective husband and father are enormous, and greatly intensify each time lessons are repeated. And, unfortunately, the costs borne by them through such lessons can also be considerable.

Marriage vows traditionally take into account tuition costs for partners' lessons, or at least that's my interpretation of "for better, for worse, for richer, for poorer, in sickness and in health". Marriage, at least in our culture, involves an explicit choice by both partners, and each has the option of dropping the course(s). My wife has been one of my best, most consistent and often unappreciated teachers ... though I like to think at least some of her tuition has been reciprocated through lessons I may have offered her over the years.

Children are typically not offered an explicit opportunity to choose whether to sign up for lessons they learn with or from their parents. My children are also among my best teachers, as they regularly help me recognize hypocrisy or duplicity when I preach one principle but practice another, or when I am otherwise not living up to my - or their - expectations of being a good father. I don't know quite how to account for their tuition costs over the years, but I like to believe the process of micro-evolution will ultimately allow them to reap some valuable rewards from the dues they've been paying.


Motivating and Visualizing Recursion in Python: Three Flavors

Yesterday, I encountered some great instructional posts on programming, Python and the IPython Notebook.

I thought it would be fun to experiment with all 3: implementing the recursive C function used by Gustavo Duarte in Python, doing so inside PythonTutor (which can generate an iframe) and then embedding the PythonTutor iframe inside an IPython Notebook, which I would then embed in this blog post.

Unfortunately, I haven't achieved the trifecta: I couldn't figure out how to embed the PythonTutor iframe inside an IPython Notebook, so I will embed both of them separately here in this blog post. Across the collection, 3 flavors of visualizing recursion are shown:

  • simple print statement output tracing the call stack (ASCII version)
  • a static call stack image created by Gustavo
  • a dynamic call stack created automatically by PythonTutor

I'll start out with embedding Motivating and Visualizing Recursion in Python, an IPython Notebook I created to interweave text, images and code in summarizing Gustavo Duarte's compelling critique and counter-proposal for how best to teach and visualize recursion, and reimplementing his examples in Python.

Next, I'll embed an iframe for visualizing recursion in Python, providing a snapshot of its dynamic execution and visualization within PythonTutor:

I really like the way that PythonTutor enables stepping through and visualizing the call stack (and other elements of the computation). It may not be visible in the iframe above (you have to scroll to the right to see it), so I'll include a snapshot of it below.

Visualizing_Recursion_in_Python_Tutor

If anyone knows how to embed a PythonTutor iframe within an IPython Notebook, please let me know, as I'd still welcome the opportunity to achieve a trifecta ... and I suspect that combining these two tools would represent even more enhanced educational opportunities for Pythonistas.


Python for Data Science: A Rapid On-Ramp Primer

IpythonIn my last post, I was waxing poetic about an IPython Notebook demonstration that was one of my highlights from Strata 2014:

"this one got me the most excited about getting home (or back to work) to practice what I learned"

Well, I got back to work, and learned how to create an IPython Notebook. Specifically, I created one to provide a rapid "on-ramp" for computer programmers who are already familiar with basic concepts and constructs in other programming language to learn enough about Python to effectively use the Atigeo xPatterns analytics framework (or other data science tools). The Notebook also includes some basic data science concepts, utilizing material I'd earlier excerpted in a blog post in which I waxed poetic about the book Data Science for Business, by Foster Provost and Tom Fawcett, and other resources I have found useful in articulating the fundamentals of data science.

nltk_book_cover.gif The rapid on-ramp approach was motivated, in part, by my experience with the Natural Language Toolkit (NLTK) book, which provides a rapid on-ramp for learning Python in conjunction with the open-source NLTK library to develop programs using natural language processing techniques (many of which involve machine learning). I find that IPython Notebooks are such a natural and effective way of integrating instructional information and "active" exercises that I wish I'd discovered it back when I was teaching courses using Python at the University of Washington (e.g., what came to be known as the socialbots course). I feel like a TiVO fanatic now, wanting to encourage anyone and everyone sharing any knowledge about Python to use IPython Notebooks as a vehicle for doing so.

I piloted an initial version of the Python for Data Science notebook during an internal training session for software engineers who had experience with Java and C++ a few weeks ago, and it seemed to work pretty well. After the Strata 2014 videos were released, I watched Olivier Grisel's tutorial on Introduction to Machine Learning with IPython and scikit-learn, and worked through the associated parallel_ml_tutorial notebooks he posted on GitHub. I updated my notebook to include some additional aspects of Python that I believe would be useful in preparation for that tutorial.

Not only was this my first IPython Notebook, but I'm somewhat embarrassed to admit that the Python for Data Science repository represents my first contribution to GitHub. When I was teaching at UW, I regularly encouraged students to contribute to open source projects. Now I'm finally walking the talk ... better late than never, I suppose.

In any case, I've uploaded a link to the repository on the IPython Notebook Viewer (NBViewer) server - "a simple way to share IPython Notebooks" - so that the Python for Data Science notebook can be viewed in a browser, without running a local version of IPython Notebook (note that it may take a while load, as it is a rather large notebook).

I'll include the contents of the repo's README.md file below. Any questions, comments or other feedback is most welcome.

This short primer on Python is designed to provide a rapid "on-ramp" for computer programmers who are already familiar with basic concepts and constructs in other programming languages to learn enough about Python to effectively use open-source and proprietary Python-based machine learning and data science tools.

The primer is spread across a collection of IPython Notebooks, and the easiest way to use the primer is to install IPython Notebook on your computer. You can also install Python, and manually copy and paste the pieces of sample code into the Python interpreter, as the primer only makes use of the Python standard libraries.

There are three versions of the primer. Two versions contain the entire primer in a single notebook:

The other version divides the primer into 5 separate notebooks:

  1. Introduction
  2. Data Science: Basic Concepts
  3. Python: Basic Concepts
  4. Using Python to Build and Use a Simple Decision Tree Classifier
  5. Next Steps

There are several exercises included in the notebooks. Sample solutions to those exercises can be found in two Python source files:

  • simple_ml.py: a collection of simple machine learning utility functions
  • SimpleDecisionTree.py: a Python class to encapsulate a simplified version of a popular machine learning model

There are also 2 data files, based on the mushroom dataset in the UCI Machine Learning Repository, used for coding examples, exploratory data analysis and building and evaluating decision trees in Python:

  • agaricus-lepiota.data: a machine-readable list of examples or instances of mushrooms, represented by a comma-separated list of attribute values
  • agaricus-lepiota.attributes: a machine-readable list of attribute names and possible attribute values and their abbreviations

The Scientific Method: Cultivating Thoroughly Conscious Ignorance

Ignorance_HowItDrivesScience_StuartFirestein_coverStuart Firestein brilliantly captures the positive influence of ignorance as an often unacknowledged guiding principle in the fits and starts that typically characterize the progression of real science. His book, Ignorance: How It Drives Science, grew out of a course on Ignorance he teaches at Columbia University, where he chairs the department of Biological Sciences and runs a neuroscience research lab. The book is replete with clever anecdotes interleaved with thoughtful analyses - by Firestein and other insightful thinkers and doers - regarding the central importance of ignorance in our quests to acquire knowledge about the world.

Each chapter leads off with a short quote, and the one that starts Chapter 1 sets the stage for the entire book:

"It is very difficult to find a black cat in a dark room," warns an old proverb. "Especially when there is no cat."

He proceeds to channel the wisdom of Princeton mathematician Andrew Wiles (who proved Fermat's Last Theorem) regarding the way science advances:

It's groping and probing and poking, and some bumbling and bungling, and then a switch is discovered, often by accident, and the light is lit, and everyone says "Oh, wow, so that's how it looks," and then it's off into the next dark room, looking for the next mysterious black feline.

Firestein is careful to distinguish the "willful stupidity" and "callow indifference to facts and logic" exhibited by those who are "unaware, unenlightened, and surprisingly often occupy elected offices" from a more knowledgeable, perceptive and insightful ignorance. As physicist James Clerk Maxwell describes it, this "thoroughly conscious ignorance is the prelude to every real advance in science."

The author disputes the view of science as a collection of facts, and instead invites the reader to focus on questions rather than answers, to cultivate what poet John Keats' calls "negative capability": the ability to dwell in "uncertainty without irritability". This notion is further elaborated by philosopher-scientist Erwin Schrodinger:

In an honest search for knowledge you quite often have to abide by ignorance for an indefinite period.

PowerOfPullIgnorance tends to thrive more on the edges than in the centers of traditional scientific circles. Using the analogy of a pebble dropped into a pond, most scientists tend to focus near the site where the pebble is dropped, but the most valuable insights are more likely to be found among the ever-widening ripples as they spread across the pond. This observation about the scientific value of exploring edges reminds me of another inspiring book I reviewed a few years ago, The Power of Pull, wherein authors John Hagel III, John Seely Brown & Lang Davison highlight the business value of exploring edges: 

Edges are places that become fertile ground for innovation because they spawn significant new unmet needs and unexploited capabilities and attract people who are risk takers. Edges therefore become significant drivers of knowledge creation and economic growth, challenging and ultimately transforming traditional arrangements and approaches.

On a professional level, given my recent renewal of interest in the practice of data science, I find many insights into ignorance relevant to a productive perspective for a data scientist. He promotes a data-driven rather than hypothesis-driven approach, instructing his students to "get the data, and then we can figure out the hypotheses." Riffing on Rodin, the famous sculptor, Firestein highlights the literal meaning of "dis-cover", which is "to remove a veil that was hiding something already there" (which is the essence of data mining). He also notes that each discovery is ephemeral, as "no datum is safe from the next generation of scientists with the next generation of tools", highlighting both the iterative nature of the data mining process and the central importance of choosing the right metrics and visualizations for analyzing the data.

Professor Firestein also articulates some keen insights about our failing educational system, a professional trajectory from which I recently departed, that resonate with some growing misgivings I was experiencing in academia. He highlights the need to revise both the business model of universities and the pedagogical model, asserting that we need to encourage students to think in terms of questions, not answers. 

W.B. Yeats admonished that "education is not the filling of a pail, but the lighting of a fire." Indeed. TIme to get out the matches.

If_life_is_a_game_these_are_the_rules_large

On a personal level, at several points while reading the book I was often reminded of two of my favorite "life rules" (often mentioned in preceding posts) articulated by Cherie Carter-Scott in her inspiring book, If Life is a Game, These are the Rules:

Rule Three: There are no mistakes, only lessons.
Growth is a process of experimentation, a series of trials, errors, and occasional victories. The failed experiments are as much a part of the process as the experiments that work.

Rule Four: A lesson is repeated until learned.
Lessons will repeated to you in various forms until you have learned them. When you have learned them, you can then go on to the next lesson.

Firestein offers an interesting spin on this concept, adding texture to my previous understanding, and helping me feel more comfortable with my own highly variable learning process, as I often feel frustrated with re-encountering lessons many, many times:

I have learned from years of teaching that saying nearly the same thing in different ways is an often effective strategy. Sometimes a person has to hear something a few times or just the right way to get that click of recognition, that "ah-ha moment" of clarity. And even if you completely get it the first time, another explanation always adds texture.

My ignorance is revealed to me on a daily, sometimes hourly, basis (I suspect people with partners and/or children have an unfair advantage in this department). I have written before about the scope and consequences of others being wrong, but for much of my life, I have felt shame about the breadth and depth of my own ignorance (perhaps reflecting the insight that everyone is a mirror). It's helpful to re-dis-cover the wisdom that ignorance can, when consciously cultivated, be strength.

[The video below is the TED Talk that Stuart Firestein recently gave on The Pursuit of Ignorance.]

 

 


Valuable Advice on Preparing for Technical Interviews ... and Careers

CrackingTheCodingInterview TheGoogleResume The cover of Gayle Laakmann McDowell's book, Cracking the Coding Interview, and links to her Career Cup web site and Technology Woman blog are included in the slides I use on the first day of every senior (400-level) computer science course I have taught over the last two years. These are some of the most valuable resources I have found for preparing for interviews for software engineering - as well as technical program manager, product manager or project manager - positions. I recently discovered she has another book, The Google Resume, that offers guidance on how to prepare for a career in the technology industry, so I've added that reference to my standard introductory slides.

While my Computing and Software Systems faculty colleagues and I strive to prepare students with the knowledge and skills they will need to succeed in their careers, the technical interview process can prove to be an extremely daunting barrier to entry. The resources Gayle has made available - based on her extensive interviewing experience while a software engineer at Google, Microsoft and Apple - can help students (and others) break through those barriers. The updated edition of her earlier book focuses on how to prepare for interviews for technical positions, and her latest book complements this by offering guidance - to students and others who are looking to change jobs or fields - on how to prepare for careers in the computer technology world.

Gayle_uwb_wide

I have been looking for an opportunity to invite Gayle to the University of Washington Bothell to present her insights and experiences directly to our computer science students since I started teaching there last fall, and was delighted when she was able to visit us last week. Given the standing room only crowd, I was happy to see that others appreciated the opportunity to benefit from some of her wisdom. I will include fragments of this wisdom in my notes below, but for the full story, I recommend perusing her slides (embedded below) or watching a video of a similar talk she gave in May (also embedded further below), and for anyone serious about preparing for tech interviews and careers, I recommend reading her books.

Gayle emphasized the importance of crafting a crisp resume. Hiring managers typically spend no more than 15-30 seconds per resume to make a snap judgment about the qualifications of a candidate. A junior-level software engineer should be able to fit everything on one page, use verbs emphasizing accomplishments (vs. activities or responsibilities), and quantify accomplishments wherever possible. Here are links to some of the relevant resources available at her different web sites:

One important element of Gayle's advice [on Slide 13] that aligns with my past experience - and ongoing bias - in hiring researchers, designers, software engineers and other computing professionals is the importance of working on special projects (or, as Gayle puts it, "Build something!"). While graduates of computer science programs are in high demand, I have always looked for people who have done something noteworthy and relevant, above and beyond the traditional curriculum, and it appears that this is a common theme in filtering prospective candidates in many technology companies. This is consistent with advice given in another invited talk at UWB last year by Jake Homan on the benefits of contributing to open source projects, and is one of the motivations behind the UWB CSS curriculum requiring a capstone project for all our computer science and software engineering majors.

IntroductionToAlgorithmsGayle spoke of "the CLRS book" during her talk at UWB and her earlier talk at TheEasy, a reference to the classic textbook, Introduction to Algorithms, by Thomas H. Cormen, Charles E. Leiserson, Ronald L. Rivest and Clifford Stein. She said that entry-level software engineer applicants typically won't need to know data structures and algorithms at the depth or breadth presented in that book, and she offers a cheat sheet / overview of the basics on Slides 23-40, and an elaboration in Chapters 8 & 9 of her CtCI book. However, for those who are interested in delving more deeply into the topic, an online course based on the textbook is now part of the MIT Open CourseWare project, and includes video & audio lectures, selected lecture notes, assignments, exams and solutions.

One potential pitfall to candidates who prepare thoroughly for technical interviews is they may get an interview question that they have already seen (and perhaps studied). She recommended that candidates admit to having seen a question before, equating not doing so with cheating on an exam, and to avoid simply reciting solutions from memory, both because simple slip-ups are both common and easy to catch.

Gayle stressed that was there is no correlation between how well a candidate thinks he or she did in an interview and how well their interviewers thought they did. In addition to natural biases, the candidate evaluation process is always relative: candidates' responses to questions are assessed in the context of the responses of other candidates for the same position. So even if a candidate thinks he or she did well on a question, it may not be as well as other candidates, and even if a candidate thinks he or she totally blew a question, it may not have been blown as badly as other candidates blew the question.

Another important factor to bear in mind is that most of the big technology companies tend to be very conservative in making offers; they generally would prefer to err on the side of false negatives than false positives. When they have a candidate who seems pretty good, but they don't feel entirely confident about the candidate's strength, they have so many [other] strong candidates, they would rather reject someone who may have turned out great than risk hiring someone who does not turn out well. Of course, different companies have different evaluation and ranking schemes, and many of these details can be found in her CtCI book.

Gayle visits the Seattle area on a semi-regular basis, so I'm hoping I will be able to entice her to return each fall to give a live presentation to our students. However, for the benefit of those who are not able to see her present live, here is a video of her Cracking the Coding Interview presentation at this year's Canadian University Software Engineering Conference (CUSEC 2012) [which was also the site of another great presentation I blogged about a few months ago, Bret Victor's Inventing on Principle].

Finally, I want to round things out on a lighter note, with a related video that I also include in my standard introductory slides, Vj Vijai's Hacking the Technical Interview talk at Ignite Seattle in 2008:


How to approximate BorderLayout with GridBagLayout or BoxLayout

I recently encountered some challenges using Java 6 Swing and AWT components to develop a GUI with a top-level BorderLayout, which did not prevent the shrinking of components in its CENTER area in response to an expanding JList in its WEST area. I provided more context about this problem (and its solution) in my last post, in which I described How to Prevent a JList in a JScrollPane on a JPanel from Resizing. As I mentioned in that post, one way I attempted to resolve the problem was to substitute a different LayoutManager, first GridBagLayout and then BoxLayout. Neither of those substitutions resolved the problem, but in exploring this trajectory, I learned how to approximate the 5 areas of BorderLayout - NORTH, WEST, CENTER, EAST and SOUTH - using GridBagLayout and BoxLayout, and wanted to share simplified versions of these approximations here, in case they may be of use to others.

BorderLayout

My simplified base example, SimpleBorderLayoutDemo, creates a 320x160 pixel GUI with a JButton in each of the 5 areas:

SimpleBorderLayoutDemo_screenshot1

The "north" and "south" buttons are stretched to fill the entire width of the window. This is the case regardless of whether one extends JButton and overrides the getPreferredSize() or getMaximumSize() methods, or uses setPreferredSize() or setMaximumSize(). More specifically, BorderLayout ignores preferred and maximum widths for components in the NORTH and SOUTH areas. Note also that the "west" and "east" buttons are stretched vertically to fill the space between the NORTH and SOUTH areas. This is because BorderLayout ignores the preferred and maximum heights for components in the WEST and EAST areas. Just for completeness, it ignores all preferred and maximum dimensions (width and height) for components added to the CENTER pane.

To get buttons that have the preferred widths and heights, each JButton can be added to a separate JPanel, which has a default FlowLayout (a LayoutManager which respects the preferred heights and widths of its components), and then each of those JPanels can be added to the main contentPane. Using separate JPanels for each JButton results in the following GUI (SimpleBorderLayoutDemo2):

SimpleBorderLayoutDemo2_screenshot1


/**
 * SimpleBorderLayoutDemo2.java
 * 
 * Joe McCarthy, 26 August 2012
 * 
 * Baseline BorderLayout GUI, with extra layer of panels
 * Used to compare with GridBagLayout and BoxLayout
 */

import java.awt.BorderLayout;
import java.awt.Dimension;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;

public class SimpleBorderLayoutDemo2 extends JFrame {
	
	public SimpleBorderLayoutDemo2() {
		// create a button to place in each section
		JButton northButton = new JButton("north");
		JButton westButton = new JButton("west");
		JButton centerButton = new JButton("center");
		JButton eastButton = new JButton("east");
		JButton southButton = new JButton("south");

		// use JPanels (with default FlowLayouts) for each button 
		// so they use preferred sizes
		JPanel northPanel = new JPanel();
		northPanel.add(northButton);
		JPanel westPanel = new JPanel();
		westPanel.add(westButton);
		JPanel centerPanel = new JPanel();
		centerPanel.add(centerButton);
		JPanel eastPanel = new JPanel();
		eastPanel.add(eastButton);
		JPanel southPanel = new JPanel();
		southPanel.add(southButton);

		// add the sections to a JPanel
		JPanel mainPanel = new JPanel();
		mainPanel.setLayout(new BorderLayout());
		mainPanel.add(northPanel, BorderLayout.NORTH);
		mainPanel.add(westPanel, BorderLayout.WEST);
		mainPanel.add(centerPanel, BorderLayout.CENTER);
		mainPanel.add(eastPanel, BorderLayout.EAST);
		mainPanel.add(southPanel, BorderLayout.SOUTH);
		
		// add the JPanel to the main contentPane & make visible
		getContentPane().add(mainPanel);
		setTitle("SimpleBorderLayoutDemo2");
		setPreferredSize(new Dimension(320, 160));
		setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
		pack();
		setVisible(true);
	}

	public static void main(String[] args) {
		new SimpleBorderLayoutDemo2();
	}

}

GridBagLayout

To approximate this 5-area layout using GridBagLayout, we would need to use 3 rows and 3 columns, in which the north and south components each consumed 3 columns. We can use GridBagConstraints fields gridx and gridy to specify rows and columns, and use the gridwidth field to enable the north and south components to occupy all 3 columns of the top and bottom rows.

GridBagLayoutForBorderLayoutDemo_screenshot0

GridBagLayout components tend to gravitate toward the middle; in order to spread them out. we can insert Insets specifying the number of pixels to use for padding above, to the left of, below and the to right of each component. If we create a new Insets object initialized with values of 10 for each its edges (top, left, bottom and right), and assign it to the GridBagConstraints insets field for the GridBagLayout, we get the following layout:

GridBagLayoutForBorderLayoutDemo_screenshot1


/**
 * GridBagLayoutForBorderLayoutDemo.java
 * 
 * Joe McCarthy
 * 26 August 2012
 * 
 * Demonstration of using GridBagLayout to approximate BorderLayout
 */

import java.awt.Dimension;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.Insets;

import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;

public class GridBagLayoutForBorderLayoutDemo extends JFrame {
	
	public GridBagLayoutForBorderLayoutDemo() {
		// create a button to place in each section
		JButton northButton = new JButton("north");
		JButton westButton = new JButton("west");
		JButton centerButton = new JButton("center");
		JButton eastButton = new JButton("east");
		JButton southButton = new JButton("south");
		
		// create a single GridBagConstraints variable 
		// (should really use separate variables for each section)
		GridBagConstraints c = new GridBagConstraints();
		// insert Insets to space components out
		c.insets = new Insets(10, 10, 10, 10);
		
		// add the buttons to a JPanel, using contraints
		JPanel mainPanel = new JPanel();
		mainPanel.setLayout(new GridBagLayout());
		c.gridx = 0;
		c.gridy = 0;
		c.gridwidth = 3;
		c.anchor = GridBagConstraints.NORTH; 	// or PAGE_START
		mainPanel.add(northButton, c);
		c.gridx = 0;
		c.gridy = 1;
		c.gridwidth = 1;
		c.anchor = GridBagConstraints.WEST; 	// or LINE_START
		mainPanel.add(westButton, c);
		c.gridx = 1;
		c.gridy = 1;
		c.gridwidth = 1;
		c.anchor = GridBagConstraints.CENTER;	// default
		mainPanel.add(centerButton, c);
		c.gridx = 2;
		c.gridy = 1;
		c.gridwidth = 1;
		c.anchor = GridBagConstraints.EAST; 	// or LINE_END
		mainPanel.add(eastButton, c);
		c.gridx = 0;
		c.gridy = 2;
		c.gridwidth = 3;
		c.anchor = GridBagConstraints.SOUTH;	// or PAGE_END
		mainPanel.add(southButton, c);
		
		// add the JPanel to main contentPane & make visible
		getContentPane().add(mainPanel);
		setTitle("GridBagLayoutForBorderLayoutDemo");
		setPreferredSize(new Dimension(320, 160));
		setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
		pack();
		setVisible(true);
	}

	public static void main(String[] args) {
		new GridBagLayoutForBorderLayoutDemo();
	}

}

BoxLayout

BoxLayout can also be used to approximate the BorderLayout. BoxLayout allows components to be laid out horizontally (along the X_AXIS) or vertically (along the Y_AXIS). In horizontal arrangements, BoxLayout attempts to respect the preferred widths of compoenents; in vertical arrangements, BoxLayout attempts to respect the preferred heights of components.

We could create a top-level BoxLayout with vertical arrangement, in which case (assuming the default top-to-bottom orientation), we would

  • add the north button
  • create and add another JPanel having a BoxLayout with vertical orientation to which we would add west, center and east buttons
  • add the south button

BoxLayoutForBorderLayoutDemo_screenshot0

Alternately, we could create a top-level BoxLayout with horizontal arrangement, in which case (assuming the default left-to-right orientation), we would

  • add the west button
  • create and add another JPanel having a BoxLayout with vertical orientation to which we would add north, center and south buttons
  • add the east button

BoxLayoutForBorderLayoutDemo2_screenshot0

In the first BoxLayout configuration, everything is shifted toward the top, and the north and south buttons appear off-center; in the second BoxLayout configuration, everything seems shifted to the left. These misalignments are due to the default alignments in a BoxLayout. There is a whole section of the Java tutorial on How to Use BoxLayout devoted to Fixing Alignment Problems, so I won't go into the full details here.

To fix the problems above, it is necessary to use setAlignmentX(CENTER_ALIGNMENT) for the north and south buttons in the first BoxLayout.

BoxLayoutForBorderLayoutDemo_screenshot0b

For the second BoxLayout, we would use setAlignmentY(CENTER_ALIGNMENT) for the west and east buttons.

BoxLayoutForBorderLayoutDemo2_screenshot0

The same tutorial also describes Using Invisible Components as Filler, which includes a few different internal padding options. A flexible "glue" filler can be used to add as much filler as necessary to evenly space out the components, in the horizontal or vertical dimensions. So, in addition to alignment adjustments, we'll also want to createHorizontalGlue() between the north and center buttons, and between the center and south buttons, in the first BoxLayout, and then createVerticalGlue() between the west button and the center panel (containing north, center and south buttons), and between the center panel and the east button. In the second BoxLayout, we'd do the opposite, using createVerticalGlue() between the west and center buttons, and between the center and east buttons, and then using createHorizontalGlue() between the north button and center panel, and between the center panel and the south button. Whichever combination we use, we end up with the following layout:

BoxLayoutForBorderLayoutDemo_screenshot1


/**
 * BoxLayoutForBorderLayoutDemo.java
 * 
 * Joe McCarthy
 * 26 August 2012
 * 
 * Demonstration of using BoxLayout to approximate BorderLayout
 */

import java.awt.Dimension;

import javax.swing.Box;
import javax.swing.BoxLayout;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;

public class BoxLayoutForBorderLayoutDemo extends JFrame {
	
	public BoxLayoutForBorderLayoutDemo() {
		// create a button to place in each section
		JButton northButton = new JButton("north");
		JButton westButton = new JButton("west");
		JButton centerButton = new JButton("center");
		JButton eastButton = new JButton("east");
		JButton southButton = new JButton("south");
		
		// create a center panel for east, center & west using BoxLayout.X_AXIS
		// insert some "horizontal glue" to space them out evenly
		JPanel centerPanel = new JPanel();
		centerPanel.setLayout(new BoxLayout(centerPanel, BoxLayout.X_AXIS));
		centerPanel.add(westButton);
		centerPanel.add(Box.createHorizontalGlue());
		centerPanel.add(centerButton);
		centerPanel.add(Box.createHorizontalGlue());
		centerPanel.add(eastButton);
		
		// adjust vertical (X_AXIS) alignments of north and south components
		northButton.setAlignmentX(CENTER_ALIGNMENT);
		southButton.setAlignmentX(CENTER_ALIGNMENT);

		// add the north button, center panel and south button to a JPanel
		// insert some "vertical glue" to space them out evenly
		JPanel mainPanel = new JPanel();
		mainPanel.setLayout(new BoxLayout(mainPanel, BoxLayout.Y_AXIS));
		mainPanel.add(northButton);
		mainPanel.add(Box.createVerticalGlue());
		mainPanel.add(centerPanel);
		mainPanel.add(Box.createVerticalGlue());
		mainPanel.add(southButton);
		
		// add the JPanel to main contentPane & make  visible
		getContentPane().add(mainPanel);
		setTitle("BoxLayoutForBorderLayoutDemo");
		setPreferredSize(new Dimension(320, 160));
		setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
		pack();
		setVisible(true);
	}

	public static void main(String[] args) {
		new BoxLayoutForBorderLayoutDemo();
	}

}

Note that each of the final layouts above has some subtle differences; in BorderLayout, the buttons in the WEST, CENTER and EAST are all aligned at the top rather the center of their respective areas; in GridBagLayout, the spaces between the buttons are all very uniform; in BoxLayout, the buttons are pushed out toward the edges. All of these can be modified with further adjustments, but my main goal here was simply to demonstrate how the basic NORTH, WEST, CENTER, EAST and SOUTH areas of a BorderLayout can be approximated using other LayoutManagers.

Potential Problems with Growing and Shrinking Components

Just to round things out, in view of the previous post on preventing the resizing of components, I'll include variations on each of the layouts above where the label of the "west" button is changed to "westwestwest" (3x), "westwestwestwestwest" (5x) and "westwestwestwestwestwestwest" (7x):

BorderLayout (version 1)

SimpleBorderLayoutDemo_screenshot2   SimpleBorderLayoutDemo_screenshot3   SimpleBorderLayoutDemo_screenshot4

In the first case, the EAST area is shrunk to the preferred size of its button; in the second case, the CENTER area is shrunk below the preferred size of its button; in the third case, the CENTER area is entirely consumed by the WEST area.

BorderLayout (version 2)

SimpleBorderLayoutDemo2_screenshot2   SimpleBorderLayoutDemo2_screenshot3   SimpleBorderLayoutDemo2_screenshot4

The same pattern of shrinking and eventual elimination of the CENTER area is repeated.

GridBagLayout

GridBagLayoutForBorderLayoutDemo_screenshot2   GridBagLayoutForBorderLayoutDemo_screenshot3   GridBagLayoutForBorderLayoutDemo_screenshot4

In the GridBagLayout, the expanding "west*" button simply pushes the components to its right further to the right, but their sizes are not changed.

BoxLayout (version 1)

BoxLayoutForBorderLayoutDemo_screenshot2   BoxLayoutForBorderLayoutDemo_screenshot3   BoxLayoutForBorderLayoutDemo_screenshot4

In the first version of BoxLayout, where the center row is a separate JPanel with a BoxLayout.X_AXIS arrangement, we see a pattern similar to that of GridBagLayout, where the expanding "west*" button keeps pushing the other buttons further to the right, without changing their sizes.

BoxLayout (version 2)

BoxLayoutForBorderLayoutDemo2_screenshot2   BoxLayoutForBorderLayoutDemo2_screenshot3   BoxLayoutForBorderLayoutDemo2_screenshot4

A similar pattern can be seen in version 2 of BoxLayout, where the center column is a separate JPanel with a BoxLayout.Y_AXIS arrangement, except that in this case the entire center column is pushed further to the right.

The solution to the problem of expanding components resulting in the shrinking or elimination of other components, as I mentioned in the previous post, is to use setPreferredSize() and/or setMaximumSize() - depending on the LayoutManager - for any components that might expand dynamically during execution and encroach upon other components ... such as a JList that accepts new String elements that may be longer than any previous element.


How to Prevent a JList in a JScrollPane on a JPanel from Resizing

I've been working on a graphical user interface to enable a user to view, modify and add relevance judgments for a set of results returned by a search engine in response to a set of topics. The GUI was developed as part of some work I've been doing on the Text REtrieval Conference (TREC) 2012 Medical Records Track. I hope to write more about the GUI and the work on TREC in the future. For now, I want to share a solution I developed to a problem with the Java 6 Swing and AWT components I was struggling with over the past few days.

The problem was a JList contained within a JScrollPane contained within a JPanel that was resizing when new String elements added to the JList were longer than its current width. I initially implemented the GUI, which extends JFrame, using a BorderLayout:

BorderLayoutExample

The offending JList was in the West (leftmost) area, and when it grew (after adding a string longer than its initial width), it shrank the JTextArea component I have in the Center area. I wanted to prevent any resizing from happening.

I read that the Center area of a BorderLayout cannot be protected from resizing - it fills whatever space is available after all the other components have been rendered - so I experimented with different LayoutManagers (GridBagLayout and BoxLayout) ... which will be the subject of a future blog post [update: see How to approximate BorderLayout with GridBagLayout or BoxLayout]. I couldn't manage to get GridBagLayout to work and play nicely with my components; BoxLayout - using a BoxLayout.X_AXIS JPanel for the West, Center and East area components, which was contained inside a BoxLayout.Y_AXIS JPanel (which was wedged between BoxLayout.Y_AXIS JPanels for North and South areas) - reduced the shrinking, but did not eliminate it.

I considered extending JPanel and overriding the getPreferredSize() or getMaximumSize() methods, but decided against this as the log files revealed that some resizing occurs after all the components in the GUI are initially populated. I wanted to allow the component sizes to settle into an initial populated state, and then prevent subsequent resizing.

After trying several other possibilities, I finally wrote a method to update the width associated with the PreferrredSize and MaximumSize, which I call after populating the components. I'll share it below, in case it is of use to others, or in case others have better solutions.

private void restrictPanelWidth(JPanel panel) {
	int panelCurrentWidth = panel.getWidth();
	int panelPreferredHeight = (int)panel.getPreferredSize().getHeight();
	int panelMaximumHeight = (int)panel.getMaximumSize().getHeight();
	panel.setPreferredSize(new Dimension(panelCurrentWidth, panelPreferredHeight));	
	panel.setMaximumSize(new Dimension(panelCurrentWidth, panelMaximumHeight));
}

Among the shortcomings of this solution is that any JPanel restricted by this method will not automatically resize if/when the containing window (JFrame) is resized. My expectation is that my GUI will fill the screen - however large that screen is - and that users will generally not want to make it any smaller than full screen. If my assumption proves unwarranted, I suppose I could reintroduce some flexibility via the componentResized() method of a ComponentAdapter, but I'm going to wait to see if any of the [currently] small group of users asks for this capability.

Update: I discovered another possible approach, which I have not now tried [see update 2 below], described in the Advanced JList Programming article at the Sun Developer Network (SDN). In the section entitled "JList Performance: Fixed Size Cells, Fast Renderers", Hans Muller suggests using the setFixedCellWidth() or setPrototypeCellValue() - which is passed a prototype (e.g., String) value that sets the cell width and cell height to the width and height of the prototype value - method to restrict the width of cells in a JList. He also notes "be sure to set the prototypeCellValue property after setting the cell renderer". The shortcoming I envision with this approach is that I would have to call setFixedCellWidth() any time that the window is resized ... though, as noted before, this is a scenario I don't currently handle in the GUI anyway.

Update 2: When I loaded the GUI with a JList containing cells wider than the desired width, the original problem recurred, so my fix was not effective. I have since used setFixedCellWidth() for the two JLists in the West and East areas, and all is well in my [GUI] world again.


def main() in Python considered harmful

Python-logoI recently graded the first Python programming assignments in the course I'm teaching on Social and Computational Intelligence in the Computing and Software Systems program at University of Washington Bothell. Most of the students are learning Python as a second (or third) language, approaching it from the perspective of C++ and Java programming, the languages we use in nearly all our other courses. Both of those languages require the definition of a main() function in any source file that is intended to be run as an executable program, and so many of the submissions include the definition of a main() function in their Python scripts.

In reviewing some recurring issues from the first programming assignment during class, I highlighted this practice, and suggested it was unPythonistic (a la Code like a Pythonista). I recommended that the students discontinue this practice in future programming assignments, as unlike in C++ and Java, a function named main has no special meaning to the the Python interpreter. Several students asked why they should refrain from this practice - i.e., what harm is there in defining a main() function? - and one sent me several examples of web sites with Python code including main() functions as evidence of its widespread use.

Comfort_zone_growth_zone_panic_zoneIn my experience, the greatest benefit to teaching is learning, and the students in my classes regularly offer me opportunities to move out of my comfort zone and into my growth zone (and occasionally into my panic zone). I didn't have a good answer for why def main() in Python was a bad practice during that teachable moment  ... but after lingering in the growth zone for a while, I think I do now.

The potential problem with this practice is that any function defined at the top level of a Python module becomes part of the namespace for that module, and if the function is imported from that module into the current namespace, it will replace any function previously associated with the function name. This may lead to unanticipated consequences if it is combined with a practice of using wildcards when importing, e.g., from module import * (though it should be noted that wildcard imports are also considered harmful by Pythonistas).

I wrote a couple of simple Python modules - main1.py and main2.py - to illustrate the problem:

# main1.py
import sys

def main():
    print 'Executing main() in main1.py'
    print '__name__: {}; sys.argv[0]: {}\n'.format(__name__, sys.argv[0])
 
if __name__ == '__main__':
    main()

# main2.py
import sys

def main():
    print 'Executing main() in main2.py'
    print '__name__: {}; sys.argv[0]: {}\n'.format(__name__, sys.argv[0])
 
if __name__ == '__main__':
    main()

The main functions are identical except one has a string 'main1.py' whereas the other has a string 'main2.py'. If either of these modules are executed from the command line, they execute their own main() functions, printing out the hard-coded strings and the values of __name__ and sys.argv[0] (the latter of which will only have a value when the module is executed from the command line).

$ python main1.py
Executing main() in main1.py
__name__: __main__; sys.argv[0]: main1.py

$ python main2.py
Executing main() in main2.py
__name__: __main__; sys.argv[0]: main2.py

When these modules are imported into the Python interpreter using wildcards, the effect of invoking the main() function will depend on whichever module was imported first.

$ python
Python 2.7.2 (v2.7.2:8527427914a2, Jun 11 2011, 15:22:34)
[GCC 4.2.1 (Apple Inc. build 5666) (dot 3)] on darwin
Type "help", "copyright", "credits" or "license" for more information.
>>> locals()
{'__builtins__': <module '__builtin__' (built-in)>, '__name__': '__main__', '__doc__': None, '__package__': None}
>>> from main1 import *
>>> locals()
{'__builtins__': <module '__builtin__' (built-in)>, '__package__': None, 'sys': <module 'sys' (built-in)>, '__name__': '__main__', 'main': <function main at 0x1004aa398>, '__doc__': None}
>>> main()
Executing main() in main1.py
__name__: main1; sys.argv[0]:

>>> from main2 import *
>>> locals()
{'__builtins__': <module '__builtin__' (built-in)>, '__package__': None, 'sys': <module 'sys' (built-in)>, '__name__': '__main__', 'main': <function main at 0x1004aa140>, '__doc__': None}
>>> main()
Executing main() in main2.py
__name__: main2; sys.argv[0]:

>>> exit()
$

Now, this may all be much ado about little, especially given the aforementioned caveat about the potential harm of using wildcards in import statements. I suppose if one were to execute the more Pythonistic selective imports, i.e., from main1 import main and from main2 import main, at least the prospect of the main() function being overridden might be more apparent. But people learning a programming language for the first time - er, or teaching a programming language for the second time - often use shortcuts (such as wildcard imports), and so I offer all this as a plausible rationale for refraining from def main() in Python.

As part of my practice of leaning into discomfort and staying in the growth zone, I welcome any relevant insights or experiences that others may want to share.


The Independent Project: An Inspiring Experiment in Student-Designed Learning

The Independent Project is an experimental school within a school, designed and implemented by a group of students at Monument Mountain Regional High School in Great Barrington, MA. I recently wrote about Carl Rogers' ideas regarding student-centered learning, in which a professor (who in this case was also a therapist) plays the role of facilitator, while graduate or undergraduate college students design and implement the course. The Independent Project takes this a step further, empowering a small group of high school students to design and implement an entire curriculum with far less direct involvement of faculty.

I first read about the project in Let Kids Rule the School, a March 2011 NYTimes op-ed piece by Susan Engel, a psychology professor at nearby Williams College, in which she describes a participatory educational framework with minimal input by or supervision from any faculty or staff:

Their guidance counselor was their adviser, consulting with them when the group flagged in energy or encountered an obstacle. Though they sought advice from English, math and science teachers, they were responsible for monitoring one another’s work and giving one another feedback. There were no grades, but at the end of the semester, the students wrote evaluations of their classmates.

During a two-day workshop at the University of Washington Bothell this week on Reinventing University-Level Learning for the 21st Century, I mentioned The Independent Project during a breakout session and wondered whether and how this experiment might be carried out in the context of a university. I started composing a followup email with an annotated link ... and as the annotations grew longer I decided I'd move it over to a blog post (and expand it further).

Since my last visit to The Independent Project web site, a few things have been added:

  • a comprehensive 16-page white paper [PDF] offering more details about exactly how they proposed, sought approval and then designed and implemented the program
  • a map showing other schools that are purportedly experimenting with the program (surprisingly, only two: one in Ireland, another in Mexico)
  • a blog with entries spanning February through March 2012, suggesting they are in the midst of a second trial of the program (a post on logistics highlights the revisions from the first trial)

There is also an extremely well-produced and inspiring 15-minute video, which I will embed below, and then followup with a few highlights.

The video starts out with a quote often - though questionably - attributed to Antoine de Saint-Exupéry, (author of The Little Prince), while the voice-over ironically talks of the project as "rocking the boat":

If you want to build a ship, don't drum up the men to gather wood, divide the work and give orders. Instead, teach them to yearn for the vast and endless sea.

Another relevant and inspiring quote, by educational reformer Ted Sizer, is shown further on:

Inspiration, hunger: these are the qualities that drive good schools. The best we educational planners can do is to create the most likely conditions for them to flourish, and then get out of their way.

Throughout the video, a number of recurring themes are emphasized by students, faculty and administrators at the school (and the school within the school): independence, exploration, questions, initiative, creativity, curiosity, caring, sharing, confidence, mutual support, engagement, freedom, responsibility, excitement, agency, a thirst for knowledge.

According to Sam Levin, the Monument student who instigated the idea and wrote the white paper mentioned above, students would start each week converging on a set of questions and allocate responsibility for answering those questions among each other, then spend the rest of the week splitting their time between individual endeavors during the mornings and working on collective endeavors in the afternoons. They would gather together to teach each other what they learned each Friday.

Among the questions they asked were:

  • How do plant cells differ from the top of the mountain to the bottom of the mountain?
  • Why do we cry?
  • How does music affect the brain?
  • How do mice react to aromatherapy?
  • What causes innovation?
  • Why do we have art?
  • How does Pixar make a film?
  • How can we clean the Housatonic River?
  • What are the dimensions?
  • Are some infinities bigger than others?
  • Is there science behind old wives' tales?

Among the books they read were

  • As I Lay Dying, by William Faulkner
  • Charlotte's Web, by E. B. White
  • Sirens of Titan, by Kurt Vonnegut
  • Tales of Weird, by Ralph Steadman
  • The House on Mango Street, by Sandra Cisneros
  • Travels in the Scriptorium, by Paul Auster
  • The Importance of Being Earnest, by Oscar Wilde
  • Flatland, by Edwin A. Abbott

Among the individual endeavors they worked on were

  • a novel
  • a play
  • a compilation of short stories
  • a study of women's trauma and recovery
  • a short film
  • practicing culinary arts
  • learning the piano

Toward the end of the video, Levin summarizes the experience:

We learned how to learn, we learned how to teach, and we learned how to work.

We learned how to learn in the sense that we learned how to ask questions, and explore the answers using different methods like the scientific method or different or different resources.

We learned how to teach in the sense that we learned how to take what we learned and share it with other people, not just because we had to, because we had a presentation, but because it was our responsibility to make sure everyone else in the group benefited from our work.

We learned how to work in the sense that we learned how to use different resources, and go to different people, and use different methods, and push each other, and be pushed, and criticize and be criticized, to produce the best work, and learn as much as possible.

Susan Engel, who is also interviewed in the video, notes that "the potential for this is right there within the walls of every single school". I'm disappointed, though hardly surprised, that the program does not appear to have gone viral. While the potential for such student-designed learning may be present in any school, I suspect most students would not be sufficiently motivated to expend the energy to design and implement their own curriculum.

Even if a sufficient number of students were sufficiently motivated, there would still be the problem(s) of scale. One of the things I'm re-learning about academia - which is also being learned by participants in the Occupy movement - is that self-governance requires a considerable investment of time and energy ... and it's very difficult to avoid the imposition of structure (aka bureaucracy) as the size of the self-governing body expands.

With the growing array of online resources freely available for learning, including videos from the Khan Academy, massive online open courses from traditional universities as well as startups, and the Peeragogy Handbook Project (to name just a few), the potential for learning increasingly extends far beyond the walls of any single school. Indeed, this expanding potential, and the growing uncertainty about the role universities might play, is the motivation behind the UWB workshop this week.

One of the outcomes of the workshop was a commitment - at least among some of the participants - to undertake more experiments in our cultivation of learning opportunities ... some of which I'm hoping will incorporate the insights and experiences from The Independent Project.

Update: Sam Levin, who is now at University of Oxford, shared some updates with me during a Skype call, which I'll summarize below.

  • Sam has also helped instigate other experimental projects involving high school students, such as Project Sprout and The Future Project.
  • The Independent Project has been contacted by approximately 200 schools from around the world, many of which are implementing their own variations.
  • During the first experiment (in Fall 2010), the participating students were awarded up to 6.5 "public school credits" which counted toward graduation but did not count toward any of the individual distribution requirements (e.g., English or Math), so some students needed to double up in preceding or succeeding years to ensure they met all the requirements.
  • The second experiment is going on now (Spring 2012), and starting in the Fall of 2012, the school will make The Independent Project a permanent part of their program, offer it for a full year (vs. a single semester), and allow students to apply credits toward individual requirements.

Much to my surprise, Sam is not aware of any researchers who are evaluating the current or past instantiations of The Independent Project at MMRHS or any other schools. He suspects this may be due, in part, to the difficulty of assessment (in general, and specifically in the case of a program where students determine their own assessment paradigm). I may be wrong, but this seems like a HUGE opportunity for researchers interested in educational innovation.


Principle-centered Invention: Bret Victor on tools, skills, crafts and causes

I just watched an incredibly inspiring video of Bret Victor's CUSEC 2012 talk, Inventing on Principle. Bret's principle is

creators need an immediate connection to what they are creating.

He illustrates this principle during the first 35 minutes of the presentation, demonstrating some fabulously empowering "live coding" tools to enable programmers to manipulate and immediately see the impact of changes to their code when working with graphics (at the 2:30 mark), games (10:25), algorithms (16:45), circuits (23:15) and animations (29:20).

BretVictor_LiveCodingTools

I've rarely heard an audience respond to a speaker at a technical conference - vs., say, a State of the Union address - with applause so many times throughout a talk, but the audience applauded each of Victor's feats of programming empowerment, leading me to think of live coding / visual programming [tools] as a form of performance art ... and political statement.

As amazing as these tools are, the most inspiring part of his talk - for me - starts just after the 35 minute mark, where Victor ties these all together as examples of inventing on [his] principle, arguing that these arose not as just problem solving opportunities, but as part of what he feels is his moral responsibility to make the world a better place, to free ideas from the unnecessary constraints imposed by poorly designed tools.

Victor goes on to offer other examples of principle-centered inventors, and how their principles enabled them to make extraordinary progress on righting a wrong not yet recognized by a culture:

  • Larry Tesler: no person should be trapped in a mode (e.g., early text editors such as vi)
  • Doug Engelbart: enable mankind to solve the world problems (empowering knowledge workers)
  • Alan Kay: amplify human reach and bring new ways of thinking to a faltering civilization that desperately needs it
  • Richard Stallman: software must be free

Victor then goes on to espouse his personal philosophy of principle-centered invention, and to contrast that with the more traditional paths for designers, engineers, researchers and even entrepreneurs that focus on building skills and/or solving open problems. While I believe he has construed both entrepreneurship and academic research a bit too narrowly - I know of several people in these roles who are principle-centered inventors (some of whom I mentioned in an earlier post on irritation-based innovation) - I do agree with his larger message that changing the world requires a larger vision beyond serially solving open problems, and that people can have far greater impact on the world if they are willing to pay attention to common threads that irritate and motivate them across a range of experiences, identify their guiding principle, and then act on that principle.

Rather than further paraphrasing his remarks, I'm going to include an approximate transcript of that last 5 minutes of his talk, in which he integrates ideas about identity, experience and insight into a compelling case for principle-centered invention (and, principle-centered living), in case it might motivate others like me who rarely take the time to watch a 54-minute video [this one was tweeted by Clay Shirky (@cshirky), who emits an extraordinarily high signal-to-noise ratio throughout all of his media streams]

Bret Victor - Inventing on Principle from CUSEC on Vimeo.

The world will try to make you define yourself by a skill. That's why you have a major in college. That's why you have a job title. You are a software engineer. And you'll probably specialize to be a database engineer, or a front-end engineer, and you'll be given front ends and asked to engineer them. And that can be worthwhile, and valuable, And if you want to pursue your life pursuing excellence, and practicing a skill, you can do that. That is the path of a craftsman. That is the most common path.

The only other path you hear about much is the path of the problem solver. So I see entrepreneurship and academic research as kind of two sides of that coin. There's a field, there's a set of problems in that field, or needs in the market. You go and you choose one, and you work it and make your contribution. And a little bit later on, you choose another problem, work it, make a contribution there. Again, that can be worthwhile and valuable, and if that's what you want to do, you can take that path.

Identity

But I don't see Larry Tesler on either of those paths. I wouldn't say he was contributing to the field of user experience design, because there was no such thing. He didn't choose some open problem to solve, he came across a problem that only existed in his own head, that no one else even recognized. And certainly, he did not define himself by his craft, he defined himself by his cause, by the principle that he fought to uphold.

I'm sure that if you look at Wikipedia, it will say that he's a computer scientist, or a user experience something, but to me that's like saying Elizabeth Cady Stanton was a community organizer. No. Elizabeth Cady Stanton established the principle of woman's suffrage. That's who she was. That's the identity she chose. And Larry Tesler established the principle of modelessness. He had this vision, and he brought the world to that vision.

So, you can choose this life. Or maybe it will end up choosing you. And it might not happen right away. It can take time to find a principle, because finding a principle is a form of self-discovery; you're trying to figure out what your life is supposed to be about. What you want to stand for as a person. It took me like a decade; 10 years before any real understanding of my principles solidified. That was my 20s.

Experience

When I was young, I felt I had to live this way. I would get little glimmers of what mattered to me, but no big picture. It was really unclear. This was very distressing for me. What I had to do was just do a lot of things, make many things, make many types of things, study many things, experience many, many things, and use all of these experiences as ways to analyze myself. Taking all these experiences and saying "Does this resonate with me?" "Does this repel me?" "Do I not care?" Building up this corpus of experiences that I felt very strongly about for some reason. And trying to make sense of it, trying to figure out why, what is the secret ingredient to all these experiences that I'm reacting to so strongly?

Now I think everyone's different, and all those guys I talked about, they have their own origin stories, which you can read about. I will just say that confining ourselves to practicing a single skill can make it difficult to get that broad range of experience which seems to be so valuable for this sort of work.

Insight

And finally, if you choose to follow a principle, a principle can't be any old thing you believe in. You'll hear a lot of people say they want to make software easier to use, or they want to delight their users, or they want to make things simple. That's a really big one right now, everyone wants to make things simple. And those are nice thoughts, and maybe give you a direction to go in, but too vague to be directly actionable. Larry Tesler liked simplicity, but his principle was a specific nugget of insight: no person should be trapped in a mode. And that is a powerful principle, because it gave him a new way of seeing the world. It divided the world into right and wrong, in a fairly objective way. So, he could look at someone selecting text, and ask "Is this person in a mode? Yes or no?" If yes, he had to do something about that. And likewise, I believe that creators need powerful tools. It's a nice thought, but it doesn't really get me anywhere. My principle is that creators need this immediate connection, so I can watch you changing a line of code, and ask "Did you immediately see the effect of that change? Yes or no?" If no, I gotta do something about that. And again, all those demos that I showed you came out of me doing that, by following this principle, and letting it lead me to what I had to do.

So if your guiding principle embodies a specific insight, it will guide you, and you'll always know if what you're doing is right.

There are many ways to live your life. That's maybe the most important thing to realize in your life, that every aspect of your life is a choice. There are default choices. You can choose to sleepwalk through your life, and accept the path that is laid out for you. You can choose to accept the world as it is. But you don't have to. If there's something in the world that you feel is a wrong, and you have a vision for what a better world could be, you can find your guiding principle, and you can fight for a cause. So after this talk, I'd like you to take a little time, and think about what matters to you, what you believe in, and what you might fight for.