← chrisjmendoza.com Sample chapter · Meeting the Machine

From the book's front matter

How this book was written

The two applications came first, built with heavy AI coding assistance. So was this book: the chapters were drafted in collaboration with AI models working directly against those two repositories, under rules written down before any drafting began.

That sentence invites a fair question about who is standing behind it, so: my own background is a Bachelor of Applied Science in Application Development from North Seattle College, on a course that ran in tracks — web applications, mobile application development, data science, and cloud computing. Mine were the first two. That is where I learned to program, years before either of these applications existed, and it is why the platform here is Android and Kotlin rather than something else. It is also, more usefully, why the book takes the shape it does. What follows is roughly the ground my own degree assumed every student already had on the first day — written down properly, for somebody who hasn’t got it yet.

What you should judge is the discipline rather than the drafting. Every quoted listing is copied from the repositories at the pinned commits below and re-checked by a script that compares the printed text against the source line by line; every count in the prose was measured by running a command rather than by remembering. Where this book tells you to trust the artifact over the author, and your own terminal over the text, it is describing its own editorial method applied to itself.

If knowing that changes how much you trust a sentence here — good. That is the correct instinct, and it is one of the things the book is trying to teach you. The remedy is the same one Chapter 15 gives for everything else: check. Everything in this book is checkable, on purpose.

← Back to chrisjmendoza.com

Chapter 1

What a Program Actually Is

source, machines, and what "running" means

You have been using software your entire adult life and you have almost certainly never seen the inside of any. That is not carelessness; it is design. A program is built to be used without being understood, the way a lift is, and it works so well that most people go a lifetime without once wondering what is actually in there. This chapter opens the panel. No typing yet — one chapter of knowing what you are looking at first, because almost everything that makes programming confusing at the start is a missing picture of what a program is.

In this chapter you will

  • find out what a program actually consists of, physically, on a disk
  • meet the most important distinction in this book: compile time and run time
  • learn what a compiler does and why anyone puts up with one
  • see why this book uses Kotlin, and what Android has to do with it
  • look at your first real program — a whole one, forty-eight lines, shipping today
  • find out how an earlier generation met the machine, and what it cost them

1.1 The thing on the disk

Start with something concrete. Somewhere on the machine in front of you is a file. It is a plain text file — the same kind of thing a shopping list is, made of nothing but characters you could type. It has a name that ends in .kt. You could open it in Notepad and read every character of it.

That file is source code. It is the thing a programmer writes, and it is the part programmers spend most of their time writing directly.

Here is one, whole and complete, from one of the two applications this book keeps pointing at. The dark bar above it names the file it came from — every quoted listing in this book carries one, and it means the code below has been copied character for character rather than tidied up for print:

model/Numbers.kt — ShaftSchematic — the complete file

package com.android.shaftschematic.model
const val MM_PER_IN = 25.4

Two lines. That is the entire file — not an excerpt, not a simplification. It sits in a real application of some thirty-nine thousand lines, and its whole job is to write down that one inch is 25.4 millimeters, once, in a place the rest of the program can find it.

Somebody was paid, in a manner of speaking, to type the number 25.4. Hold that thought; by Chapter 3 you will think it was money well spent.

You are not expected to know what package or const val mean. You will, in two chapters. The point right now is only this: a program is text in a file. Not a special kind of thing, not something the computer manufactures. Text. Somebody typed it.

A way to picture it — the machine that cuts the metal

Somewhere near you there is almost certainly a factory with a CNC lathe in it: a machine tool that cuts metal automatically, without anybody guiding the cutter by hand. It does not know anything. What it has is a program — a text file, typed by a person, listing every move in order. Go here. Spin at this speed. Cut to this depth. Stop.

That file is not the part, and it is not the machine. It is instructions in a text file, waiting. Somebody can open it and read it, disagree with it, and find the line where the wrong depth got typed. Then a machine carries it out, and steel comes off a bar.

Those are the three things this chapter is keeping straight, and they are the same three every time: the text, the thing that carries it out, and the result. It happens to be an unusually literal example rather than a metaphor — a CNC program really is a program in the sense this book means — which is why it is the one worth having in your head first.

1.2 The machine does not read Kotlin

Now a problem. The file above is text, in something quite close to English. The processor inside your computer cannot read it. Not “finds it difficult” — cannot, in the same way a lathe cannot read a sentence.

What a processor understands is machine code: numbers. Astonishingly small instructions, each doing something like copy this number from here to there or add these two numbers or if that value is zero, jump to a different instruction. There is nothing else. Every piece of software you have ever used — every game, every browser, every bank app — is millions upon millions of those, executed in order, several billion of them a second.

Nobody writes that by hand. People did, for about a decade, and it was miserable. Instead we write in a programming language — text with names and structure in it, shaped for people — and then get a program to do the translation for us.

That translating program is called a compiler, and this is the moment worth slowing down for, because a beginner’s mental model of it decides how much of the next year makes sense.

Words for the toolbox

  • source code — the text a programmer writes, in a file, readable by a human. The .kt files in this book are all source code.
  • machine code — the numeric instructions a processor actually executes. Nobody writes it by hand any more.
  • programming language — the rules and vocabulary that source code is written in. Kotlin is one; there are thousands.
  • compiler — a program that translates source code into something the machine can run. It is also, as you will discover in Chapter 15, the best proofreader you will ever work with.

1.3 Compile time and run time

Here is the distinction that this entire book, and the next one, and your whole career, rest on. If you take one thing out of Chapter 1, take this.

There are two separate moments in the life of a program, they happen at different times, on possibly different machines, and things that are true in one are not true in the other.

COMPILE TIMEonce, on the programmer's machine, before anything runsRUN TIMEevery time anyone runs it, anywhere, lateryou, typingMainActivity.ktthe compilerreads every linea built appnothing has runchecks the rules of thelanguage and STOPS ifyou broke onecompile-time erroryou see it · nobody else doessomebody taps itmonths laterthe app runson their devicereal data arrivestyped, downloaded, tappedno compiler is anywherenear this. it left monthsagorun-time errora user sees iteverything Kotlin makes you say up frontis a bid to move a fault from the right panel to the left
Figure 1.1 — The two moments in a program's life. Everything on the left happens once, on the programmer's machine, before anyone runs anything. Everything on the right happens every time the program runs, possibly years later, on somebody else's device.

Compile time is when the compiler reads your source and translates it. You are sitting there. Nothing is running yet. The compiler is checking your text against the rules of the language, and if you have broken one, it stops and tells you. The program that comes out the other end has not done anything yet — it has merely been built.

Run time is when somebody actually runs the result. It might be you, ten seconds later. It might be a stranger, on a phone, two years later, on a bus. Now things happen: numbers get added, files get opened, buttons get tapped.

Why does this matter so much? Because errors divide neatly along that line, and the two kinds feel completely different to live with.

Compile-time error Run-time error
When you find out Immediately, while writing When the program is running
Who sees it You Possibly a user
Example You misspelled a name; you passed text where a number was required You divided by zero; the file you tried to open wasn’t there
Cost of fixing Minutes Anywhere from minutes to a very bad week

A compiler that catches a mistake at compile time has done you an enormous favor and it will not feel like one. It feels like being nagged. It is worth deciding now, before you have any scars, that a compile error is a good outcome — it is a bug that will never reach a user, found by a machine, for free.

Kotlin is a language that leans hard in this direction. A great deal of what you will learn in Chapters 3 through 14 is really about giving the compiler enough information to catch your mistakes early, and Chapter 10 is about a single category of run-time crash that Kotlin has very nearly abolished by moving it to compile time.

Drills

For each of these, say whether it is a compile-time problem or a run-time problem. No Kotlin knowledge needed — reason from the definitions above.

  1. You typed printn instead of println, and there is no such thing as printn.
  2. The program asks the user for their age, and they type banana.
  3. You wrote a line that adds a number to a word, which the language forbids.
  4. The app tries to save a file, and the disk is full.
  5. You gave two different things the same name in the same place.
  6. The app downloads a picture, and the phone loses signal halfway through.
  7. You opened a curly brace and never closed it.
  8. A calculation divides by a number that happens to be zero this one time.

Questions from the floor

Q: If the compiler catches mistakes, why do finished programs still crash? A: Because the compiler can only check things that are knowable in advance, from the text alone. It can prove you never misspelled a name. It cannot know that the user will type banana, or that the network will drop, or that this particular customer has a shaft with no keyway on it. Everything that depends on what happens later has to be handled by the program itself, at run time, and that is a large part of what programming is.

Q: Does the compiler run every time the program runs? A: No — and this is exactly the beginner trap. Compiling happens once, when you build. The result gets shipped. When a user taps your icon, no compiler is anywhere near them.

Q: So the compiler is like a spellchecker? A: A spellchecker that refuses to let you send the letter until the spelling is right, and that also checks the grammar, and also that you have not addressed the envelope to a person who does not exist. It is more insistent than a spellchecker and considerably more useful.

1.4 What actually runs

For Kotlin on Android there is one more step in the chain than you might expect, and it is worth seeing once, because it explains a word you will meet constantly.

your fileMainActivity.kttext you typedthe compilerat build timechecks it, translates itan app fileone, for everyoneinstalled on a devicethe runtimealready on the phonefinishes the translationchipruns ithappens ONCE, on your machinehappens on EVERY device, every timethe extra hop is why one build reaches phones you have never seen
Figure 1.2 — Source to running app. The compiler translates your text once, at build time. The result is packaged into an app, installed, and only then does anything execute — inside a runtime that stands between your code and the actual hardware.

Your Kotlin does not get translated directly into instructions for the specific processor in one specific phone. It gets translated into an intermediate form, and a piece of software already on every Android device — the runtime — takes care of the last step, for whatever chip that particular device happens to have.

Read that word carefully, because it is not the one you met in §1.3. Run time, two words, is a moment: the time at which somebody runs the program. Runtime, one word, is a thing: a piece of software sitting on the device. The two are related — the runtime is what is doing the work at run time — but they are not interchangeable, and the space between them is the whole difference.

The practical consequence is the one that matters: you write your program once and it runs on a great many different devices, none of which you own or have ever seen. That is not a small thing, and it is why the extra step exists.

Pinch point — the file is not the program

This one catches everybody exactly once, and it is worth being warned rather than bitten.

You have the app running on your phone. You spot a mistake, you open the source file, you fix it, you save it. You look at the phone. Nothing has changed.

Of course nothing has changed. The running app is not reading your file. It has not read your file since the moment it was built — it is the output of a translation that happened before it was installed. Editing the source changes what the next build will produce, and nothing whatever about the one already running.

Change the source, build again, install again. Then look.

Modern tools blur this — Android Studio has a feature that pushes small changes into a running app, and Chapter 17 uses it — but it is a convenience laid on top of the real model, not a replacement for it. When it fails, and it will, it fails in ways that only make sense if you are holding the real model in your head.

1.5 Why Kotlin, and why Android

The honest first answer is: because the two applications this book points at are Android apps written in Kotlin, and a book whose whole point is here is that same idea in real software needs real software to point at.

But there are better reasons than convenience, and they are worth stating because “which language should I learn first” is a question you will be given a great many confident and contradictory answers to.

Kotlin is strict in the places where strictness helps a beginner. It insists you say what kind of thing each name holds, so it can catch you putting a word where a number belongs — at compile time, for free. It has an unusually good answer to the single most common crash in the history of software, which Chapter 10 is entirely about. It is wordy where being wordy prevents mistakes and terse everywhere else.

It is a real working language, not a teaching one. Some languages are designed to be learned and then left. Kotlin is what Android development is actually done in — Google made it the recommended language in 2019 — so nothing you learn here is scaffolding to be discarded later.

Android gives the ideas somewhere to go. By Chapter 17 you will have built something that runs on a phone, and there is a difference in kind between a program that prints text into a window on your own machine and a thing you can hand to someone. It is worth working toward.

Questions from the floor

Q: Do I need to be good at math? A: No. You need to be comfortable with the arithmetic you already learned by the age of about twelve, and that is genuinely it for most programming. Some corners are mathematical — one of the two applications here is full of geometry, because it draws engineering diagrams — but the overwhelming majority of professional software is text, lists, dates, and rules. Chapter 4 covers every piece of math this book requires, and it is mostly about the ways computers get arithmetic subtly wrong.

Q: Do I need a powerful computer? A: A modest one. Android Studio is the heaviest thing you will install and it wants around 8 GB of memory to be pleasant. It will run on less, slowly. You do not need an Android phone — Chapter 2 explains the emulator.

Q: Am I too old / too late / too non-technical? A: This is asked so often, and so anxiously, that it deserves a straight answer rather than encouragement. Programming is a skill acquired by repetition, like welding or playing an instrument, and it rewards patience and stubbornness more than youth or cleverness. The people who struggle are almost never the ones who started late. They are the ones who read about it instead of doing it. Do the drills.

Q: Should I learn Python / JavaScript / C++ instead? A: Eventually, probably several of them. But not simultaneously and not first. Every language teaches the same handful of underlying ideas — the things in this book’s table of contents — and once you have them in one language, the second rarely starts from zero, though syntax, libraries, and occasionally the whole way of thinking can differ. Pick one, go deep, and ignore anybody who tells you the choice is momentous. It isn’t.

1.6 How everybody used to meet the machine

You are meeting the machine through a compiler, an editor with opinions, and a language designed in 2011. It is worth knowing what the previous doorway looked like, because the difference between the two explains most of what this book teaches.

BASIC was a programming language from 1964, and for a stretch in the 1980s it was how most people met programming at all — home computers switched on to a blinking prompt with BASIC already in them, and a generation learned to type things like:

10 PRINT "HELLO"
20 GOTO 10

Every line was numbered. GOTO 10 meant jump back to line 10 and carry on from there, which meant this program printed HELLO forever, which was the single most popular program in the history of the British school computer lab.

Two things about that little program are worth keeping.

First, the BASIC in those home computers was interpreted, not compiled. There was no build step. You typed RUN and the machine started working through your lines one at a time, translating as it went. That is the other way to get a program to run, it is still very much in use, and the difference from §1.3 is one of when the translation happens rather than whether it happens at all. Interpreted languages give you an instant answer; compiled languages give you a machine that checks your homework before you ever run it, and a program that runs faster afterward.

Second, GOTO is why the rest of this book looks the way it does. A language where any line can jump to any other line produces, in programs of any size, a tangle that nobody — including the person who wrote it — can follow. The name that stuck for it is spaghetti code, and getting out from under it produced most of the structure you are about to learn: functions, loops with defined beginnings and ends, blocks with braces around them. Edsger Dijkstra’s famous two-page argument against GOTO was published in 1968 and the profession spent the following decade agreeing with him. You are inheriting something that was expensive to work out.

So the machine a fourteen-year-old met in 1982 was far easier to walk up to and far harder to build anything large on. You are meeting a stricter one with much better tools, and nearly everything in the eighteen chapters after this one — functions, tests, the compiler’s complaints, the whole apparatus of structure — exists because of the difference between those two encounters.

How it’s done in the shop

Nobody has it memorized.

There is a fantasy about programming, and it survives mostly because programming on television is always shot the same way: an expert stares at a screen and types without pausing, producing correct code from memory at speed.

Actual professional programming looks like a person with the documentation open in another window, searching for the exact name of a function they have used two hundred times, because they can never remember whether the arguments go in that order. It involves a great deal of looking things up, trying something, being wrong, and adjusting. Everyone does this. The senior people do it fastest and least apologetically.

What separates people is not recall. It is being able to hold a problem in your head while you go and find out something you need, and come back without having lost the thread. That is a real skill and it improves with practice, which is why this book asks you to type things instead of only reading them.

Two practical consequences, starting today. Do not try to memorize syntax — Appendix B exists precisely so that you do not have to, and you will stop needing it through use rather than through effort. And do not measure yourself by what you can produce from a blank page unaided, because that is not the job and nobody does it.

1.7 A whole real program

You are one chapter into a book, you have written nothing, and you are about to look at a complete file from a shipping application. That is on purpose.

Here is MainActivity.kt from ShaftSchematic — every line of it, imports and documentation and all. It is the app’s front door: the file Android goes to when somebody taps the icon.

Out in the wild

Do not read this for comprehension. Read it for shape — the way you would look at a page of a language you do not speak and still be able to say where the paragraphs are.

MainActivity.kt — ShaftSchematic — the complete file, forty-eight lines

// file: app/src/main/java/com/android/shaftschematic/MainActivity.kt
package com.android.shaftschematic

import android.os.Bundle
import androidx.activity.ComponentActivity
import androidx.activity.compose.setContent
import androidx.activity.enableEdgeToEdge
import androidx.compose.material3.Surface
import androidx.compose.runtime.collectAsState
import androidx.compose.runtime.getValue
import androidx.lifecycle.viewmodel.compose.viewModel
import com.android.shaftschematic.ui.nav.AppNav
import com.android.shaftschematic.ui.theme.ShaftSchematicTheme
import com.android.shaftschematic.ui.viewmodel.ShaftViewModel
import com.android.shaftschematic.ui.viewmodel.ShaftViewModelFactory

/**
 * MainActivity
 *
 * Purpose
 * Single-activity host for the Compose UI. Creates the app-scoped [ShaftViewModel]
 * using our factory (required because the ViewModel extends AndroidViewModel)
 * and passes it to the navigation graph, wrapped in the user-selected theme
 * (Settings → Appearance).
 *
 * Contract
 * - No business logic here.
 * - Do not perform file I/O or SAF work here.
 * - ViewModel is created once per Activity and handed to AppNav.
 */
class MainActivity : ComponentActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        enableEdgeToEdge()

        setContent {
            // IMPORTANT: use the factory so AndroidViewModel receives Application
            val vm: ShaftViewModel = viewModel(factory = ShaftViewModelFactory)
            val themeMode by vm.themeMode.collectAsState()
            val highContrast by vm.highContrast.collectAsState()
            ShaftSchematicTheme(themeMode = themeMode, highContrast = highContrast) {
                Surface {
                    AppNav(vm = vm)
                }
            }
        }
    }
}

What you can already tell. The block starting /** is a comment — text for humans that the compiler ignores entirely, and you can tell because it is written in English sentences. The lines starting import are at the top, all together, which suggests they are some kind of preamble. Curly braces { and } open and close things, and they nest: something opens, something else opens inside it, and they close in the reverse order, like brackets in arithmetic. Indentation follows that nesting exactly, which is a convention rather than a rule, and it is doing a lot of work for your eye right now.

What you cannot tell yet, and where it gets explained. class is Chapter 11. val is Chapter 3. fun is Chapter 8. The block passed to setContent { … } is a lambda, which is Chapter 14, and everything inside it is Jetpack Compose, which is Chapter 17. by, override, and the whole business of ShaftViewModelFactory are not in this book at all — they belong to Reading the Machine, chapters 5 and 7.

What the file is actually saying, in one sentence: when Android starts this app, get hold of the thing that holds the app’s data, find out which theme the user picked, and draw the screen. Forty-eight lines, of which twelve are imports and sixteen are comment.

That is the real ratio, and it is worth noticing on your first day. Roughly a third of that file is instructions to the machine. The rest is bookkeeping and explanation for people. Professional code is much more about being read than most beginners expect.

Chew on this

Is a recipe a program?

It has ordered steps. It has quantities, which Chapter 3 will teach you to call values. It has things that look a lot like loops — stir until it thickens — and things that look like conditions: if the dough is too dry, add water.

But a recipe is written for a cook, and a cook fills in an enormous amount. Season to taste. A splash of oil. Until golden brown. Every one of those assumes a reader with judgment, context, and a sense of what the dish is supposed to be.

Now try to imagine writing that recipe for something with no judgment at all, that will do precisely what you wrote, in exactly the order you wrote it, ten million times without ever once thinking that can’t be right. What would you have to add? What would “golden brown” have to become?

Sit with that. It is not a trick question, and the answer is most of what makes programming hard. It is very rarely the syntax.

On the bench

You have not installed anything yet, so this one is done in a web browser, and it should take about ten minutes.

Go to github.com/chrisjmendoza/ShaftSchematic/tree/book-1e and look around. The /tree/book-1e on the end matters: it pins the page to the exact version this book was written against, so what you see is what is printed here rather than whatever the project has become since. Chapter 2 explains what that name is. You are not reading code — you are getting a sense of scale and shape, the way you would walk once around a building before going in.

  1. Find the README.md on the front page and skim it. What does this application claim to do?
  2. Click into app/src/main/java/com/android/shaftschematic/. Count the folders. Write the list down; you will meet several of these names again.
  3. Open model/Numbers.kt — the two-line file from §1.1. Confirm for yourself that this book has not simplified it.
  4. Now open geom/ and click into any file at random. Scroll it. It will be incomprehensible, and that is the correct and expected result; note roughly how long it is.
  5. Do the same walk around github.com/chrisjmendoza/postmark/tree/book-1e, and write one sentence on how its top-level folder names differ from ShaftSchematic’s.

The purpose of this exercise is not comprehension. It is to have stood in the building once, so that the wild boxes for the next eighteen chapters are visits to somewhere you have been rather than photographs of somewhere you haven’t.

Spec sheet

  • A program is text in a file, written by a person. Numbers.kt is two lines long and is a real file in real software.
  • Processors execute machine code, not Kotlin. A compiler does the translation.
  • Compile time happens once, on the programmer’s machine, before anything runs. Run time happens every time anybody runs the result.
  • Errors divide along that line. A compile-time error is caught for free and reaches nobody; a run-time error can reach a user. Kotlin is designed to move as many as possible into the first category.
  • The running program is not reading your source file. Change the source, build again, install again.
  • On Android, compiled code runs inside a runtime already present on the device, which is why one build works across many different devices. One word, and a different thing from run time two bullets above: that is a moment, this is a piece of software.
  • BASIC was interpreted and used GOTO; the structure you are about to learn — functions, loops, braces — exists because of what unrestricted jumping did to programs that got large.
  • Nobody has the syntax memorized. Looking things up is the job, not a failure of preparation.
  • Entry-point files like this one are roughly a third instructions and two thirds explanation and bookkeeping. Being readable is most of it.

Further reading

  • Petzold, Code: The Hidden Language of Computer Hardware and Software (2nd ed., 2022) — builds a working computer up from a torch and a piece of wire, and is the best account there is of what is underneath §1.2.
  • Hunt & Thomas, The Pragmatic Programmer (20th anniversary ed., 2019) — the professional habits in this book’s How it’s done in the shop boxes, at book length.
  • Dijkstra, Go To Statement Considered Harmful (1968) — two pages, free online, and the actual argument §1.6 summarizes. Readable on day one, which is unusual for a famous paper.

Review questions

  1. In one sentence each, define source code, machine code, and compiler.
  2. Explain the difference between compile time and run time to someone who has never programmed. Do not use the word “compile” in the explanation.
  3. Why is a compile-time error described in this chapter as a good outcome?
  4. You edit a source file while the app is running on your phone and nothing changes on screen. Explain why, in terms of §1.3.
  5. Give one example of a mistake a compiler can catch, and one it cannot catch even in principle. What distinguishes the two?
  6. On Android, your compiled code is not translated directly into instructions for one specific processor. What is it translated into instead, and what does that buy you?
  7. MainActivity.kt is forty-eight lines, of which twelve are imports and sixteen are comment. What does that ratio suggest about what professional code is optimized for?
  8. BASIC’s GOTO allowed any line to jump to any other line. Name one thing modern languages provide instead, and say what problem it was solving.