Difference between revisions of "Coding best practices"
P.petrelli (talk | contribs) |
P.petrelli (talk | contribs) |
||
Line 2: | Line 2: | ||
{{Template:Working on}} | {{Template:Working on}} | ||
− | <span style="font-family:Arial,Helvetica,sans-serif;"><span style="font-size:medium;">There are code standards and conventions available depending on the language you are using and sometimes also conventions adopted for specific collaborative projects. While below we provide a few links to these, here we are just going to focus on some basic tips that can help you making your code more readable and safer from bugs. These can be applied to any language. | + | <span style="font-family:Arial,Helvetica,sans-serif;"> |
+ | <span style="font-size:medium;">There are code standards and conventions available depending on the language you are using and sometimes also conventions adopted for specific collaborative projects. While below we provide a few links to these, here we are just going to focus on some basic tips that can help you making your code more readable and safer from bugs. These can be applied to any language.</span> | ||
− | === <span style="font-size:large;">''' | + | === <span style="font-size:large;">'''Naming'''</span> === |
− | ==== | + | ==== <span style="font-size:medium;">'''Use long and descriptive names for variables and functions''' ==== |
− | + | There is no advantage in using short names for variables and functions, it is good practice instead to use names that are descriptive, even if this will make them longer. Particularly for functions it is good to specify in the name what they do. | |
− | + | For example for a function that calculates an anomaly use calculate_anomaly() rather than calc().This also reduce the chances of using a reserved word. | |
+ | NB If you're using an IDE to edit your code then you can easily auto complete the names | ||
− | + | ==== '''Avoid reserved keywords and names of common functions''' ==== | |
− | + | Reserved keywords are words that are used for special functionalities, they change with the language but usually are used to control the flow of the code as "if", "for", "import" or used for declarations like "None", "True", "global, so they cannot be used to name anything else. Any other word can be used as a name but be careful, in [https://www.geeksforgeeks.org/why-python-is-called-dynamically-typed/ dinamycally typed languages] like Python a variable is evaluated while running the code, it is not declared at the start. This is because a variable name is just a link to an object and so the same name can refer to different objects in the same code. | |
− | + | For example if I have a function called ''mean'' and later on in the code assigned a float value to it. | |
− | <syntaxhighlight lang=bash> | + | |
− | #For example if I have a function called mean | + | I won't get an error then, but I will when trying to call ''mean'' as a function |
− | def mean(): | + | <syntaxhighlight lang="bash"> |
+ | #For example if I have a function called mean | ||
+ | def mean(variable): | ||
... | ... | ||
− | + | return value | |
mean = 45.3 | mean = 45.3 | ||
#if I try then to call the function I will get an error | #if I try then to call the function I will get an error | ||
Line 28: | Line 32: | ||
</syntaxhighlight> | </syntaxhighlight> | ||
− | + | mean type of variable can be are some that is still best to avoid, common examples are 'file' | |
− | + | There are also some that can be used as a name,like 'file', 'format', 'int', 'list', 'dict' , but that are already names of existing functions. This will of course also depend on which modules you are using and how you import them. | |
− | ==== | + | ==== '''Use consistent naming across the code''' ==== |
− | + | Try to be consistent in the way you name your variable, constants and functions. There are a few conventions out there among the most common: | |
− | * | + | *lowercase_words_with_underscores |
− | * | + | *CapitalisedWords (also known as CamelCase) |
− | * | + | *ALL_CAPITALS for constants values |
− | * | + | *mixedCase |
− | + | Whatever you choose try to be consistent, use the same conventions for the same type of objects. | |
− | Avoid hard-coding values | + | ==== '''Avoid hard-coding values''' ==== |
− | + | ==== '''Initialising variables''' ==== | |
You | You | ||
[https://www.python.org/dev/peps/pep-0526/#global-and-local-variable-annotations https://www.python.org/dev/peps/pep-0526/#global-and-local-variable-annotations] | [https://www.python.org/dev/peps/pep-0526/#global-and-local-variable-annotations https://www.python.org/dev/peps/pep-0526/#global-and-local-variable-annotations] | ||
+ | </span> | ||
+ | === <span style="font-size:large;">'''Code structure''' </span>=== | ||
− | === <span style="font-size: | + | ==== <span style="font-size:medium;">'''Indents''' ==== |
− | + | Some languages like Python enforce indenting, but even where it is not necessary indenting your code can help outlining the code structure. Again try to be consistent either use tabs or spaces, some languages like python have a preference for spaces. | |
− | + | ==== '''Comments''' ==== | |
− | + | Comments are extremely useful to document what your code is doing. Again you do not need to comment every line, as that might actually made the code less redable. But it is a good practice to have: | |
− | + | *a block of comments at the start of the code listing author, license,a a date for the last update, what the code does and how to use it. | |
+ | *similarly have a fe wlines of comments for each function or before a coherent block of code in the main program, for example before an "if/else" block. | ||
− | + | It can also be useful starting a code by writing what do you want to do as comments. For example | |
− | |||
− | |||
− | |||
<nowiki># Assign arguments | <nowiki># Assign arguments | ||
# Open data files | # Open data files | ||
Line 71: | Line 75: | ||
# Save output to file</nowiki> | # Save output to file</nowiki> | ||
− | | + | In this way you have a draft of your comments and you can work out the best structure, individuate blocks that can be included in a function etc, before you even start coding. It can save you a lot of time. |
− | ==== | + | ==== '''Subdive your code using functions or sub-modules''' ==== |
− | + | Ideally a function should execute one coherent operation. As none of us it's a software developer we are not suggesting every line of code is a function , more than a logical block of lines should be included in a function. This is particularly true and useful if it's a block of code you might want to repeat in other parts of this same or others programs. | |
+ | Another good reason to enclose a block of code in a function it is to make it easier to add a test. Use tests It is a good idea to test at least critical parts of your code. You want to be sure that a calculation which is critical to your results, is producing consistent and correct results, no matter what changes you introduce to the same function or other part of your code. | ||
+ | No matter how many tests you are conducting it is hard to preview all the possible ways a code can be used and it is often the case that as soon as you sue a different set of data you are going to find some bugs. Every time you fix a bug make sure you are adding a test to capture it. So you will know if accidentally you re-introduce it later on. | ||
==== DRY code ==== | ==== DRY code ==== | ||
− | ==== | + | ==== '''One statement per line''' ==== |
− | + | Cramming a lot of instructions in one line of code won't make your code faster, just less readable. It will also make it more difficult to pinpoint what is causing an error if you have a few instructions in the same line. | |
− | ==== ''' | + | ==== '''Keep your files a reasonable length''' ==== |
− | + | Main message here is to be consistent and descriptive, in the end any conventions aim is to have consistency. Even if you are not using an established convention, being at least consistent across all of your codes will help making them more readable and re-usable. | |
− | + | Order of preference | |
− | + | make your intentions clear even if it is not necessary | |
− | === ''' | + | === '''Functions''' === |
− | ==== ''' | + | ==== '''Clear flow Try to have only one exit point in a function''' ==== |
− | + | Return example | |
− | === ''' | + | === '''Style guides''' === |
− | * | + | *[https://www.python.org/dev/peps/pep-0008/ Python: pep8] Python Enhancement Proposal |
**[https://docs.python-guide.org/writing/style/ https://docs.python-guide.org/writing/style/] | **[https://docs.python-guide.org/writing/style/ https://docs.python-guide.org/writing/style/] | ||
**[https://realpython.com/python-pep8/ https://realpython.com/python-pep8/] | **[https://realpython.com/python-pep8/ https://realpython.com/python-pep8/] | ||
− | *[https://realpython.com/lessons/reserved-keywords/ | + | *[https://realpython.com/lessons/reserved-keywords/ Python reserved keywords] |
− | * | + | *[https://docs.julialang.org/en/v1/manual/style-guide/ Julia: style guide] |
− | * | + | *[https://cran.r-project.org/web/packages/AirSensor/vignettes/Developer_Style_Guide.html R style guide] |
− | *[https://www.datamentor.io/r-programming/reserved-words/ <span style="font-size:medium;">R reserved keywords | + | *[https://www.datamentor.io/r-programming/reserved-words/ <span style="font-size:medium;">R reserved keywords] |
* | * | ||
Line 115: | Line 121: | ||
This page was inspired by the seminar "[https://www.eventbrite.com.au/e/reproducible-research-how-to-write-code-that-is-built-to-last-tickets-153241109283# Reproducible research how to write code that is built to last] organised by DataTas. A recording is available on their facebook page. | This page was inspired by the seminar "[https://www.eventbrite.com.au/e/reproducible-research-how-to-write-code-that-is-built-to-last-tickets-153241109283# Reproducible research how to write code that is built to last] organised by DataTas. A recording is available on their facebook page. | ||
+ | |||
+ | </span></span> | ||
[[Category:Data induction]] | [[Category:Data induction]] |
Revision as of 21:43, 11 July 2021
There are code standards and conventions available depending on the language you are using and sometimes also conventions adopted for specific collaborative projects. While below we provide a few links to these, here we are just going to focus on some basic tips that can help you making your code more readable and safer from bugs. These can be applied to any language.
Naming
Use long and descriptive names for variables and functions
There is no advantage in using short names for variables and functions, it is good practice instead to use names that are descriptive, even if this will make them longer. Particularly for functions it is good to specify in the name what they do.
For example for a function that calculates an anomaly use calculate_anomaly() rather than calc().This also reduce the chances of using a reserved word. NB If you're using an IDE to edit your code then you can easily auto complete the names
Avoid reserved keywords and names of common functions
Reserved keywords are words that are used for special functionalities, they change with the language but usually are used to control the flow of the code as "if", "for", "import" or used for declarations like "None", "True", "global, so they cannot be used to name anything else. Any other word can be used as a name but be careful, in dinamycally typed languages like Python a variable is evaluated while running the code, it is not declared at the start. This is because a variable name is just a link to an object and so the same name can refer to different objects in the same code.
For example if I have a function called mean and later on in the code assigned a float value to it.
I won't get an error then, but I will when trying to call mean as a function
#For example if I have a function called mean
def mean(variable):
...
return value
mean = 45.3
#if I try then to call the function I will get an error
sst_mean = mean(sst)
#as "mean is now referring to the float object "45.3" as i have overwritten the link to the mean
mean type of variable can be are some that is still best to avoid, common examples are 'file'
There are also some that can be used as a name,like 'file', 'format', 'int', 'list', 'dict' , but that are already names of existing functions. This will of course also depend on which modules you are using and how you import them.
Use consistent naming across the code
Try to be consistent in the way you name your variable, constants and functions. There are a few conventions out there among the most common:
- lowercase_words_with_underscores
- CapitalisedWords (also known as CamelCase)
- ALL_CAPITALS for constants values
- mixedCase
Whatever you choose try to be consistent, use the same conventions for the same type of objects.
Avoid hard-coding values
Initialising variables
You
https://www.python.org/dev/peps/pep-0526/#global-and-local-variable-annotations
Code structure
Indents
Some languages like Python enforce indenting, but even where it is not necessary indenting your code can help outlining the code structure. Again try to be consistent either use tabs or spaces, some languages like python have a preference for spaces.
Comments
Comments are extremely useful to document what your code is doing. Again you do not need to comment every line, as that might actually made the code less redable. But it is a good practice to have:
- a block of comments at the start of the code listing author, license,a a date for the last update, what the code does and how to use it.
- similarly have a fe wlines of comments for each function or before a coherent block of code in the main program, for example before an "if/else" block.
It can also be useful starting a code by writing what do you want to do as comments. For example # Assign arguments # Open data files # Calculate ... # Plot ... # Save output to file
In this way you have a draft of your comments and you can work out the best structure, individuate blocks that can be included in a function etc, before you even start coding. It can save you a lot of time.
Subdive your code using functions or sub-modules
Ideally a function should execute one coherent operation. As none of us it's a software developer we are not suggesting every line of code is a function , more than a logical block of lines should be included in a function. This is particularly true and useful if it's a block of code you might want to repeat in other parts of this same or others programs. Another good reason to enclose a block of code in a function it is to make it easier to add a test. Use tests It is a good idea to test at least critical parts of your code. You want to be sure that a calculation which is critical to your results, is producing consistent and correct results, no matter what changes you introduce to the same function or other part of your code. No matter how many tests you are conducting it is hard to preview all the possible ways a code can be used and it is often the case that as soon as you sue a different set of data you are going to find some bugs. Every time you fix a bug make sure you are adding a test to capture it. So you will know if accidentally you re-introduce it later on.
DRY code
One statement per line
Cramming a lot of instructions in one line of code won't make your code faster, just less readable. It will also make it more difficult to pinpoint what is causing an error if you have a few instructions in the same line.
Keep your files a reasonable length
Main message here is to be consistent and descriptive, in the end any conventions aim is to have consistency. Even if you are not using an established convention, being at least consistent across all of your codes will help making them more readable and re-usable.
Order of preference
make your intentions clear even if it is not necessary
Functions
Clear flow Try to have only one exit point in a function
Return example
Style guides
- Python: pep8 Python Enhancement Proposal
- Python reserved keywords
- Julia: style guide
- R style guide
- R reserved keywords
References
This page was inspired by the seminar "Reproducible research how to write code that is built to last organised by DataTas. A recording is available on their facebook page.