Tag: technology

  • 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

  • Why Shouldn’t the Idira (CyberArk) Digital Vault Be on the Same Network as Everything Else?


    If you’ve worked with Idira (formerly CyberArk) for a while, you’ve probably heard this recommendation before:

    “The Digital Vault should not be joined to the domain and should be isolated from the corporate network.”

    Most people simply accept that recommendation because “it’s in the documentation.”

    But sooner or later, almost every customer asks the same question:

    “Why?”

    Honestly, it’s a fair question.

    At first glance, it doesn’t seem to make much sense. After all, every other server in the environment lives happily inside the corporate network. Why should the Vault be treated differently?

    The answer becomes much simpler if we stop thinking of the Vault as just another server.

    It’s not really a server…

    Imagine you own a bank.

    Inside the building, you have computers, printers, employee desks, meeting rooms, and ATMs.

    Now think about where the money is kept.

    It isn’t sitting next to someone’s desk.

    It’s locked inside a heavily protected vault, separated from everything else.

    The reason is obvious.

    If someone manages to enter the building, you don’t want them to immediately reach the place that contains the most valuable assets.

    The Digital Vault follows exactly the same idea.

    It stores the credentials that protect your entire organization.

    Administrator passwords.

    Service accounts.

    Application secrets.

    Certificates.

    Encryption keys.

    Audit information.

    In many environments, if someone gains full control of the Vault, they can potentially gain access to almost everything else.

    That’s why it deserves a different level of protection.


    What happens if everything lives together?

    Imagine a company where the following servers all share the same network:

    • Active Directory
    • SQL Server
    • File Server
    • Web Servers
    • PVWA
    • CPM
    • PSM
    • Digital Vault

    Everything looks organized.

    Everything communicates easily.

    Everything is simple.

    Now imagine a web server gets compromised because someone forgot to install a security update.

    It happens every day.

    The attacker now has a foothold inside your network.

    From there, they begin exploring.

    They scan the network.

    They identify other servers.

    They try connecting to different services.

    They attempt lateral movement.

    Eventually, they discover the Digital Vault.

    Now, to be clear, discovering the Vault doesn’t mean they’ve compromised it.

    The Vault was specifically designed to resist attacks.

    But here’s the important point:

    Why make it easier for an attacker to even find it?

    Security isn’t only about building strong walls.

    It’s also about making those walls harder to reach.


    Security is about reducing opportunities

    One lesson I’ve learned working with PAM solutions is that good security isn’t only about blocking attacks.

    It’s about reducing the number of opportunities attackers have.

    Think about your own house.

    You probably lock your front door.

    But you probably also close your windows when you leave.

    Not because you expect someone to break in every day…

    …but because removing opportunities is always a good idea.

    The Digital Vault follows exactly the same philosophy.

    Instead of allowing every server in the company to potentially communicate with it, only a very small number of systems should ever know it exists.

    Less visibility.

    Less exposure.

    Less risk.


    Why doesn’t the Vault join the Active Directory domain?

    This is another recommendation that often surprises customers.

    “We already trust Active Directory.”

    “So why shouldn’t the Vault trust it too?”

    The answer is actually pretty interesting.

    The Vault is designed under the assumption that one day your corporate infrastructure could be compromised.

    Notice I didn’t say will.

    I said could.

    Because that’s exactly how security architects think.

    If an attacker gains Domain Admin privileges, they can usually control almost every Windows server in the environment.

    Group Policies.

    Authentication.

    Administrative access.

    DNS.

    Certificates.

    All of these become potential attack paths.

    By keeping the Vault outside the domain, you’re creating one more security boundary.

    Even if the domain is compromised, the Vault isn’t automatically affected.

    It’s one less dependency.

    And in security, fewer dependencies usually mean fewer problems.


    Why avoid DNS?

    I’ll admit this one confused me the first time I read the recommendation.

    Running a server without DNS feels almost wrong.

    But then it starts making sense.

    DNS is another service your infrastructure depends on.

    If DNS is unavailable, servers may struggle to find each other.

    If DNS is compromised, traffic could potentially be redirected somewhere it shouldn’t go.

    The Digital Vault doesn’t really need dynamic name resolution.

    Its communication is very controlled and very predictable.

    Using static IP addresses and a carefully managed hosts file removes yet another dependency from the equation.

    Again…

    The goal isn’t convenience.

    The goal is resilience.


    Assume the network is already compromised

    One of the biggest mindset shifts in cybersecurity is this:

    Don’t build your defenses assuming nothing will ever go wrong.

    Build them assuming something eventually will.

    That’s the philosophy behind many modern security frameworks, including Zero Trust.

    The Digital Vault follows that same mindset.

    If someone compromises a workstation…

    the Vault should still be protected.

    If someone compromises Active Directory…

    the Vault should still be protected.

    If someone compromises DNS…

    the Vault should still be protected.

    It’s not about distrust.

    It’s about planning for bad days.


    The Vault isn’t isolated because it’s fragile.

    It’s isolated because it’s valuable.

    That’s a very important distinction.

    Sometimes people assume isolation exists because the Vault can’t handle attacks.

    Actually, it’s almost the opposite.

    The Vault is one of the most hardened components in the entire PAM solution.

    The isolation exists because it protects the most valuable secrets in your organization.

    And when something is that valuable, giving it an extra layer of protection simply makes sense.

    Just like we don’t keep cash in the reception area of a bank…

    we shouldn’t treat the Digital Vault like an ordinary server.


    Final thoughts

    One thing I really like about the Idira (CyberArk) architecture is that many of its recommendations stop making sense if you only look at them individually.

    Don’t join the domain.

    Avoid DNS.

    Isolate the Vault.

    Restrict network access.

    At first, they can seem overly cautious.

    But once you step back and think about what the Digital Vault actually represents, the picture becomes much clearer.

    It isn’t just another server.

    It’s the place where the keys to your entire infrastructure are stored.

    And if there’s one lesson security has taught us over the years, it’s this:

    The strongest lock in the world doesn’t help much if you leave the vault in the middle of the lobby.