Computational Thinking: Learning to Solve Problems Before Writing Code

In the past, when I first heard the expression computational thinking, I immediately associated it with programming.

I imagined algorithms, programming languages, loops, functions, variables, and all the things we normally connect with software development.

But while studying the subject, I realized something much more interesting:

Computational thinking is not really about learning how to code. It is about learning how to structure a problem.

And that distinction matters.

You can use computational thinking, for example, before writing a PowerShell script, while troubleshooting an application, when designing an automation, when investigating an incident, or even when solving problems completely unrelated to computers.

The material I was studying describes computational thinking as a tool for understanding how computers work, designing software, and solving problems. It also emphasizes something important: understanding what computers can and cannot do.

So I started asking myself:

What does it actually mean to think computationally?

This article is my attempt to explain what I learned in the same way I would explain it to a colleague sitting next to me.


First, forget the computer for a moment

Suppose I tell you:

“The application is not working.”

What would you do?

You could immediately start checking logs, restarting services, testing the network, looking at the database, checking credentials, inspecting certificates, and opening configuration files.

But there is a problem.

You still do not really know what problem you are solving.

“The application is not working” is not a technical diagnosis.

It is only a description of a symptom.

Computational thinking encourages us to transform this vague statement into something structured.

For example:

Application is not working
|
+-- Is the server reachable?
|
+-- Is the service running?
|
+-- Is authentication working?
|
+-- Can the application reach its dependency?
|
+-- Is the expected response being returned?

Suddenly the problem becomes much easier to reason about.

That is where computational thinking starts.


A computer is extremely fast, but extremely literal

One of the ideas that helped me understand this topic is surprisingly simple.

Computers are incredibly good at executing instructions.

But they need sufficiently precise instructions.

The document explains an algorithm as a sequence of logical steps created before those steps are translated into a programming language.

The example used in the material is calculating BMI.

The algorithm is basically:

1. Ask for the person's weight
2. Ask for the person's height
3. Calculate BMI
4. Display the result

Only after defining that logic do we translate it into Java, Python, PowerShell, or another programming language.

That gave me a useful mental model:

The algorithm is the solution. The code is one implementation of that solution.

This sounds obvious, but it changes how we approach scripting.

Instead of opening PowerShell and immediately typing:

foreach (...)
{
...
}

we can first ask:

What exactly am I trying to accomplish?
What information do I need?
What decisions must be made?
What should happen if something fails?
What should the final result look like?

Only then do we write the code.


The four ideas I use to think about a problem

While learning computational thinking, I found four concepts particularly useful:

decomposition, pattern recognition, abstraction, and algorithms.

The document explicitly discusses decomposition and data abstraction as important techniques when computational thinking must scale to increasingly complex problems.

I like to translate the four ideas into very simple questions:

Break it. Compare it. Ignore the noise. Define the steps.

Let me explain.


1. Decomposition: break the problem into smaller problems

Imagine that I receive this task:

“Create an automation that changes a password on a remote system.”

That sounds simple.

Until we start looking more closely.

We can decompose it:

Password Management
├── Receive account information
├── Retrieve current credential
├── Connect to target system
├── Authenticate
├── Generate or receive new password
├── Change password
├── Validate new password
├── Handle errors
└── Log the result

Now I no longer have one big problem.

I have several smaller problems.

And smaller problems are much easier to understand, test, and troubleshoot.

Interestingly, the document also discusses decomposition in the context of software architecture: architecture defines components and their interactions, and decomposition is described as an indispensable tool for identifying those parts.

This made something click for me.

Decomposition exists at many levels.

We can decompose:

a problem
a solution
a system
components
functions
instructions

That is essentially how complexity becomes manageable.


2. Pattern recognition: have I seen this before?

Suppose a PowerShell script works with most passwords but fails with some of them.

At first the failures appear random.

Then I collect examples:

Password ABC123! → works
Password Hello2026! → works
Password My*Password → fails
Password Test*123 → fails

Now something interesting appears.

There is a pattern.

The failures are associated with *.

Instead of investigating:

“Why does PowerShell randomly fail?”

I can ask a much narrower question:

“How is the * character being interpreted when this command is constructed?”

That is a dramatically better problem.

Pattern recognition is useful because many technical problems are repetitions with small variations.

For example:

Server A fails after certificate renewal
Server B fails after certificate renewal
Server C fails after certificate renewal

The shared characteristic deserves attention.

Or:

Account A works
Account B works
Account C fails
Difference:
Account C belongs to another domain

Again, we have a clue.

For me, pattern recognition in troubleshooting means continuously asking:

What is common between the failures, and what is different between successful and unsuccessful cases?


3. Abstraction: what actually matters?

This one was initially less intuitive for me.

I used to think abstraction was mainly an object-oriented programming concept.

But it is much broader.

Imagine that I am troubleshooting an authentication problem, and I have this information:

Server: APP01
Operating System: Windows Server 2022
CPU: 23%
Memory: 51%
Disk: 62%
Datacenter: Amsterdam
Application version: 4.2
Authentication: Failed
Account status: Locked
Wallpaper: Company Standard

Do I need all this information?

Probably not.

For the problem I am currently investigating, I might reduce the model to:

Authentication request
Account
Locked?
Credentials valid?
Permissions correct?

That reduction is abstraction.

I am deliberately hiding information that is not currently useful.

The study material explains that software design itself relies on abstractions: architecture, data structures, interfaces, and components are models of the system that exist before they are represented in code.

That helped me understand abstraction differently.

Abstraction is not about ignoring reality.

It is about creating a useful representation of reality for the problem we are trying to solve.


4. Algorithms: define the procedure

After decomposing the problem, identifying patterns, and removing irrelevant information, we need a procedure.

That procedure is our algorithm.

For example, imagine a script that checks whether a Windows service is running on 100 servers.

Before writing PowerShell, we can define:

Get list of servers
For each server:
Test connectivity
If unreachable:
Record "Unreachable"
Continue to next server
Check service
If service is running:
Record "OK"
Otherwise:
Record "Service stopped"
Generate report

That is already most of the intellectual work.

The PowerShell implementation becomes the translation of that reasoning into syntax.

The source material makes the same distinction: an algorithm defines the logical steps, and afterward those steps are converted into code that a computer can interpret.


Let us solve a real troubleshooting problem

Suppose I receive the following incident:

“The automation stopped changing passwords.”

This is exactly the kind of statement that can send us in twenty different directions.

Instead, I can apply computational thinking.

Step 1: Decomposition

First, I divide the operation:

Input
Retrieve credentials
Connect
Authenticate
Build command/request
Execute
Receive response
Validate
Log result

Step 2: Find the boundary of the failure

Now I test each stage.

Input ✓
Retrieve credentials ✓
Connection ✓
Authentication ✓
Build command ✓
Execute command ✗

This is one of my favorite troubleshooting techniques.

Instead of asking:

“Why does the automation not work?”

I can now ask:

“What is happening between command construction and command execution?”

My search space has become much smaller.

Step 3: Look for patterns

Maybe successful executions use passwords like:

Secret123!
Password2026@

while failures use:

Secret*123

Now I have a hypothesis.

The special character may be changing how the command is interpreted.

Step 4 — Create a test

I do not need to investigate the entire production workflow.

I can build a small test:

Input password containing *
Construct command
Print or inspect command safely
Execute
Observe result

We have now transformed a large operational incident into a controlled experiment.

This is computational thinking in practice.


Complexity is the real enemy

Another part of the document that caught my attention was its discussion about complexity.

It states that managing complexity is one of the most important technical concerns in software development.

It also describes three bad situations:

Complex solution → simple problem
Simple but incorrect solution → complex problem
Complex and inappropriate solution → complex problem

The important observation is that the underlying problem may already be complex, but we can still accidentally add unnecessary complexity through our solution.

I think this is extremely relevant outside software engineering too.

Imagine a requirement:

“Once per day, retrieve a file from a server.”

We could design:

Kubernetes
Microservices
Message Queue
Database
Multiple APIs
Monitoring stack

Technically impressive.

But maybe all that was actually required was:

Scheduled PowerShell script
Retrieve file
Validate
Log result

Computational thinking is not about creating the most sophisticated solution.

It is about creating an appropriate solution.


This changed how I think about requirements

There is another interesting connection here.

Engineering is not simply receiving a request and implementing exactly what was requested.

The document describes engineers as people who have to consider users, stakeholders, technical possibilities, cost, and sometimes conflicting objectives in order to create a practical solution.

That is an important lesson.

Suppose somebody asks:

“Can you create a script that restarts the service every hour?”

The easiest response would be:

“Sure.”

But computational thinking encourages another question:

Why does the service need to be restarted every hour?

Maybe the restart is not the requirement.

Maybe it is a workaround for:

memory leak
network timeout
authentication expiration
application bug
dependency failure

If we automate the restart without understanding the underlying problem, we may simply automate the symptom.

This is where technical work starts becoming engineering.


Thinking in the small and thinking in the large

Another concept from the study material that I found useful is the distinction between:

thinking in the small

and

thinking in the large.

For a small script maintained by one person, relatively simple reasoning may be enough.

But once the solution grows:

1 developer
5 developers
multiple teams
many components
thousands of users
years of maintenance

the nature of the problem changes.

The document explains that when software grows in scale and teams become involved, additional practices are required. Computational thinking expands into techniques such as decomposition, abstraction, encapsulation, information hiding, project management, and software lifecycle management.

This is interesting because it shows that the solution that works for a small problem does not necessarily scale to a large one.

A 50-line PowerShell script might be perfectly understandable as:

Input
Logic
Output

A 5,000-line automation may require:

Configuration
Authentication module
Connection module
Business logic
API module
Validation
Logging
Error handling

Same goal.

Different scale.

Different way of thinking.


A simple framework I want to start using

After studying this topic, I created a small checklist for myself.

Whenever I face a technical problem, instead of jumping directly into commands or code, I want to write:

PROBLEM
What exactly is happening?
EXPECTED RESULT
What should happen instead?
DECOMPOSITION
What smaller parts make up this problem?
PATTERNS
What works?
What fails?
What is common between the failures?
ABSTRACTION
Which information is relevant right now?
What can I ignore temporarily?
ALGORITHM
What sequence of tests or actions should I perform?
VALIDATION
How will I know that the problem is actually solved?

There is also one question I find particularly powerful:

At what exact point does the behavior stop matching what I expected?

For example:

Input
Connection ✓
Authentication ✓
API Request ✓
API Response ✓
Response Parsing ✗

Now I do not have an “API integration problem.”

I have a response parsing problem.

That is a much better problem to have.


Computational thinking does not mean thinking like a computer

This may be the biggest misunderstanding I had before studying the subject.

Computational thinking does not mean turning ourselves into machines.

Quite the opposite.

Computers are extremely good at executing instructions.

Humans have to decide which instructions make sense in the first place.

The material summarizes this nicely through the relationship between input, processing, and output: information enters the system, is processed according to instructions, and produces a result.

Our role is to design that reasoning.

So today I would describe computational thinking like this:

Computational thinking is the ability to transform an unclear problem into a structured problem that can be understood, tested, and eventually automated.

Programming can come afterward.

And sometimes programming is not necessary at all.


Final thoughts

The more I study software development and automation, the more I realize that knowing commands is only part of the job.

Knowing PowerShell syntax is useful.

Knowing an API is useful.

Knowing Linux, Windows, networking, or security products is useful.

But when something unfamiliar breaks, none of us knows every command.

What remains useful is the ability to reason:

Understand
Break down
Find patterns
Remove noise
Create a hypothesis
Test
Learn
Adjust

That is probably the part of computational thinking that interests me the most.

It gives us a method for dealing with problems we have never seen before.

And for someone working with technology, troubleshooting, scripting, and automation, I think that may be much more valuable than simply memorizing another command.


Reference

This article (It has been written in Portuguese) was inspired by my study of the “Pensamento Computacional” educational material published by the Universidade Federal de Goiás (UFG). The material approaches computational thinking through computer systems, algorithms, software engineering, complexity, decomposition, abstraction, and software design.

One detail I would keep exactly as it is in this version is the curious-student voice. Instead of presenting yourself as someone teaching “the correct methodology,” the article repeatedly uses ideas such as “this made something click for me,” “I started asking myself,” and “the way I understand it now.” That makes the article fit very naturally with the conversational technical style you have been developing for your blog.

https://portaldelivros.ufg.br/index.php/cegrafufg/catalog/view/212/127/595

Comments

Leave a comment