Easier to read with cream paper, a tint, more contrast or larger text? Choose your colours and text, once, for every page.

Free lesson

Reading a codebase you did not write

After this lesson: I can find where a feature lives in code I did not write by following its calls from file to file.

60 min lesson14 commandsEveryday Linux commands lab: the thirty commands engineers type from memory

How to find where a feature lives

A codebase is all the code of one program. On your first day at a job you are handed one that other people wrote, with thousands of lines and no map.

Nobody reads it all. You learn to ask one question, search for the answer, and follow the calls from there.

By the end of this lesson

Note

I can find where a feature lives in code I did not write by following its calls from file to file.

Key words

WordWhat it means
Codebaseall the files of code that make up one program
Entry pointthe file or function where a program starts running
Searchlooking through every file for a word, with a tool such as grep
Callera line of code that uses a function
Call chainthe functions one call leads to, one after another
Test as documentationa test that shows, in code, what a function promises

The cells students fill in are left blank in this preview.

Start with a question, not a file

Do not open the first file and read down. Ask something small: where is the coupon discount worked out?

Look at the shape of the folders first. Run the program to see what it does. Then search for a word you can see on the screen.

Make the project first. A hidden cache folder would add noise to the searches, so the first Run turns it off.

Stop Python writing cache folders

Command
export PYTHONDONTWRITEBYTECODE=1

Shown here, not run. Create a free account to press Run and type it into your own lab’s terminal.

Make the two folders

Command
mkdir -p ~/readcode/shop ~/readcode/tests

Shown here, not run. Create a free account to press Run and type it into your own lab’s terminal.

Go into the project

Command
cd ~/readcode

Shown here, not run. Create a free account to press Run and type it into your own lab’s terminal.

Write the price list

Command
printf 'PRICES = {"tea": 250, "mug": 899, "book": 1200}\n\n\ndef unit_price(code):\n    return PRICES[code]\n' > shop/prices.py

Shown here, not run. Create a free account to press Run and type it into your own lab’s terminal.

Write the coupons

Command
printf 'COUPONS = {"SAVE10": 10, "HALF": 50}\n\n\ndef discount_percent(code):\n    return COUPONS.get(code, 0)\n' > shop/discounts.py

Shown here, not run. Create a free account to press Run and type it into your own lab’s terminal.

Write the order total

Command
printf 'from shop.prices import unit_price\nfrom shop.discounts import discount_percent\n\n\ndef order_total(items, coupon=None):\n    total = 0\n    for code, count in items:\n        total = total + unit_price(code) * count\n    percent = discount_percent(coupon)\n    return total - total * percent // 100\n' > shop/orders.py

Shown here, not run. Create a free account to press Run and type it into your own lab’s terminal.

Write the command

Command
printf 'import sys\nfrom shop.orders import order_total\n\n\ndef main(args):\n    items = [("tea", 2), ("mug", 1)]\n    coupon = args[0] if args else None\n    print(order_total(items, coupon))\n\n\nmain(sys.argv[1:])\n' > shop/cli.py

Shown here, not run. Create a free account to press Run and type it into your own lab’s terminal.

Write the tests

Command
printf 'import unittest\nfrom shop.orders import order_total\n\n\nclass OrderTest(unittest.TestCase):\n    def test_no_coupon(self):\n        self.assertEqual(order_total([("tea", 2)]), 500)\n\n    def test_save10(self):\n        self.assertEqual(order_total([("tea", 2)], "SAVE10"), 450)\n' > tests/test_orders.py

Shown here, not run. Create a free account to press Run and type it into your own lab’s terminal.

Look at the shape of the project

Command
ls -R

Shown here, not run. Create a free account to press Run and type it into your own lab’s terminal.

Run it with a coupon

Command
python3 -m shop.cli SAVE10

Shown here, not run. Create a free account to press Run and type it into your own lab’s terminal.

Search for a word you can see

The program printed 1260. The coupon was called SAVE10, and that word must be written down somewhere. grep -rn searches every file under the folders you name, and prints the file, the line number and the line.

A name on the screen is the best way into code you do not know.

Search for the coupon name

Command
grep -rn "SAVE10" shop tests

Shown here, not run. Create a free account to press Run and type it into your own lab’s terminal.

Follow the call to the next place

The search found a table of coupons in discounts.py. A table does nothing alone, so ask the next question: who uses it?

Search for the function that reads the table. One line defines it, one imports it and one calls it. The call is where the discount reaches the order.

Find every use of the function

Command
grep -rn "discount_percent" shop

Shown here, not run. Create a free account to press Run and type it into your own lab’s terminal.

Worked example: the call chain of one command

StepFile and lineWhat happens
1shop/cli.py, mainThe entry point reads the coupon from the command line
2shop/orders.py, order_totalAdds up the prices, then asks for the discount
3shop/prices.py, unit_priceGives the price of one item
4shop/discounts.py, discount_percentLooks the coupon up, or gives 0

The cells students fill in are left blank in this preview.

Read the tests to learn what code promises

A good test says what a function is meant to do, with real inputs and the answers. It is the one piece of documentation that cannot go out of date, because it fails when it does.

List the test names, then run them. If they pass, what you read is true today.

List the tests

Command
grep -n "def test" tests/test_orders.py

Shown here, not run. Create a free account to press Run and type it into your own lab’s terminal.

Run the tests

Command
python3 -m unittest discover -s tests 2>&1 | grep -E "^(OK|FAILED)"

Shown here, not run. Create a free account to press Run and type it into your own lab’s terminal.

A common mistake

Warning

Many people read every file from the top, hoping to understand it all first. It takes days and most of it is not about your question. Ask one question, search, follow the call, and stop when you can answer it.

Going further: a bigger project

Choose a project you use, with its source on your machine. Pick one thing it does, such as how it reads a settings file.

Write the question, the word you searched for and the chain of files you followed. How many steps was it?

About this lab and its source: Everyday Linux commands lab: the thirty commands engineers type from memory

Teaching a class? Set this module for your students with a teacher guide, marked assignments and a lab for every student.