EMFAD Courses

Module 1: Foundations

Why DSA Matters for Real Engineers

Data structures and algorithms (DSA) can seem like an academic topic, something you study only to pass technical interviews. In practice, they are the difference between a feature that responds instantly and one that freezes when your user base grows from a hundred customers to a hundred thousand. Every time you choose between a list and a dictionary, decide how to search records or design how data flows through a system, you are making a data structure and algorithm decision, whether you realise it or not.

What data structures and algorithms are

A data structure is a way of organising data so that certain operations are efficient. A list keeps items in order and lets you reach any position instantly by index. A dictionary (hash map) lets you find an item by key almost instantly. A tree keeps data sorted so you can find ranges quickly. A queue processes items in arrival order.

An algorithm is a step-by-step procedure for solving a problem: sorting records, finding the shortest route, detecting duplicates, matching payments to invoices. The same problem can usually be solved by several algorithms with very different costs in time and memory.

The two go together. Choosing the right data structure often makes the algorithm simple. Choosing the wrong one can make even a good algorithm slow.

Worked example: matching payments to customers

Suppose a utility company in Kisumu receives a daily file of mobile money payments, each with an account number, and must match them to its customer list. A first version might look like this:

def match_payments_slow(payments, customers):
    matched = []
    for payment in payments:
        for customer in customers:                # scans the whole list
            if customer["account"] == payment["account"]:
                matched.append((customer["name"], payment["amount"]))
                break
    return matched

For each payment, this scans the customer list from the start. With 1,000 payments and 1,000 customers that is up to a million comparisons, which is still quick. With 50,000 payments and 200,000 customers it is up to ten billion comparisons, which can take a very long time in Python. The code is correct; the data structure is wrong for the job.

Build a dictionary keyed by account number once, then look up each payment directly:

def match_payments_fast(payments, customers):
    by_account = {c["account"]: c for c in customers}   # one pass to build
    matched = []
    for payment in payments:
        customer = by_account.get(payment["account"])   # near-instant lookup
        if customer is not None:
            matched.append((customer["name"], payment["amount"]))
    return matched

Building the dictionary takes one pass over the customers, and each lookup takes roughly constant time on average. The total work now grows in proportion to the number of payments plus customers, about 250,000 steps instead of billions. Same result, completely different scaling. You will learn to describe this precisely with Big-O notation in the next lesson.

Where DSA shows up in everyday engineering

  • Databases: indexes are typically built on tree structures such as B-trees, which is why adding the right index can turn a slow query into a fast one.
  • Caching: a cache is usually a hash map, often combined with a linked list to evict the least recently used items.
  • Job processing: background job systems use queues, and schedulers use priority queues to run the most urgent tasks first.
  • Navigation and logistics: route planning for deliveries uses graph algorithms.
  • Autocomplete and search: prefix trees (tries) and sorted structures make suggestions fast.
  • Undo features and browser history: stacks.
  • Detecting fraud or duplicates: hash sets and sliding windows over time.

You will rarely implement these structures from scratch in production; your language and libraries provide excellent, well-tested versions. The skill is knowing what each one is good at, so you choose correctly and recognise when slow code is caused by the wrong choice.

This course uses Python for examples because it is readable and widely used, but every concept applies in any language. Install Python 3 from python.org and use any code editor to follow along.

Common mistakes to avoid

  • Thinking DSA only matters for interviews. Performance problems in real systems are very often data structure problems.
  • Optimising before measuring. Write clear code first, then improve the parts that are actually slow.
  • Implementing your own version of a structure the standard library already provides well.
  • Testing only with tiny data sets, which hides scaling problems until production.

Exercise

Copy both match_payments functions into a Python file. Generate 20,000 fake customers and 20,000 fake payments with random account numbers using the random module, then time each function with time.perf_counter(). Confirm both return the same matches, and record how many times faster the dictionary version is. Repeat with 40,000 of each and note how each time changes.

Key points

  • A data structure organises data so some operations are efficient; an algorithm is a procedure.
  • The wrong structure can make correct code unusably slow at scale.
  • Databases, caches, queues and search all rely on classic data structures.
  • Use standard library structures, but understand what each is good at.

Enjoyed this lesson?

The full course has 16 lessons with exercises, a quiz after every module, a final project and a certificate of completion. About 7 hours, USD 49, lifetime access.

Course details