Computational Thinking
Computational thinking is not programming. Programming is a skill; computational thinking is a way of approaching problems that predates computers and transcends any particular language or machine. Jeannette Wing defined it in 2006 as "the thought processes involved in formulating problems and their solutions so that the solutions are represented in a form that can be effectively carried out by an information-processing agent." This skill catalogs the core techniques of computational thinking with emphasis on their application as general problem-solving tools.
Agent affinity: papert (constructionist pedagogy, Logo, learning by building), lovelace (computational vision, seeing beyond calculation)
Concept IDs: code-sequential-thinking, code-decomposition, code-pattern-recognition, code-abstraction
Part 1 -- The Four Pillars
Pillar 1 -- Decomposition
Definition: Breaking a complex problem into smaller, manageable sub-problems.
Why it matters. A problem that is overwhelming as a whole becomes tractable when divided. Each sub-problem can be understood, solved, and tested independently. The solutions compose into a solution for the whole.
The decomposition question. Given a problem P, ask: "What are the independent pieces?" If piece A does not depend on piece B, they can be solved in any order (or in parallel). If A depends on B, solve B first.
Worked example: Building a weather application.
The monolithic problem ("build a weather app") decomposes into:
- Data acquisition -- fetch weather data from an API
- Data parsing -- extract temperature, humidity, wind from the response
- Display -- render the data in a user-friendly format
- Location -- determine the user's location or accept manual input
- Caching -- avoid redundant API calls for recent data
- Error handling -- cope with network failures, invalid locations, malformed data
Each sub-problem has a clear input, output, and boundary. A team of six people could work on all six simultaneously with minimal coordination.
Recursive decomposition. Sub-problems can be further decomposed. "Data parsing" becomes: parse JSON, extract nested fields, convert units, validate ranges. Decompose until each piece is simple enough to implement directly.
When decomposition fails. Problems with tight coupling resist decomposition. If every piece depends on every other piece, you cannot solve them independently. This is a signal that the problem needs re-framing (different abstraction) rather than further splitting.
Pillar 2 -- Pattern Recognition
Definition: Identifying similarities, regularities, and recurring structures across problems or data.
Why it matters. If you have solved problem A, and problem B has the same structure, you do not need to solve B from scratch -- adapt the solution for A. Patterns reduce the number of truly novel problems you encounter.
Types of patterns.
- Structural patterns. This tree structure is the same shape as that tree structure. A file system, an HTML document, and an organization chart are all trees. Algorithms that work on one work on all.
- Behavioral patterns. This sequence of operations repeats. Every web request follows the same lifecycle: receive, authenticate, validate, process, respond. Middleware chains exploit this pattern.
- Data patterns. These numbers follow a rule. The sequence 1, 1, 2, 3, 5, 8 is Fibonacci. Recognizing the pattern gives you the generating rule and enables prediction.
- Problem-class patterns. This optimization problem has the same structure as the knapsack problem. This scheduling problem is a graph coloring problem in disguise.
Pattern recognition as a meta-skill. The more problems you solve, the larger your pattern library becomes. Expert programmers do not think faster -- they recognize more patterns, which means they spend less time on first-principles reasoning and more time on adaptation.
Pillar 3 -- Abstraction
Definition: Removing unnecessary detail to focus on what matters for the problem at hand.
Why it matters. Every real-world problem has infinite detail. A map is useful because it omits most of reality. An abstraction is useful because it omits most of the implementation. The right abstraction makes the problem simple; the wrong abstraction makes it harder.
Levels of abstraction in computing.
| Level | Sees | Hides |
|---|---|---|
| User interface | Buttons, text fields | All code |
| Application logic | Functions, data structures | Memory layout, OS calls |
| Operating system | Processes, files, sockets | Hardware registers, interrupts |
| Hardware | Gates, registers, buses | Physics (electron flow, quantum effects) |
Each level provides a simpler model of the level below. A programmer writing a web application does not think about transistors. A hardware designer does not think about HTTP headers. Abstraction makes this possible.
Abstraction as interface design. A good abstraction exposes what the user needs and hides everything else. The interface to a hash table is: put(key, value), get(key), delete(key). The user does not need to know about hash functions, collision resolution, or load factor management. But the abstraction must not leak -- if the user needs to know the hash function to avoid performance degradation, the abstraction has failed.
The Dijkstra principle. "The purpose of abstraction is not to be vague, but to create a new semantic level in which one can be absolutely precise." Abstraction is not about hand-waving; it is about precision at the right level.
Pillar 4 -- Algorithm Design
Definition: Creating a step-by-step procedure that solves the problem for all valid inputs.
Why it matters. A solution that works for one input is an example. A solution that works for all valid inputs is an algorithm. The transition from example to algorithm is the core act of computational thinking.
The algorithm design process.
- Understand the problem. What are the inputs? What are the outputs? What constraints apply?
- Try small cases. Solve by hand for small inputs. This builds intuition about the structure.
- Generalize. What rule did you follow for the small cases? Can it be stated precisely?
- Formalize. Write the rule as pseudocode or a flowchart. Every step must be unambiguous.
- Analyze. What is the time complexity? Space complexity? Does it terminate for all inputs?
- Verify. Test on edge cases (empty input, single element, maximum size, invalid input).
Part 2 -- Computational Problem-Solving Methodology
The Polya-Papert Synthesis
George Polya's "How to Solve It" (1945) provides a four-phase framework for mathematical problem solving: understand, plan, carry out, look back. Seymour Papert extended this into the computational domain by adding the idea that building (not just analyzing) is how understanding develops.
Phase 1 -- Understand. What is the problem? What are the inputs, outputs, and constraints? Can you restate the problem in your own words? Is there a simpler version of the same problem?
Phase 2 -- Decompose. Break the problem into sub-problems. Identify dependencies between them. Determine which sub-problems are familiar (pattern recognition) and which are novel.
Phase 3 -- Generalize. For each sub-problem, find or design an algorithm. Start with a brute-force approach -- correctness before efficiency. Then optimize if the brute-force approach is too slow.
Phase 4 -- Formalize. Translate the algorithm into code. Test incrementally -- write a little, test a little.
Phase 5 -- Verify. Does the solution handle all edge cases? Is it correct? Is it efficient enough? Could it be simpler?
The Papert addition. Phases 3-4 are not purely intellectual -- they involve building and testing concrete artifacts. Understanding develops through construction, not just con