Profile picture
Uncle Bob Martin @unclebobmartin
, 14 tweets, 3 min read Read on Twitter
I spent the last few days fixing bugs in, and refactoring, a relatively small function that added a new feature to an existing system. It was a horror scene. The previous programmer (who released the code and then quit) had not thought the problem through very carefully.
So there were a number of logical holes that were found by customers within hours of the initial release.

As I examined the code I saw that there were no tests anywhere. There was no way for me to probe the behavior of the code without using the GUI.
Bit by bit, hour by painful hour, I was able to find and repair the logic errors. And I found a lot more of those errors than the customers did (thankfully). But the repairs were _dirty_. I mean really ugly.
I could hack the code to get it to work (probably) but without tests there was no safe way to refactor the code in any meaningful sense. And the code _badly_ needed refactoring.
So once I got it working (as far as I could tell) I created a set of characterization tests. I did this by wrapping the function with another that wrote the arguments and return values out to a file. Then I copied those values into the tests.
Let me just add, at this point, that the arguments were complex data structures, many thousands of elements long. The return values were simpler, but still significant. This function sat in the middle of a long complex process with wide data flows.
It took me some time to get the characterization test working because there was no infrastructure for testing — no test framework — no test directories — no...tests at all.
Once the characterization tests were working I could refactor. The function was a tangled web of assumptions, bizarre data manipulations, and dependencies. It took me several hours to understand the 40ish lines of code.
As I teased it apart I noticed that the original programmer had made some early assumptions that turned out to be unnecessary; but he carried the artifacts of those assumptions through the whole function.
To eliminate these superfluous assumptions I had to touch virtually every line of code in the function; removing the unnecessary manipulations that the author had thought would be necessary; but never were.
The more I read, the more I understood what the author had been thinking, and the missteps he had taken. It was clear that rather than correct those missteps as he discovered them later in the function, he simply integrated them into the overall flow.
In the end I was able to clean things up pretty well. I got rid of the missteps. Disentangled most of the dependencies. Broke the 40ish lines into 8 or 9 little well-named functions, and made the overall flow much more apparent for the next reader.
I know the project well. I know the folks who run it. There was no time pressure. Managers were not breathing down this programmer’s neck. He had been encouraged to work well, and keep the code clean. He had been encouraged to write tests.
And so I am left wondering what the hell goes through the minds of programmers as they ship horrible code with no tests to their customers and then walk away into the sunset with their paychecks in their pockets.
Missing some Tweet in this thread?
You can try to force a refresh.

Like this thread? Get email updates or save it to PDF!

Subscribe to Uncle Bob Martin
Profile picture

Get real-time email alerts when new unrolls are available from this author!

This content may be removed anytime!

Twitter may remove this content at anytime, convert it as a PDF, save and print for later use!

Try unrolling a thread yourself!

how to unroll video

1) Follow Thread Reader App on Twitter so you can easily mention us!

2) Go to a Twitter thread (series of Tweets by the same owner) and mention us with a keyword "unroll" @threadreaderapp unroll

You can practice here first or read more on our help page!

Did Thread Reader help you today?

Support us! We are indie developers!


This site is made by just three indie developers on a laptop doing marketing, support and development! Read more about the story.

Become a Premium Member and get exclusive features!

Premium member ($3.00/month or $30.00/year)

Too expensive? Make a small donation by buying us coffee ($5) or help with server cost ($10)

Donate via Paypal Become our Patreon

Thank you for your support!