What I Found Tearing Apart a 5-Year-Old Legacy Payment Module
I was put in charge of refactoring the payment module at work. More precisely, I volunteered for it in an atmosphere where everyone agreed, "Anyone can see this needs fixing." It was code that eight people had cycled through over five years.
On the first day, I opened the file and found a single 1,800-line class containing payments, refunds, settlements, and notifications all in one. There were no comments, and even the commit messages were things like "fix," "fix2," and "final_for_real." At first, I thought I had to understand all of it before I could fix it, so I made no progress for days.
The turning point came in the third week. I decided to stop trying to understand it and write tests first. After I wrote about 200 tests that recorded the existing behavior exactly as it was, I started to see what I could safely touch.
Then I set an order:
- Step 1: Lock down current behavior with tests
- Step 2: Split payments, refunds, and settlements into separate classes
- Step 3: Wrap external PG provider calls behind interfaces
- Step 4: Clean up the duplicate logic that remained after all that
Steps 1–2 took three weeks, and Steps 3–4 took five weeks. Two months in total, and half of that went into tracing why the code had ended up the way it did.
The biggest lesson was that legacy code isn't born from laziness; it's born from missing information. When you're rushing to bolt on features, anyone can end up writing code like that. And refactoring without tests is just gambling.
The payment module is now down from 1,800 lines to 700. Not a single feature changed. I'm proud of that.
7 answers
Making 200 tests first—that judgment is what real skill looks like. Most people start by fixing the code, end up rolling it back, and run away lol
What about after step 3? I’m most curious about the part that wraps the PG provider interface, but the post cuts off right there.
Real final lol—everyone’s been there. We even had ‘Real_Final_Edited_For_Release’.
Well, I’m curious whether the time spent creating 200 tests was actually within the approved scope. With a payment module, schedule pressure is usually no joke, so spending three weeks just writing tests seems a bit idealistic... Of course, I get that it’s a good thing.