Gilded Rose

Level: Advanced 60–90 min

Concepts: 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 name
  • sellIn — days remaining to sell the item
  • quality — how valuable the item is (0–50)

At the end of each day, sellIn and quality decrease by 1.

Special rules:

  1. Once the sell-by date passes (sellIn < 0), quality degrades twice as fast
  2. quality is never negative
  3. “Aged Brie” increases in quality the older it gets
  4. “Sulfuras, Hand of Ragnaros” is legendary — never sold, never decreases in quality, quality is always 80
  5. “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)
  6. quality never 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

ItemSellInQualityNext Day SellInNext Day Quality
Normal Item1020919
Normal Item020-118
Normal Item5040
Aged Brie1020921
Aged Brie020-122
Aged Brie550450
Sulfuras10801080
Backstage passes15201421
Backstage passes1020922
Backstage passes520423
Backstage passes020-10
Conjured Item1020918
Conjured Item020-116

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.