The Power of PseudoCode

By | July 13, 2020

“Pseudocode” is a powerful way to write and document software. Put simply Pseudocode is just plain english text describing what the code should do – it is not actually code itself. I found this old-school screen cap on Google that describes nicely a few of the reasons why Pseudocode is great:

How to Write Pseudocode: 15 Steps (with Pictures) - wikiHow

The following is an example of what a good use of Pseudocode looks like. In this case I’ve written out the basics of a function to handle user logins:

/**
* login:
* 
* The purpose of this function is to attempt to login a user.
*
* Returns: 
* User record: On successful login or
* false: On error or failed login
*/
function login(username, password) 
{
    // TODO: Check for valid inputs to this function:

    // TODO: Get the user from the database:

    // TODO: Check the user is valid:

    // TODO: Check the user is not locked out:

    // TODO: Validate the user's password:

    // TODO: If the user passes all above checks and has a valid
    // password, then return their user record, otherwise 
    // return false:
}

As you can see we haven’t written real code. We really only wrote the skeleton of a function and then wrote out in plain english comments what our code will do.

The Benefits of Pseudocode

Why would you write out Pseudocode instead of just writing the code? Well there are a few reasons:

  1. Breaking Down the Problem: By writing out the basic steps to implement our function we have to think about the entire problem to be solved by the function. This helps us break down how the code should work and how it must work when there is bad input or an error.
  2. Specify the Interface: Pseudocode can help us to define the input and output of our function, class or code blocks. In the case of the example above we have to handle two cases – a successful login and a failed login, so we need to have returns for both. It also allows us to share our planned interface with other developers before we have written the code.
  3. Identify Opportunities for Reuse: For each of the high level steps of the function, we have a TODO line. In some cases we can identify through these steps items that could be made separate functions that could be reused. In the case of this example, there are at least 3 items that should be separate reusable functions.
  4. Find Gaps in Understanding: The final benefit of Pseudocode is that it can help you determine what you need to know that you don’t know right now. In our hypothetical example, after writing out the function it is clear we don’t really have a strategy for error handling and that needs to be addressed. Returning “false” when a login fails is OK – but does not communicate errors, or reasons why a user could not login. We won’t address it here, but proper error handling is definitely a topic for the future.

Actually Writing the Code

Taking into consideration our four points above we can actually write out or code by filling in the TODOs. We will do this with some basic operations and calls to external functions/libraries we either write or have available:

/**
* login_v2:
* 
* The purpose of this function is to attempt to login a user. 
* We've made some changes based on our thoughts so far.
*
* Returns: 
* User record: On successful login or
* false: On error or failed login
*/
async function login_v2(username, password) 
{
    // ------------------------------------------------------ 
    // Check for valid inputs to this function. 
    // ------------------------------------------------------ 
    if ((username != undefined) && (username != '') && 
        (password != undefined) && (password != ''))
    {
        return false;
    }

    // ------------------------------------------------------ 
    // Get the user from the database - this should be
    // a reusable function:
    // ------------------------------------------------------ 
    var the_user = await users_service.get_user_by_username(username);

    // ------------------------------------------------------ 
    // Check the user is valid and is not locked out:
    // ------------------------------------------------------ 
    if (the_user == undefined || the_user['status'] != 'VALID')
    {
        return false;
    } 

    // ------------------------------------------------------ 
    // Validate the user's password:
    // ------------------------------------------------------ 
    var valid_password = await users_service.validate_password(the_user['password'], password);

    // ------------------------------------------------------ 
    // If the user passes all above checks and has a
    // valid password, then return their user record, 
    // otherwise return false:
    // ------------------------------------------------------ 
    if (valid_password == true)
    {
        return the_user;
    }
    else
    {
        return false;
    }
}

A lot changed between our initial Pseudocode and what we have now. But, the key take away is that the code we added just filled in the pieces we created with our Pseudocode.

Creating/Using Reusable Functions

Most of the above is pretty simple code. It may or not be an optimal solution or example, but it is instructive. One key concept shown in this example is how Pseudocode can help you identify reusable code.

The “users_service” is an example of what I mentioned above. Pseudocode helps you find places where you will need to do something in other places – and the user operations in this function are exactly that. You will need to get user records frequently so write the code to do it once and reuse it. Similarly password checks may need to be used in multiple places, so write it once and reuse it.

Often times when I build code, I will define services to handle various pieces of functionality. One very common one I use is a “users_service” that handles all user operations – get, create, update, delete, search, and validate operations will all be part of the service.

Finding these places where you will want to create reuse-able code is one of the strong benefits of the exercise of Pseudocode. It will become very clear when you go through what code will be something you would want just here in this function vs. something you can use over and over.

Added Benefit: Code Documentation

Another great benefit of writing Pseudocode first before you write code is now you have code documentation already written. It’s already written as part of your Pseudocode. You just need to tweak it to match the actual code you have written as needed.

Some may say that the comments above are trivial and unneeded. To some extent that is true, but in this case we’re providing a simple example so the comments help.

Self Documenting Code is a LIE

I hold the VERY STRONG opinion that code comments are required and you can never have too many code comments.

I absolutely HATE the idea that code is “self documenting”. It’s not. Stop lying to yourself and your team.

Let me repeat myself. Your code is NOT self documenting. You, the original author of the code may have a complete understanding of it at the time. You or the poor bastard that comes behind you 18 months later will have no clue what you meant or what business rules you were using.

(Note: I’m not the only one who thinks this by any stretch. Here is another great article on the topic: https://medium.com/it-dead-inside/self-documenting-code-is-mostly-nonsense-1de5f593810f)

I’ve seen and had to work on code that is more than 10 years old many times. I’m talking about code running enterprise applications at billion dollar companies. Very rarely do these ancient applications have any code comments.

The worst example I can think of was a 21 year old PHP applicaiton. This code was initially written 5 major PHP versions ago. It has been heavily tweaked, changed, and refactored over the years. No one ever added code comments and so no one knows how it really works. Working on new functionality or making bug fixes takes forever because you have to read through a ton of code to figure out what is even going on.

This is the nightmare you create without code comments. Nightmares for whoever the poor bastard is that has to work on your code down the road. That poor bastard might be you by the way.

But by writing Pseudocode first, you already have a basis for code documentation and code comments. So, I advise that you do so, and continue to comment your code as it grows and evolves. You will thank me later. Your colleagues and folks who come behind you will thank you too.

Start Today

If you don’t already make a habit of writing out code in Pseudocode – try it out today, or the next time you are writing code. It will help you better understand and structure your code – plus it comes with the added benefit of having already written code comments to help you and any future developers who have to touch your code.