Deep Teaching |
Written by Mike James |
Thursday, 10 December 2015 |
Computer Science Education week and the Hour of Code is a good time to consider what teaching programming and computer science is really all about. It is time we turned from shallow teaching to deep teaching.
A lot of people think that it is easy to teach people to code. You just tell them what you know. If you have tried this approach then you might well find that things don't go according to your expectations. The beginner generally hasn't the mechanisms necessary to understand what you are telling them and, if you don't just give up, you basically have to perform a backtracking operation until you hit a point of mutual understanding. Of course, the alternative it to simply give up on the student and mark them as incapable of understanding the subtle ideas involved. There are just enough capable learners who survive the course to make this all seem very reasonable. You have some successes so obviously your teaching method works for those able to learn the material. Even a bad teaching method has some successes. A determined or able learner will overcome any obstacles you place in their way. So what is "doing a good job"? It is all too easy to think of teaching programming as teaching whatever language you happen to be familiar with. However, programming skills are largely language-independent and to identify those skills you have to be able to program, or have programmed, in many more than one language. You have to have seen what remains when you change from one programming language to another. Programming isn't about using a particular language no more than reasoning is about speaking English or Chinese. It should be a rule that a mono-lingual programmer is barred from teaching beginners. If you think that teaching computers and programming is about teaching a particular programming language, as the number one concern then you need to get out more. The problem is that it is too easy to focus on the surface detail of what we do. It is a terrible shame that the Hour of Code uses the term "code". Not only does it give all the wrong impressions, it focuses on the mastery of some cryptic language. It would have been so much better to have called it something like "hour of computer understanding" or "hour of algorithmic thought" but .... The key is that you don't teach programming by teaching code. You have to use code to teach programming but it is incidental to the task. To paraphrase Dijkstra: "teaching code to programmers is like teaching telescopes engineering to astronomers". What tends to happen in all sorts of different areas is that teachers teach the surface or shallow detail of a subject and hope that students will find a way to the deep detail on their own. After all that's most likely what the teacher did. By learning the details of a programming language you can slowly but surely start to see the deeper principles. Let us take an example. You may have been introduced to an assignment statement say:
and then some arithmetic
and then a statement that uses the variable on the left- and the right-hand side:
Slowly, but surely you build up a model for the internal workings of the language. There is something called a "variable" that you can store things in and retrieve things from and its operation is a bit like a box that you can take something out of, modify it and then put it back in. I'm not suggesting that this is the best or the only way to think of a variable and its behaviour, but it more or less corresponds to the rough-and-ready concept that most programmers have of what is going on. If you have been exposed to machine hardware ideas you probably think of a variable in a more refined way as an area of read/write memory and perhaps even think of its name as being roughly equivalent to its address and so on. If you haven't been exposed to low-level hardware then you might instead formulate a view that a name is a reference, which is another way of saying a pointer, which in turn is another way of saying an address. Notice I'm not writing a text book here - I'm talking informally and you either know what I'm getting at or you will eventually. There are ideas behind what we do with "code" and these tend not to be used in the teaching of beginners. Of course there are exceptions to this observation but in sampling some of the online offerings you can say that you are unlikely to encounter any of them. What you will encounter are often irrelevant concepts brought in to some how justify the teaching of the code - just got to functions - well talk about the stack or the stack frame or the heap or Turing machines or ... Adding in spurious computer science ideas when the beginner is just trying to cope with a fundamental idea isn't deep teaching - it is obfuscation by aggrandisement. All teachers occasionally feel the need to play to the gallery, to demonstrate to their peers that they know stuff. This isn't helpful to the student.
What we need to do is move from shallow teaching - the teaching of the rules of the task - and look deeper to the way we think about doing the task. We need to move from shallow teaching to deep teaching. This is all beginning to sound like a very tall order, and you might be thinking that deep teaching is just too tough a task. It is difficult, but far from impossible. When you teach someone something - and it applies to most subject areas - don't concentrate on what you do or the details of how you do it. First step back from the topic and try to discover how you think about what is going on. For example, in the case of a function you probably have a "picture" in you head of a transfer of control to the start of the function and then a jump back to where you came from at the end of the function. A function remembers where it came from and goes back there when it is done. Now you have a starting point for building a framework of deeper concepts that make your understanding and use of a function in any language possible, and even natural. It is the context for your ability to write code. Only after you get this sorted out can you really worry about what keyword is used to declare a function, and so on. The syntax is vitally important but utterly trivial. Of course one deep concept doesn't make for deep teaching, but it is a start. You can use it as a way in to discover what else you use to get to grips with a programming idea. For functions you probably have a model for how parameters behave and deep principles that apply to most languages - such as anywhere you can use a number you can use a variable, anywhere you can use a variable you can use an expression. This isn't always 100% right, but it's what you expect and the exceptions you remember as exceptions. The point is that programming is full of what look like meaningless or arbitrary rules unless you deep teach and demonstrate that they are far from arbitrary. For example, why do some things obey value semantics and others obey reference semantics? When you first start learning it is often the way that you are simply told what uses value and what uses reference and you have to remember. Later on as things settle down it becomes clear that it isn't an arbitrary rule but one that is about making choices that provide the best programming construct in any given situation. The same goes for the mysterious "pass by value" and "pass by reference" and the way that these interact with value and reference types. Eventually you abstract the key underlying concept of indirection, or the use of pointers, or whatever you want to call it - it's the same idea. Some of the deep ideas are too deep and too interrelated with other ideas to be used in teaching a beginner. For example, you don't really want to take a detour into the workings of a LIFO stack when first introducing functions; to do so would be academic self-indulgence. However, there are less technical ways of getting the same concept across in terms that don't need an explanation of computer architecture. Later, when functions have been absorbed as part of the beginners toolkit then it is time to use functions and their behaviour to motivate and explain stacks. It is all a question of working out the best route though the complex network of interrelated idea. Of course to navigate the network you need to be aware of it and blinded by looking at everything though the peephole of a single language.
Whenever you find yourself relating what seems to be an arbitrary rule, look inside your head and see how you think about it and how you justify the rule in terms of what you know about computing. If you can't do it then there is probably some deep idea or principle of implementation you are unaware of. Go and read up on the topic. For example, even syntax, that most trivial of topics, can be motivated by reason. If you tell a student that a statement has to end with a semicolon, or whatever terminator is in use, point out the difficulty of working out where a statement ends and another begins without it. To say every statement ends with a terminator is shallow; to teach that there has to be some way to tell when a statement ends is deep. Not very deep but you are heading in the right direction. Finally we need to consider what you can expect from your students. It is true that not everyone is cut out to be an ace programmer but everyone can learn the deep ideas in programming and get something very general from them. Not everyone who learns to write becomes a poet, but it is still worth doing and it is even worth seeing if you can write a poem.
More InformationRelated ArticlesTeach Code In School - Before It's Too Late! MOOCs Fail Students With Dark Age Methods Programming - A Life Long Challenge
To be informed about new articles on I Programmer, install the I Programmer Toolbar, subscribe to the RSS feed, follow us on, Twitter, Facebook, Google+ or Linkedin, or sign up for our weekly newsletter.
Comments
or email your comment to: comments@i-programmer.info |
Last Updated ( Thursday, 10 December 2015 ) |