Computational thinking is a nebulous concept that we can summarise as the ability to solve problems through the application of algorithms. The Raspberry Pi foundation consider computational thinking to include logical thinking, decomposition, abstraction, pattern recognition, algorithm design, evaluation and organising data. For the purposes of this article I will go with this interpretation. With the aid of concrete examples, I will unpick each of these components in turn.
I will start with logical thinking because logic is integral to the other aspects of computational thinking. We are familiar with this way of thinking because many puzzles and games of strategy such as chess, and solving Rubik's cube require us to think logically. To solve these types of problems we need to be able to think clearly and have sound reasoning. Consider the following two statements:
Decomposition is the ability to break a complex problem down into smaller more manageable parts. Each component can then be tackled individually before assembling them into the final solution.
Let us take a look at how this might work in practice by way of example. Suppose we have 20 people in a room. How many handshakes will need to take place for every person to shake the hand of every other person? To start with we might just simplify the problem and consider only 2 people in the room. In that case the answer is 1 handshake. Now let us consider 3 people in the room. Well that is only slightly harder. Alice shakes the hand of Bob and Cathryn, and Cathryn shake hands with Bob, so that makes 3 handshakes in total. For four people there will be 6 handshakes. We could be really keen and produce a table like this:
Number of Number of
people handshakes
---------------------------------------
2 | 1
3 | 3
4 | 6
5 | 10
6 | 15
7 | 21
By now it is only a simple step to realise that we need to add up all the integers between 1 and the number or people in the room minus 1 to work out the number of handshakes. So if there are 8 people in the room then there will be 7+6+5+4+3+2+1 handshakes, which gives us 28. By breaking the problem down we have worked out the strategy and underlying pattern that can help us solve this problem. Therefore, for 20 people in the room the answer is 20 +19 …..+1 which is 190. Through this approach we may have also discovered that there is a quicker and more succinct method using the formula (n(n-1))/2, where n is the number of people.
In this example we saw how the underlying pattern emerged after we had broken down the problem. This brings us onto pattern recognition which is the ability to see patterns so that we can recognise problems or parts of problems that we may have solved before. Lots of programming is concerned with reusing pieces of code that were originally developed for other solutions. Even within a piece of code we are writing we may notice that quite a lot of our code is repeated. It is our ability to notice those repetitions that help us write more succinct and generalisable code using functions perhaps.
Let us look at something more concrete. Suppose we wish to give instructions for drawing a square using the following algorithm:
forward 50 steps
turn left 90 degrees
forward 50 steps
turn left 90 degrees
forward 50 steps
turn left 90 degrees
forward 50 steps
turn left 90 degrees
Straight away we notice a pattern: That the pair of instructions
forward 100 steps
turn left 90 degrees
is repeated four times. So we can write this algorithm more succinctly using:
repeat 4 times [forward 50 steps; turn left 90 degrees]
Next we many wish to draw shapes with a different number of sides, so for a triangle the pseudocode might look like:
repeat 3 times [forward 50 steps; turn left 120 degrees]
or for a hexagon:
repeat 6 times [forward 50 steps; turn left 60 degrees]
As before we could draw up a table relating the number sides of the shape to the angles turned.
number | turn
of sides | angle
-----------------------
3 | 120
4 | 90
5 | 72
6 | 60
7 | 51
8 | 45
9 | 40
10 | 36
Using this we can work out the relation between the number of sides and the angle within which we need to turn.
angle_to_turn = 360 / number_of_sides
So now we have found a general way of writing an algorithm for a polygon:
repeat number_of_sides times [forward 50 steps; turn left angle_to_turn]
And we do not need to write different code for triangles, squares, pentagons and so on. We can use the same code for any shape. Thus we have used our ability to find patterns for a general solution for the problem of drawing a shape.
Abstraction is the ability to extract the most salient aspects of a problem and ignore those elements that are superfluous. The iconic map of London Underground is often cited as a great example of abstraction. The map contains only basic information like the stations, what line they are on, where the hubs are, and which stations have wheelchair access. But the information that it does not contain is to some extent what makes it interesting. It does not show the distance between stations, or depth of the stations. It does not show the London streets. It does not even have a scale. In short it only contains information that is relevant to passengers to help them navigate their way around the underground. All other information is irrelevant and is not included. But what information we deem relevant or not depends on our purpose. The underground map is basically useless to the cab drivers who are plying their trade on the streets above. What they need are the street maps. Or would need had they not consigned this information to their long-term memory!
Algorithm design is concerned with finding a solution that requires a sequence of steps that follow on from one another in a specified order to solve a specific task. Algorithms are not necessarily confined to computer programs and we could codify day-to-day processes as algorithms, like the steps we take to make a cup of tea.
In the movie "Die Hard with a Vengeance" there is a riddle that requires algorithmic thinking. Bruce Willis is given a 3 litre vessel and a 5 litre vessel neither of which have any markings. He needs to measure out exactly 4 litres of water. I can't remember exactly why he needed to do this but it was to prevent a bomb going off in 30 seconds or something like that. The sequence of steps he took to avoid this catastrophe were:
Evaluation considers the testing and debugging of code. This means that we not only need to identify a range of suitable tests for our code but also to think of all the possibilities and issues that might arise. When we do encounter problems with our code we need to be able to isolate and identify where the problems are. For experienced coders it is second nature to test small units of code as it is being developed. But for novices debugging is an incredibly frustrating process, but with careful scaffolding we can turn this into an opportunity to build in resilience into the student's armoury.
Finally organising data in our programs mean what data structures do we use. Do we use lists, variables stack and so on. Which data structure is the most efficient for processing or memory usage? Also we need to consider how we store data. Do we want to store the data in text files, binary files or in databases?
Although algorithms appear in our everyday lives in computer science algorithms are synonymous with computer programs and so the ability to think algorithmically is the same as our ability to find a solution we can put into code that can be understood by a machine.
As a teacher I find that children pick up the elemental programming concepts like sequencing, assignment, selection and iteration quickly. But the challenge lies in getting them to transfer their knowledge of these concepts to solve more complex problems. In short, what seems to be their difficulty is their ability to think computationally. It is an important skill because computational thinking is not limited to the domain of computer programming but can be applied in other contexts. There appears to be no shortcut to improving children’s problem-solving abilities. The current best pedagogy is to get pupils to practice solving scaffolded problems in different contexts. After a while we can then expect the pupils to solve increasingly more complex problems with less and less support. Many children do get there but there are some who find it a struggle. It is those children we should have in mind when we are planning our lessons so that no child is left behind.
Further reading
I will start with logical thinking because logic is integral to the other aspects of computational thinking. We are familiar with this way of thinking because many puzzles and games of strategy such as chess, and solving Rubik's cube require us to think logically. To solve these types of problems we need to be able to think clearly and have sound reasoning. Consider the following two statements:
- All computer science teachers eat cake
- No cake eaters cycle bicycles
Decomposition is the ability to break a complex problem down into smaller more manageable parts. Each component can then be tackled individually before assembling them into the final solution.
Let us take a look at how this might work in practice by way of example. Suppose we have 20 people in a room. How many handshakes will need to take place for every person to shake the hand of every other person? To start with we might just simplify the problem and consider only 2 people in the room. In that case the answer is 1 handshake. Now let us consider 3 people in the room. Well that is only slightly harder. Alice shakes the hand of Bob and Cathryn, and Cathryn shake hands with Bob, so that makes 3 handshakes in total. For four people there will be 6 handshakes. We could be really keen and produce a table like this:
Number of Number of
people handshakes
---------------------------------------
2 | 1
3 | 3
4 | 6
5 | 10
6 | 15
7 | 21
By now it is only a simple step to realise that we need to add up all the integers between 1 and the number or people in the room minus 1 to work out the number of handshakes. So if there are 8 people in the room then there will be 7+6+5+4+3+2+1 handshakes, which gives us 28. By breaking the problem down we have worked out the strategy and underlying pattern that can help us solve this problem. Therefore, for 20 people in the room the answer is 20 +19 …..+1 which is 190. Through this approach we may have also discovered that there is a quicker and more succinct method using the formula (n(n-1))/2, where n is the number of people.
In this example we saw how the underlying pattern emerged after we had broken down the problem. This brings us onto pattern recognition which is the ability to see patterns so that we can recognise problems or parts of problems that we may have solved before. Lots of programming is concerned with reusing pieces of code that were originally developed for other solutions. Even within a piece of code we are writing we may notice that quite a lot of our code is repeated. It is our ability to notice those repetitions that help us write more succinct and generalisable code using functions perhaps.
Let us look at something more concrete. Suppose we wish to give instructions for drawing a square using the following algorithm:
forward 50 steps
turn left 90 degrees
forward 50 steps
turn left 90 degrees
forward 50 steps
turn left 90 degrees
forward 50 steps
turn left 90 degrees
Straight away we notice a pattern: That the pair of instructions
forward 100 steps
turn left 90 degrees
is repeated four times. So we can write this algorithm more succinctly using:
repeat 4 times [forward 50 steps; turn left 90 degrees]
Next we many wish to draw shapes with a different number of sides, so for a triangle the pseudocode might look like:
repeat 3 times [forward 50 steps; turn left 120 degrees]
or for a hexagon:
repeat 6 times [forward 50 steps; turn left 60 degrees]
As before we could draw up a table relating the number sides of the shape to the angles turned.
number | turn
of sides | angle
-----------------------
3 | 120
4 | 90
5 | 72
6 | 60
7 | 51
8 | 45
9 | 40
10 | 36
Using this we can work out the relation between the number of sides and the angle within which we need to turn.
angle_to_turn = 360 / number_of_sides
So now we have found a general way of writing an algorithm for a polygon:
repeat number_of_sides times [forward 50 steps; turn left angle_to_turn]
And we do not need to write different code for triangles, squares, pentagons and so on. We can use the same code for any shape. Thus we have used our ability to find patterns for a general solution for the problem of drawing a shape.
Abstraction is the ability to extract the most salient aspects of a problem and ignore those elements that are superfluous. The iconic map of London Underground is often cited as a great example of abstraction. The map contains only basic information like the stations, what line they are on, where the hubs are, and which stations have wheelchair access. But the information that it does not contain is to some extent what makes it interesting. It does not show the distance between stations, or depth of the stations. It does not show the London streets. It does not even have a scale. In short it only contains information that is relevant to passengers to help them navigate their way around the underground. All other information is irrelevant and is not included. But what information we deem relevant or not depends on our purpose. The underground map is basically useless to the cab drivers who are plying their trade on the streets above. What they need are the street maps. Or would need had they not consigned this information to their long-term memory!
Algorithm design is concerned with finding a solution that requires a sequence of steps that follow on from one another in a specified order to solve a specific task. Algorithms are not necessarily confined to computer programs and we could codify day-to-day processes as algorithms, like the steps we take to make a cup of tea.
In the movie "Die Hard with a Vengeance" there is a riddle that requires algorithmic thinking. Bruce Willis is given a 3 litre vessel and a 5 litre vessel neither of which have any markings. He needs to measure out exactly 4 litres of water. I can't remember exactly why he needed to do this but it was to prevent a bomb going off in 30 seconds or something like that. The sequence of steps he took to avoid this catastrophe were:
- Fill up the 3 litre vessel
- Pour the contents of the 3 litre vessel into the 5 litre vessel
- Fill up the 3 litre vessel
- Pour as much of the contents of the 3 litre vessel into the 5 litre vessel. One litre of water should now be remaining in the 3 litre vessel
- Empty the 5 litre vessel
- Pour the contents of the 3 litre vessel into the 5 litre vessel. There is now 1 litre of water in the 5 litre vessel.
- Fill up the 3 litre vessel
- Pour the contents of the 3 litre vessel into the 5 litre vessel where there is already 1 litre of water. The 5 litre vessel now contains 4 litres of water.
- Mark Year 10 test papers
- Organise trip to the First Lego League at Cambridge University
- Register students of the Informatic Olympiad
- Plan tomorrow's Year 13 lesson on TCP/IP
- Write Year 12 mock exam paper
- Create GCSE knowledge organiser on computer security
- Complete this blog post!
For sure some of those tasks will have greater urgency than others, for instance you might think that I should prioritise planning tomorrow's lesson, but it does not matter the order in which these tasks are carried out as they are not dependent on one another. As a consequence this sequence of instructions is not an algorithm; it is merely a list of unrelated items.
Evaluation considers the testing and debugging of code. This means that we not only need to identify a range of suitable tests for our code but also to think of all the possibilities and issues that might arise. When we do encounter problems with our code we need to be able to isolate and identify where the problems are. For experienced coders it is second nature to test small units of code as it is being developed. But for novices debugging is an incredibly frustrating process, but with careful scaffolding we can turn this into an opportunity to build in resilience into the student's armoury.
Finally organising data in our programs mean what data structures do we use. Do we use lists, variables stack and so on. Which data structure is the most efficient for processing or memory usage? Also we need to consider how we store data. Do we want to store the data in text files, binary files or in databases?
Although algorithms appear in our everyday lives in computer science algorithms are synonymous with computer programs and so the ability to think algorithmically is the same as our ability to find a solution we can put into code that can be understood by a machine.
As a teacher I find that children pick up the elemental programming concepts like sequencing, assignment, selection and iteration quickly. But the challenge lies in getting them to transfer their knowledge of these concepts to solve more complex problems. In short, what seems to be their difficulty is their ability to think computationally. It is an important skill because computational thinking is not limited to the domain of computer programming but can be applied in other contexts. There appears to be no shortcut to improving children’s problem-solving abilities. The current best pedagogy is to get pupils to practice solving scaffolded problems in different contexts. After a while we can then expect the pupils to solve increasingly more complex problems with less and less support. Many children do get there but there are some who find it a struggle. It is those children we should have in mind when we are planning our lessons so that no child is left behind.
Further reading
Kramer, J. Is Abstraction the Key to Computational Thinking?
Curzon, P. Computing without Computers
Wing, J.M. Computational Thinking
Curzon, P. Computing without Computers
Wing, J.M. Computational Thinking
Comments
Post a Comment