I believe that "doing it" is the best way of "learning it'', i.e., I believe the best learning occurs as a subconscious adaptation of routine behaviors. For example, I never remember how I learned to use chopsticks to reach out for food, or when I learned that 1+1=2, etc. These knowledge have become my subconscious concepts, or "built-in" knowledge in computer-geek terms. My philosophy of teaching thus is to mimic that subconscious adaptation process in the class as vividly as possible, in order to let students learn in a most comfortable way.
Toward that goal, I carefully designed a series of projects for each of my classes. Students are led by these projects to work step by step on a semester-long endeavor to develop their own skills for solving problems introduced in each class. For example, every detail has been provided in the project descriptions and a great deal of actual implementation examples have been given in my compiler class, to show students how a compiler can be developed using available compiler-generator tools, standard programming techniques and a well designed plan.
Then, I often augment the depth of each course with more advanced topics that are beyond the extent of the projects. By introducing these topics in the lectures and testing them in the midterm and final exams, students can truly appreciate the advanced concepts even in a time-limited one semester course. Because they can compare what they learned in the lectures with their own experience in developing similar, albeit simpler solutions. The ultimate goal of my classes is to prepare our students with the confidence of having developed a complex solution themselves, such as a compiler, so they can face any potential challenge in their future career.