- Gather complete requirements.
- Take the time to write down what the end product needs to achieve. Clarity of thought at this stage will save a lot of time down the line.
- Write an implementation plan (or model).
- For something small and self-contained, this might just be a basic flowchart or an equation.
- For larger projects, it helps to break it into modules and consider what job each module must do, how data gets passed between modules, and within each module how it will function.
- Although it is fun to dive straight into code, it is equally tedious to spend hours debugging. By taking the time to design the structure on paper, you will drastically reduce your debugging time (and you may also spot more efficient ways of doing things even before you write the first line of code).
- Add Comments to your code.
Whenever you feel your code needs some explanation, drop some comments in. Each function should be preceded by 1-2 lines describing the arguments and what it returns. (Comments should tell you why more often than what. Remember to update the comments when you update your code!)
- Use naming conventions for variables.
It will help you keep track of what type the variable is and also what it's purpose is. Although this means more typing than x = a + b * c, it will make your code easier to debug and maintain. One popular convention is Hungarian notation where the variable name is prefixed with its type. e.g. for integer variables, intRowCounter; strings: strUserName. It doesn't matter what your naming convention is, but be sure that it is consistent and that your variable names are descriptive. (See Warnings below)
- Organize your code.
Use visual structure to indicate code structure. i.e. indent a code block that sits within a conditional (if,else,...) or a loop (for,while,...) Also try putting spaces between a variable name and an operator such as addition, subtraction, multiplication, division, and even the equal sign (myVariable = 2 + 2). As well as making the code more visually elegant, it makes it much easier to see the program flow at a glance. (See tips on indentation below)
Start by testing it with inputs that you would typically expect. Then try inputs that are possible but less common. This will flush out any hidden bugs. There is an art to testing and you will gradually build up your skills with practice.
Write your tests to always include the following:
- Extremes: zero and max for positive values, empty string, null for every parameter.
- Meaningless values, Gibberish. Even if you don't think someone with half a brain might input that, test your software against it.
- Wrong values. Zero in a parameter that will be used in a division, negative when positive is expected or a square root will be calculated. Something that is not a number when the input type is a string, and it will be parsed for numeric value.
- Practice. Practice. Practice.
- Be prepared for change.
In a realistic working environment, requirements change. However, the clearer you are at the start about the requirements and the clearer your implementation plan, the less likely those changes will be down to misunderstanding or "Ah, I hadn't thought of that" scenarios.
- You can take an active role in improving clarity of thinking by presenting your requirements document or your implementation plans before coding to ensure that what you are planning to create is actually what's been asked for.
- Structure the project as a series of milestones with a demo for each block. Approach the programming one milestone at a time - the less you need to think about at any moment, the more likely you will think clearly.
- Start simple and work towards complexity.
When programming something complex, it helps to get the simpler building blocks in place and working properly first.
For example, let's say you want to create an evolving shape on screen that follows the mouse and where the degree of shape change depends on mouse speed.
- Start by displaying a square and get it to follow the mouse, i.e. solve movement tracking on its own.
- Then make the size of the square relate to mouse speed, i.e. solve speed-to-evolution tracking on its own.
- Finally create the actual shapes you want to work with and put the three components together.
- This approach naturally lends itself to modular code writing, where each component is in its own self-contained block. This is very useful for code reuse (e.g. you want to just use the mouse tracking in a new project), and makes for easier debugging and maintenance.