by Jonathan Y. H. Sim
Computational thinking. The word “computer” is in it, but it has very little to do with computers and programming. Of course, programmers use computational thinking all the time, but it is not the same as programming. Here, we’re using the old meaning of the word “computation,” which refers to the act of calculating things in an abstract way in order to solve a problem.
The word, “abstract,” is critical here. Unlike the other modes of problem-solving, computational thinking is primarily concerned with taking a problem in the real world, and abstracting it in a way (often with the help of models) that will allow us to figure out a solution. One great value in solving problems in the abstract, is that these abstract solutions can find applications in a variety of situations and context far different from the original problem. An abstract solution for matchmaking could very well be used to match people to schools, or for organ donations to help more people live longer (true story!).
Consider this incredibly trivial problem that you learnt back in Primary school:
James has five apples. He gave two apples to Mary, threw a rotten one away, and ate the rest. How many apples did James eat?
We can abstract this real world “problem” into the following model:
5 = 2 + 1 + x
If we solve for x, we know that x = 5 – (2 + 1) = 2. So James ate 2 apples. Notice how the solution is so abstract I could apply it to problems other than apples?
Of course, this is a trivial example. But the point is to illustrate just how we’ve been using computational thinking from such a young age to solve problems that it’s almost second nature to us, that we don’t realise the mental processes involved in helping us move from the real world to the abstract world, and then finding a solution there, before coming back to the real world.
Yet the very same process can help us solve more challenging problems in a very sophisticated manner. It may provide us with a means for analysing a situation, present us with an answer, or the solution may be as sophisticated as an algorithm that we can regularly apply to solve a variety of problems.
The mathematician, George Polya, developed a popular 4-step approach to problem solving in a computational manner. It goes like this:
(1) Understand and define the problem
(2) Translate and model the problem
(3) Solve the problem
(4) Review and refine the solution
This looks a lot like common sense. But how often do we actually solve a problem strategically in this way?
More often than not, because of the sense of urgency that problems present us, we tend to jump straight into Step 3 (Solving the Problem), without a proper understanding of the problem, nor with a proper plan or strategy in sight.
Think of all the times where you encountered a problem. How did you try to solve it? Most of the time, we would approach it in a very “no brainer” method. Or in Singlish, we like to say, “anyhow whack.” This is one way, and it is not a bad way for solving problems. If you think about it, it’s an almost primitive approach. How often do you smack your computer (or whatever device you have) whenever it doesn’t work? It’s a very primitive response.
Whenever we try to solve problems without much planning or strategising, we tend to fall back on this “anyhow whack” approach. But think about all the times you’ve done something like that. Isn’t it very inefficient?
If at any point, you asked: Could I have solved the problem in a more efficient manner? Could I have solved the problem in a way that might have produced a better outcome?
Once you begin asking questions like that, you have started walking down the path of computational thinking!
1. Step 1: Understanding and Defining the Problem
There are two conceptual tools useful for understanding a problem: (1) decomposition, and (2) abstraction. We do these most of the time, so it isn’t exactly new to us. The point here is to create the awareness of what we usually do when we are attempting to understand a problem, so that you can recognise them as tools, and be empowered to use them to better understand a problem.
Have you ever been handed a task that is so big that it overwhelms you? How do you even begin addressing a problem like that? Decomposition is a kind of divide-and-conquer strategy. There are two aspects to decomposition.
First, we can apply decomposition to break a big overwhelming problem down to smaller issues (or sub-components). Finding a romantic life partner can seem like a very scary task for someone who is trying to do so for the first time. There are so many things to worry about that it can feel suffocatingly overwhelming. But we can apply decomposition to break down the problem into a list of issues small enough that we can manage one at a time. The key to decomposition is to be as thorough as possible, and breaking the big issue down to as many smaller parts or sub-issues as possible. When we do this, we can begin categorising the problems. This is useful because decomposition can help us figure out a solution (or a series of solutions) that can tackle more than one of these sub-issues at the same time.
Second, we can also apply decomposition to break down a solution into smaller manageable tasks that we can easily manage. Sometimes it’s not the problem that is overwhelming, but the task assigned to us that appears overwhelming. Once again, decomposition allows us to break it down into smaller items for our todo list. It can feel very artificial doing it, and in fact many people who start out learning programming struggle with it. We’re just not used to articulating stuff that we do so spontaneously in real life.
If I want to boil water, I just do it! Why do we need to think about it? But imagine if you are one of those people who suffered a stroke and lost your motor abilities on one side of your body. You’re living on your own, so you can’t just boil water like you used to. Now, you have to be aware of each and every step that you take.
First, you need to find the kettle, and grab it. Does it matter how you hold the kettle? If the kettle is empty, no. But if it has some water inside, you must hold it at an angle where the water won’t spill. Now you have to find the water source and walk to it. How far is the tap? If it’s a short distance and there’s enough support you can slowly inch your way to the tap. Otherwise, you might have to hold a walking stick to assist you. You’re now at the tap. How much water do you have to boil? Well, given how your motor abilities are not that great, it’s not a good idea to try to boil a full kettle. So maybe half a kettle will do. This will be enough to make a nice hot cup of tea. Now that you’ve got the kettle filled, you’ve got to go back. Do you still have enough energy to carry the kettle of water back? If so, not a problem, you can bring the kettle back to its stand to start boiling it. Otherwise, you might have to rest a while before you complete the task.
That’s a lot of things to consider. But what we have done is that we have decomposed the problem of boiling water into many sub-problems. All that said, decomposition is a skill. The more we consciously practice it, the better we become. The benefit is that we become very thorough in our thinking, analysis of situations, and planning. We can easily generate a long checklist of actions that must be done, and work towards it to solve the problem.
1.2 Abstraction: The Art of Figuring Out What You Really REALLY Need to Solve the Problem
Once we have identified one approach that can address some of these sub-issues, we can then move on to the next conceptual tool: abstraction. This is a very powerful conceptual tool that is important for allowing us to simplify a complex problem into a simpler, abstract model. What it involves is asking questions like: (a) What information (inputs) do I need? (b) What kind of answers (outputs) am I looking for? (c) Are there constraints (limits) to my inputs or outputs? (d) Do I have any criteria to optimise, e.g. shortest time, etc.
The temptation that many of us have is to say: I want everything! But having everything is precisely the opposite direction of simplifying the problem.
To illustrate how abstraction works, let’s imagine that we are trying to develop an elderly monitoring system. We want to detect when grandma has fallen. What are the information (inputs), and answers/responses (outputs) that we need in order to detect that grandma has fallen? Let’s not talk about sensors, or worry about how we’ll get the information. For now, let’s just be concerned about the information that we really really need.
So, what are the inputs that we need for this? For a fall, we’ll definitely need to sense a sudden drop motion from a specific height. That’s for certain.
Would it be a useful input to sense that she’s lying flat on the ground? It might be useful, but there’s a lot of activities that involve grandma lying flat on the ground, e.g. yoga exercise, or sleeping on the cold floor because of the hot weather. Also, people sometimes don’t fall perfectly flat on the floor. They could have landed on something else while falling, e.g. a foot stool, or some boxes on the floor.
So it would seem that lying flat on the floor is not a good input to use. How about using the lack of motion as an input? On its own, grandma could be motionless because she’s sleeping or meditating. But we can measure how long she has been motionless after our system detected a sudden drop motion. So perhaps if she’s motionless for a period of time, we could use that as a sign that something is wrong.
From this discussion, we have identified three inputs: (1) a sudden falling motion; (2) a lack of motion after the sudden fall; and (3) time.
Now, let’s consider the outputs. What kinds of information do we need the system to produce? For starters, we can have an output like, “Fall detected.” That’s what our system was designed to do after all.
But do we need it to say “No Fall Detected”? This might not be helpful as it would lead to a lot of useless information being transmitted to our system. But then again, it might be useful to send this output from time to time, just so we know that our system is still working. Otherwise, there is no way to determine whether the system crashed or died due to a blackout or bug.
Or how about outputs like, “An event like a fall was detected”? Or “Near Fall Detected”? Well, that would depend on the big picture of the problem you’re trying to solve. A simple system will only report a detected fall. But if you want a more sophisticated system, we can choose to log the number of times a near-fall was detected. As the number of near-falls per day increases, we can get a good sense of whether grandma is losing her motor abilities. But that’s only if you want your system to do that. If you want a simple system, it will suffice to just output “Fall Detected.”
As you can see from the example above, abstraction is a process of determining what information we need (the inputs) in order to make the final decision (the output, i.e. detecting that grandma has fallen). As we are only at the problem understanding stage, we shouldn’t worry too much about how we are going to get that information or how we will process it. All that matters here are the inputs and outputs. Once we have a good idea of what we need, it will help us to focus onto the things that really matter.
With the inputs as the starting point, and the outputs as your end point. It becomes easier to figure out the process that will get you from start to finish. If you don’t have a clear picture of your start or end points, it will be incredibly difficult to figure things out. Or to put it a bit differently: How do you intend to find a solution to a problem if you don’t even know where you’re going?
So, how do we put decomposition and abstraction together? When faced with a big problem, we can apply decomposition to break the problem down into parts. When we have identified a sub-problem, or a set of similar sub-problems, that we want to address, we can then set out to find a solution. To do that, we will then have to apply abstraction to identify the kinds of answers (outputs) we want that will solve that sub-problem (or set of them), and the information we require in order to do so. This will help us to simplify the problem, thereby allowing us to find a solution. Once all these are done, we can move on to Step 2.
2. Step 2: Translating and Modelling the Problem
Unlike the natural and social sciences, computational thinking doesn’t look out for causality and correlation. Computational thinking is focused primarily on solving problems, rather than knowledge creation. For this reason, we look out for patterns. This involves a process known as pattern recognition. Patterns are all around us. On one hand, patterns exist naturally in the world, on the other hand, our minds impose patterns onto the world, allowing us to perceive the world more easily (this is also why we can so easily mistake correlation for causation , or think that coincidental correlations must be related, because we think we’re seeing patterns between these things).
Patterns provide us with the means for solving problems with ease. There are many seemingly complicated problems that can be easily solved once you have found a pattern for solving them.
Let’s say we are trying to work out a system for detecting road congestion. How do we know whether a road is congest or not? Well, when the road is congested, there is the regular pattern of a lot of cars moving very slowly. Whenever we see a pattern like this, we can conclude that this is a congested street.
But pattern recognition can be a double-edged sword, especially when it comes to human-related issues (which also explains why despite having computers for more than half a century, we are only starting to apply computational methods on humans). Let’s go back to the elderly monitoring system in the previous section. Imagine that we want to develop the system to detect whether grandma has fallen. We might have studied thousands of falling grandma cases, and we’ve found a pattern! That pattern involves grandma lying on the ground for a very long time (i.e. more than 1 hour).
Shall we model our solution based on this pattern? Could anything go wrong if we were to do it this way? Definitely! This way of modelling the problem is quite inaccurate. Grandma could be taking a nap on the floor. We could refine our model of fall-detection based on other patterns of falling grandmothers. But we may never fully capture all cases of falling. There will always be grandmothers who have slipped through the cracks (pun intended).
This then brings me to the profound point about algorithms. Whenever we translate things in the real world into language, into instructions, into models, or into algorithms, the translation will always be inaccurate and faulty. Words say too much and too little at the same time, and there’s often a lot of distortion in the process. If I say, “The sky is cloudy,” different people will imagine different coloured skies. Some will picture a white sky, some will picture a blue sky, some will picture a grey sky, and some unique individuals will picture a purple-orange sky. None of these answers are wrong. They are all interpretations of my statement of reality. As a statement, I have taken away the fullness of that reality. Perhaps I witnessed a cloudy red sky (yes, the sky can also be red on certain evenings). But because I failed to accurately translate reality into a sentence, you have pictured something else instead. Even if I told you, “The sky is cloudy and red,” you might imagine something totally different from what I saw.
This is a problem that is common to all kinds of translation. It arises when people attempt to translate from one language to another. But it also arises whenever we attempt to translate a problem in reality into a model that we can solve, regardless of whether we are computing tangible, quantitative matters, but especially when we are dealing with intangibles and qualitative things.
Here’s another example. Let’s imagine that we want to detect elderly loneliness. What model can we use to detect it? Some may say, “Grandma is lonely when she is alone at home and doesn’t talk to anyone.” Sure, this is something many of us will agree with. Yet, others may say, “Grandma is lonely when she goes out and talks to everyone.” Again, this is not wrong, and many of us will agree to that. If we do pattern recognition, we’d observe these two patterns in the world. Modelling our detection based on either one is problematic. Sure, it will capture some instances of lonely old people. But it will also detect many false positives. It also won’t work if we were to use both in our detection model. The two statements are almost like A and ~A. In which case, everyone is lonely according to such a detection model.
Perhaps the closest we can use is a stress hormone (there’s no loneliness hormone). But even that is not a direct measure of loneliness. Grandma might be feeling stressed because her grandson is sitting for an important pre-university exam. So her stress hormones will shoot up. So this is still not a good solution. Ultimately, none of these solutions are perfect. Bad translations lead to bad results.
Here’s the main point: every way of modelling a problem, especially human problems, will almost certainly be doomed to fail because of translational issues. We may work to refine and develop a more accurate model, but a more accurate model is always flawed, and it is not the same as a perfect model. And so, just because a system works well does not mean that it is fine. Just like the story of the black swan that surprised all of Europe when they were so confident that swans could only be white (having observed only white swans for centuries), our computational solution will only seem fine until the very day we discover the black swan, the very instance that will cause things to go wrong, thereby proving that our solution is flawed.
3. Step 3: Solving the Problem
This brings us to Step 3. But before we can dive into solving the problem, we need to first be aware of the tools that we can use to solve it. Again, how can you solve a problem if you have no idea what tools you can use to solve it?
3.1 Identifying and Constructing Primitives
What do you need in order to embed a nail into a wooden fence? Intuitively, we’d say we need a hammer. But what if you don’t have a hammer, and the hardware shop is too far away? In this case, we require something as hard as a hammer. A rock would suffice, and we can go around to search for a rock or anything hard enough to function as our make-shift hammer.
Clearly, we are aware of the kind of tool we need to solve this problem (of embedding a nail into a fence). Identifying the tools you need is the first step to solving a problem. While the above example was pretty common-sensical. Yet, the difficulty in many problems is that many times, it’s not clear what tools are available for us to use.
From a Computational Thinking perspective, it is highly important for us to identify all the basic tools that we have. These are known as lower-order primitives. They are called lower-order primitives as they are like building blocks, and we can use them to construct more sophisticated tools known as higher-order primitives. Higher-order primitives are especially useful when no ready-made tool is available.
Let’s say you need to change a bulb on the ceiling. You have no ladder, but you have lots of big solid boxes. These boxes would then function as your lower-order primitives that you can then stack together to construct a higher-order primitive, i.e. a staircase, to get to the top.
That was a simple illustration. Let’s consider a more sophisticated example. Let’s imagine that we want to develop a system that will monitor grandma’s heart rate so that we can determine that she’s ok. It’s clear that as an input, we require her heart rate. But what tools do we have available to monitor that? It’s easy to say, “Let’s use a heart rate monitor.” Here, we are treating the heart rate monitor as a kind of tool, as a primitive. If we can purchase ready-to-use heart rate monitors, we can treat the heart rate monitor as a lower-order primitive.
But if we have to build our own, then the heart rate monitor is a higher-order primitive, and the tools for it would comprise our lower-order primitive. What do we need? Well, if we want something cheap and good, then all we need is light (to illuminate the capillaries) and a light sensor to sense the pulsing of blood through the capillaries). These will be our lower-order primitives.
Yet, it’s not enough to just say, I need a light and a light sensor. We still have to question how we are to put these tools together. If we put these in the wrong location, we won’t get any useful readings.
3.2 Putting It All Together with Composition
This is where we will require the conceptual tool of composition, a process by which we question how we put things together. This is a process where we question the “where,” and the “when” of applying our primitives.
If you ever had to work as a barista, or tried to make a café latte on your own, the order of sequence is important. You can only add the frothed milk after you’ve filled the cup with espresso. If you put the milk in the cup first, and then added the espresso, all your beautiful froth would be gone! So the order in which we do things are very important.
This is also perhaps best illustrated with origami. Have you tried folding an origami horse before? If not, you should google the instructions and give it a try! If you’re not careful, you might end up with a horse looking like a dog (because the neck’s too short), or a horse looking like a giraffe (because the neck’s too long). Once again, solving a problem isn’t just about carrying out the things that need to be done. It’s about identifying where and when we must do certain actions. A small mistake in the step could lead to a very different outcome.
4. Step 4: Reviewing and Refining the Solution
One thing we must be more aware of is the fact that since algorithms are all around us (whether as policies, workflows, standard operating procedures (SOPs), or as computer systems that manage our lives). They are so tightly intertwined with our day-to-day living, that we aren’t just solving technical problems all the time. For this reason, it is not enough to just solve a problem. What is just as important is HOW we solve the problem. This then brings up the whole issue of societal and ethical problems stemming from the uncritical use of our computational thinking solutions.
Let’s return to the elderly monitoring system I’ve been talking about in this chapter. We started off designing a system to detect whenever something happens to grandma. Perhaps we could send notifications to her children’s and grandchildren’s smartphones if anything happened. This will allow the younger generation to take care of grandma especially when they’re so busy working and studying. If anything happens, they will get a notification, and they can come to her aid.
But what about when grandma’s ok? What will the smartphone do? Absolutely nothing? What are the societal implications of such a system? Well, for one, if we become carelessly over-reliant on such a technology, it is quite likely that we will adopt the mentality that as long as we have a system monitoring her, we don’t need to visit her so regularly. We have the notifications to alert us.
Here’s the bigger problem. Essentially, we have reduced grandma into a smartphone app or a Tamagotchi. Have you played with a Tamagotchi before? It’s a little electronic pet. At the beginning, kids go crazy with it, caring for it all the time. But as the weeks go by, we become bored with it. Many just leave it in their bags, only to take it out when it beeps to alert us that it’s hungry or it has soiled itself. Otherwise, it remains in our bags and we forget about it as if it didn’t exist. This is precisely the danger that awaits grandma. How we will interact with grandma over a smartphone app can turn out to be like a Tamagotchi if we aren’t careful with its implementation and its processes.
While technology doesn’t make us neglect grandma, one thing technology is good for is that it facilitates human laziness. If all the sensors work well, then we might become so over-reliant on the system that we stop visiting grandma. Now, that’s some food for thought. We have created a solution but created a new problem!
So, implementing a solution isn’t just about where and when to execute our tasks. What is just as important is HOW we do it. Where problems concern humans, we can do things in a dehumanising way, by treating us like a what rather than a who. Or we could do it in a way that respects humans as humans.
This then brings us back to Step 1. Part of why our solutions can be so dehumanising is because of the way we define the problem we want to solve. It often happens that when we get too obsessed with solving a problem, we end up narrowly defining it in such a way that it does just that: it solves it but forgets about everything else that’s part of the picture. If we broaden our definition of the problem beyond its purely technical aspects, and enrich our understanding with perspectives from other disciplines, we can develop a more holistic solution, one that does not reduce grandma or anyone else into a Tamagotchi.
This is the danger of solving problems in the abstract. It’s important that we do not be content with a solution that merely works. Today, it’s important to also consider how it works, whether it works well, and its ramifications on us. These things are never obvious (if it were, it wouldn’t be a problem).
Hence, there is a need to always look back and review our solutions, and even the way we approached it from the start: Have we solved the problem well, or have we created a new problem? How can we solve it better?
Notice how, the answers to these questions are questions that forces us out of the Computational Thinking mode of problem solving. Once we begin asking such questions, we need to extend out of this discipline and reach out to the other disciplines to richly inform our worldview to broaden our horizon on the matter.
5. Our Solutions are a Reflection of Who We Are
5.1 Experiential Learning with Machine Learning
If you have never wrote a computer programme before, a quick and easy way to get your hands dirty would be to engage in some Machine Learning (ML). Go to https://machinelearningforkids.co.uk/, click on “Get Started,” and click on “Try it now.”
Despite the name, “Machine Learning for Kids,” this website links you to a very powerful supercomputer, the IBM Watson. It’s a supercomputer that understands the English language very well. It has won many game shows, and it is trusted by many specialists in making decisions on their behalf. In fact, some doctors rely on Watson to diagnose their patients!
The good thing about this machine learning exercise, is that we can have a fully (dis)functional machine without having to do any programming whatsoever.
So here’s a scenario for you to try. Imagine that your a systems developer for your local taxi company. To improve the quality of service of your taxi drivers, you want to create an artificial intelligence (AI) that will automatically rate your drivers.
To get started, click “Add a new project,” give the project a name, and select it to recognise “text.” After that, you will be shown a list of projects. Click on the project you just created, and click “Train.” Once you’re in there, click “Add new label,” and create three categories:
(1) Excellent driver
(2) Mediocre driver
(3) Lousy driver
Once you have done that, add examples into each category to teach the machine. The great thing about machine learning is that it tries to figure out patterns on its own. We don’t have to figure out the patterns ourselves. Try to do this activity as strategically as possible. Apply decomposition to each category of driver. What makes a driver excellent, mediocre, and lousy? And then come up with as many examples as you can, that are representative and exhaustive of those qualities. (You need at least five examples for each category before you can begin teaching IBM Watson)
When you have completed that, click “Back to project,” click “Learn & Test,” and then click “Train new machine learning model.” This will take about 2 minutes. When it’s done, you can test it by typing other examples to see if it evaluated it rightly. What you should do is to try to find ways that the machine is wrong. And once you found those, go back to add more examples to rectify the problem. If the machine gives you an answer with 0% confidence, it means that you neglected to teach it about that issue. If the machine gives you an unexpected result, it means that there’s something wrong with your examples.
Do not continue reading until you are done refining your machine!
If you are confident with the answers your machine gives you, try the following test cases:
(1) Driver is polite
(2) Driver molested me
(3) Driver is chatty
(4) Driver drives fast
Were the results unexpected?
5.2 Learning Points from this Activity
What can we learn from this activity? Some of you may have done it and thought to yourself: this website must be a sham! But let me assure you, you are having the real experience of machine learning, the experience that people are not talking enough about.
First, “mediocre” is a very difficult category. Why’s that the case? Why is it so much easier for us to define and give examples of the extremes, but so difficult for us to define something so-so, meh, or average? There’s actually a good explanation for this. Did you know that the etymology for the word “definition” comes from the Latin verb, “definire,” which is to set the boundaries to something. When you define something, you are setting the boundaries, the limits (or the extremes) of things. It’s easy to definite excellent driver, because these are qualities that are not-lousy. And so too for the other extreme, the lousy driver. Mediocrity is difficult to define and difficult to find examples for, simply because it is just not here, not there. How do you set boundaries for something that isn’t here nor there? This has implications for many things.
Imagine that you didn’t read this and went ahead creating an AI machine to automatically rate taxi driver, would you have included a mediocre/average category? Chances are, you would not. Partly because it didn’t occur to you, but also because it’s really tough to define it. Now, imagine the consequences if we were to have a taxi driver AI rating system that doesn’t have such a middle category. Every driver is either excellent or lousy. That is quite extreme. Can you imagine the social ramifications of such an implication?
The second lesson is that ALL computational solutions (SOP, processes, algorithms, and even AI) are reflections of who we are. They reflect our biases, our ignorances, and our level of maturity in thought. If you programmed the machine to learn rubbish, like only evaluate the driver based on how good/bad s/he smells, then the machine is only an expert at evaluating based on smells. It’s a nonsensical programme, but only because of the rubbish we gave it. This is what computing folks refer to as: Garbage In, Garbage Out.
If you think chatty drivers are awful, you would have taught your machine to evaluate them as lousy drivers. If you think fast drivers are great, you would have taught your machine to evaluate them as excellent drives.
How about the other two test cases? “Driver is polite” and “Driver molested me.”
When I taught this in my classes, some groups’ machines yielded a 0% confidence level to “driver is polite.” This is a reflection of the group’s neglect of politeness as an important evaluation criteria.
Some groups had machines that gave unexpected answers, like a polite driver is a lousy driver, or “driver molested me” is an excellent driver! (Did this happen to you?)
Why was this the case?
Was the AI supercomputer broken? Absolutely not! Rather, the supercomputer merely took your examples and brought them to a logical conclusion. In some ways, this is rather scary. Could we be citing examples where we ourselves are simply ignorant of their implications or logical consequences? Or could we have taught the machine a pattern that we ourselves didn’t see, but would have disagreed strongly with it? Are we blinded by our own biases (confirmation bias) to see where our own examples were heading towards?
If you’re wondering whether it’s because you’re not experts working on AI, let me assure you that it happens even to the best developers out there. Facebook recently had an embarrassing situation where, on America’s Independence Day, it began censoring the American Declaration of Independence as their machine learning AI saw it as hate speech. (https://www.theguardian.com/world/2018/jul/05/facebook-declaration-of-independence-hate-speech)
I hope this activity was insightful. This is in fact the dark side of algorithms and AI that most people don’t talk about very much. It is super apparent to us only because we’re new at it, and therefore bad at making it work so well. But the truth is, even with the best developers around, their ugly biases and ignorances will reveal themselves from time to time.
Speaking about ugly biases, IBM Watson seems to have an encoded gender bias. One of my students found that whenever you use the masculine pronoun, IBM Watson would rate the driver as excellent. But if you put in a feminine pronoun for the same sentence, IBM Watson would rate the driver as lousy. (Give it a try!) If you think this sounds far-fetched, Fortune Magazine has an interesting story about how Amazon killed their AI Recruitment System because it constantly discriminated against women. (http://fortune.com/2018/10/10/amazon-ai-recruitment-bias-women-sexist/)
Unexpected answers is part of the surprise that AI brings. The scary thing about it is that it is often left unaudited for two reasons: One, a lot of AI is black boxed, so you can’t audit the machine’s train of reasoning, and two, even if you have an AI that can be audited, the amount of info is just too vast, most people don’t know how to sieve through it to even make sense of it.
But let’s not get too focused on AI. Everything that I said above is also applicable for traditional algorithms, and that includes standard operating procedures (SOPs), workflows, policies, and more! The problems mentioned above are all present for anything that is a step-by-step solution, or even a decision criteria!
6. The Politics of Algorithms
How we make decisions about things is itself an algorithm. To be precise, it is a set of nested IF-THEN-ELSE statements. Most times, a set of IF-THEN-ELSE conditions are pretty innocent. But that’s because we tend to look at it removed from the context in which it is applied.
Take the USA Bank Housing Loan policy in the 1930s. It has a very innocent decision algorithm:
IF loan applicant lives in poor residential area
THEN mark applicant as having a high risk on defaulting on loans
ELSE mark applicant as having a low risk on defaulting on loans
This may seem like an innocent algorithm that would seem to make sense. Here’s the next decision algorithm (is it still innocent to you?):
IF loan applicant has a low risk on defaulting on loans
THEN approve loan application
ELSE reject loan application
Again, does this look innocent to you? What if I told you that in the 1930s, minority ethnicities all lived in poor residential areas? This means that almost every applicant from a minority race was denied a housing loan. Fast forward to where we are today, and the majority of homeowners are – you guessed it – white Americans. Most people of colour in the US are still stuck in poor neighbourhoods (and they don’t even own a home: they can only rent it).
Algorithms don’t just reflect our own biases, they encode the biases we have (intentionally or not) to emend systemic biases that unjustly deny opportunities to people.
But here’s the thing about algorithms. Algorithms aren’t people. Yet algorithms can and do in fact exert power over people. They aren’t agents but they possess agentic properties that exert a political, sociological, and ethical influence on us. And we often don’t pay attention to things like this. Let’s say you’re visiting an area in Singapore that you have never visited before, and you’re now very hungry. These days, the first thing we do is to go on Google and search for places to eat in the area – and no surprises here – we often choose the eatery we find on the first search result.
We do things like this all the time, unquestioningly. But why should we take it for granted? Why was I presented with those few results at the top? An algorithm has somehow decided that those few posts are the ones of utmost relevance to you. But in doing so, it has also decided what information are irrelevant to you, and have cut them out from your world view (or put so far down on the search results that you won’t see it).
How does this shape how we see the world, understand ourselves (or others), or make our own decisions? I can’t (and won’t) cover this in detail, but I do invite you to think through these issues yourself, and maybe do more readings about it.
6.1 Case Study 1: Grab’s 5-Star Rating System (How Algorithms Carry Over into Policies)
Let me spur your thoughts with this interesting case study. If you have taken a Grab ride, you’d be familiar with the driver rating system. At the end of your ride, you’ll be asked to rate you driver, and your rating will affect their total rating. The driver rating is helpful for passengers to decide whether or not to ride with the driver (just like every other review system on the Internet).
Suppose you took a ride, and you got to your destination without dying. The driver wasn’t annoying, but the driver wasn’t very friendly either.
How would you rate your driver?
Some people give 3 stars by default, and give additional stars if the driver makes the effort to be nice. To these people, 3 stars is in the middle, and it would indicate a neutral rating.
Some people give 4 stars by default, and give the additional fifth star if the driver does something incredible, as a bonus grading.
Some people have a more binary approach to this, giving 5 stars by default, and give 1 star instead if the driver does something bad.
Notice how everyone uses a very different standard? On a whole, this still seems fine. But what happens when the people who decide on policy have a narrow way of thinking? So how does Grab interpret the 5-star system?
Did you know that every time you give a driver 4 stars or less, the driver’s job is at stake. If you read the Grab driver’s FAQ page, drivers are required to maintain an average rating of 4.8 and above. (https://www.grab.com/sg/blog/driver/thank-lucky-star-rating-grabs-star-rating-works/) That’s essentially 5-stars for almost every ride!
If they’re below 4.8, they will receive a warning. The moment they hit a rating of 4.3, they lose their jobs! (https://cdn.grab.com/sg/wp-content/uploads/sites/4/2017/03/Annex-A-and-B-1.pdf)
According to their website, 50% of drivers have a rating of >4.8. But this is a very skewed statistic. Bad drivers aside, if a decent driver keeps getting customers who give 3 stars by default, they either give up working for Grab (because there’s no way to pull up their rating fast enough, or worse, no way to pull up their ratings at all if they happen to live in a neighbourhood of 3-star-givers), or they get fired eventually.
Is the 5-star rating system a good system for making policy or managerial decisions? If everyone thinks the same way, yes. But as we’ve discovered in our little class discussion, everyone has their own standard for 5-stars.
But let me complicate things a little… If you pay attention to the way most males and females in Singapore think, there is a pattern to the way the different genders rate their drivers. In general, most men will give 5 stars to their drivers as long as the ride is decent, and 1 star if anything upsets them. Conversely, most women will give either 3 or 4 stars by default, and will have some additional requirement before giving 5-stars to the driver (e.g. driver must chit chat to get the 5-stars).
What will drivers do when if become aware of such patterns of rating? If they want to game the rating system to earn bonuses, the more sociable drivers will be compelled to make chit chat with female passenger in order to get a good rating. The more socially awkward ones will simply not pick up female passengers knowing they will get a 3 star rating.
Notice how, as a consequence of the algorithm, the behaviour of drivers are shaped in the process. What seems like an innocent measure of a driver has become something that feedback into the driver’s psyche and changes the way drivers behave. Did our computational solution actually solve a problem, or did it create a new reality that looks like it solved the problem?
By the way, the same is true for all rating systems like the one for toilet cleaners in Changi Airport. If you give anything less than 5-stars, they’ll be in trouble. Likewise for social media like Facebook, Instagram, etc. Innocent metrics like the number of “likes,” or followers can affect the way we perceive ourselves, how we think and act. How do these rating systems change our behaviours?
6.2 Case Study 2: Is Netflix Actually Recommending You Shows to Watch or Changing Your Tastes in Shows?
Here’s another case to consider. For a very long time, Netflix has been trying to come up with a system that can accurately predict your tastes in movies and do a better job recommending you shows. (At the moment their algorithm functions like this: http://www.wired.co.uk/article/how-do-netflixs-algorithms-work-machine-learning-helps-to-predict-what-viewers-will-like)
The movie recommendation algorithm is itself an attempt at understanding our taste in shows, so as to recommend us shows that we might like to watch. But it’s worthwhile to consider: is the Netflix recommendation system actually predicting the kinds of shows you might like to watch, or is it slowly altering your own preferences in shows and movies (i.e. changing the reality)?
Here’s an anecdotal example. I’ve been watching anime on Netflix quite a lot. I started out watching “No Game, No Life” a show where two siblings were taken out of their home world and placed in a different world. The next show it recommended (and I watched) is based on the same premise: a person is taken from his home world and placed in a different world. After that, every anime that Netflix recommends me is a show involving some person put in a different world (you have no idea how many shows are like that). Have you noticed this happening with your own Netflix experience? Have you noticed something similar going on with your online shopping experience?
The same can be said about all your preferences on Facebook, Instagram, Twitter, YouTube, Tinder, etc. There’s been a lot of discussion about echo chambers creating extremists. How much of it is due to the self-reinforcing cycle of such systems biasing certain outcomes?
The moral of the story is this. Not all algorithms, models and systems are innocent. We need to be aware of how they change our own preferences, desires, and behaviours. In the old days, technical problems were just technical problems. It didn’t matter how you resolve those problems. All is good as long as you can get the job done. But in this day and age, where technology is becoming more closely intertwined with humanity, we cannot simply think of problems as merely technical problems. It’s not just the results that matters, but how we do it. Because how we do it can result in processes that support specific outcomes and shape reality in ways that we did not intend.
Once we recognise how algorithms can have a political, societal, or ethical effect on us, it’s worth considering: can algorithms be pseudo-scientific? There is something scary about this because algorithms are usually not subject to the same kind of academic rigour as scientists go through. You don’t see computer engineers having their codes peer reviewed by experts the same way social science models are peer reviewed. And if we bear in mind the great challenges in conducting social science research, it’s worth considering whether or not these computational solutions are pseudo-scientific.
Is it possible to subject these algorithms to greater scrutiny? How might we go about with it?
8. Monolith versus Modularity
Whether you’re trying to understand a problem or solve it, the conceptual tools presented above can allow you to divide a problem into very small parts, or modules, that you can then slowly solve on your own piece-by-piece, or you can then divide the work up to share it with others in your team (or outsource it).
On the other hand, the brute force problem solving method tends to treat problems as a singular whole, or a monolith. One interesting phenomenon that you will find in the working world is that there are many people (especially team leaders) who don’t know how to divide work up for their subordinates or colleagues to work together (or if they do share, they only get others to do the mindless tasks). Even in universities, where there are group projects, there are some who end up doing everything and are unable to divide the work. More often than not, it’s not that they don’t want to divide the work. Rather, the reason why they do everything by themselves is because they don’t know how to split up the work. This comes from not knowing how to break the problem down into smaller modules using the conceptual tools of computational thinking. Without the tools of decomposition and/or identifying primitives, all one sees is a huge ball of mess where everything seems connected to everything.
This might seem to suggest that modularity is the best approach to all problems. And this is the prevailing attitude amongst many people who are well-versed with such the problem-solving techniques of computational thinking.
The beauty of modularity is that it helps us with the design of robust systems. If you can modularise your solution, you can easily create back-up plans or easily replace modular components when things go wrong. For example, it’s a lot easier (on the wallet) to replace the hard disk if your hard disk broke instead of buying a new computer. Or you can easily produce customisable solutions by swapping out specific modules with other more relevant ones for your clients.
Many car manufacturers have also gone with this option. If a component in your car became defective, it’s a lot easier to replace an entire module. Almost anyone can do it. You don’t need an expert to diagnose and find the defective component and do a lot of time-consuming and expensive repairs.
A lot of human organisations utilise modularity as well. Organisations are comprised of departments and smaller units. The army is perhaps a good example of this. We have modules within modules within modules. The big modules are the army, air force, and navy. Within the air force are several commands, and within each command are several squadrons. If a squadron is destroyed, the air force can continue operation as there are other similar squadrons that perform similar tasks. One of these squadrons can take on the new assignment with ease.
The real beauty of modularity is that it links to the idea of robust systems. When we can modularise our solution, we can create redundant solutions, or even have modular backup plans. Going back to the hot date discussion in tutorial, if you one of the activities in the date is to go to the beach, we can treat the beach activity as a standalone module. If it rains, instead of emo-ing over the fact that the plan has been ruined, we can swap in a different module activity. But this works only insofar as you design your activities as standalone modules. If you design everything to be related to everything, e.g. eating and movie watching must be done at the beach, then you cannot easily create a modular solution. If it rains, your entire plan would be ruined.
However, modularity does have its limits, and it’s important for us to assess when modularity might be a bad idea. Modularity can be quite problematic as well. It’s not the perfect solution to everything. The healthcare system is an example where efforts are now being made to DE-modularise it. Modularisation does indeed create efficiency: the heart department has all it needs to do heart-related things, the eye department has all it needs to do eye-related things, etc.
But in recent years, hospitals have discovered how such a modular setup can be highly detrimental. Many times, patients require surgery that involve resources from more than one department, and they are pushed from one operating theatre to the next. Many die while being pushed along the corridors. The healthcare system in Victoria, Australia, has since been reformed to become more monolithic in its structure. Singapore is trying to follow-suit now. But the move towards less modularity in health systems will present its own sets of advantages and disadvantages.
A similar case study will be the university, where professors and students are split up according to their faculties and departments. So the computing people will study and research computing solutions, while the philosophy people will study and research on ethical problems. One downside is that these people rarely talk to each other. Cross-disciplinary work is rarely done because it’s not part of a departmental key performance indicator (KPI). Similarly, most computing students will not take philosophy modules, nor will most philosophy students take computing modules. This is largely why we don’t encounter enough work done on the ethics of algorithms and apps, etc. This is one of the great downsides of modularity that we have to be aware of.
Similar problems of modularity can be found across so many other organisations. Have you ever had a problem that didn’t quite fit a particular department? If you call that organisation’s hotline, you’ll find yourself being forwarded from one department to the next. It’s not that no one wants to handle your case. Rather, the modular design of departments do not allow for departments to handle cases beyond their modular purposes.
Modularity can be a double-edge sword. While modularity is often conceived in terms of solving specific problems (as part of a bigger problem), we need to factor in extra considerations about the potential disadvantages and what we will lose out in the process of modularising, especially when it concerns the organising of humans. While it can be efficient in terms of the use of resources and for reaching specific goals, those modular teams may not be able to achieve other goals having since lost that synergy with other teams.