Before you start
This is the closer of the SOLID module. You've drilled each principle on its own; now you use all five at once on a realistic refactor.
Why the "drill" format
Because this is what a real design interview asks you to do.
Interviewer: "Here's an existing system. Refactor it." You: (hold all five principles in your head, apply each one in turn, produce a clean design.)
If you've only practiced the principles one at a time, this scenario melts your brain. If you've practiced them together even once, it doesn't.
Suggested order of attack
Do them in this order — each step makes the next easier:
SRP first. Split the god class by job. Ignore OCP / LSP / etc. for now. Just move the jobs into their own classes. Once done, you'll have
Report, some formatters, some storage thing, some notifier thing.OCP second. Anywhere you see
if fmt == "csv": elif fmt == "json":, replace it with a base class + subclasses. The if/elif goes away.LSP third. Check every subclass hierarchy you introduced. Does every child honestly keep the parent's promises? For this exercise, everything should be fine — but the habit of checking matters.
ISP fourth. Look at each interface. Is it as small as it can be while still being useful? For this exercise, the interfaces are already small (each has one method) — again, the habit is what matters.
DIP last. Rewrite
ReportService(the top-level coordinator) to take its dependencies as constructor arguments. Nothing gets built inside except local values.
Following this order, the whole refactor is maybe 60-80 lines. Trying to do all five at once without a plan is 300 lines of pain.
What the strict tests are checking
test_report_has_no_formatting_persistence_delivery— SRP: the data class stays a data class.test_new_formatter_added_without_touching_service— OCP: a new formatter extends the system with ZERO changes to existing code.test_service_does_not_hardcode_concretes— DIP: the coordinator only names the abstract types.test_service_takes_all_three_deps— DIP: the constructor takes all three collaborators.- Every formatter / storage / notifier test checks abstract bases (LSP + ISP).
If any of these fail, you've brought back one of the smells the refactor was supposed to remove. Read the failure message and identify which principle is warning you.
After this lesson
You have the whole SOLID toolkit. The next module is design patterns — every pattern uses at least one SOLID principle, and most use several. You'll spot them naturally now.