The Book That Made Me Delete 8 Lines of Code and Write 1
I was an API caller. A report export module taught me how much a complicated interface costs the caller.

In my fifth year, I learned to write less code
Early in my career, I was an API caller.
Business said, "Add an export."
I said, "Okay."
Then Controller called Service, Service called Mapper, Mapper hit the database, and ExcelUtil.export() wrote the file. The code ran. Tests passed. Nothing caught fire. I counted the day as good.
My standard for code was simple: does it run?
Variable names? data, list, map, temp.
Functions? One method, 300 lines, from parameter validation to SQL concatenation to logging.
Design? If business asked for a rule, I stacked another if-else. It ran. I was useful.
Then I took over a report export module. That module pushed me into a different stage.
The ask sounded small: support CSV and Excel, support pagination, support field permissions, support large-data streaming. Later, maybe PDF.
I had just read a few design pattern books. I wanted practice. I drew a class map:
ExportController
ExportService
ExportStrategyFactory
CsvExportStrategy
ExcelExportStrategy
ExportContext
ExportConfig
ColumnPermissionFilter
PaginationHelper
The diagram looked professional. Each class did a small thing. I thought that was object-oriented programming.
The caller wrote this:
java
ExportContext context = new ExportContext();
context.setFormat(format);
context.setQuery(query);
context.setPermissions(permissions);
context.setPagination(page, size);
context.setOutputStream(out);
ExportStrategy strategy = ExportStrategyFactory.create(format);
strategy.export(context);Eight lines. The caller had to know format, permissions, pagination, stream, context, factory, and strategy. It wanted to export a report. It had to learn an export framework first.
Business asked for PDF.
I changed the factory, the context, the tests, and the caller. Six files. Unit tests mocked seven or eight dependencies. Test code ran longer than business code.
A coworker looked at it and said, "Your caller is more complex than your implementation."
I said nothing. He was right.
Later I read A Philosophy of Software Design, 2nd Edition. The book talks about deep modules. A good module has an interface simpler than its implementation. Complexity stays inside the module. It does not move to the caller.
I hit the desk.
My export system was a pile of shallow modules. Each class was thin. The caller had to learn every concept. I used patterns. Complexity did not disappear. It moved.
I refactored along deep module lines.
One entry point:
java
ReportExporter.export(query, out);The caller writes one line. It knows two things: what query to run, where to write.
Format, permissions, pagination, field mapping, CSV/Excel writing, exception conversion, all inside. Inside can have private classes and layers. Outside there is one entry.
Adding PDF: caller zero changes. Inside, a new writer, register the format, done.
Tests became simple: in-memory data, ByteArrayOutputStream, call ReportExporter.export(), assert the output. No seven mocks. No ExportContext fields.
After the refactor, I deleted eight lines. I replaced them with one. Compile. Tests green.
That afternoon, I went to get water. The cup was empty. I stood at the cooler waiting for it to fill. I thought: before, I asked how to implement a feature. Now I ask how many concepts the caller needs.
The book did not teach a new framework. It gave me a different set of questions:
Is this interface simpler than its implementation?
Is complexity inside the module, or leaked to the caller?
If I add a feature, how many files change?
How many mocks does a unit test need?
These questions changed the code.
Before, I thought more classes meant better design. More patterns meant higher skill. Now I think: if a module has one simple entry and handles complex business inside, that is good. Class count is not the problem. The caller knowing too much is the problem.
With bad code, I either tolerated it or rewrote it. A rewrite risked breakage. Now I add tests first. Then I pull complexity into deep modules. I do not tear down the building. I make the caller simple first. Then I clean the inside.
Debugging used to mean tracing a value through call stacks. Now module boundaries are clear. A problem is inside or at the caller. Inside has unit tests. The caller has integration tests.
Code Complete was a mirror. It showed me the mess in my code. It taught me what good code looks like. It sets the baseline.
Refactoring gave me courage. Bad code does not need to be tolerated. It does not need a full rewrite. It can be changed step by step.
Computer Systems: A Programmer's Perspective took me below the framework. Memory, cache, linking, processes, exceptions. When a strange bug or performance problem appears, I do not guess.
The Soul of Computing by Wu Jun took me out of syntax. It talks about computational thinking. It fits after years of engineering.
If I pick one book that changed how I design software, it is A Philosophy of Software Design.
Code Complete showed me what good code looks like. Refactoring gave me the nerve to change code. A Philosophy of Software Design gave me a way to make design decisions.
After a few years, many people hit a stage. They know syntax and frameworks. They can write business code. But the code is bloated. Design is weak. Complex systems are hard. Coding hits a ceiling.
The first reaction is to learn a new framework. Spring, then Spring Cloud. Vue, then React. Java, then Go. After that, the code looks the same. The framework changed. The bad design stayed.
The difference often comes from books that change how you decide. They do not teach a new language. They do not teach a new tool. They change how you ask questions.
If you are stuck at "can write, but design is weak," here is a concrete suggestion.
Do not rush to a new framework. Find a book that changes how you decide, like A Philosophy of Software Design. As you read, do not just underline. Do not just take notes. Take a module you wrote. Ask:
How many concepts does the caller need to know?
Which concepts must the caller know? Which are internal decisions?
If I add a feature, how many files change?
How many mocks does a unit test need?
Is the interface simpler than the implementation, or more complex?
Then refactor it into a deep module.
One simple entry. Complexity inside. Add tests. Keep behavior. Step by step.
You will hit a strange moment: caller code goes from dozens of lines to one. Internal code may add private classes. The system becomes clear.
Now I write the caller line first. If that line needs a comment, I rewrite it.
About the Creator
Jin
Writer of reamstories
https://reamstories.com/jin
Enjoyed the story? Support the Creator.
Subscribe for free to receive all their stories in your feed. You could also become a paid subscriber, letting them know you appreciate their work.
Comments
There are no comments for this story
Be the first to respond and start the conversation.