wiki:HowtoGoodProgrammingTechniques

Version 25 (modified by Thanatermesis, 7 years ago) ( diff )

--

http://main.elivecd.org/images/misc/maton.png

This is a list of some programming tips that I found or brainstormed over the time

Programming Procedure

I normally follow a simple steps procedure when coding, that should be done on every new function:

  1. Write: I have the idea in mind, so I need to make it working first, this is normally ugly code but, the goal is to make it working
  2. Make it good: Then I make the code better, including the methodologies of this coding like correct returning values, making a better structure and readable identation
  3. Understanding: Good variable and function names is maybe the best programming tip that you can have, see the section of convention-names, this is a little slow procedure since thinking of best names to use requires some brainstorming
  4. Cleanup: Now it's time to remove all the useless parts, the goal is to use the simplest solutions and procedures, they are usually the most appropiate ones, try to reduce the code as much as possible, this step consist in multiple reading of the function thinking on how it works, you will discover on this step a lot of bugs in your code that you won't imagine that exists.

States

When you are programming, you will see that your code needs to be intelligent, it needs to know what to do now and how to deal with specific situations, this is a lot more easy to reach with states, in short, put boolean states everywhere they are cheap!, this way we can always know how to deal in specific situations, but keep in mind we dont want a bloated code with confusing states, so we need to think of a good way to organize them in our code, for example, the prefix is_ is one of the best ones to use, just think about the possibilites to have states (as booleans) marked like is_sources_get, is_sources_compiled, is_interactive... So everytime your application does a specific thing, you can set or unset the affected variables to define the state/progress of the application to know what to do next. Your application can also have different ways of work, so you can prefix those states with mode_, see for example mode_interactive or mode_editing, another useful one is also the ignore_ prefix in order to ignore steps on our application.

It's important to think about the possible expected situations, since we are humans this is hard to acheive but we need to keep in mind every different situation, like if the file is deleted when... or if at the same time the user...

Special Situations

To have states and flags to know how to deal with situations is good, but it's even better if you don't need to do that! before dealing with any special situation just think if it's possible to deal with this element in a better way or totally avoid this need, try to always avoid complex coding.

Integration

An application does a lot of steps, the process does something and then save it to the database, but in fact, you only want to save it in the database only and only if the entire process is successful, but how to know that on this actual step ? well, just create a boolean variable with a state or flag saying that it needs to do that in the end, and when the entire process finishes you have a function called final_steps that runs all the steps that needs to be commited if the entire process has finished succesfully, this is useful for example for remove temporal directories, for commit or send things, for umount or closing shared medias, etc...

Checks

Your code should be perfect, but in fact, it is not... so don't assume that everything is OK, sometimes by an unkown reason something fails and you could have catastrophic disasters, in order to avoid a buggy application or catastrophic disasters, there's a simple rule: always check everything, simply create short functions for that, for example i have one that is called check_directories with arguments passed by commas which you should understand what it does, another called check_variables and another called check_files, I decided to stay with this name-convention, they are simple and they are in the group of checkers and to have them by the prefix files_ variables_ directories_ make no sense.

Human factors

Memory

You don't have genius memory, you won't remember exactly "what this code does" or "why is this thing there", a good way to avoid this is by adding comments but sometimes you forget to do that or the comments you made are not sufficient enough, in most cases you think that you don't need it in this part of the code or that the element of the code is old and not-needed-anymore or similar things. What I personally do to accelerate the development process and to not think about it at the moment is to add on this step a function name "step_requires_fixme message", which is ran at the prompt/shell if I come to this state of the code it will asking me what im doing here or to verify something.

Visual Readability

Readability is very important, but is not only a matter of using good names, it also depends of the visual appearance of the elements, for example:

  • If you have an else 40 lines away of its if, do not use else but instead close it and start a new if in the place, is more easy to read
  • Align vertical blocks of similar elements by its columns
  • Whitespaces improves readability a lot, use them, if you combine them with foldings in your editor you will not suffer the side-effect of removing contents visually

Visual Blocks

Similar as previously said, we need to see visually the blocks of code, for example sometimes we have a big block of looping code, if you add a new feature you may not even see that you are in our even out of the loop, so you can insert code that should run inside the loop outside of it, on such case you can use a plugin in your editor to fold visually the desired part of the code, or put the biggest parts to external functions

And similarly, the ifs blocks and other blocks has the same problem, they needs to be correctly visual in your eyes to know inmediately where it starts or finishes, or if you are simply in a block at all

Think less

If you think less, you can read faster, for example:

  • Don't say equal or less than 2 if you want to say less than 3
  • Never use negatives, they are harder to think than afirmatives, for example:
    • if not accept becomes if ignore
    • if is not disabled becomes if enabled (stupid but very common)
    • ignore is also a form of negative, use want when you can instead
  • write shorter and clever sentences

Convention Names

Names in variables and functions are something very important, the convention to use is to be the smallest-size possible with a perfect understanding of its name and what exactly does, think on the structure like in object-programming languages, where the first name needs to be the biggest element and the last the smaller one, and in the end include the action, it should look like an hierachy in object-oriented elements.

It is a good procedure to rename all the functions after the app is finished, by reading the list of all of them and decide the optimal names structure for the entire code, same for global variables.

Never create names like this

  • download_resource_now: It doesn't make any sense or description, the action is in the first, now means nothing and resource nothing too
  • stmb_sizer_here_here: The double here means that your code is so ugly that you don't even believe it, sizer is not easy to understand and if stmb is not the name of a library or evident element, it is almost impossible to understand what it means

The good way

  • cookie_download: we know that we are talking about cookies, and we don't need to include now because download is already the action, in case that we will have 2 different kinds of download we should use download_foo and download_bar, without keeping the possibility of a single download and having an extendeded one

The optimal way

  • myplugin_net_cookie_download: Structuring everything entirely is the best option, all our elements should start by myplugin which is our entire work about, net means the section were we are those codes (let's say we have core, net, visual, and sound)

In short, most of the times you will see that the names are written in inverse mode that is how you talk them, if you doubt, just imagine to have some similar possible names and you sort them, you will see how they are sorted and which part of the name needs to come before the other ones

It is good to know what's exactly that variable, to know if we are dealing with a file, with a directory, or with a value, I personally use for that a suffix (ending in) in the variables like _v for values, _d for identifying directories, _f for identifying a file, there's also a good practice to use _ as prefix for any local variable.

Big Applications

Big applications are very hard to found where a bug is to fix it, very hard to maintain, etc, the best way to avoid these pains are:

  1. Keep everything modularized but independent, this means that every function, tool or feature, can be called independently without depend of any other thing, think about use external commands
  2. When those external commands or global tools/functions are called, make sure to include a debug entry showing how it is called, on this way you can easly reproduce the same callback outside the application
  3. Never delete or rename old functions, you will have tools that still depend of it, instead, replace it with the new function and add a warning line telling the user that this function is deprecated
  4. Never refactor changing the final behaviour, unexpected results will happen to applications that uses these functions

7+1 rules for names that must-read from this article, summarized as:

  1. The variable name has to be as descriptive as possible. Don´t use generic names.
  2. The variable name has to be as short as possible.
  3. It´s OK to use abbreviations, but explain the abbreviation with a comment.
  4. Use proper Hungarian notation when necessary.
  5. Don´t use negative logic for your variable names.
  6. Be consistent.
  7. Map the application domain terminology with your names.
  8. Golden rule: Spend a few minutes thinking about your variable names.

The 5 steps coding procedure

  1. Write the feature and make it work
  2. Minimize the code (less lines, simple and short functions, less-complex algorithms, etc)
  3. Structure it correctly (spaces/readability, comments, begin-end parts, local variables, etc)
  4. Document (comment) the needed parts to make it easly understandable, is suggested to use doxygen syntax
  5. Convention names, take some time to decide the optimal names for your variables and functions

Wisdom

  1. The secret to building large apps is never build large apps. Break your applications into small pieces. Then, assemble those testable, bite-sized pieces into your big application.
  2. Reducing the amount of code in your product should be a goal.
  3. If you are changing more than 25% of a class or method, consider simply rewriting it. You will write the code more cleanly.
  4. Accept that you have no idea how this will grow. The key is to acknowledge from the start that you have no idea how this will grow. When you accept that you don't know everything, you begin to design the system defensively... You should spend most of your time thinking about interfaces rather than implementations.
  5. Write all your functions to be able to work independently without requiring extra data like global variables, this let's you to test them independently, or even re-use them elsewhere. Thanatermesis

Common Excuses For A Software Rewrite

Why Rewriting Is (Almost) Never A Good Idea

  • It Always Takes Longer Than You Expect
  • Markets Change
  • Existing Customers Become Frustrated
  • Refactoring Can Cleanup The Code
  • You Don't Control The Rewrite, It Controls You

The Zen of Python

  • Beautiful is better than ugly.
  • Explicit is better than implicit.
  • Simple is better than complex.
  • Complex is better than complicated.
  • Flat is better than nested.
  • Sparse is better than dense.
  • Readability counts.
  • Special cases aren't special enough to break the rules.
  • Although practicality beats purity.
  • Errors should never pass silently.
  • Unless explicitly silenced.
  • In the face of ambiguity, refuse the temptation to guess.
  • There should be one-- and preferably only one --obvious way to do it.
  • Although that way may not be obvious at first unless you're Dutch.
  • Now is better than never.
  • Although never is often better than *right* now.
  • If the implementation is hard to explain, it's a bad idea.
  • If the implementation is easy to explain, it may be a good idea.
  • Namespaces are one honking great idea -- let's do more of those!

Art of Unix programming

  • Rule of Modularity: Write simple parts connected by clean interfaces.
  • Rule of Clarity: Clarity is better than cleverness.
  • Rule of Composition: Design programs to be connected to other programs.
  • Rule of Separation: Separate policy from mechanism; separate interfaces from engines.
  • Rule of Simplicity: Design for simplicity; add complexity only where you must.
  • Rule of Parsimony: Write a big program only when it is clear by demonstration that nothing else will do.
  • Rule of Transparency: Design for visibility to make inspection and debugging easier.
  • Rule of Robustness: Robustness is the child of transparency and simplicity.
  • Rule of Representation: Fold knowledge into data so program logic can be stupid and robust.
  • Rule of Least Surprise: In interface design, always do the least surprising thing.
  • Rule of Silence: When a program has nothing surprising to say, it should say nothing.
  • Rule of Repair: When you must fail, fail noisily and as soon as possible.
  • Rule of Economy: Programmer time is expensive; conserve it in preference to machine time.
  • Rule of Generation: Avoid hand-hacking; write programs to write programs when you can.
  • Rule of Optimization: Prototype before polishing. Get it working before you optimize it.
  • Rule of Diversity: Distrust all claims for “one true way”.
  • Rule of Extensibility: Design for the future, because it will be here sooner than you think.

Extra

  • Always use local variables, don't share them externally or you can have catastrophic results
  • Never change the value of a local variable if your function is more than 15 lines long, for that, use a new local variable
  • Use a good powerful editor with good plugins, like vim with a good setup
  • trap signals, like exit errors etc
  • the simplest procedure/option is the best, do not think in complex ways to do supa-dupa-intelligent-features if they are not needed
  • Think on multi-work, if you use a temporary directory called /tmp/myapp, you could have conflict when another user try to use the same application which will point to the same location (so /tmp/user-myapp is a good option). Or also including the ID of the process is also a good method for avoid re-using the same directory if the application can be launched multiple times
Note: See TracWiki for help on using the wiki.