Introduction to Programming Concepts and Methodologies · Chapter 1 · Foundations
Before any code gets written, computational thinking breaks the problem apart — then pseudocode and flowcharts let you plan the solution in a form no compiler ever checks.
bookSHelf · Introduction to Programming Concepts and Methodologies · §1.5 · a self-paced section
Learning objectives — by the end of this section you will be able to
console.log to find out what a program is really doing §1.5.8–1.5.9§1.5.1 — the two problems typing solves only one of
A program has two separate difficulties: working out what the steps are, and writing those steps in JavaScript. Doing both at once means you can never tell which one you're stuck on.
Think before you type.
Context Pause — the bridge, not the machine
A computer does exactly what you tell it, at enormous speed — including the wrong thing.
Everything that decides whether the answer is right happens before the first line of code. That is the part this section is about.
§1.5.1 — the name for the thinking half
Definition 1.5.1 — Computational Thinking
Computational thinking is a problem-solving process, rooted in principles from computer science, that breaks a complex problem into smaller, more manageable parts and devises systematic approaches to solve them. A complex problem is one that is difficult because it involves many different interrelated parts or factors.
Figure 1.5.1: This diagram illustrates the main components of computational thinking.
Computational thinking is the bridge between the problem and its resolution — it lets you separate a problem's parts and form solutions both computers and people can follow.
Insight — a plan has no language
The same plan can be written several different ways.
Section 2.2 makes this concrete: an algorithm is a plan that exists before any code does. The tools here are how you write a plan down before it has a language.
§1.5.1 — a shorter framing
ISTE lists computational thinking's components in full, but a shorter framing compresses them into three moves: abstraction, automation, analysis.
Figure 1.5.2: The three As — abstraction, automation, analysis — illustrate the power of computational thinking.
§1.5.1 — taught as four techniques
In practice, computational thinking is usually taught as four techniques — a systematic way to attack a problem using tools such as data structures.
Figure 1.5.3: Users can explore the essence of computational thinking through decomposition, logical thinking, abstraction, and algorithms.
§1.5.1 — Practice
Try It Now 1.5.1
Before reading on, list five instructions you would give a robot to make a jam sandwich. Then hand the list to a classmate — he is playing the robot, and he follows every instruction completely literally. Which one breaks first?
Answers vary, but nearly every list breaks in the same places: "Get the bread" — from where? "Spread the jam" — with what, the knife was never picked up. "Put the bread on the plate" — which bread, which side up? Ordinary instructions rely on an enormous amount of unstated knowledge, and a computer has none of it.
§1.5.2 — the first two techniques, applied
Decomposition breaks a hard task into components; pattern recognition groups what decomposition turns up into categories you can act on.
Break it down. Then look for the pattern.
§1.5.2 — breaking a problem into self-contained parts
Definition 1.5.2 — Decomposition
Decomposition is the analytical process of breaking a complex problem or system into smaller, self-contained parts that can be understood and solved on their own.
Definition 1.5.2: Decomposition breaks one whole problem into smaller, self-contained parts.
In the jam sandwich example, decomposition means identifying every ingredient required and every step the robot must take to end up with a sandwich.
§1.5.2 — pattern recognition groups what decomposition finds
| Ingredients | Equipment | Actions |
|---|---|---|
| Bread | Plate | Repeat x times |
| Jam | Knife | Left hand (LH) |
| Butter | Right hand (RH) | |
| Pick up | ||
| Unscrew |
Table 1.5.1: A first pass at decomposing and grouping the jam sandwich problem.
Read it: the things decomposition turned up sort naturally into ingredients, equipment, and actions — the more you think of, the clearer the final instructions will be.
Insight — categories are compression
Twelve unrelated facts become three groups.
Once "pick up," "unscrew," and "spread" are all filed under actions, you stop tracking twelve unrelated facts. That is the entire trick — pattern recognition makes a big problem small enough to hold.
§1.5.2 — Practice
Try It Now 1.5.2
Lucía has to get to school on time tomorrow. Decompose her problem into at least six smaller tasks, then group those tasks into two or three categories of your own choosing.
One reasonable answer — the night before: pick clothes, pack the bag, charge the phone, set the alarm. The morning: wake up, eat breakfast, check the bus time. The trip: walk to the stop, board the bus. Half of her tasks turn out to belong to the night before — the sort of thing you only see once the problem has been taken apart.
§1.5.3 — pulling out what matters
Abstraction means pulling out the important details and identifying the principles that carry over to other problems or situations.
Keep what matters. Discard the rest.
§1.5.3 — a simplified representation, not the whole system
Definition 1.5.3 — Abstraction
Abstraction is a simplified representation of a complex system or phenomenon that keeps the details relevant to the problem at hand and discards the rest.
In the jam sandwich example, abstraction means forming an idea of what the sandwich should look like — a model of the desired outcome, with the details simplified away.
§1.5.3 — layers of abstraction
Ask a generative AI tool for help: you interact through a plain interface and see none of the underlying complexity. Your prompt is handled by the application's logic, then processed at the back end and returned — each layer serving a separate role, invisibly to you.
Figure 1.5.5: When using GenAI, a user interacts with the interface while the application processes the prompt with layers of abstraction on the back end.
Context Pause — you already trust abstraction constantly
You drive a car without knowing how the engine mixes fuel.
You send a message without knowing how it is routed. Abstraction is not a programming trick; it is the only reason any complicated system is usable at all.
§1.5.3 — Practice
Try It Now 1.5.3
You are describing a bus route to Priya, who moved to your town last week and has never taken it. Name two details you would keep for her and two you would leave out, and say why.
Keep: the stop where Priya gets on, and the stop where she gets off — without those the description is useless. Leave out: the colour of the bus and the name of every street it turns down. The test for abstraction is always the same: does dropping this detail change the action the reader has to take? If not, drop it.
§1.5.4 — a plan, written down before it has a language
Definition 1.5.4 — Algorithm
An algorithm is a finite, ordered sequence of unambiguous instructions that solves a problem or completes a task.
Algorithms are most commonly written as either pseudocode — a mixture of ordinary language and high-level programming ideas — or a flowchart, which shows the flow of decisions visually. Either is fine; it comes down to preference.
§1.5.4 — indentation shows what belongs inside what
Definition 1.5.5 — Pseudocode
Pseudocode is a description of a program's steps written in plain language and arranged like code, with indentation showing which steps belong inside which. It is not written in any programming language and cannot be run.
Definition 1.5.5: Pseudocode: indentation shows containment, so the indented lines live inside the while and the unindented one runs once.
§1.5.4 — putting the two conventions to work
Example 1.5.1 — Pseudocode for a decision
Write pseudocode that decides whether someone may vote, based on their age.
ask the user for their age
if age is 18 or more
print "You may vote"
otherwise
print "Too young to vote"
Note what this does not say: nothing about how to ask, what a variable is, or which language this will become. The plan is right or wrong on its own terms, and you can check it by reading it to somebody.
Context Pause — no compiler is the point
No machine checks it.
Pseudocode is worth writing precisely because no machine checks it. A syntax error tells you nothing about whether your plan makes sense. Reading five lines of plain English to a classmate finds "you never told it to stop" far faster than a debugger will.
§1.5.4 — Practice
Try It Now 1.5.4
Write pseudocode for finding the largest of three numbers. Use indentation to show which steps are inside a decision.
set largest to the first number
if the second number is bigger than largest
set largest to the second number
if the third number is bigger than largest
set largest to the third number
print largest
One correct answer — others work too. Pseudocode has no single right form, only clearer and less clear ones.
§1.5.5 — the same plan, drawn as a picture
Definition 1.5.6 — Flowchart
A flowchart is a diagram of a program's steps, using ovals for start and end, rectangles for actions, and diamonds for decisions, connected by arrows showing the order of execution.
Figure 1.5.7: The symbols used in a flowchart are associated with their instructions.
The diamond has one way in and two ways out, and the two paths join up again afterwards — that shape is selection, drawn.
§1.5.5 — Practice
Try It Now 1.5.5
Sketch a flowchart for this task: get a number; if it is even, print "even"; otherwise print "odd". Name the shape you used for each step.
Five shapes, in order — Oval: Start. Rectangle: get the number. Diamond: is the number even? Two exits, yes and no. Rectangle on each branch: print "even" / print "odd". Oval: End, with both branches joining back together before it. A flowchart whose paths never meet again has two endings, which almost always means a step was forgotten.
§1.5.6 — a function that calls itself
Definition 1.5.7 — Recursion
Recursion is a technique in which a function calls itself on a smaller version of the same problem, stopping at a base case — an input simple enough to answer directly without calling itself again.
Figure 1.5.8: A flowchart represents an iterative solution for adding n numbers.
Comparing the two is a good way to see what recursion actually buys you: fewer moving parts in the code, at the cost of some work moving into memory where you cannot see it.
Insight — deferred, not repeated
A chain of deferred operations, not a loop.
recursiveSum(10) cannot finish until recursiveSum(9) answers, and so on down. Those pending operations are held in memory until the base case lets the chain unwind. Leave out the base case and the chain never ends.
§1.5.6 — Practice
Try It Now 1.5.6
Run the code below. It is missing its base case. Predict what will happen before you press Run, then add the base case so it prints 55.
function recursiveSum(x) {
return x + recursiveSum(x - 1);
}
console.log(recursiveSum(10));
Without a base case, x keeps decreasing past 0 forever: RangeError: Maximum call stack size exceeded. The fix is the missing stopping condition:
function recursiveSum(x) {
if (x === 0) { return 0; }
return x + recursiveSum(x - 1);
}
console.log(recursiveSum(10)); // 55
§1.5.7 — every browser has a JavaScript engine built in
Definition 1.5.8 — Developer Console
The developer console is a panel built into the browser where JavaScript can be typed and run immediately, and where error messages and console.log output appear. It is opened with F12 in most browsers.
For anything you want to keep, you use a code editor — a text editor built for code, which colours your syntax and indents for you. The console is a scratchpad; the editor holds the program.
Insight — the boxes on this page are both at once
An editor and a console at the same time.
The runnable boxes in this book are a third option, and a deliberate convenience — you can change an example and run it without leaving the page. Everything in them is ordinary JavaScript and behaves the same way anywhere else.
§1.5.7 — the browser console
Try It Now 1.5.7
Open your browser's console with F12 and type 2 + 2 * 3, then press Enter. Then type it again as (2 + 2) * 3. What are the two answers, and what does the difference tell you?
The first prints 8, the second prints 12. Multiplication happens before addition unless parentheses say otherwise. The useful part is not the arithmetic — it is that you settled the question in about four seconds without writing a file, saving it, or reloading anything. That is what the console is for.
§1.5.8 — the browser tells you what happened
Uncaught ReferenceError: totl is not defined
at line 3
ReferenceError. A name was used that does not exist.totl is not defined. It names the exact thing it could not find.That message is telling you there is a typo, and telling you what the typo says. The fix is to compare totl with the name you meant.
Context Pause — describing the problem often solves it
"It doesn't work" is not a description.
"It says ReferenceError: totl is not defined on line 3" describes a problem, and often answers it while you are typing it out. Reading the message is the first debugging step and it is free.
§1.5.8 — reading an error message
Try It Now 1.5.8
Run the code below, read the error it produces, and say which of the three parts of the message told you where to look. Then fix it.
let greeting = "hello"; console.log(gretting);
The error: Uncaught ReferenceError: gretting is not defined. The detail is the part that solves it — the name it could not find is spelled with the letters transposed. The place narrows it to the line; the kind tells you it is a name problem rather than a value problem. Fix: console.log(greeting);
§1.5.9 — belief versus reality
Definition 1.5.9 — Debugging
Debugging is the process of finding and fixing the cause of incorrect behaviour in a program. Its basic technique is to compare what you believe the program is doing with what it is actually doing.
Testing works by taking turns: one person reads out each instruction, the other follows it exactly. Each instruction is a test case — and when one fails, debugging finds the source of the problem and fixes it.
§1.5.9 — Practice
Try It Now 1.5.9
The code below should print the area of a rectangle 4 by 5, which is 20. Add console.log lines to find out what it is actually doing, then fix it.
let width = 4;
let height = 5;
let area = width + height;
console.log("The area is " + area);
Printing the pieces shows width is 4, height is 5, area is 9 — both inputs are right, so the mistake is in the line that combines them: + should be *.
let width = 4;
let height = 5;
let area = width * height;
console.log("The area is " + area); // 20
Key Terminology
Key Terminology
ReferenceError — The error raised when a name is used that does not exist; usually a typo or a missing declaration.console.log — The basic debugging tool: print a labelled value to check whether it is what you expected.§1.5 — Conclusions
Plan first, in a form no compiler checks — pseudocode, a flowchart, or plain English read aloud to somebody — and only then translate the plan into JavaScript. Doing both at once means you can never tell which difficulty you are stuck on.
Debugging is the same technique in reverse: compare what you believe the program is doing against what it is actually doing, one line at a time, until the mismatch is the only thing left.
Next: Chapter 2 — Control Flow, where these plans start branching and looping for real. Back to start.