2.1.1 – Computational Thinking

How do we actually get machines to do things for us? The dream many decades ago was that we would simply sit in front of a ChatGPT like interface and just dictate our problems into a machine and a few moments later the answers would pop out of a printer or appear on a screen.

The truth is, although we are slowly grinding our way towards this idea of computers generating code for us, solving problems based on a description, the reality is still some decades ahead in the future for certain.

Right now, this leaves us in the position of having to bring ourselves down to the level of a computer in order to give it instructions to follow. This is no easy task – as we discovered in Unit 1, computers do not possess intelligence, they cannot “think” and they certainly cannot understand ambiguity – words like “maybe.”

Computational thinking, then, is the skill of being able to translate our real world problems into smaller pieces that can then be tackled with the limited set of logical and mathematical operations that are the building blocks of all programs.

In this section:

Abstraction

The London Underground map is one of the most famous examples of abstraction. It presents the network in an easy to understand way, so travellers can work out where to get on and off the train. However, the network does not look like this in real life – the map hides the underlying complexity of the real rail network. Image credit – London Transport Museum

I’m sure you’ve been there. You’re asked to do as task, a piece of work and you just sit there, staring at it.

“I don’t even know where to start.”

This is a real problem when we set out to design and create a computer system or program – if you don’t know where to even begin, how can we possibly set out to create well made, robust program code?

The place to start is with something called “scope.” All projects need a scope and this is a decision that is best made as soon as possible when tackling a given problem. Scope refers to how broad your problem is, how far you will go. In more simple terms this can be described as “What will we include? What will we exclude?”

Take the example of making one of the most successful games of all time – GTA V. Although not appropriate for young audiences, you will be aware that GTA recreates a rather realistic and detailed American city through which you are free to travel and do as you please.

When Rockstar games sat down to design their game they had to make some big decisions before a single line of code was written. Although the world of GTA is very detailed, it is not exactly true to life. For example, if you decided you wanted to plant a tree, the game won’t let you do it – there is no facility for this. This is a decision of scope – is it necessary to have this feature in the game? No, so they didn’t include it!

However, if you decide you wish to steal a car and drive it off a building, you absolutely can do this – it is “within the scope” of the game. A deliberate decision was made to include this feature. But… if I wanted to get out of my stolen car, pop open the bonnet and check the oil level in the engine… I can’t do this. What’s going on here?!

The answer is abstraction.

Computers and games consoles do not have unlimited power and resources. Nor do we have an infinite number of programmers who can make our every wish come true. When we decide to make a game as described previously, we cannot possibly include every imaginable feature and represent the experience with 100% accuracy. This is for two reasons:

  • The problem would be too complex to turn into program code
  • The problem would take too long to solve / implement in program code

Therefore some compromises are required. When software engineers come up against a project such as “make a driving game” they first must decide what is necessary to include, and what is not. This process is called abstraction.

Abstraction is the removal, hiding or obscuring of unnecessary detail in order to simplify a problem or system.

In Operating Systems, a perfect example is the user interface – you click a button and a program loads. Simple. But the reality is very different and so much complexity has been hidden from you to make your life easier.

In programming, abstraction is the compromise of what is and is not included in a program. Do you need to be able to check the oil level in your stolen GTA car? No. Not really, so this has been removed – it has been “abstracted” and the driving experience you do get is an “abstraction” of the real world, meaning anything you didn’t absolutely need in order to play the game has been left out.

Abstraction has some big advantages for software engineers:

  • Unnecessary detail is removed from the problem…
  • …which makes it easier / quicker to solve
  • …which makes the development process cheaper
  • …which enables programmers / developers to focus on the important detail

Ultimately, spending time abstracting a problem is time well spent. It will ensure that software engineers and programmers have a tight, clear, focussed set of objectives that they are trying to achieve. They will know exactly what does need to be included and what does not. In other words – the scope of the project will be well defined!

Decomposition

Decomposition is the process of iteratively breaking a task down until you are able to write program code for each part of the problem. Image Credit – BBC Bitesize

Once a problem has been abstracted, software engineers are left with what is effectively a list of features that must be included in the final solution. However, these features are likely to be quite broad or large in nature such as “provide online multiplayer” or “allow users to save their data to the cloud.”

Programmers do not simply take the requirements specification for a project and start merrily programming away. If they did, then very quickly you end up with poorly written code, missing features and systems that are prone to breaking in spectacular and unpredictable ways.

The next phase of development is called “decomposition.”

Decomposition is the systematic breaking down of problems into its constituent or component parts.

More simply, decomposition is the process of taking a big problem such as “save to the cloud” and working out the steps that would be required to do this.

For example:

Save to the cloud:

  • Establish if a live network connection is present
  • Create a connection to the network
  • Collect and authenticate user details
  • Retrieve account details and status from the server
  • Add any necessary meta data to the save data
  • Request upload to the server
  • Wait for confirmation of successful upload
  • Close network connection

As a first try, this isn’t a bad attempt at describing the things that may need to take place in order to save a document to a cloud storage service. However, decomposition is an iterative process meaning you do not just do it once. A software engineer would then take the bullet point list above and begin to break each of those tasks down into its constituent parts.

Ideally, decomposition stops at the point where the problem has been broken down so much that it starts to look like a written description of code – there is enough detail that each part of the decomposition can easily be translated into actual program code.

Decomposition is an essential phase in the creation of software and has the following advantages:

  • It makes them easier to solve – it significantly simplifies the problem
  • We can focus on each small part of the problem systematically, one at a time
  • It makes a larger program/problem easier to manage
  • Small blocks of code are easier to test individually rather than all at once
  • Small parts of a bigger problem can be divided amongst different people to solve

Algorithmic Thinking

Algorithmic thinking is an odd term. It means “being able to think of logical steps to solve a problem.”

So, what is algorithmic thinking? What do you need to learn?

The answer is that it is not simply a piece of knowledge, a key term that you can learn a definition for. It is a skill and therefore something that requires practise.

When a problem has been abstracted and decomposed, we are ready to write program code. For simple problems it may well be the case that you can just sit at a computer and tap out some decent code. For most problems, this step will require a little more design work and thought.

Algorithmic thinking brings together two key skills:

  • The ability to plan algorithms using tools such as flow charts or pseudo code
  • The ability to recognise where key building blocks of programming, such as decisions, loops or data structures are required.

Therefore, your ability to “think algorithmically” will come from practicing solving programming problems both using pseudo code and real program code. You should be aiming to arrive at a point where if you are given a programming question, you can read through and instantly recognise the key building blocks (iteration, sequence, selection etc) that you will need in order to solve that problem.

In that case, we best move on to the next section!