In the history of humanity there have been three major inventions that have enabled people to think in entirely new ways. They allow us to learn more, think bigger thoughts and solve harder problems. They are:

- Writing: a means to store knowledge in a brain-independent form that can be easily replicated, transmitted and preserved
- Mathematics: a methodology for constructing abstract systems, reasoning about them precisely and finding connections between them
- Science: a methodology for finding abstract systems which map closely to the real world

The reason why we teach these in schools to everyone everywhere is that they are part of your cultural inheritance as a human. It is your right to have these tools. Over the last few hundred years they have empowered us to eradicate diseases, light the dark and explore the stars.

Recently there has been a fourth major tool added to the list:

- Computing: a way to arrange inanimate systems to simulate arbitrary abstract systems

Take a step back and think about what a remarkable idea it is a universal computer is even possible. We can take this inanimate system and arrange it so that it’s behaviour gives us information about another, completely unrelated system. We sit down and press buttons for a while and the machine churns and the screen glows and suddenly we know whether or not it will rain tomorrow. We discovered that the same system can be implemented using digital circuits or vacuum tubes or the atmosphere of a planet. Somehow the physical substrate doesn’t matter - the system has a life independent of it’s physical existence.

This idea of entangling unrelated systems so that the heap of silicon you hold can tell you what the weather will be tomorrow or what just happened on the other side of the world is impossibly and wonderfully strange and yet hardly even noticed.

The process of entangling one of these miraculous devices is called programming. At some point the internet collectively decided to have a civilised debate about whether or not programming is maths. The implied subtext wavers between “if you don’t know category theory you are a bad programmer and should feel bad” and “maths ought to stay up in its ivory tower where it belongs and stop getting in the way of good honest engineering”.

Aside from being nonsensical, the question is missing the point. For a start, it’s not clear that either side of the argument agrees on what math even is. Tragically, most people’s exposure to mathematics consists solely of memorising algorithms to solve numerical problems expressed in arcane syntax without reference to anything that they might ever care about. Lockhart has more and better to say on this topic than I can manage. Suffice to say that most of what you endured in school is the math equivalent of making you compile java into binary in your head for six years without ever showing you a computer or explaining why you might want to write a program in the first place.

But if you can get past the childhood trauma, the poor presentation and the awful syntax there is a whole world of important and beautiful ideas to explore. Mathematics is not about calculation and memorisation, but about building and studying different abstract systems and the connections between them.

Mathematics is:

- A set of methods for thinking correctly and precisely about abstract systems
- A body of knowledge generated by those methods
- A collection of conventions, notations and terminology for talking about that knowledge

Andy diSessa notes that Galileo’s proofs of the laws of uniform motion cover page after page to establish complicated relationships that young students today can express and remember simply as ‘d=vt’. Notation matters. Not the little details of what particular symbols we use or the arrangement of characters but the frameworks within which we hang our ideas. Galileo was one of the greatest minds of his century but his seminal work could today be performed trivially by anyone with a passing knowledge of algebra. This represents a massive increase in humanities collective intelligence.

If you are an experienced programmer, you have likely already developed a natural talent for proof and abstraction. But talent alone has limited use. Knowledge is leverage. For hundreds of years mathematicians have been creating tools for understanding the world; tools that are applicable to almost every human endeavour. Those tools belong to you.

# How to learn

To gain access to these tools, you must first perform several rituals. These rituals don’t just give you access to the body of knowledge accumulated over hundreds of years, they also give you the tools to build your own. Even if the problem you are working on has never been studied before, you can approach it with a huge collection of tools and techniques as well as the experience and confidence to apply them correctly.

- Ritual 1: Learn to read and write proofs

A proof is just an argument which is sufficiently detailed to convince the listener. In most cases the listener is just a more suspicious and pessimistic version of yourself - suspicious because they have learned that humans are not good at reasoning precisely about abstract structures. As a programmer, you spend a great deal of time forming informal proofs about your code and the systems it interacts with. After all, you have to convince yourself that the code you have written actually does what you want it to do, all the time, on every input. Many of the established practices for writing good code - separation of concerns, clean interfaces, isolation of effects - boil down to making reasoning easier by reducing the amount of complexity you have to handle at once.

Anyone who was forced to study mathematics at a university level probably has unpleasant memories of being asked to prove some simple obvious fact in tedious detail. Every pedantic little mistake or ambiguity is picked out and criticised. For many people the whole experience is frustrating and seems pointless.

The goal of this exercise is to debug your thought process. It is surprising how many things are totally obvious and yet not true. How many times have you been convinced that a program is absolutely definitely correct this time only for blatant bugs to emerge within minutes? By becoming conscious of the reasoning process itself and by correcting it’s mistakes you can learn to reason correctly and precisely. These skills are initially practiced on the solid ground of trivial theorems so that they are second nature by the time you reach less sure footing.

As your skills develop you can return to more fast-and-loose reasoning most of the time. As Terence Tao explains, the purpose of rigour is to develop and guide intuition. The working mathematician proceeds in rapid leaps and bounds when on familiar ground, only resorting to careful tiptoeing proofs when in unfamiliar territory. Through practice they develop a good sense of when a detailed proof is needed to catch mistakes and when they can get away with just a sketch and a wave, in the same way that a good programmer knows which code can be churned out in a moment and which needs careful thought, review and testing.

Intuition also guides proof. A student unfamiliar with a particular subject will stumble around trying to construct a proof by brute force but an experienced practitioner will find the correct proof just emerges fully formed in their head as if by magic. To paraphrase Rich Hickey: proofs are guard rails - they are essential for safety but you don’t drive by bouncing back and forth off the guard rails. Somehow the image of mathematics has become one of drudgery and endless formality when the reality is a balance between the intuitive leaps of understanding and the pillars of proof that prop them up afterwards.

- Ritual 2: Learn the language

You need at least a passing familiarity with numbers, functions, sets, relations, vectors, matrices, graphs and predicates as well as the syntax used to describe them, their basic properties and how they relate to each other. The amount of knowledge may seem intimidating, but your average math undergraduate learns all this in their first year whilst mostly drunk. You are smarter than them and possibly more sober.

One of the huge benefits of the second ritual is that the knowledge starts to link together. Each fact slots into a huge web with many connections so that you have multiple pathways to remember and understand it. The more different ways you have to look at a subject, the more likely it is that one of them will click and make sense. Theorems and definitions are no longer handed down from on high to be memorized, but seem intuitive and natural because you understand *why* they are true.

- Ritual 3: Practice

Mathematical theories are tools and only by applying them repeatedly in different contexts will you learn to wield them properly. Like any other skill, mathematical thinking becomes truly powerful when it is so practiced that it no longer requires conscious effort or awareness. It just becomes another lens through which you can see the world.

Read books. Expect this to be hard. Studying maths texts is less like reading a novel and more like trying to unravel a knot. If something doesn’t make sense, skip it and come back later. Study it again and again, in different orders. Don’t just read passively, fight back. Can you find concrete examples of each theorem? Can you find counter-examples? Can you find alternate proofs of key theorems? Can you make the result of a theorem stronger by adding more conditions? If you take away conditions, can you prove a weaker version? Why prove this theorem at all - what does it mean and what problems can you use it to solve?

Find your own puzzles to solve. When walking to work, is it always fastest to take the first green light at an intersection? Does it depend on the timing of the lights? Is it possible to get to work earlier by leaving later to avoid rush hour traffic? If there were half as many cars but they were twice as long, would traffic be better or worse? Would adding more roads relieve traffic by reducing the density or increase traffic by adding more intersections? Write down the proof and send it to a friend. Tear holes in their proofs. Find ways to falsify your own proofs. The only way to know if your foundations are solid is to kick the shit out of them and see if they fall down.

# Where to start

The high school math syllabus across most of the western world was designed to create rocket scientists. Literally. Trigonometry, laws of motion and calculus gained pride of place during the space race over fears that Soviet schooling was producing superior rocket scientists. Rote calculation and memorisation were vital skills before the advent of computers. It’s little surprise that students don’t see maths as being relevant to their lives.

The programming world is little better. Any discussion of maths in programming quickly turns to lambda calculus, type theory or category theory. These topics may be interesting in their own right, but the ratio of time-invested to problem-solving-abilities-gained is less than compelling. Automata theory and complexity theory fare a little better but still don’t inspire much.

It’s easy to forget that programmers do more than program. The entire goal of programming is to solve problems in the real world and maths has been helping solve those problems for hundreds of years in every field. If you want to learn, study whatever you find interesting and apply it to whatever you enjoy doing.

Find a friend to study with. It’s easy to get stuck or misunderstand something but the chances of you both making the same mistake is much lower. Talking it over with someone else is often the quickest way to make sense of a problem.

The transition from high school memorise-and-calculate to real problem solving is legendarily jarring. Suddenly there is not a correct path laid out for you but a bewildering swamp which can only be navigated by skilled reasoning. Learning to think and communicate *precisely* is useful everywhere but is especially vital when reasoning about complex algorithms or concurrent/distributed systems. How To Solve It is a classic text on tactics for solving hard problems in general. How To Prove It deals more specifically with finding and expressing proofs and also covers the core constructs of mathematics (logic, numbers, sets, relations, functions).

Depending on how long ago you broke up with maths, you may need to brush up on the foundations. If you need to consciously think about basic algebra and logic you won’t have enough brain power left over to handle more advanced material. Whenever you get stuck with something, head over to Khan Academy and make sure that you are completely fluent in the prerequisites. Algebra I is especially important. Khan Academy focuses more on developing concrete intuition than on abstraction and rigour so it’s a good complement to more theoretical sources.

# Where to go

You won’t live long enough to learn more than a tiny fraction of all there is to know. Ideas have costs in the time it takes to learn them, the amount of maintenance required to remember them and the amount of effort it takes to apply them. Prefer ideas that have a high power-to-cost ratio. Some of my personal favourites:

**Randomised algorithms**are often faster, simpler and easier to understand than the best deterministic algorithms. The Power of Two Random Choices gives a laundry list of important applications for one simple idea. Probability and Computing covers the entire field from the absolute basics of probability to the most sophisticated modern applications.**Entropy**is a very simple concept that governs compression and error-correcting codes, without which modern communications would be impossible. A Mathematical Theory of Communication managed to lay the foundations for an entire field whilst still being readable by anyone with a basic knowledge of probability.**The possible-worlds model**is a powerful way to reason about distributed algorithms. Using Reasoning about Knowledge to Analyze Distributed Systems introduces the model and shows how it simplifies reasoning about a variety of famous algorithms and impossibility proofs.**Denotational design**is a technique for designing composable abstractions. While it is commonly used, the only explicit description I have encountered is in Denotational design with type class morphisms. For a real world example see Constraint Propagation - Models, Techniques, Implementation which smoothly transitions from a simple mathematical model of finite-domain constraints to one of the faster constraint solvers in the world.

Surf wikipedia. Get a sense the major areas of study in mathematics and what kinds of problems they deal with. That way, when you encounter a new and scary problem you at least know where to look for the solution.

Keep reading. Read textbooks. Read papers. Read blogs. Read puzzle books. Watch videos.

Play around. Don’t limit yourself to learning ‘official’ theory - discover and invent new ideas for yourself.

Teach somebody. The best way to really understand something is to try and explain it to someone else.

Enjoy yourself. Life is too short not to.