Wednesday, July 30, 2014

Rules of Programming

Introduction

Since I started programming, I've discovered a handful of rules that guide how I program. I posted these on Google+ several months ago, but I want to go into more detail about them. These rules may not apply to all situations, but they have been very good guidelines for me through the years. 


Rule 1 - Make it work, then make it fast

I spent a year and a half or so in college working as a teaching assistant for the Algorithm Analysis class. One of the requirements for all programs that students wrote in that class was that they finish in a certain amount of time. Of course, the programs were still expected to return the correct results. If a program was supposed to sort 1000 numbers and their result only included 999, I gave them a lower grade. I can't count the number of times students came to me and asked why they got a low grade when their program ran in the time required. Every time, I had to explain that anybody can write a fast program. Their goal was to write a program that was both fast and correct. They would usually get a better grade if they were slow but correct.

I decided from that experience that the best way to write a program is to write a "baseline" version that will get the right answer. It may be slow, and it may be ugly, but it's right. Then you can take that program, start tweaking, adjusting and changing it until you have a program that still gets the right answer (compare the results to the baseline) and is now fast enough.

In practice, I've also found that trying to write a program that is designed for speed causes me trouble because I'm trying to juggle too many things in my head at once. With every line of code I have to ask myself "Is this getting me closer to the correct result?" and "How will this affect my speed?". When I can separate those two questions and write the code in two passes (first for accuracy then for speed) I end up with a much better result.

Rule 2 - A working solution is a solution, even if you did it the "wrong" way

This rule is really sort of an extension of Rule 1. Almost anything you can do in a computer program can be done a dozen different ways. When you are first learning a new language or library, or just doing something or the first time, it's likely that you'll do it in a weird, inefficient way. For example, maybe you write a complex algorithm because you didn't realize that the library has it built-in. There's nothing wrong with that. You wrote a program that works. That's the key. As long as your solution gets the right answer, you did it right. You can be happy and celebrate that. You can release that version of your program. It's a good solution.

Rule 3 - Do it the wrong way until you learn the right way

Now we're moving on from Rule 2. Once you have developed a way to solve a problem (no matter how ugly), keep using it whenever that problem comes up. There's nothing wrong with that. Of course, the day will come that you find a better way to do it. It may be that you found that command that was hidden in the library. Or maybe you just thought of a better way to write the code. Programmers have at least two major reactions to this situation:

First, you may say that you spent so much time on your first solution that you don't want to have wasted all that time and you don't use the new solution. Frankly, this seems stupid to me. Your time wasn't wasted. You solved the problem the best way you could. You had a perfectly valid, working solution. Now, you just need to realize that you've learned something new. That's a good thing. A programmer that isn't learning new things is stuck in a rut and will be bored, stagnant and pretty soon obsolete.

Second, you decide that your solution has had its time to shine, but now it needs to be put out to pasture. You start using the new method immediately and every time you come across the problem again, you use the new solution. I think this is the right way to go. When you do this you will be continually learning and growing. You will be improving your skills and keeping up with the times.

Rule 4 - Once you learn the right way, be willing to go back and throw out your old "wrong" code

So, once you've moved on from your old solution to a new one, what do you do to your old code? Well, that depends. If it ran just fine before and doesn't need other updates, leave it alone. You can drive yourself insane going back to old code and constantly improving it. You'll never develop anything new. On the other hand, if it's important code that could really be improved by having the new solution implemented into it, feel free to go back and fix it. You may find yourself tearing out code that you slaved over. It's a weird feeling watching 15 or 20 lines of code that you worked so hard to figure out turn into a single call into a library. Nobody wants their work to go to waste, but remember that your old code wasn't a waste. I think we can all agree that, typically, changing from version 1.0 to 2.0 is a good thing. That's what you're doing with your code. You're upgrading it. You don't owe it anything. Your old code has served its purpose and is ready to be replaced. If you're sentimental about it, print it out and hang it on your wall. But if it can be improved, do it and release it.

Rule 5 - Write your code assuming that when you come back to it, you won't remember anything

Something funny happens to code that I leave alone for a long time. Even when I'm the guy that wrote it, I look at it and can't remember exactly how it all works. It's like it changes without me staring at it. I know that it's all in my head. The code isn't changing, I just don't remember it. But it sure feels like the code changed while I wasn't looking. To combat this, I write comments. Lots of them. I recommend that you do the same.

Now, I don't comment every single line. I've known guys that do that and I don't think it's worth the effort. Too much time to format it and maintain it. Instead, I write a comment at the start of a block telling me what that block of code is supposed to do. For example, I might have a comment before a for() loop that says "Find the requested client in the list". I now know what that loop is trying to do. If there's an individual line that is doing something that may not be totally apparent, I'll put a comment on that line, too. My comments tend to read sort of like a high-level view of what my code is doing, with occasional low-level details thrown in.

Another tool to writing readable code is formatting. I'm not going to tell you whether to use spaces or tabs or whether opening braces belong on their own line. I have my opinions about these, but there's a bigger thing to discuss here. Consistent formatting will make your code much more readable. The key word there is "consistent". Pick your favorite formatting rules and stick to them. Make sure that everyone in your team follows the same conventions. All of the code in a project should follow the same conventions. If some files are formatted one way, and some are formatted another, then the project becomes harder to understand. Have your team pick formatting rules, and then formalize them. Write them down, create an Eclipse formatter file, something. But everyone on the team needs to know the rules and stick to them.

Rule 6 - Keep your code in a version control system

One of the most important tools I use while programming is a version control system. Again, I don't want to tell you which one is the best, but you want to find one that works for you. A good version control system helps for a number of reasons.

First, you can always look through the history to see what you (or members of your team) changed. These logs can help remind you of what the code does.

Second, it will help you save code in case you do something really strange or disastrous and need to roll back. I also use it to write debug code. (This trick works best with a distributed system like Mercurial or Git.) I make sure that the broken code is saved in the version control system. Then I can add print statements or whatever else I need to find and fix the bug. Then, once I've found the bug and know how to fix it, I revert back to the original, broken code and put the fix in. This lets me scatter debug statements liberally throughout the code without requiring me to go back and find them all when I'm done with them.

Third, if your code repository is stored off-site (or at least off of your local machine) then you have a really nice back up solution already in place. I think we can all agree on the importance of those. I put the repositories for my personal projects in DropBox. That way they are backed up and available to me from just about any computer.

Conclusion

So, there are my major rules of programming. There may be times when they don't apply. You might need to think about speed from the very beginning of a project. That's fine. But in 99% of the code that I've written over the years, these have worked for me.

What rules do you have? Anything you'd like to share? Let me know. I'm curious. And I'm always looking for ways to improve.

No comments:

Post a Comment

ShareThis