O'Reilly logo

Apprenticeship Patterns by Adewale Oshineye, Dave Hoover

Stay ahead with the world's most comprehensive technology and business learning platform.

With Safari, you learn the way you learn best. Get unlimited access to videos, live online training, learning paths, books, tutorials, and more.

Start Free Trial

No credit card required

Chapter 2. Emptying the Cup

image with no caption

Can’t you see the cup is already full and overflowing?

The young philosopher

A Zen master of great renown was visited by a young philosopher who had traveled from a distant land to meet him. The master agreed to see him because the philosopher came with high recommendations by his teachers. The two sat under a tree to converse and the subject hastily turned to what the master could teach the young philosopher. Recognizing the flame of youth, the master smiled warmly and started to describe his meditation techniques. He was cut short by the philosopher, who said: “Yes, I understand what you are talking about! We did a similar technique at the temple, but instead we used images to focus!”

Once the philosopher was done explaining to the master how he was taught and practiced his meditation, the master spoke again. This time he tried to tell the young man about how one should be attuned to nature and the universe. He didn’t get two sentences in when the philosopher cut him short again and started talking about how he had been taught meditation and so on and so on.

Once again, the master patiently waited for the young philosopher to end his excited explanations. When the philosopher was quiet again, the master spoke of seeing humor in every situation. The young man didn’t lose any time and started to talk about his favorite jokes and how he thought they could relate to situations he had faced.

Once the philosopher was done, the Zen master invited him inside for a tea ceremony. The philosopher accepted gladly, having heard of how the master performed the ceremony like no other. Such a moment was always a privileged one with such a man. Once inside, the master performed flawlessly up to the point where he started to pour the tea in the cup. As the master was pouring, the philosopher noticed that the cup was being filled more than usual. The master kept pouring tea and the cup was soon full to the brim. Not knowing what to say, the young man stared at the master in astonishment. The master kept pouring as if nothing was wrong, and the cup started to overflow, spilling hot tea on the floor mattresses and the master’s hakama. Not believing what he was seeing, the philosopher finally exclaimed: “Stop pouring! Can’t you see the cup is already full and overflowing?”

With those words, the master gently placed the teapot back on the fire and looked at the young philosopher with his ever-present warm smile and said: “If you come to me with a cup that is already full, how can you expect me to give you something to drink?”

This story was adapted from Michel Grandmont’s “Tasting a New Cup of Tea.”[9] We retell it here to illustrate the sort of attitude a successful apprenticeship requires. The more experience you already have, the more effort you will need to put into “emptying your cup,” clearing your mind of bad habits, setting aside the pride you have in your skills, and opening yourself up to the different, often counterintuitive, approaches of your more experienced colleagues.

The patterns in this chapter should provide you with the tools to start your apprenticeship on the right foot and with an open mind. Wearing The White Belt represents maintaining a beginner’s mind regardless of your expertise. Unleashing Your Enthusiasm will propel you through common beginner roadblocks such as frustration, confusion, and discouragement and will allow you to venture deep into Your First Language. Acquiring Concrete Skills in a specific technology will open doors for you and give you opportunities to explore the more advanced patterns in later chapters. But don’t allow yourself to become too comfortable! Use the final four patterns together to systematically acquire an increasingly broad set of technologies. Allow yourself to Expose Your Ignorance in a specific technology in order to focus your attention on what you need to learn next. Then Confront Your Ignorance and let your team and your customers watch you flex your knowledge-acquisition muscles. Eventually you’ll have the opportunity to take on an audacious task, a chance to dive into The Deep End and either learn how to swim or sink to the bottom. That may sound scary, but there is no better time in your career to take this sort of risk. When all of this new information and mind-stretching becomes overwhelming, it’s important to Retreat into Competence, remember how far you’ve come and the skills you’ve developed, and gather yourself to ascend to the next plateau.

Your First Language

image with no caption

By relieving the brain of all unnecessary work, a good notation sets it free to concentrate on more advanced problems, and in effect increases the mental power of the race.[...T]he technical terms of any profession or trade are incomprehensible to those who have never been trained to use them. But this is not because they are difficult in themselves. On the contrary they have invariably been introduced to make things easy.

Alfred North Whitehead, An Introduction to Mathematics


You are just starting out and have only a shallow understanding of one or two programming languages.


You feel your job depends on you delivering a solution written in a specific programming language and of the same standard of quality as your teammates. Alternatively, obtaining a job in the first place depends on your proficiency in a specific programming language.


Pick a language. Become fluent in it. For the next few years this will be the main language you use to solve problems, as well as the default skill you hone whenever you are practicing. Making this choice is a challenge. It is important that you carefully weigh the options, as this is the foundation upon which your early career will be built.

If you are asked to solve a problem and it dictates a programming language, let the drive toward the solution direct your learning. If you’re pursuing a job that requires a specific language, build a toy application using that language, preferably an open source project so it is easy for your prospective employer to see a sample of your work. Either way, ask the most experienced and available programmer you know for ongoing help. Having someone immediately available can be the difference between a problem taking minutes or days of your time. However, keep in mind that you don’t want to become completely dependent on your more experienced friend to solve all your problems.

One of the fundamental ways to improve the experience of learning your first language is to have an actual problem to solve. This helps to ground your learning in reality and provides you with your first, relatively large, feedback loop. Learning with the small, contrived examples in books and articles is limiting, and you lose the benefit of applying your discoveries to a problem you have in your head, which, after all, is what you’d be doing on the job. The fundamental way to improve this experience is to seek out opportunities to create feedback loops. In particular, creating short feedback loops helps you gauge your progress. Some languages have better tools for feedback than others, but regardless of the language, you can take some steps to set up a learning sandbox to experiment in.

In Ruby, there is the interactive command-line tool irb. In Rails, there is script/console. Similarly, Erlang has erb. Firebug provides many useful ways to explore the JavaScript runtime in the Firefox web browser, including an interactive shell. Many languages provide equivalent tools.

Sometimes these tools won’t suffice and you’ll need a bigger sandbox. Dave likes to keep an empty Java class open in his IDE when he needs to play around with an unfamiliar API or language feature:

public class Main {
    public static void main(String[] args) throws Exception {
		  System.out.println(/*play with stuff here*/);

Once you’ve learned enough to actually start writing code, test-driven development techniques can keep you focused on taking small steps and ensure you check your assumptions. Thanks to the popularity of test-driven development, you’ll be hard-pressed to find a language that doesn’t have a testing framework. Don’t hesitate to write simple tests to check your understanding of the language, or just to familiarize yourself with the testing framework.

Start by taking almost insanely small steps; as you learn more, your steps can grow correspondingly larger. For instance, the Ruby language has a feature that lets you apply a block of code to every element in a list and collect the results into a new list. You might write the following code to clarify your understanding of this feature:

require "test/unit"

class LearningTest < Test::Unit::TestCase
	def test_my_understanding_of_blocks_and_procs
		original = [1, 2, 3]
		expected = [2, 3, 4]
		p = Proc.new { |n| n + 1 }
		assert_equal expected, original.map(&p)

You’re not limited to using learning tests for learning a language; you can also apply this process to learning about how other people’s libraries work. Over time, these vendor tests (as Ade christened them during a lightning talk at the London Test Automation Conference[10]) can be used to check that upgrading to a later version of a library will not break your system. When the system breaks, the tests point to the new library as the source of the problem since the only functionality they exercise is that which you depend on the library to provide. In well-factored systems, they can also be used to verify that a different implementation of a library’s functionality does all the things you need.

Eventually, you will go from just writing learning tests to writing tests that check your actual code rather than your understanding of language constructs and APIs. Over time, you will find that there are many other techniques beyond simple unit testing that use the computer to verify your work as well as communicate with other members of your team.

The following is a discussion of learning to think differently by learning a new language, but the advice of Ralph Johnson (coauthor of Design Patterns) applies to a first language as well.

Ralph’s advice ties directly into the Find Mentors pattern and the impact that mentors can have on your learning. Thus, the availability of feedback from a nearby language expert should be a major factor when selecting your first language. We should also mention that by choosing a language, you’re also opting into a virtual community of practice with established idioms, social gatherings, and mechanisms for communication. You should take advantage of that support network so that you don’t just learn a language, but in fact join your first community of Kindred Spirits. The preferred work, boundaries, prejudices, and beliefs of this community will be all you have at first. When choosing to learn a language, you should attend meetings of a local group of that language’s enthusiasts (or visit one of their Internet forums) and see if you want to belong to that community.

One of the advantages of belonging to a community that shares its code is that you learn to go beyond the obvious grammatical constructs and start to express yourself idiomatically. But that’s just the beginning. Every language also has its own subtleties that are difficult to pick up solely by reading other people’s code.

For example, in XSLT there is the Muenchian method, while Perl has the Schwartzian Transform and C has Duff’s Device. These techniques can all be learned by reading code, but learning to appreciate why they’re important and when to use them requires the pooled experiences of a community. Sometimes this pool exists only as an oral tradition, and you have to talk to a particular person in order to gain the knowledge. Sometimes the knowledge exists only in the archives of a mailing list or perhaps in an online cookbook, where the lack of context makes it hard to appreciate its significance. In these situations, people new to the language have to immerse themselves in the community for years in order to tap into this pool of knowledge. Nowadays, though, these subtleties are often captured in books like Effective Perl Programming (Addison-Wesley), Effective Java (Prentice Hall), and Effective C++ (Addison-Wesley). Reading books such as these as soon as you have mastered the basic syntax can greatly accelerate your learning and help you avoid common mistakes.

All this will help you dig deeper into your first language. For several years, your first language will be the framework against which you learn other languages. The better you know your first language, the easier it will be to learn your next language. Although you will primarily be using this language to solve day-to-day problems and deliver functionality, periodically take some time to stretch it beyond where you would in the normal course of your work. Stretching the language in unconventional directions will help you discover where one language excels and one language struggles.

Eric Merritt’s blog post “The Shape of Your Mind” dives into how programming languages can have a profound impact on your problem-solving skills:

One danger of digging deep into your first language is getting stuck. It likely will remain with you throughout your career as your native tongue. But do not allow your proficiency in it to prevent you from learning and using other languages. A healthy career should introduce you to the diverse language landscape of software development. Each language provides an opportunity to solve problems using different paradigms. As you move beyond your first language, look for opportunities to learn languages that take a radically different approach than the ones you already know. Apprentices comfortable with an object-oriented language should explore a functional programming language. Apprentices comfortable with dynamic typing should explore static typing. Apprentices comfortable with server-side programming should explore user interface design. Along the way, you will certainly develop preferences for languages and problem-solving approaches, but avoid the dogmatic, religious subcultures that try to push you toward a one-size-fits-all approach. This broadening is the first small step toward the wide-ranging mastery required of a master craftsman.


Find your language’s specification. Read it. For some languages this may be as easy as picking up a published book. For others there may only be a grammar available. For still others the only specification may exist in the language’s implementation. Consider taking up the challenge of writing the specification.

If the language’s standard library is open source, read through it using the techniques described in the Use the Source pattern. You may not be impressed by the quality of the code you see there, but keep in mind that the writers of that code had no community to learn from and had to make things up as they went. Consider sending them a patch to fix any bugs you spot.

Another approach you can take to building up your knowledge of a language is to ask the people you work with how they chose the first language they mastered. Then add the criteria they give you to the set you already used when you chose your first language. These will come in handy when it is time to choose your next language.

Finally, you can find out more about the idioms we mentioned earlier: the Muenchian method, the Schwartzian Transform, and Duff’s Device. They’re all named after programmers who had a practical problem to solve. Try to track down the problems that these idioms were originally meant to solve, and ask yourself how you would solve the same problems in your primary language.

With Safari, you learn the way you learn best. Get unlimited access to videos, live online training, learning paths, books, interactive tutorials, and more.

Start Free Trial

No credit card required