Authoring Small, Concise, Readable, Agile Code


When you come upon legacy code that has a method with 100+ lines, multiple conditional statements, boolean flags, or multiple variables with the same name with just a number appended on the end, it's usually really hard to read, understand, and change.  Sometimes it's not even legacy code.  You may have just wrote it!  

It can be helpful to just get thoughts out of your head and into the program.  Thinking about how you should restructure your code into multiple structs/classes before the logic is out of your head might lead you to bad structures.  However, once you get it out, you need to refactor!  Don't skip that step.  Ever.

I liken this to a book author (or even when you authored a paper in school).  An author never writes his book the first time through then publishes it.  No.  Instead, there are multiple revisions, even peer or editor reviews.  It is refined and refactored.  We as developers should never think of our first cut as a final product.   It needs refinement.

For new developers, it is really hard to think outside of just a big, long sequential set of code.  It is certainly a learned skill to refactor your code into smaller, logical chunks.  It's almost an art, really.  I see new developers (and even veterans) shy away from refactoring.  The thought at the time is sometimes, "it works, don't touch it." 

However, when we avoid refactoring, the next person might waste a lot of time trying to wrap their head around what the code is doing.


For those of you who have attended the Global Day of Coderetreat (https://www.coderetreat.org), you know the exercises emphasize small, expressive, and concise code.  Here are some tips to chopping those monster methods up and recognizing when you should refactor:

  1. Whenever you make a new block (an IF-statement, FOR loop, SWITCH, etc), consider that a resounding clue that perhaps there should be a new function, method, or even a new struct/class.  This is not always the case, but it should be a place where you stop and ask yourself the question.
  2. Speaking of Switch statements, many times they can indicate there are multiple structs/classes calling out to be separated.  If you are using OOP, then you may be able to use inheritance, injection, interfaces, and abstract classes to your advantage.
  3. Any time you have a "flag" variable (either it be a Boolean, enum, or an int), it is a strong indication that there may be multiple structs/classes calling out to be separated (or maybe a simply a new method?).  Separate by behavior, just like you are trying to do with the flag.
  4. If your method is named something like "execute", stop and ask yourself, "What is this method doing?"  If the answer has multiple parts, then you need to start chunking out the smaller pieces of logic into separate methods.  Once you have them separated into different methods, you may start to see groupings of functions which can be made into different classes or structs.
  5. Multiple variables named the same, but have a number appended at the end, are an indicator that you need to refactor. Are there different behaviors happening? Could you have multiple classes calling out to be freed?
  6. Comments are bad. Yes, bad. Ok, I'll say inline comments. There are rare cases where what you are doing is so obscure (like in a workaround for a library or bug in a dependency) that you do need to explain what the code is doing or why it is that way.  Otherwise, any time you feel the urge to put in a comment, it's a strong indicator that there might be a function needing to be abstracted. Name your classes, structs, and functions well, and you'll never need a comment! (Documentation is always good for public methods, so comments are appropriate there)
  7. Is all 3000+ lines of code in one package or namespace?  Or, I dare say, one class/struct?  Refactor!

You might argue that you don't have time.  If we said that for everything we had to learn, then we wouldn't be very good professionals.  Let's say it took you 12 hours to write up some code, and it finally works.  But, it's 300+ lines in one method.  You might argue you are busy, and you need to move onto the next thing.  It works, right?  Okay, so 2 months later, you have to modify that code to add a feature.  You wrote it, so it only takes you about 30 minutes to understand it again.  Because you're short on time, again, you just shoehorn in your updates, and ship it.  

Well now, let's say it's a year or two later.  You still remember what you did?  Will it now take you a hour or more to understand this monster?  How about the new gal that's never seen this before?  If you latest change takes 15 minutes, but it takes you an hour or more to understand, you just wasted development time.  This continues to compound over time.  

I've seen projects come to a screeching halt because it now has 10 functions that are all 100+ lines that call each other and you want to make "one simple change."  Where do you make the change?  Does that change cascade?  If it cascades, now you have to understand all those functions with all 1000+ lines of code.

Instead, if we are diligent in refactoring when we get to "green" in the red-green-refactor cycle (look up TDD if you don't know that that means), now we have smaller chunks to understand.  Additionally, those chunks should be divided into logically understandable entities.  

For example, if I started out with a class called "Library" and I pull all my code in one function of that class, how do I know where to go to make a change?  However, if I have several classes of "Book", "Shelf", "Person", and etc., then I it would be much quicker for me if I have to change something regarding a book.  I go to the "Book" class.

In summary, it might seem like this make things “more difficult” or take more time to refactor.  However, I’ve learned from some fantastic developers over the years, and I have “seen the light.”  I used to code contrary to how I preach, currently.  Once it all clicked for me, I have been so much happier with my coding results. 

Refactoring is your friend.

Comments

Popular Posts