Make your code more readable by using Breadth-First Programming, not Depth-First Programming

I recently finished reading a book called The Art of Readable Code by Boswell and Foucher. Overall, it was a good book on programming style – touching on many of the timeless pearls of wisdom that Steve McConnell wrote about in Code Complete using a more modern flair. One chapter that really piqued my interest was Chapter 10 – Extracting Unrelated Subproblems. This chapter touched on some really key points for enhancing your code’s readability: identifying unrelated subproblems, techniques for extraction, decoupling, watching out for when you inadvertently take things too far, etc.

All in all, the purpose of extracting unrelated subproblems is, as Steve McConnell put it, to reduce complexity – Software’s Primary Technical Imperative (i.e. Keep it Simple). Techniques used for achieving this are things like using proper layers of abstraction, ensuring a method has proper cohesion, Domain-Driven Design, and of course, as discussed by Boswell and Foucher, extracting unrelated subproblems, amongst other things.

For me, personally, the problem of needless complexity is often encountered during code reviews (CRs). One thing that I often struggle with is reverse engineering what the code is supposed to be doing based on the code as it is written. This can be really frustrating if the author isn’t immediately available, if there is a lot of code with no obvious design doc, and when high-level methods are riddled with needless low-level details that obfuscate the code’s intent.

To combat these types of issues such as the obfuscation of the code’s intent, unrelated subproblems, lack of method cohesion, and in general, needless complexity, there is one technique that I frequently use which really helps me: Use Breadth-First programming instead of Depth-First programming.

By breadth-first programming and depth-first programming, I’m not talking about using the breadth-first and depth-first traversal algorithms throughout my code. 😝 Instead, I’m talking about an approach to how we actually think about and write the code that we write into our IDEs.

For example, suppose I am tasked with writing a web service API for a legacy client that validates whether or not a booking should be accepted as legitimate. We’ve met with the stakeholders, done our design, and have come with the following sequential tasks to be performed by our “Verification Gateway”:

  1. Transform the request XML payload into a POJO data model.
  2. Enhance the POJOs with extra information – useful for downstream processing.
  3. Call a downstream Verification Service for with our enhanced POJOs for further processing – used to determine whether the booking is truly legitimate.
  4. Marshall the response back into a XML payload that the caller expects.

Regardless of how contrived this example is, this is our high-level description of what we want to do. To make our system as simple as possible, it would be great if we used the Breadth-First programming technique and wrote a simple high-level function that looked something approximating the following code:


public class VerificationGateway {
  public String verify(String xmlRequest) {
    BookingRequest bookingRequest = generateBookingRequestFromXml(xmlRequest);
    enhanceBookingRequest(bookingRequest);
    BookingResponse bookingResponse = verifyBooking(bookingRequest);
    String xmlResponse = generateXmlFromBookingResponse(bookingResponse);
    return xmlRespoinse;
  }
}

The above code has advantages that include the following:

  1. It’s easy to see what the high-level intention of the code for an engineer who has little context when asked to do a CR.
  2. It’s cohesive – having a consistent level of abstraction.
  3. It keeps things simple.
  4. It has extracted and identified the keyproblems subproblems to be solved – like generating a POJO form of the XML payload, enhancing the payload, verifying the booking, and converting the response back into an XML payload again.

For me, I tend to write high-level logic only when I force myself to think about the problem at a high-level, and focussing with pain on managing my own shiny object syndrome. Ironically, I find it hard to write simple high-level code.

Instead, I find that my natural unfortunate tendency is to write code like the following:


public class VerificationGateway {
  public String verify(String xmlRequest) {
    // Thought 1: I need a method that can parse an XML request and hydrate
    // a request. I'll write a method that does that first. Thus, I start writing
    // the `generateBookingRequestFromXml()` method without even finishing the
    // `verify()` method first.
    BookingRequest bookingRequest = generateBookingRequestFromXml(xmlRequest);

    // Thought 3: I need functionality that can add datum1 to the booking request.
    // Let's write that now.

    // functionality that adds datum2 to the booking request


    // Thought 4: I need functionality that can add datum2, ..., datum_n to the booking request.
    // Let's write that now.

    // functionality that adds datum2 to the booking request

    // Thought 5: Now that all that's done, I know that I need to call the Verification Service,
    // so let's write that now.

    // messy code that calls the Verification Service, most of which is within the scope of the
    // top-level `verify()` method.

    // Thought 6: I need a method that can parse out the XML payload as a string from my current
    // `BookingResponse` instance. That's clearly low-level logic that isn't business logic
    // related, so let's extract that method, a simple call.
    String xmlResponse = generateXmlFromBookingResponse(bookingResponse);
    return xmlRespoinse;
  }

  private BookingRequest generateBookingRequestFromXml(xmlRequest) {
    // Thought 2: Implement this method before I finish the `verify()` method, leaving a broken
    // `verify()` method until the very end of my implementation.
  }

  private String generateXmlFromBookingResponse(bookingResponse) {
    // Thought 7: Implement this method.
  }
}

As you can see, I added comments that allow you to gain a small glimpse into how certain undisciplined thinking leads to this kind of crap code. It’s also the kind of code that both myself, and engineers that I respect have written before. IMO, this type of code comes from depth-first thinking and Shiny Object Syndrome. In this second code sample immediately above, my comments delineate how I’m guilty of being distracted by the next low-level problem each time I encounter one. My verify() method is never finished until almost the very end of the implementation. Consequently, it’s really difficult to discern the requirements from this code. Most of the key logic is now in a bloated verify() method that really ought to just be a simple high-level method that delegates each of sub-problems to a downstream method.

But, when I force myself to think in a disciplined manner about my problem, and forcing myself to think in a high-level bread-first manner about a problem, I end up writing code that is pretty maintainable and simple. It also makes things easier of the engineers doing the CR because it’s easy to see what I’m trying to do. Sure there are probably errors in the lower-level problems, but the verify() method is now so simple that it becomes easy to reason that there are no errors in the high-level problem is being solved.

In sum, based purely on my own personal, anecdotal experience, I have that using a breadth-first approach to programming leads to better code that’s simpler and more maintainable. I hope you find the same. Thanks for reading.

Transdermal Magnesium vs. Oral Magnesium for Sleep

TL;DR

If you’re trying to get more energy and health in your life and work by improving your sleeping habits, don’t rely on transdermal magnesium to help you sleep better. It has no more proven benefits that oral magnesium supplementation.

Long-winded version

So lately I’ve been reading the book, Sleep Smarter, by Shawn Stevenson. Up to my research for this blog article, I feel that this book has been pretty good, but my view of it has been severely tainted based on my research for this article. It definitely contains a lot of good tips on sleeping well and it strikes home the message of why proper sleep is important. One part really piqued my interest – the part about magnesium. In Sleep Smarter, pages 57-8 of 256 on the Kindle, magnesium is referred to as “one mighty mineral”, an “anti-stress mineral”, it “helps to balance blood sugar, optimize circulation and blood pressure, relax tense muscles, reduce pain, and calm the nervous system.” According to Sleep Smarter, humans are chronically deficient in magnesium, as “estimates show that upwards of 80 percent of the population in the United States is deficient in magnesium.”

In the section on magnesium supplementation, one paragraph, in particular, is noteworthy.

Again, because a large percentage of magnesium is lost in the digestive process, the ideal form of magnesium is transdermal from supercritical extracts. You can find more information on my favorite topical magnesium, Ease Magnesium, in the bonus resource guide at sleepsmarter.com/bonus.

I did a little research of my own, and I could only find one credible scientific study on the effectiveness of transdermal magnesium – a study by members of the National Center for Biotechnology Information titled: Myth or Reality—Transdermal Magnesium? The first sentence of the article’s abstract reads as follows:

In the following review, we evaluated the current literature and evidence-based data on transdermal magnesium application and show that the propagation of transdermal magnesium is scientifically unsupported.

Basically, this NCBI article discusses how while oral magnesium supplementation has proven benefits, transdermal magnesium does not.

I traced Shawn Stevenson’s sources and was really disappointed. In my opinion, the cited sources in his bibliography effectively boiled down to little more than personal anecdotal evidence of bloggers.

This made me really disappointed in the Sleep Smarter book because it made me ask the following question: If the stuff about transdermal magnesium is total bullshit, then how confident can I be in all the rest of Shawn’s “facts”? Are they proven facts or are they just alternative facts? One of the biggest reasons for reading non-fiction is so that you don’t have to do the countless hours of research yourself. You, the reader, benefit from the hard-won research of others by paying a few bucks for that knowledge. In that light, I feel really let down by Sleep Smarter because I just don’t know what to believe and what not to believe. But at this point, my trust in the book is greatly diminished.

The aversion to using Java’s continue keyword

I’ve recently been reading The Art of Readable Code by Dustin Boswell and Trevor Foucher. So far, it’s a decent book. The Art of Readable Code professes many of the style recommendations (such as nesting minimization) that Steve McConnell’s classic, Code Complete 2nd Ed., contains, but with a more modern flair. However, one quote, in particular, piqued my interest while reading.

In general, the continue statement can be confusing, because it bounces the reader around, like a goto inside the loop.

Basically, amongst developers, there is a fair amount of consternation around the use of Java’s continue keyword. I remember getting into an argument with a colleague and friend of mine, Neil Moonka, about this very issue back when we worked at Amazon together. The summary of the argument was that I was using Java’s continue keyword excessively in a loop – multiple times, leading to somewhat confusing code. As I recall, my counterargument was a highly legitimate one (not at all stemming from ego or insecurities) that sounded something like: “Are you f#%king kidding me!? This code is f#%king perfect!” At the time, and honestly, to this day, I really don’t see much wrong with the continue keyword, in and of itself. IMO, it’s a nice complement to Java’s break keyword, and both keywords have their places. Unlike break, instead of jumping out of the loop, you just jump back up to the top of the loop. In fact, using the continue keyword is a nice way to avoid excess nesting inside your loops. I have a tendency to use continue as the equivalent of an early return statement inside loops.

That being said, this points to a potentially deeper issue with code that uses the continue keyword excessively. Namely, the issue is that methods that use the continue keyword excessively tend to lack cohesion. The level of abstraction of a method outside a loop tends to be different than the level of abstraction of what’s inside the loop. Since the method simultaneously deals with these two levels of abstraction, it lacks cohesion by definition.

To solve this problem, you can just refactor your code such that the innards of your loop’s logic is extracted into its own lower-level method.

For example, consider the following code:

for (Item item : items) {
  if (item != null && newState != null) {
    continue;
  }
  if 
  if (item.isValid() && State.isValid(newState)) {
    continue;
  }
  item.setState(newState);
}

Admittedly, the above loop is straight-line code, going directly from top to bottom without going diagonally. However, the higher level method that you don’t see could likely be made more cohesive by extracting the loop’s innards out into a new method. For example, consider the following revised code:

  for (Item item : items) {
    updateState(item, newState);
  }
  
  // ..
}

private void updateState(Item item, State state) {
  if (item != null) {
    return;
  }
  if (item.isValid()) {
    return;
  }
  if (state != null) {
    return;
  }
  if (State.isValid(state)) {
    return;
  }
  item.setState(newState);
}

With this new version of the code, the purpose of the inside of the loop is fairly obvious. Moreover, the main method doesn’t need to be concerned with the lower level details of the prerequisites of setting the state. Thus, the main method maintains its cohesion, which won’t be degraded by adding in low-level details of the prerequisites of setting the state of the item.

So while the continue keyword is useful, excessive use of it can be off-putting. When such occurrences arise, consider refactoring your code such that the loop’s logic is neatly encapsulated within a new method.