Declare your intentions.
Be upfront. As soon as you know you're going to be using a variable, declare it. This means putting all of your variables at the top of a function. Think of it as setting up the characters that your story is going to use. You want to give the readers of your code an idea of who the main players of the function are going to be. Of course, all your variables will end up being hoisted up to the top of their scope anyway, but this adds to readability and makes it clear which scope the variable will be available in.
It's also helpful to add a few lines of commenting at the beginning to describe what the program will do. Think of it as a thesis statement for a viewer (or future you) so they know what to expect in the lines to come. And if you'd still like to add some clarification, you can...
Test your assumptions.
How many times have you written something that in theory, should work, but at runtime something unexpected happens? We can't predict every outside force that is going to act on the program, and this is where testing comes in. Writing tests helps in a couple of ways: first, by writing them out, you're forced to be very clear about what your program should be doing, and what you expect the result to be. Second, you can find out pretty quickly if this is what the program is actually doing. It's hard to predict exactly how every aspect of a program is going to be received by the environment we're running it in, so writing tests helps to ensure it's being received the way we intended it to be. Starting out a program by writing tests for it first makes sure your code is staying on track with its purpose, and that you're always working on functional code. And as an added bonus, you can go forth and refactor confidently knowing that you aren't breaking your code (or, at the very least, knowing exactly what it was that you did that broke it).
Think of your audience.
It's easy, sitting there with your head in Sublime, to forget that you're not the only one who will be seeing your code. With that in mind, write for your audience. Keep in mind that a new viewer to your code doesn't have the full context of the program that you do. Continue to ask yourself as you write what clues you can add to your program to give more context to an outside viewer. Is there a variable that looks out of place because it's relying on the syntax of a gem? Add some comments to clarify why it's there. Find ways to keep your audience on your level of understanding.
Clean up your code.
If your intentions for the program or a function change, rewrite your code to reflect this new purpose. We've all written code with good intentions at the time, but then our goals or intentions changed, and the code we originally wrote no longer serves a purpose. Going back to rewrite or delete code that is no longer serving the purpose it needs to as soon as possible helps your program flow, and also helps to ensure that every piece of the program is serving a specific and clear purpose. In other words, if a piece of code is no longer needed, let it go.
After writing a program, go back to rearrange the functions in the order that they are called. Ordering functions in order of use makes it clearer for others to see what the interactions between the functions are. It also makes finding functions a lot easier— if you know when in your program the function should be called, you also have a pretty good idea of when it should appear in your file.
Even after all of these methods, there may still be areas where a reader of your code can get lost. If you think there's a chance for confusion in your program, add comments to clarify why a function exists or what exactly it's doing. Err on the side of over-explaining, and your readers will thank you (but don't get crazy— your project should be more code than comment).
And by that I really mean, don't be careless. If a variable only needs to be in scope of one function, don't allow it to become a part of the global namespace. If a function really belongs to a class, make it a prototype, and don't let it become a global function. Be honest with each part of your program about what it does, what other elements it should be able to interact with, and what other parts have access to it. Keep everything in its rightful place.
One place where this really becomes an issue is in the global section of your program. If you've got a lot of variables mixing around in the global namespace, and functions that can be called at any time, it's much easier to run into unexpected issues with conflicting variables. Again, think of it in the context of a novel: It's much easier (and enjoyable) to follow a novel that handles one plotline at a time between just a few select characters, as opposed to a novel that's trying to simultaneously juggle multiple plotlines between fifty different characters.