, 24 tweets, 4 min read Read on Twitter
Refactoring Pro-Tip: I optimize my code for scannability, readability, and writeability in that order.
I won't argue my case in detail, there's a video if you'd rather watch me make it instead of reading it, and I'll just sketch the case briefly here in the muse.

geepawhill.org/optimizing-a-p…
When I'm coding, I notice that I spend significantly more time scanning the code than I do reading it, and significantly more time reading the code than I do writing it.

So when I optimize for my performance rather than the code's performance, I focus first on scannability.
What's this "scanning" thing? Well. It happens in a lot of different cases. We don't really have one word for it, so I chose "scanning". What it amounts to is rapidly moving my eyes across a chunk of code, picking out features of it as I go.
What kind of features? Well, that depends on what I'm up to.
When a codebase is unfamiliar, I scan to pick out features like flow-of-control, naming, function or data dependencies.
When I know a codebase relatively well, I more often scan for things like: another call to the function I'm about to call; confirmation of something I think I know but want to be sure of; some syntax variant i can never remember (i'm looking at you stream operations).
When I am debugging, I usually am scanning for "that place where I suspect the problem is". That is, I believe something's going south during the fritzifying, and I want to find where that happens in the code.
So. What things make scans easier or harder to do for me?
The easiest code in the world to scan is a straight line of well-named method calls:

openTheDoor()
getInTheSeat()
closeTheDoor()
TurnTheKey()
StepOnTheAccelerator()
I barely have to glimpse that code to get it in to my head. Notice, I have to do way more to understand it deeply. That's okay, when I'm scanning code I'm not *trying* to understand it deeply. I'm trying to, I spoze in this case, figure out where the key comes from or some such.
An aspect of that little sample that's less obvious typographically: it is all at the same level *conceptually*. To get a feel for this, imagine if the second line said, instead of getInTheSeat(), something like

seat.put( body.parts["ass"].substring(2,9).
(Presumably, the 2th through 8th part of the ass string contains the cheeks. Idunno, whaddayawantfromme? You get the point, I'm sure.)
Every branching point that enters that straight line also makes it harder to scan. If the branch is an if it makes me have to hold two states in my head simultaneously, or to pause and confirm one of the states. (Schrodinger's Geek?)
if it's an if-only branch -- that is, there is no else -- that easier than if-else. switches are harder than that. nested if's are harder still. a loop with nested if-else's is the hardest code there is to scan.
So in practical terms, I put it a lot more simply: I prefer to minimize indentation. I do this by a) killing it off entirely when I can, and b) making it function-wide when I can't.
I think you'll buy "kill when I can" without further argument, though you might wonder how that's done, and we'll ultimately have to talk about that. But what's this "function-wide" thing?
I tend to put the code one puts inside a multi-statement scope in a whole separate function.

if( condition ) { // multi-statement blah-blah-to-do-the-thing }
else { // multi-statement other thing }

becomes
if(condition) doTheThing()
else otherThing()
I might even then put that whole *if* in yet another function: doTheRightThingDoneByThoseTwoBranches().

This depends on whether the two branches are really doing the same "thing" using different techniques, an extremely common situation.
There are lots of variations on this theme. Loop bodies, switch bodies, if-else-bodies. All of that stuff that introduces indents, I'm prone to pulling out separately.
I also use early returns. (I swore I was gonna get to this.) And for the same reason: because an early return kills one level of indentation from everything that comes after it. (Mentally, it does more than that, but that's the non-rigorous shorthand.)
(A note: some folks use "guard clause" to characterize early returns. I don't. Guard clauses are usually about detecting a no-op condition and not doing anything. Early returns can still do things.)
Often, when I encounter slalom code, I can dramatically flatten its curves -- reduce its indentation -- to a simple series of un-nested if's, just by using early returns.
I optimize for scannability first, over readability or writability, cuz I scan more than read or write. A big target is to kill or move indentation. A big technique for doing that is early returns.

Have a lovely late Thursday night! Tomorrow's another day in the silicon mines.
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 GeePaw Hill
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!

Follow Us on Twitter!

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 ($3.00/month or $30.00/year) and get exclusive features!

Become Premium

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!