Every app, game and website is built from precise written instructions. This guide takes you from your first line of Python to tracing code, flowcharts, searching, debugging and good habits, with tested code and worked examples.
Coding is the practice of writing precise, step-by-step instructions that a computer can carry out. That is the whole idea. Everything else, from a calculator app to the software in a self-driving car, is the same idea scaled up. This guide starts at the very beginning and builds towards the concepts professional developers use every day. The code examples are in Python, and every one of them was run to check the output shown. By the end you should be able to read simple programs, trace what they do by hand, find bugs, and know what to practise next.
Helpful background: How Computers Work explains the processor and binary that your code is eventually turned into.
A computer's processor only understands binary instructions, patterns of 0s and 1s. Writing directly in binary would be painfully slow for people, so we write in programming languages: structured, readable text that follows strict rules, which another program then translates into binary. "Coding", "programming" and "writing software" all mean essentially the same thing: telling a computer exactly what to do in a form it can follow.
The key word is precisely. Human language is full of shared context ("put the kettle on" is understood even though it is vague). A computer has none of that. It does exactly what it is told, including your mistakes, which is why logical thinking matters more in coding than memorising.
It helps to separate three words:
If you have ever followed a recipe exactly, in order, you have done the core mental work of coding. A program is a recipe for a computer: an ordered list of steps, plus decisions ("if the mixture is too thick, add milk") and repetition ("stir for two minutes"). Every program you will ever read is built from these three things: sequence, decisions and repetition.
Source code has to be converted into machine instructions before the processor can run it. There are two main approaches:
The line between the two has blurred. Many languages first translate code into an intermediate form and then use further tricks to speed it up while it runs. But the useful picture is still "translate everything first" versus "translate as you go".
No language is best for every job, because each makes different trade-offs between ease, speed, safety and the ecosystem of ready-made tools around it. Here are some well-known ones and what they are commonly used for:
| Language | Commonly used for |
|---|---|
| Python | Learning to code, data analysis, automation, science and AI |
| JavaScript | Making web pages interactive; it also runs on servers |
| Java and C# | Large business applications, and (for C#) many games and Windows software |
| C and C++ | Operating systems, game engines and software where speed matters |
| Swift and Kotlin | Apps for Apple devices and Android |
| Rust | Systems software, with a focus on safe memory use |
| SQL | Asking questions of databases |
| Scratch | Learning the ideas by snapping together visual blocks |
A common confusion: HTML and CSS are not usually called programming languages. HTML describes the structure of a web page and CSS describes how it looks. They do not contain decisions and repetition in the same way. They are still essential for building websites, and they work alongside languages like JavaScript.
Languages look different, but nearly all are built from the same handful of ideas. Once you know them, learning a new language mostly means learning new vocabulary. The examples use Python because its syntax is plain and readable.
Variables store a value under a name so it can be used again. The = sign here means "store this value", not "is equal to".
age = 12 name = "Amara" is_studying = True print(name, "is", age, "years old")
Data types describe what kind of value something is, and the type decides what you can do with it.
| Data type | Example | Used for |
|---|---|---|
| Integer (int) | 12, -5, 1000 | Whole numbers |
| Float | 3.14, 0.5 | Decimal numbers |
| String (str) | "hello" | Text |
| Boolean (bool) | True or False | Yes/no decisions |
| List | [1, 2, 3] | An ordered collection of values |
Types matter because the same symbol can behave differently. With two pieces of text, + joins them. With two numbers, it adds them:
a = "5" b = "3" print(a + b) print(int(a) + int(b))
Conditionals let a program make decisions. Python uses indentation (the spaces at the start of a line) to show which lines belong to each branch.
score = 72 if score >= 80: grade = "A" elif score >= 60: grade = "B" else: grade = "C" print(grade)
Loops repeat instructions without having to write them out again and again. In Python, range(1, 4) gives the numbers 1, 2 and 3, stopping before 4.
for lap in range(1, 4): print("Lap", lap)
Functions package up a set of instructions under a name so you can reuse them. A function takes inputs (called parameters) and can give back an output with return.
def celsius_to_fahrenheit(c): return c * 9 / 5 + 32 print(celsius_to_fahrenheit(100)) print(celsius_to_fahrenheit(37))
One of the most useful coding skills is working out what code does without running it. This is called tracing. Take this program, which adds the numbers 1 to 5:
total = 0 for n in range(1, 6): total = total + n print(total)
Step 1: Before the loop, total is 0.
Step 2: The loop runs once for each value of n from 1 up to 5. Write down both variables after each pass:
| Pass | n | total (before) | total (after) |
|---|---|---|---|
| 1 | 1 | 0 | 1 |
| 2 | 2 | 1 | 3 |
| 3 | 3 | 3 | 6 |
| 4 | 4 | 6 | 10 |
| 5 | 5 | 10 | 15 |
Step 3: After the loop ends, print(total) shows 15. It matches the output above, and also 1 + 2 + 3 + 4 + 5 = 15.
Habit to build: predict the output first, then run the code. When your prediction is wrong, you have found something to learn.
Before writing code it often helps to sketch the steps. A flowchart shows a program as boxes and arrows: rounded boxes for start and end, rectangles for actions, parallelograms for input or output, and diamonds for decisions. A loop appears as an arrow that goes back up.
The same plan written as pseudocode, which is plain-English steps that are not tied to any language:
pick a secret number
repeat:
ask for a guess
if guess equals secret: say "You win!" and stop
otherwise: say whether the guess was too high or too low
Real programs deal with many related values. A list holds an ordered collection. A dictionary stores labelled pairs, so each value has a name instead of just a position. Items in a list are numbered from 0, not 1, so the first item is at position 0.
student = {
"name": "Amara",
"age": 12,
"subjects": ["Math", "Science", "English"]
}
print(student["subjects"][0])
print(len(student["subjects"]))
Choosing the right data structure for the job is a real skill. The wrong choice can make a program slow or hard to follow.
Getting a correct answer is the first goal. Professionals also care about efficiency: how the time a program needs grows as the amount of data grows. Compare two ways of finding a number in a sorted list:
def linear_search(items, target): steps = 0 for index in range(len(items)): steps += 1 if items[index] == target: return index, steps return -1, steps numbers = [3, 8, 12, 17, 23, 29, 35, 41] print(linear_search(numbers, 29))
def binary_search(items, target): low = 0 high = len(items) - 1 steps = 0 while low <= high: steps += 1 mid = (low + high) // 2 if items[mid] == target: return mid, steps elif items[mid] < target: low = mid + 1 else: high = mid - 1 return -1, steps numbers = [3, 8, 12, 17, 23, 29, 35, 41] print(binary_search(numbers, 29)) print(binary_search(numbers, 41))
The result is a pair: the position found, and how many steps it took. Searching for 29 in a list of 8 numbers took 6 steps with linear search but only 2 with binary search.
List (positions 0 to 7): [3, 8, 12, 17, 23, 29, 35, 41]. Find 29.
| Step | low | high | mid | Item at mid | Decision |
|---|---|---|---|---|---|
| 1 | 0 | 7 | (0+7)//2 = 3 | 17 | 17 < 29, so look to the right: low = 4 |
| 2 | 4 | 7 | (4+7)//2 = 5 | 29 | Found at position 5 |
Two steps, matching the output (5, 2). The // operator divides and drops the fraction.
Searching for 41 (the last item) takes 4 steps, which is the most that a list of 8 items can need, because each step halves what is left: 8 → 4 → 2 → 1.
Each binary-search step halves the remaining items, so the worst case is about the number of times you can halve n before reaching 1, plus the final check.
For 1,000,000 items: 220 = 1,048,576, which is more than 1,000,000, so at most 20 comparisons are needed.
For 1,000,000,000 items: 230 = 1,073,741,824, more than a billion, so at most 30 comparisons.
Linear search in the worst case checks every item: 1,000,000 or 1,000,000,000 comparisons.
Ratio for a billion items: 1,000,000,000 ÷ 30 ≈ 33 million times fewer comparisons with binary search.
The catch: binary search needs the list sorted first, and sorting takes work too. It pays off when you search the same data many times.
Programmers describe this growth with Big O notation:
| Notation | Name | Example | If the data doubles |
|---|---|---|---|
| O(1) | Constant | Reading an item by its position | Time stays the same |
| O(log n) | Logarithmic | Binary search | One extra step |
| O(n) | Linear | Linear search | Time doubles |
| O(n log n) | Linearithmic | Efficient sorting methods | A little more than double |
| O(n²) | Quadratic | Comparing every pair of items | Time grows four times |
For 1,000 items, an O(n²) method does about 1,000 × 1,000 = 1,000,000 steps, while an O(n log n) method does about 1,000 × 10 = 10,000, roughly a hundred times fewer. Big O ignores constant factors, so it is a guide to how a method scales, not an exact stopwatch.
Every programmer, however experienced, writes bugs. A bug is a mistake in a program, and debugging is finding and fixing it. There are three broad kinds:
A syntax error, caused by a missing closing bracket:
print("Hello"
A runtime error, caused by an impossible operation:
print(10 / 0)
Read error messages from the bottom up. The last line says what went wrong, and the lines above show where. (Your Python version may print extra marker lines.) A logic error gives no message at all, as in this attempt to find the average of three numbers:
a, b, c = 6, 9, 12 average = a + b + c / 3 print(average) average = (a + b + c) / 3 print(average)
The first answer, 19.0, is wrong. Python does division before addition, so c / 3 was calculated first. Brackets fix it, giving the correct 9.0.
Practical debugging habits:
print to look inside. Printing a variable at key points shows where reality and your expectation first differ.Code is read far more often than it is written, and the next reader is usually you in a month's time. Good habits include:
total_price says more than x.def celsius_to_fahrenheit(c): return c * 9 / 5 + 32 assert celsius_to_fahrenheit(0) == 32 assert celsius_to_fahrenheit(100) == 212 print("All tests passed")
An assert statement stops the program with an error if the claim is false. So the program printing "All tests passed" means each claim was true. Writing a test before the code, then making it pass, is a method professionals use called test-driven development.
The examples so far follow a procedural style, a sequence of steps and functions. Many languages also support object-oriented programming (OOP), which bundles related data and the functions that use it into a class. Each thing created from a class is an object.
class Student: def __init__(self, name, age): self.name = name self.age = age def introduce(self): return f"Hi, I'm {self.name}, age {self.age}." amara = Student("Amara", 12) print(amara.introduce())
In the class, __init__ sets up each new object, and self refers to the object itself. OOP is useful as programs grow because it keeps related data and behaviour together. It is one of several styles, and another common one is functional programming, which builds programs mostly from functions that do not change shared data.
Real software changes constantly and is often written by many people. Version control records every change to a project, so you can see who changed what, work in parallel without overwriting each other, and go back to an earlier version if something breaks. The most widely used tool is Git. Platforms such as GitHub and GitLab host Git projects online so people can collaborate. Even if you work alone, learning basic Git early is a very good habit.
On a team of five building a shopping app, one developer can work on checkout while another works on search. Git lets them combine their changes into one version, flags conflicts where two people edited the same lines, and keeps the full history, so a mistake can be undone.
For a wider look at how computers developed, see The History of Computing.
AI tools can now suggest or write code from a plain-language request. They can be a helpful tutor and speed up routine work, but they can also produce code that looks right and is wrong, or that is insecure or does not do what you meant. You are still responsible for understanding it. That is why the skills in this article matter more, not less: reading code, tracing it, testing it and debugging it. Never paste passwords, private keys or other people's personal data into any tool, and test generated code on small examples before trusting it.
Try each question first, then tap it to reveal the answer. A scored multiple-choice quiz follows below.
An algorithm is the step-by-step method, which can be described in plain words. Source code is that method written in a particular programming language.
print("5" + "3") show, and why?53, because the values are text, so + joins them instead of adding.
total = 0, then for n in range(1, 4): total = total + n, then print(total)6, because n takes the values 1, 2 and 3, and 0 + 1 + 2 + 3 = 6.
About 10, because 210 = 1,024 is more than 1,000.
A syntax error is reported by the translator, while a logic error runs without any message and just gives the wrong answer.
Reproduce the problem, because a bug that cannot be made to happen reliably cannot be tested or fixed.
Program a classmate (no computer needed): one student gives exact step-by-step instructions to guide another around an obstacle course, or to build a drawing, while the "robot" follows them literally. Discuss what happened when an instruction was vague. This is the lesson of "precisely".
Trace and predict: give students short programs on paper and have them fill in a table of variable values like Worked Example 1 before any code is run.
Guess-the-number search game: pick a number from 1 to 100 and let students guess with "higher or lower" hints. Compare the strategy of guessing 1, 2, 3... with always guessing the middle, to feel binary search.
Bug hunt: give students working code with one deliberate mistake and ask them to follow the debugging loop to find it.
Safety note: only run code from sources you trust, and never type real passwords or personal details into practice programs or online tools. Use a school-approved or parent-approved coding environment.
This article is original EDUSAMBAM writing. Every code example was run with Python 3.12 and the outputs shown are the real results (some error messages vary slightly between Python versions). The ideas follow standard introductory computer science teaching, the history is from the public record, and the diagrams are original EDUSAMBAM schematics. The comparison counts in the worked examples are calculated from powers of two.
Languages and tools change quickly, so check the current documentation for any tool you use. This article does not recommend any particular course, company or product.
10 questions. Select an answer for each, then submit to see your score instantly.