loading...
Cover image for Make Your Pseudocode Your Real Code

Make Your Pseudocode Your Real Code

cannikin profile image Rob Cameron Updated on ・4 min read

If you've been coding for any amount of time you've probably come across the concept of pseudocode: a quick "mockup" of a class, object or algorithm that uses human-friendly shortcuts to get across the concept of something you're working on.

Here's some pseudocode for deciding whether or not to display a button (and which button) to a user based on their login status and permission:

if logged_in?
  if user_can_create_post?
    show_create_post_button
else
  show_login_button

It's very clear what's happening at each step: you take it for granted that "logged_in?" will return true if the user is logged in and false if they aren't. We don't care about the details of what being "logged in" means at this point because it doesn't matter in the big picture of what this code is trying to do.

There's a reason we use pseudocode when trying to get a concept across: it's a very low-overhead way to demonstrate to someone, even someone non-technical, how some code will work.

One possible implementation of this in real code (in this case Ruby) could look something like:

if session[:user].present? && current_user = User.find(session[:user])
  if current_user.permissions.find_by(:name => 'can_create_post').present?
    render :partial => 'button', :label => 'Create Post'
  end
else
  render :partial => 'button', :label => 'Login'
end

This works. And at the time you're writing it it's probably fairly clear to you. But come back across it 6 months from now, or show it to a new developer, and you have to stop and look at each method call and expend some mental overhead translating each step into what it actually does in the context of your app:

# does user have a user ID in session?
session[:user].present? 

# is this a real user ID in the database? If so, save it as a local variable `current_user`
current_user = User.find(session[:user]) 

# does user have a permission record in the database?
current_user.permissions.find_by(:name => 'can_create_post').present? 

# show a little view snippet for an HTML <button> with the given text label
render :partial => 'button', :label => 'Create Post' 

I think many developers don't realize (or pretend they don't care) how much time they spend converting statements like this in their heads over and over again. If you could simplify that process, or even eliminate it completely, why wouldn't you?

That pseudocode was pretty clear...what if our real code was that simple to parse and understand? How close can we get? (Fair warning: some languages will make this an easier exercise than others. Ruby especially so. If you're coding in a strongly typed language it's going to be hard to avoid that ceremony of type declarations that will make this code much "busier".)

(Also: if you don't know, Ruby automatically returns the last statement in a method call so we don't need any explicit return statements in these new methods.)

def show_action_button
  if logged_in?
    if can_create_post?
      show_create_post_button
    end
  else
    show_login_button
  end
end

def logged_in?
  current_user.present?
end

def current_user
  if session[:user].present?
    User.find(session[:user])
  else
    nil
  end
end

def can_create_post?
  current_user.present? and current_user.permissions.find_by(:name => 'can_create_post').present?
end

def show_create_post_button
  show_button('Create Post')
end

def show_login_button
  show_button('Login')
end

def show_button(label)
  render :partial => 'button', :label => label
end

That's pretty darn close. It sure is more lines of code, though. But that's a tradeoff I'm happily willing to make—I want this code to be quick to understand and edit in the future. I don't really care that a computer has to work a little harder and make the stack a little deeper in order to execute it.

We've extracted everything into methods that are a) reusable, b) clearly named for what they do and c) do one thing. And our main algorithm show_action_button reads just like our original pseudocode.

Some additional benefits:

  • DRYed up the code that rendered the button
  • Simpler to test since each method can be tested independently
  • If you find a problem with this code at some point in the future the sections of the code are basically labeled with what they do to make it that much easier to find

You'll come across all kinds of advice for how to break your code into reusable methods, DRYing up a section, or making sure that your methods only do one thing. If you try and write your algorithm so that it looks like pseudocode, these axioms naturally come about as a happy side effect.

Next time you're looking at a piece of code and trying to figure out if it can be made simpler, think about how you can turn that real code into pseudocode!

For further reading take a look at this post by Martin Fowler where he talks about giving your functions "intention revealing" names so you can skip the implementation details and get to the core meaning of the top-level function/class that much quicker.

Discussion

pic
Editor guide
Collapse
ben profile image
Ben Halpern

Very very well explained. This applies to all sorts of languages, but it's extremely true in Ruby. The language's cleanliness is lost if you don't leverage it.

Collapse
cannikin profile image
Rob Cameron Author

Thanks! I was working on a random controller or presenter in Rails a couple of months ago and after some refactoring I sat back and looked at it and realized it almost looked like some pseudocode that I'd write on a whiteboard when planning. I looked through the codebase and ended up seeing that pattern everywhere and realized that's basically what most "good" code ends up looking like—I just hadn't heard anyone phrase it as such!

Collapse
aeddi13 profile image
Patrick Decker

Great advice!
Code should always be written in a way that it is easy to read and understand. Even if it takes longer to write.
Always keep in mind. Code is only written once, but it can be read infinite times.

Collapse
olusamimaths profile image
Olusola Samuel

This forum is a blessing for a beginner like me. I would heed to this keenly🤔

Collapse
imthedeveloper profile image
ImTheDeveloper

Really like this. Human readable is one thing I hear discussed by clean coding posts but human understandable is what this really gives!