# Explain inherited legacy code before you have to change it

> Get a business-level explanation of unfamiliar legacy code, its side effects, the parts that only look removable, and a safe plan for your specific change.

- **Author:** [Youssef Hassan (@youssef_hassan)](https://promptabide.com/youssef_hassan)
- **Tested on:** Claude · Opus 5.5
- **You fill in:** `code`, `change`, `level`
- **Published:** 2026-08-23
- **Updated:** 2026-09-24
- **Tags:** `coding`, `refactoring`, `learning`
- **Keywords:** explain legacy code with ai, understand old php code prompt, explain code before modifying it, chatgpt explain unfamiliar codebase, legacy code walkthrough prompt
- **Views:** 1667
- **Likes:** 27

**Best for:** Developers who inherited code with no docs and no original author, and have a concrete change to make soon.

## Prompt

```
Explain this code to me. I have to change it soon and nobody who wrote it is still here.

Code:
{{code}}

The change I need to make: {{change}}
My background: {{level}}

Give me:
1. One paragraph on what it does in business terms. Not line by line.
2. The data flow: inputs → transformations → outputs, and every side effect (database writes, locks, globals, files, network).
3. The non-obvious parts: magic numbers, ordering that matters, anything that looks removable but isn't. Say why each is probably there. If you're guessing, label it "guess".
4. For my change: which lines I'll touch, what could break, and what to check before and after.
5. Anything dangerous as it stands (security, data integrity), briefly.

Do not rewrite the code or suggest general refactors. I need to understand it, not replace it.
```

## Variables

- `{{code}}` — The code you need to understand, pasted in full (e.g. next_invoice_no() from an old PHP billing module)
- `{{change}}` — The change you've been asked to make (e.g. Add credit notes with their own CN number sequence)
- `{{level}}` — Your background, so the explanation is pitched right (e.g. Comfortable with PHP 8 and Laravel, never touched raw mysqli code)

## Example input

````
change: Add credit notes. They need their own number sequence with a CN prefix, separate from invoices.
level: Comfortable with PHP 8 and Laravel, never touched raw mysqli code.
code:
```php
function next_invoice_no($db, $branch) {
    $y = date('y');
    $m = date('n');
    $fy = $m < 4 ? ($y - 1) . $y : $y . ($y + 1);
    $db->query("LOCK TABLES invoice_seq WRITE");
    $r = $db->query("SELECT last_no FROM invoice_seq WHERE branch='$branch' AND fy='$fy'");
    $row = $r->fetch_assoc();
    if (!$row) {
        $n = 1;
        $db->query("INSERT INTO invoice_seq (branch, fy, last_no) VALUES ('$branch', '$fy', 1)");
    } else {
        $n = $row['last_no'] + 1;
        $db->query("UPDATE invoice_seq SET last_no=$n WHERE branch='$branch' AND fy='$fy'");
    }
    $db->query("UNLOCK TABLES");
    return strtoupper(substr($branch, 0, 3)) . '/' . $fy . '/' . str_pad($n, 5, '0', STR_PAD_LEFT);
}
```
````

## Output

*Produced by Claude · Opus 5.5.*

```
**1. What it does**
It hands out the next invoice number for a branch, such as `MUM/2627/00042`. Numbering restarts at 1 every Indian financial year (April to March), and each branch has its own counter. This is what Indian GST rules expect: a consecutive serial number, unique within the financial year.

**2. Data flow**
- Inputs: the branch name and the server's current date.
- Computes `$fy`: in September 2026, `$m = 9` gives `"26" . 27` = `"2627"`. In February 2027 it gives `(27 - 1) . "27"` = `"2627"`.
- **Side effects:** locks the whole `invoice_seq` table, reads the counter, then either inserts a new row (first invoice of the year for that branch) or updates `last_no`, and unlocks.
- Output: the formatted string. It doesn't write the invoice itself. The caller does.

**3. Non-obvious parts**
- **`LOCK TABLES` is not removable.** Without it, two invoices created at the same moment read the same `last_no` and get the same number. Duplicate GST invoice numbers are a compliance problem, not just a bug.
- **Nothing releases the lock on failure.** If a query errors between LOCK and UNLOCK, the table stays locked until the connection closes. With persistent connections, that can freeze invoicing. (Guess: it has rarely bitten because the queries are trivial.)
- **`date()` uses the server's timezone.** On a UTC server, an invoice raised at 00:30 IST on 1 April gets last year's `$fy`.
- **`str_pad(..., 5)`** means 99,999 invoices per branch per year, after which numbers become 6 digits. That's harmless but visible.
- **`substr($branch, 0, 3)`**: two branches starting with the same three letters (e.g. "Pune" and "Punjab") share a prefix but not a counter, so numbers can collide on paper.

**4. Your change**
- Add a `doc_type` column (`'INV'`, `'CN'`) to `invoice_seq`, default `'INV'` for existing rows, and make the unique key `(branch, fy, doc_type)`. Check whether a unique key exists today. The code assumes one but doesn't show it.
- Add a `$type` parameter, include it in the SELECT/INSERT/UPDATE `WHERE` clauses and in the prefix.
- **Watch the length:** GST caps the serial at 16 characters. `MUM/CN/2627/00001` is 17. Use `MUMCN/2627/00001` (16) or drop a separator.
- Before: record the current `last_no` values. After: raise one invoice and one credit note per branch, and confirm the invoice sequence continued unchanged.

**5. Dangerous as it stands**
`$branch` goes straight into SQL. If it can ever come from user input, that's SQL injection. Use a prepared statement when you touch these lines anyway.
```

## Why it works

Asking for **business terms first** gets you the purpose (GST-compliant serial numbers), which explains every odd line that follows. The **"looks removable but isn't"** instruction targets the main risk with legacy code: a newcomer deleting a lock or ordering that exists for a reason. The **"guess" label** stops the model presenting speculation as fact. Tying the explanation to **your specific change** is what caught the 16-character limit, which a generic walkthrough would never raise. **"Do not rewrite"** keeps the answer on understanding instead of a refactor you didn't ask for.

## When not to use it

It won't help much when the behavior lives outside the snippet: stored procedures, triggers, framework magic or config the function depends on. Paste those too, or use a repo-aware agent that can follow references. Legal or regulatory claims in the explanation (like the GST rules here) are worth confirming with your accountant or the official source before you rely on them.

---

Canonical HTML: https://promptabide.com/bides/explain-legacy-code-before-changing-it
Agent guide: https://promptabide.com/llms.txt · https://promptabide.com/agent-instructions.md
Sitemap: https://promptabide.com/sitemap.xml
