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
| Word | What it means |
|---|---|
| Codebase | all the files of code that make up one program |
| Entry point | the file or function where a program starts running |
| Search | looking through every file for a word, with a tool such as grep |
| Caller | a line of code that uses a function |
| Call chain | the functions one call leads to, one after another |
| Test as documentation | a 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
export PYTHONDONTWRITEBYTECODE=1Shown here, not run. Create a free account to press Run and type it into your own lab’s terminal.
Make the two folders
mkdir -p ~/readcode/shop ~/readcode/testsShown here, not run. Create a free account to press Run and type it into your own lab’s terminal.
Go into the project
cd ~/readcodeShown here, not run. Create a free account to press Run and type it into your own lab’s terminal.
Write the price list
printf 'PRICES = {"tea": 250, "mug": 899, "book": 1200}\n\n\ndef unit_price(code):\n return PRICES[code]\n' > shop/prices.pyShown here, not run. Create a free account to press Run and type it into your own lab’s terminal.
Write the coupons
printf 'COUPONS = {"SAVE10": 10, "HALF": 50}\n\n\ndef discount_percent(code):\n return COUPONS.get(code, 0)\n' > shop/discounts.pyShown here, not run. Create a free account to press Run and type it into your own lab’s terminal.
Write the order total
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.pyShown here, not run. Create a free account to press Run and type it into your own lab’s terminal.
Write the 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.pyShown here, not run. Create a free account to press Run and type it into your own lab’s terminal.
Write the tests
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.pyShown 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
ls -RShown here, not run. Create a free account to press Run and type it into your own lab’s terminal.
Run it with a coupon
python3 -m shop.cli SAVE10Shown 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
grep -rn "SAVE10" shop testsShown 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
grep -rn "discount_percent" shopShown 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
| Step | File and line | What happens |
|---|---|---|
| 1 | shop/cli.py, main | The entry point reads the coupon from the command line |
| 2 | shop/orders.py, order_total | Adds up the prices, then asks for the discount |
| 3 | shop/prices.py, unit_price | Gives the price of one item |
| 4 | shop/discounts.py, discount_percent | Looks 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
grep -n "def test" tests/test_orders.pyShown here, not run. Create a free account to press Run and type it into your own lab’s terminal.
Run the tests
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?