Common Boat Anchors in Programming and How to Avoid Them

A boat anchor is a metaphor that describes something that is obsolete or useless. In programming, boat anchors are everywhere. If you aren’t careful, boat anchors can ruin your productivity and cause confusion. Luckily, boat anchors are easy to prevent and correct if you look out for them. With just a little bit of foresight, you too can preserve your sanity.

TODO comments


Everyone’s used it. A seemingly innocent TODO comment. No harm done, since it’s just a little reminder for yourself right?

Wrong.

TODO comments are not only useless, but a productivity sink as well. Firstly, the “TODO” that you gave for yourself usually never gets done, as it’s buried in some function or class that you probably won’t even revisit for another week or two. Even if you do see the TODO, you’ll most likely ignore it as you’ll be too focused on your current task.

Secondly, TODO comments are bad because they waste the reader’s time. TODO comments belong in a Trello board or some other organizational system, not in your code base. No one wants to waste time reading about something that you should have/want to have done, but never got around to.

Commented Code


In this day and age, if your organization uses GitHub or some other form of version control, commented code is absolutely useless. This isn’t referring to commenting your code with useful English messages, but rather commenting out chunks of runnable code.

Commented code is essentially noise for the reader. If you push commented code to your repository because you think you might “need it later”, then you are ignoring the key purpose of version control.

Version control saves code. If you ever need that snippet of code that you deleted two months ago, it’s easily accessible. Don’t comment out code, or you’ll end up with hundreds and hundreds of obsolete lines of code.

Uncommented Code That Is Unused


Imagine you’ve written a utility class that calculates mortgages for you.

Suddenly, you’re told that the feature is scrapped, but that it might make a reappearance in the future.

Upon hearing that it might be used again in the future, you decide to leave the utility class in the code, since you might “need it later”. Once again, this goes back to the idea of version control. If it’s not relevant, and if it’s never used or referenced, then it doesn’t belong in your repository. Delete it.

Obsolete Documentation


Let’s say you have a nifty little method that method that divides every number in a list by 4.

def list_divide(list, dividend):
  """
  Divides every number in a list by a
  dividend and returns a new list with 
  the resulting numbers.
  """
  ret_list = []
  
  for num in list:
    ret_list.append(num/dividend)
  
  return ret_list

Suddenly, you remember about division by zero and quickly add a check to your function.

def list_divide(list, dividend):
  """
  Divides every number in a list by a
  dividend and returns a new list with 
  the resulting numbers.
  """

  if dividend == 0:
    print("Dividend must not be zero.")
    return

  ret_list = []
  
  for num in list:
    ret_list.append(num/dividend)
  
  return ret_list

Unfortunately, since you didn’t update the documentation, the docstring is now a lie. It doesn’t tell the user what the function actually does. There is no reference to division by zero in the docstring, causing the documentation to become a boat anchor.

Outdated documentation causes all sorts of issues for users. Luckily, this issue is easy to resolve. As a rule of thumb, if you add additional functionality to a function, document it. Even if you don’t like documentation, or if you think it’s tedious and pointless, do it anyway. You’ll save other programmers from headaches and wasted time.

Adding Ticket Numbers as Comments


Although not extremely common, some people feel the need to compulsively comment every change they make with a ticket number.

For example, you might see something like this :

#Added foobar function to resolve ticket 53
def foobar(num):
  #Fixes ticket 281
  if num == 0:
    print("Hello World!")
  elif num == 3:
    #Added because of ticket 571
    print(num/9)
  #Added else because of ticket 1528
  else:
    #Due to ticket 4713, changed to 'Goodbye World!' 
    print("Goodbye World!")

Before long, everything in your code will have a comment regarding a ticket.

If you are guilty of doing this, stop it. No one cares what ticket number the fix was in. Make the fix, commit, and push. All of the comments about tickets and issue numbers are utterly pointless and end up as unnecessary noise to the reader.

If you feel that the change is so strange or quirky that you absolutely must give some sort of background information, then write a comment. Making the reader search up a specific ticket to understand the code is a gigantic time sink, especially since most tickets have multiple comments. No one wants to read through all that text. Summarize it in a single comment and move on.

Storing Variables For No Reason


It’s a common practice for developers to do something along the lines of this :

def foobar(num):
  return num * 13

#Doing this
num = foobar(32)
print(num)

#As opposed to
print(foobar(32))

In this case, as long as “num” is not set to some wildly long function call, there is no reason to store it as a variable. In this case, foobar(32) is short, so it should be directly inputted into another function, rather than being set to a variable, and then inputted into the function.

Assigning it to a variable when the functional call is short tells the reader, “The variable num is important. It will be reused later in some way somewhere down the line.”

Not only that, but unnecessarily creating variables adds extraneous code for no good reason.

Conclusion


Boat anchors are everywhere in code. If you can avoid them, you will make not only your life easier, but everyone else’s as well. No one wants to waste time reading excessive code. Reading code is already difficult. Making your peers read more code than necessary hurts their productivity and makes coding an unpleasant experience.

So be a good person. Prune off the excess and correct the outdated. If you find any excessive code, then remove it. If the documentation is inaccurate or outdated, fix it. It might be a thankless job, but know that you’ll have made the world just a little brighter in the process.

Advertisements

Null Island – The Most Famous Island that Doesn’t Exist

It’s been a long and tiresome week of work, and you want a vacation.

You search online for some decent vacation spots.

Hawaii? Nah. Canada? Already been there.

But hold on, something catches your eye. Null Island? Thousands of visitors? And look at that population density! All those posts from (0,0)?

And so you set out on an arduous and dangerous journey to Null Island, only to find this.

Null-island-buoy
Photo from Wikipedia

Yep. Null Island, the most popular tiny island you’ve found in your life, doesn’t exist.

What’s Going on Here?

Null Island, located with the geographic coordinates (0,0), is a byproduct formed by bad programming.

How did it happen?

Some developers who were creating a GPS system decided that, if a person’s coordinates couldn’t be found, that instead of setting them (Null, Null), they were instead set to (0,0).

In psuedocode, it went down something like this :

if user's x coordinate is Null
  set user's x coordinate to 0

if user's y coordinate is Null
  set user's y coordinate to 0

Not only is this kind of code an anti-pattern, but for something such as position tracking, this can have serious consequences.

For example, in Wisconsin, many voters were in locations that did not have registered coordinates. However, in order to vote, they needed to use a new geocoding system that tied their house address to a geographical coordinate.

Unfortunately, the Wisconsin voters were given a geographical coordinate of (0,0), or Null Island. For a population of nearly 6 million, the problem was quickly discovered and fixed, but it is yet another example of how bad programming can wreck havoc.

To prevent mistakes like these, ask yourself if what you’re doing makes sense in a different context.

Here are some similar scenarios, using the same logic that caused the Null Island issue.

if user's phone number is Null
  set user's phone number to 000-000-0000

if user's pin number is Null
  set user's pin number to 0000

if user's credit card number is Null
  set user's credit card number to
    0000 0000 0000 0000

In scenarios where the 0 is significant, you cannot replace null with zero. If your wallet is null, it means you don’t have any money. Your balance is 0. If your friend count is null, it means you have no friends, so your friend count is 0.

However, if the zero matters, such as in a phone number, you can’t set the user’s phone number to 000-000-0000. Similarly, if you have an expensive watch, and the price is null because it’s not for sale, that doesn’t mean your watch costs $0.00. That would imply that you’re giving it away for free.

Conclusion

Null Island is a silly coding mistake that carries significant consequences, even today.

That’s not to say that every single mistake you make will effect an entire state’s voter population, but it can happen.

If you want to avoid creating the next equivalent of Null Island, leave your user’s input as is instead of attempting to change it. Null means null. Leave it as null.

Bogosort : Moving At The Pace of a Random Snail

Bogosort is a sorting algorithm, much like quick sort, and merge sort, with a twist.
It has an average case performance of O((n+1)!).

Bogosort is known by many other names, including stupid sort, monkey sort, and permutation sort.

Knowing this critical information, let’s dive into the meat of this sorting algorithm.

How Does It Work?


Bogosort works by taking an input list, and checking if it is in order. If it is, then we are done, and the list is returned. This means that Bogosort has a best case performance of O(n).

If the list isn’t in order, then we will shuffle the list until we get a list that is sorted. Unfortunately, since the list will be shuffled randomly, Bogosort technically has a worst case performance of O(∞).

 

Implementation


Bogosort’s implementation is short and concise.

import random

def Bogosort(list):
    while not isSorted(list):
        random.shuffle(list)
    return list

def isSorted(list):
    if(len(list) <= 1):
        return True

    if(list[1] >= list[0]):
        return isSorted(list[1:])
    else:
        return False

Simple and crisp. Let’s try it on some inputs.
Note that I used Python’s time module to print out the time, which is quick and dirty, but it does the job.

Bogosort([5,4,3,2,1])
Time = 0.000202894210815

Okay. Now let’s try it again on an input size of 10.

Bogosort([10,9,8,7,6,5,4,3,2,1])
52.8398268223

Since it is completely randomized, running this will give different times each time it is run, but the ballpark figure will at least be somewhat similar.

Normally, I’d try on a larger input size, but since the growth rate is going to be exponential, an input size of 11 will cause a time that is much longer than when an input size of 10 is used.

In fact, in our example, running on an input size of 10 took over 260,000 times longer than when run on an input size of 5.

However, since the numbers are random, it is impossible to determine exactly how much longer it will take , but it should be somewhere around that range.

Conclusion


If you are looking for a horrendously slow sorting algorithm for any reason, Bogosort is the perfect candidate. It works by randomly shuffling the list until it gets a sorted list, which means that its average performance is going to be O((n+1)!).

Of course, Bogosort should not be taken as a serious sorting algorithm, and is intended to be used as a comparison to other sorting algorithms like quick sort and merge sort.

Unless your goal is to create slow code, stay far far away from this monstrosity.

 

Java Lambdas : Syntactic Sugar

You glance down at your list of invited guests for your party.
Suddenly, you see someone with the last name of “Dang”, the very same family that ruined your party the last time they showed up.

Furiously, you write a program to sort through the hundreds of invited guests to remove everyone with the last name “Dang”.

For the sake of simplicity, a smaller list will be used, but nonetheless, you end up with this hideous snippet:

public class Party {

    static List invitedGuests;

    public static void main(String[] args){

        invitedGuests = new ArrayList() {{
	    add("Henry Dang");
            add("Joe Dang");
	    add("Kevin Smith");
	    add("John Dang");
	    add("John Doe");
	    add("Michelle Sans");
        }};

	for(Iterator iterator = invitedGuests.iterator(); iterator.hasNext();){
            String guestName = iterator.next();

	    if(guestName.contains("Dang")){
                iterator.remove();
	    }
	}

	for(String guests : invitedGuests){
	    System.out.println(guests);
	}
    }
}

 

What a terribly cluttered mess!

But what if you could have done it in a simpler, more concise way?
With Java 8’s lambdas, you can cut down the length of the logic to 1/5th of its size!

public class Party {

    static List invitedGuests;

    public static void main(String[] args){

        invitedGuests = new ArrayList() {{
	    add("Henry Dang");
            add("Joe Dang");
	    add("Kevin Smith");
	    add("John Dang");
	    add("John Doe");
	    add("Michelle Sans");
        }};

     invitedGuests.removeIf(name -> name.contains("Dang"));
     invitedGuests.forEach(name -> System.out.println(name));
    }
}

Just like that, your code instantly becomes clean, concise, and expressive.
The removeIf method simply takes a Predicate, which is basically a boolean. It checks if the name contains the word “Dang” in it, and if it does, it instantly removes it from the list.

The line after it is just a fancy for each loop, except it’s only one line long. The forEach method takes in a Consumer object, which basically says, “Give me a parameter, and something to do with that parameter.” You pass in the parameter “name”, and print all the names in the list.

Now that you’re done, all the Dangs are off your list, and you’ve shortened your otherwise obnoxiously verbose code by 8 lines.