Gilded Rose
Level: Advanced 60–90 minConcepts: RefactoringEdge CasesLegacy Code
You have inherited the Gilded Rose inn’s inventory system. The code works but is a tangled mess of nested conditionals. Your job: add support for a new item type without breaking existing behavior.
This kata is different from most — you start with existing code, not a blank slate. The first step is understanding what the code does, not writing new features.
Existing Behavior
The system updates inventory daily. Each item has:
name— the item namesellIn— days remaining to sell the itemquality— how valuable the item is (0–50)
At the end of each day, sellIn and quality decrease by 1.
Special rules:
- Once the sell-by date passes (
sellIn < 0),qualitydegrades twice as fast qualityis never negative- “Aged Brie” increases in quality the older it gets
- “Sulfuras, Hand of Ragnaros” is legendary — never sold, never decreases in quality, quality is always 80
- “Backstage passes” increase in quality as the concert approaches:
- Quality increases by 2 when there are 10 days or less
- Quality increases by 3 when there are 5 days or less
- Quality drops to 0 after the concert (
sellIn < 0)
qualitynever exceeds 50 (except Sulfuras which is always 80)
The Legacy Code
function updateQuality(items) {
for (var i = 0; i < items.length; i++) {
if (items[i].name != 'Aged Brie' && items[i].name != 'Backstage passes to a TAFKAL80ETC concert') {
if (items[i].quality > 0) {
if (items[i].name != 'Sulfuras, Hand of Ragnaros') {
items[i].quality = items[i].quality - 1
}
}
} else {
if (items[i].quality < 50) {
items[i].quality = items[i].quality + 1
if (items[i].name == 'Backstage passes to a TAFKAL80ETC concert') {
if (items[i].sellIn < 11) {
if (items[i].quality < 50) {
items[i].quality = items[i].quality + 1
}
}
if (items[i].sellIn < 6) {
if (items[i].quality < 50) {
items[i].quality = items[i].quality + 1
}
}
}
}
}
if (items[i].name != 'Sulfuras, Hand of Ragnaros') {
items[i].sellIn = items[i].sellIn - 1
}
if (items[i].sellIn < 0) {
if (items[i].name != 'Aged Brie') {
if (items[i].name != 'Backstage passes to a TAFKAL80ETC concert') {
if (items[i].quality > 0) {
if (items[i].name != 'Sulfuras, Hand of Ragnaros') {
items[i].quality = items[i].quality - 1
}
}
} else {
items[i].quality = 0
}
} else {
if (items[i].quality < 50) {
items[i].quality = items[i].quality + 1
}
}
}
}
}
Your Task
Step 1: Write characterization tests. Before changing anything, write tests that capture the current behavior for all item types. These are your safety net.
Step 2: Refactor. Clean up the nested conditionals. Make the code readable. Your characterization tests should stay green throughout.
Step 3: Add “Conjured” items. Conjured items degrade in quality twice as fast as normal items.
Test Cases
| Item | SellIn | Quality | Next Day SellIn | Next Day Quality |
|---|---|---|---|---|
| Normal Item | 10 | 20 | 9 | 19 |
| Normal Item | 0 | 20 | -1 | 18 |
| Normal Item | 5 | 0 | 4 | 0 |
| Aged Brie | 10 | 20 | 9 | 21 |
| Aged Brie | 0 | 20 | -1 | 22 |
| Aged Brie | 5 | 50 | 4 | 50 |
| Sulfuras | 10 | 80 | 10 | 80 |
| Backstage passes | 15 | 20 | 14 | 21 |
| Backstage passes | 10 | 20 | 9 | 22 |
| Backstage passes | 5 | 20 | 4 | 23 |
| Backstage passes | 0 | 20 | -1 | 0 |
| Conjured Item | 10 | 20 | 9 | 18 |
| Conjured Item | 0 | 20 | -1 | 16 |
Hint
Start with characterization tests. Run the existing code with known inputs and assert the actual outputs — even if the behavior seems wrong. Your job is to capture reality, not fix it. Once you have a full safety net, refactoring becomes mechanical.