Jauhar's Blog


Does Software Engineering Require Math?

2024/05/06

TLDR: You do need math, but might not need its notation. Math notation is just like a language, you don’t have to know it. But, that means, you can’t learn from that language. You can still learn from another language, though. But, knowing the math is not enough. You also need creativity to solve a problem.

Does software engineering require math? That question is often asked by people who think they are not good at math but want to be a programmer. For some reason, people think that somehow to be a good programmer, you need to be good at math. Especially in Indonesia, I’m not quite sure about other countries, and I’ve never seen people outside Indonesia asking this question. I want to post my view on this question.

First of all, what do you mean by math? The field of mathematics is broad. There are a lot of subjects in Math starting from logic, arithmetic, algebra, number theory, geography, statistics, etc. Which field are you talking about? If you mean all fields, then I can guarantee you, that nobody in this world is good at all of the mathematics field. There are just too many fields in mathematics that it’s impossible to be good at all of them.

You Need Math To Function As A Human

Now, here is the thing, of course, you need some math to be a good programmer. Not only that, in order to become a human, you need to be good at math, especially in the branch called logic in math. You use math on a daily basis to make a decision and conclusion. You just don’t realize it and don’t write a mathematical notation to do that. You don’t model your daily problem using math and proof that your decision is logical, it’s just so intuitive that it happens naturally without the need for such notation. Let me give you an example: suppose, you want to go to your school. It’s raining. Because of that, you bring an umbrella. That simple decision-making is already a part of math. You have these 4 equations:

$$ \begin{equation} \begin{split} p =& \text{it's raining} \\ q =& \text{you get wet} \\ r =& \text{you bring an umbrella} \\ p \land \lnot{r} \implies q =& \text{if it's raining and you don't bring an umbrella,} \\ &\text{you will get wet} \end{split} \end{equation} $$

Your goal is \(\lnot{q}\). Based on this, you can use a rule inference called modus tollens, which says, that if you have \(p \implies q\) and \(\lnot{q}\), you can conclude \(\lnot{p}\), let’s try this:

$$ \begin{equation} \begin{matrix} &p \land \neg r &\implies &q \\ &&&\neg q \\ \hline \therefore &\lnot{(p \land \lnot{r})} \end{matrix} \end{equation} $$

So, the conclusion is \(\neg (p \land \neg r)\). Next, you can use De Morgan’s law to simplify it: \(\neg(p \land \neg r) = \neg p \lor r\) You know that \(p\) is true (it’s raining), so \(\neg p\) is false, the only solution for \(r\) is \(r = T\), because if \(r = F\) then \(\neg p \lor r\) is false. So, in conclusion, if you don’t want to get wet, you should bring an umbrella.

As you can see, there is math there, it’s just so intuitive to humans, that you can skip all of those steps including modeling your problem using proposition, writing the equation in math form, using the modus tollens rule, using De Morgan’s law, etc.

Now, imagine you are not good at math (especially in the branch of logic). You read a sentence like this: “If you murder a person, you will go to jail”, then you see a person in jail, and make a conclusion like this “That person must have killed another person”. You see, it’s not logical, let’s write it down:

$$ \begin{equation} \begin{split} p &= \text{you murder a person} \\ q &= \text{you go to jail} \\ p \implies q &= \text{if you murder a person, you will go to jail} \\ \end{split} \end{equation} $$

We see a person in the jail, so we have:

$$ \begin{equation} \begin{split} p \implies &q \\ &q \\ \end{split} \end{equation} $$

Now, if our conclusion is \(p\), it’s wrong, here is the proof: In order to decide if a conclusion is true, you need to prove that \((p_1 \land p_2 \land p_3 \land \dots) \implies q\) is a tautology. Let’s do that:

\(p\) \(q\) \(p \implies q\) \(q \land (p \implies q)\) \((q \land (p \implies q)) \implies p\)
T T T T T
T F F T T
F T T F T
F F T T F

As you can see, \((q \land (p \implies q)) \implies p\) is not a tautology, hence the conclusion p is not correct. And again, it’s so intuitive that you know it’s not correct without going through all the maths and proving it. It’s just so natural to humans to have this logic, that we don’t need a notation for that. You can directly say to yourself: “It’s not always true you know, just because a person is in jail, doesn’t mean they’ve murdered someone. They might do some other crime”.

That’s one example of using math for logics. We already know this because it’s intuitive to human. Another example where math is useful for your daily activities is a field of math called arithmetic. You want to buy a meal for Rp20.000,00, you give Rp50.000,00, you know you need Rp30.000,00. How do you know this? You just subtract Rp20.000,00 from Rp50.000,00. It happen so naturally that you forgot that there it’s a part of math field called arithmetic.

In summary, you do need math to function as a human in your daily activities. But, it’s just happen naturally that you don’t need all of these inference processes and you also don’t need to model them and write them in math notation. It happen so fast in your head, skipping all of those unnecessary steps.

Math Doesn’t Teach Problem Solving

Well, even though math can be used for problem-solving, it actually doesn’t teach you about problem-solving. You need more than math to solve a problem, you need creativity. Math gives you tools that are necessary to solve problems, but it just doesn’t teach you how. In the above example, I showed how math is used to solve a problem, but it actually does not. You see, the math above is used for modeling the problem and performing a logical step that brings us closer to the solution, but we need to think about those steps ourselves. Math doesn’t tell you that you have to use modus tollens and De Morgan’s law, you came up with that on your own. What Math does is just tell you, that there is this tool called modus tollens that you can use to draw a conclusion. There is this tool called De Morgan’s law that you can use to simplify negated expressions. But in the end of the day, it doesn’t tell you which rules you need to use to solve your problem.

Another way to think about it is that math does give you a solution to a problem, but the problem has to be known before. Modus tollen does give you a solution to your problem, but the problem is specific when you have two premises: \(p \implies q\) and \(\neg q\). But, you need to combine those rules on your own to solve your own problem, which is not exactly the same as the problem solved by modus tollens. It’s like how nails and hammers solve a specific problem. Nails and hammers can join two woods together. But in order to build a house, you need creativity, combining multiple tools in such a way that the house can be built.

Now, how do we learn problem-solving? Well, problem-solving is like art, it requires creativity. And it’s hard to teach because creativity can’t be taught in words. For some people, ideas just come to their head naturally. The key is to make the idea come to your head naturally as well. You can do this with a lot of practice. Look at how other people solve problems, see the pattern, try it yourself, repeat it a million times. By doing that, ideas will just come to your head when you are solving problems.

Maths In Software Engineering

We’ve established that math is used daily. What about specifically for being a software engineer? Again, of course, you need math, but sometimes it just happens so naturally and intuitively that you don’t write all of your steps in math notations.

Let me give you a concrete example. You work for an e-commerce company, and there is a 9.9 campaign in the next few weeks, you have an estimation of how big will the traffic be. Let’s say you need to handle 10.000 orders per second. You need to make sure your servers can handle that many orders. How many servers do you need to provision? Here is what you might do: first you look at historical data, you observe that you can handle 500 orders per second by provisioning 5 servers, which means one server can handle 100 orders per second, which means to handle 10.000 orders per second, you need to have 100 servers. You might add an extra few servers just in case. Let’s see what just happened here. What you just did is model your server capacity using a linear equation, you assume that the growth of your server is linearly proportional to the traffic. Because of that, based on your historical data, you make a linear equation to model your server capacity, and the model is capacity (orders per second) = 100 * #server. You add some extra servers because you know the model is never accurate, which is true in statistics. That’s why we have a study of errors in statistics. Just like that, you just use linear algebra & statistics branch of math naturally. Again, those things are just intuitive to the human brain and happen naturally without the need to write all of the steps in mathematical notation.

What about when writing code? it’s the same thing. The theory of computation is actually a branch of mathematics. Most business problems are intuitive to solve without thinking about the math. It’s similar to logic, you just know it without thinking too much. To filter a list of users based on height, you just need to iterate it, check it for every iteration, and push the user that has matched criteria to a new list and return it. It is just so intuitive that you don’t need to prove that it’s correct using math.

The more experience you have, the more you can skip the math processes to solve the problem. To write a program that can run efficiently, you need to think about how a computer works and model it mathematically. For example, when writing a sorting algorithm, you need to model how fast it is by using math. We know a computer works by executing machine instructions, so we can model the performance of the algorithm by counting the number of machine instructions. Counting the exact number of instructions is hard because different CPU has different sets of instructions, so we model it by counting some instructions like swapping two numbers, iterating, comparing two integers, etc. Then you can compute the number of instructions of various sorting algorithms like selection sort, quick sort, etc. To compute and proof the number of instructions, you need math. But again, if you are experienced, you can just do all that in your head without proving it using math notation and theorem.

Another example is when writing a parser. There is actually a branch in math called automata that is quite close to mathematical logic. This branch studies abstract machines that have various properties like machines with finite states, machines with stacks, machines with infinite states, etc. It talks about how such a machine can parse a formal language, which gives born to the compiler technology.

Nowadays, modern programming languages often have a strong type system. Rust, Typescript, and OCaml are some good examples. Do you know that the Rust type system is close to a type system called the Hindley-Milner type system that is used in a branch of math called lambda calculus? Your type inference feature is also born from that.

In addition, the modern compiler often has code optimization to improve our code performance. That optimization usually requires us to represent our code in graphs, which is also part of a mathematical branch called graph theory. To perform such optimization we also need proof that ensures that our optimization doesn’t change the meaning of the program. This is true in the database field as well. Our SQL database is based on a branch of math called relational algebra, and our query can be represented as a tree (which is also part of graph theory). Our database needs to optimize our query, and usually, they do that by modeling their system using a mathematical model, assuming every operation has costs and we need to make a tree with the smallest cost possible.

However, some things are not intuitive and natural for average human intelligence to comprehend without talking about a concept in math. One example is matrix transformation. It’s hard to visualize what a matrix looks like in nature. There is no good analogy for matrix in nature as well. A vector, on the other hand, is quite easy to comprehend. You can picture a vector as an arrow showing the direction and velocity of a moving object, you can picture it visually in your head. You can also picture a vector as a point in 3d space (or 2d space). But, when it comes to matrix, it’s not that easy to visualize for some people. We can visualize it as the transformation of a 2d grid, but not a lot of people can visualize it. It will become harder and harder to visualize for 3d space when the matrix is multiplied by another matrix. But, we can visualize it using mathematical notation. We know multiplying a matrix to a vector transforms that vector, and we know we can compose a matrix independently because a matrix has an associative property. With these facts, we can make a transformation matrix to transform vertex in our world’s space into the camera point of view and we can make a 3D game. For this kind of thing, it’s just easier to talk with math concepts and notation compared to human’s natural language.

Another good example is cryptography. A lot of fundamental concepts in cryptography are hard to comprehend by the human brain without intermediate representation in mathematical notation. A prime number is one example. It’s hard to explain a prime number and how it’s useful in nature. It will become harder when we talk about the elliptic curve, there is just no equivalent concept in our daily activity that resembles the elliptic curve. In this case, it is just easier if we just talk in mathematical notation and use mathematical concepts.

But again, knowing the math doesn’t make you able to solve the problem. You also need creativity. You might be able to check other people’s work, proving its correctness and estimating the performance. But, coming up with a solution to a problem requires creativity. If there is a procedure to solve problems, then we don’t need humans to solve a problem, we can just create a program to do that. The problem is, that creativity is a very abstract concept that we just can’t teach. Let me give you an example. Blockchain is a very interesting technology. Blockchain requires a lot of concepts in computer science like hash function, digital signature, networking, number theory, prime numbers, etc. But, knowing all of them is not enough to come up with a blockchain protocol. You need creativity to see that you can make a distributed byzantine fault-tolerance system called a blockchain. It’s similar to writing code, knowing how ifs, loops, functions, algorithms, and data structure doesn’t make you magically a genius problem solver, you still need creativity to solve the problem. They are just the tools.

In summary, a lot of subjects in software come from mathematical concepts. But, if you are working on software like e-commerce, booking systems, TODO lists, social media, etc, you might not see it because it’s just so intuitive and natural to human intelligence that you don’t need to read any math book to understand any of that. However, some concepts are hard to comprehend by the human brain because there is no natural equivalent of that concept in the real world. In this case, it’s just easier to talk in mathematical notation and use mathematical terms.

I Can Build Good Software Without Understand Math. Why Should I Learn Math?

If you can build software without understanding any mathematical concept, good for you, and that’s ok. But, what actually happens is that: you already understand math, you just don’t know that it’s math and you don’t use mathematical notation to talk about it. Understanding math has 2 sides. Understanding what it does is one thing, understanding its notation is another thing. You already understand what it does, that’s why you can build software.

Now the question changed: is it important to understand the notation? Well, mathematical notation is like language, a language that is very precise and less ambiguous. People use it because, well, it’s less ambiguous and precise. It is different from natural human language, and of course, if you are not familiar with it, you might not be able to understand it. Why do we use it if it’s so hard to understand? Well, again, because it is very precise and less ambiguous. The meaning is clearer, and sometimes it can convey so much with so few symbols. Correctness is expensive. Proving something is correct is not easy. Even a simple statement like \(\forall a, b \in \mathbb{N} , a + b = b + a\) is not that easy to prove. First of all, what do we mean by \(a\), \(b\), and \(+\)? What do we mean by \(\mathbb{N}\)? We need to define it first to make no error. In order to prove something to be true, we can’t make assumptions other than the axiom we use. An axiom is a set of things that we just define to be true. Peano axiom is one of them. It goes like this:

  1. There is a thing called natural number, and zero is a number
  2. There is a successor function S, such that: for every natural number \(x\), \(S(x)\) is a natural number.
  3. For all natural number \(x\) and \(y\), \(S(x) = S(y) \implies x = y\)
  4. For all natural number \(x\), \(S(x) = 0\) is false.

Building on those axioms, you can define what operator \(+\) means, and you can derive that \(a + b = b + a\). This proves that the addition of natural numbers is commutative. You can check the statement is correct, by checking if the proof is correct. As long as the proof follows the logical rule of inference, the proof is correct. As you can see, it’s very pedantic (but clear) to prove something is true, whereas it’s naturally very intuitive. When you add 3 apples and 5 apples, of course it’s the same as having 5 apples and 3 apples. But, the language of mathematics can prove it without ambiguity.

Ok, I see how it can prove the correctness of a statement, but how is this useful? Well, not only it can prove a statement, but it can also convey an idea. Check out this paper about CRDT for JSON. It talks about how to make some kind of collaborative app with JSON data type. The author of this paper used the concepts of function, set, and logic to convey their idea to replicate JSON data through the network. The state of your local computer is modeled as a set, and it defines the result of executing an operation as an inference. If you don’t know how to read this notation, it will be hard to understand the paper. If the paper were to use a natural language, it would add ambiguity to the idea, and it would be hard to prove its correctness.

Another example is when reading WebAssembly Spec. The spec is written in a mathematical notation used in the branch of mathematics called automata which studies abstract machines. WebAssembly is indeed an abstract machine. If you don’t know how to read those notations, it will be hard for you to understand what the specification says. You can try to find another resource to learn about WebAssembly, but they will have more ambiguity compared to this mathematical notation. It doesn’t mean you can’t use it. Of course, you can reduce the ambiguity by reading a lot of other resources and doing experiments. But there is no guarantee you will get that many articles explaining it, especially when the topic is very niche.

Other than that, as I said before. Some concepts are just hard to understand without mathematical notation like a formula of some statistical metrics, matrix, elliptic curve, etc. In this case, people just explain it using mathematical notation because it’s easier that way. If you can’t read it, then yes, it would be tough.

Summary

So, in summary, back to the original question. Does software engineering require math? The answer is yes, you need to understand math, but you don’t necessarily need to understand its notation. At the very least, you need to use logical inference and arithmetic. Depending on the software you are building, you might also need additional branch of math like number theory if you’re building cryptographic software, linear algebra if you’re building machine learning software or game engine, automata if you’re building compiler, etc. You just need to understand them, but not necessarily understand the notation. However, understanding the notation can be important sometimes. Mathematical notation is just like another language that has less ambiguity and is very precise to convey an idea. Sometimes, it can be way simpler to convey an idea using mathematical notation compared to natural language. You might need to understand mathematical notation to understand other people’s ideas if they convey them using mathematical notation. You might also need mathematical notation if you want to convey your idea without ambiguity. Of course, sometimes, it can be very pedantic to do it. But, being pedantic is important if you need precision. Additionally, you also need creativity to solve a problem. Knowing the math is just like knowing the tool, you still need creativity to use a bunch of those tools together to solve a problem. Knowing just the math, you might be able to check the correctness of a solution, estimate its performance, and understand how other people solve a problem, but you won’t be able to solve those problems yourself. To improve your problem-solving ability, you need to improve your creativity, and to do this, you need a lot of practice.