Note:

If you want to create a new page for developers, you should create it on the Moodle Developer Resource site.

Development hints and tips: Difference between revisions

From MoodleDocs
(Updating links to User docs)
 
(26 intermediate revisions by 2 users not shown)
Line 1: Line 1:
{{Work in progress}}
{{Work in progress}}


There is a great deal of development experience amongst the Moodle developers. This page is some general hints and tips that may help people starting out in PHP and Moodle development.  
There is a great deal of development experience amongst the Moodle developers. This page is some general hints and tips that may help people starting out in PHP and Moodle development. These apply as much to people writing their own plugins as core developers.


== Avoid writing code in the first place ==
== Avoid writing code in the first place ==
Line 10: Line 10:


Moodle has a well developed set of [[Coding|Coding Guidelines]]. Read them and follow them. It's surprising how many custom plugins for Moodle do not. It instantly prevents your code from being incorporated in core Moodle.
Moodle has a well developed set of [[Coding|Coding Guidelines]]. Read them and follow them. It's surprising how many custom plugins for Moodle do not. It instantly prevents your code from being incorporated in core Moodle.
Pay particular attention to the security information. A basic understanding of security in a web development environment is no longer optional. If you don't know what an XSS attack or an SQL injection are then you need to find out.
== When in Rome, do like the Romans ==
The Coding Guidelines do not describe every possible situation. When you find yourself in that situation, try to follow the example of how things are done in other parts of Moodle. Just because Moodle is not written the way you would do it if you were starting from scratch does not matter. In a large project like Moodle, it is more important to keep the code consistent than it is to satisfy your personal prejudices about how code should be. That makes it easier to maintain the code, and if you start writing Moodle-style code, you will find it easier to understand the other bits of Moodle code you look at.
Of course, some parts of Moodle are just badly written. You should not copy what is done in those places. ;-) When looking for examples to follow, try to find code that has been written recently by one of the reliable core developers.
Getting involved in a large Open Source project can be a bit of a culture shock if you are not used to it. Lots of advice (and, sometimes, constructive criticism) is readily available. Don't be afraid to ask - that's what the General Developer Forum is for.


== Use a Version Control system ==
== Use a Version Control system ==


If you are developing without a version control system then you are doing it wrong. The benefits run well beyond just being able to keep past versions of your code. Moodle currently uses CVS for core development but this is probably a poor (out of date) choice for a new project. The world seems to be moving towards [[Git tips|Git]]. This is a powerful distributed system and does take a bit of getting your head around but the effort is worth it.
If you are developing without a version control system then you are doing it wrong. The benefits run well beyond just being able to keep past versions of your code. Moodle uses [[Git tips|Git]] for developing so it makes sense to learn it. This is a powerful distributed system and does take a bit of getting your head around but the effort is worth it.


== Find an editor or IDE that works for you and learn it properly ==
== Find an editor or IDE that works for you and learn it properly ==


There are many different development platforms from complex Integrated Development Environments (IDEs) to simple editors and command line tools. Choose something that works for you and then take the trouble to learn how to use it properly.
There are many different development platforms from complex Integrated Development Environments (IDEs) to simple editors and command line tools. Choose something that works for you and then take the trouble to learn how to use it properly.
Find the editor's customisation options and make it fit in with Moodle's coding guidelines - example, most editors can be persuaded to use the correct number of spaces (4 in Moodle's case) rather than the tab character.


== Comment effectively ==
== Comment effectively ==


Don't be shy about putting comments in code. If the code deserves a blank line it probably deserves a comment. It's obvious what the code does now but it won't be in six months.  
Don't be shy about putting comments in code. If the code deserves a blank line it probably deserves a comment. It's obvious what the code does now but it won't be in six months.
 
== KISS (Keep It Simple Stupid) ==
 
Albert Einstein didn't ''actually'' say "Everything should be made as simple as possible, but no simpler" but it would still have been good advice if he had. Take the trouble to come up with the simplest solution to the problem at hand. Resist the temptation to add code for things that you ''might'' need in the future or ''might'' be required one day. They usually never happen and you can always change the code later if requirements change. For example, don't use some insanely complex object factory when old-fashioned procedural programming will do. Don't use old-fashioned procedural programming when a class-hierarchy models the real-world problem more intuitively. Avoid complex abstractions where they are not actually needed to get the job done. Any additional code increases the risk of bugs, security problems and maintenance issues in the future.


== Use good variable and function names ==
== Use good variable and function names ==


It should be easy and obvious to pick a name for a variable or a function. If it isn't you are either trying to make that function too complicated (simplify and break it up) or you haven't full understood what you are trying to do (another cup of coffee?). Names should always say what they are for or what they do - plainly.
It should be easy and obvious to pick a name for a variable or a function. If it isn't you are either trying to make that function too complicated (simplify and break it up) or you haven't fully understood what you are trying to do (another cup of coffee?). Names should always say what they are for or what they do - plainly.


== Pretty code is good code ==
== Pretty code is good code ==
Line 33: Line 49:
== Write Plugins. Use APIs ==
== Write Plugins. Use APIs ==


Always, when developing custom features, write a standard plugin rather than modifying core code. Even if you have to compromise the functionality a bit. Most Moodle plugin structures are able to easily create database structures, handle role capabilities, define language files and ease future updates. Furthermore, the end result can all be delivered in one simple zip file. It doesn't rely on one particular build of Moodle either. These are real and big advantages. A core code patch is only guaranteed to work with the exact build it was written with, it probably won't survive upgrades and patches are notoriously difficult to apply properly - even for experienced developers. If in doubt look at blocks - you can do an awful lot with a block (even if it's never actually added as a visible block). Blocks are reasonably easy to understand and to develop, too.  
Always, when developing custom features, write a standard plugin in preference to modifying core code. Even if you have to compromise the functionality a bit. Most Moodle plugin structures are able to easily create database structures, handle role capabilities, define language files and ease future updates. Furthermore, the end result can all be delivered in one simple zip file. It doesn't rely on one particular build of Moodle either. These are real and big advantages. A core code patch is only guaranteed to work with the exact build it was written with, it probably won't survive upgrades and patches are notoriously difficult to apply properly - even for experienced developers. If in doubt look at blocks - you can do an awful lot with a block (even if it's never actually added as a visible block). Blocks are reasonably easy to understand and to develop, too.  


Similarly, take the trouble to investigate existing Moodle APIs and library calls. Your code will last longer and be more reliable.
Similarly, take the trouble to investigate existing Moodle APIs and library calls. Your code will last longer and be more reliable.
Line 39: Line 55:
== Separate out functionality ==
== Separate out functionality ==


Or... don't muddle up the user interface with the database access and other logic. For example, alarm bells should ring if you are writing functions like '''get_data_and_display()'''. It is a much better idea to write '''get_data()''' and then '''display_data()'''. The effort is little or no different, however, the end result is often easier to follow and (say) if someone asks you to dump the data to Excel rather than display it the latter method saves you a costly refactor. Even if you are not writing functions and your logic is all on one page try to split things into logic blocks - read the input, THEN do the calculations and database access, THEN display the output. It will be easier to refactor or to modify.
Or... don't muddle up the user interface with the database access and other logic. For example, alarm bells should ring if you are writing functions like '''get_data_and_display()'''. It is a much better idea to write '''get_data()''' and then '''display_data()'''. The effort is little or no different, however, the end result is often easier to follow and (say) if someone asks you to dump the data to Excel rather than display it the latter method saves you a costly refactor. Even if you are not writing functions and your logic is all on one page try to split things into logical blocks - read the input, THEN do the calculations and database access, THEN display the output. It will be easier to refactor or to modify.
 
== Object Oriented Programming... or not ==
 
Object Oriented Programming provides many useful tools and techniques that can improve code and productivity. It is particularly useful for organising code, controlling hierarchies and controlling visibility. However it has (arguably) been horribly oversold in the past and can, if used unwisely, promote some deeply obscure and flawed development practices. The whole thing is a massive subject by itself. If you don't know, you should do some reading but make sure you read the articles about why it can be a BAD idea too (start with  [http://www.geocities.com/SiliconValley/Lab/6888/oopbad.htm|Object Oriented Programming Oversold]). Use it only when it makes the code *better* not just because you think you should. Always avoid making code more obscure and hard to debug no matter how elegant the solution may seem.


== Don't Make Me Think ==
== Don't Make Me Think ==


It's actually a title of a book by Steve Krug (and it should be obligatory reading for all web designers), however, the point is really about Usability. Usability is hard but you still have to try. Don't make your users have to think. Good documentation is important but it's hard to keep it up to date and it's a partial failure if someone has to resort to reading it. In particular, be quite clear that ordinary Moodle users don't care about clever implementation or super flexibility. Anything that complicates the job of getting effective learning materials to students is "a bad thing". Anything that in the name of adding flexibility or functionality makes an ordinary user's job more complex is a regression. If something must be done then the code must do it - do not burden the user.  
It's actually a title of a book by Steve Krug (and it should be obligatory reading for all web designers), however, the point is really about Usability. Usability is hard but you still have to try. Don't make your users have to think. Good documentation is important but it's hard to keep it up to date and it's a partial failure if someone has to resort to reading it. In particular, be quite clear that ordinary Moodle users don't care about clever implementation or super flexibility. Anything that complicates the job of getting effective learning materials to students is "a bad thing". Anything that in the name of adding flexibility or functionality makes an ordinary user's job more complex is a regression. If something must be done then the code must do it - do not burden the user.  
Force yourself to think like a user and not a programmer. A clever, elegant solution to a programming problem is not guaranteed to result in a feature that is simple and intuitive to use. Look at the forums. If lots of people are having trouble using a feature then you need to consider if the feature is doing the job well enough.


It should be hard (or even better impossible) for users to break things. The greatest invention ever was the undo button - it doesn't only protect the user against mistakes it allows them to safely experiment. Users don't learn to use software by reading the manual - they experiment and guess. Make it easy for them.
It should be hard (or even better impossible) for users to break things. The greatest invention ever was the undo button - it doesn't only protect the user against mistakes it allows them to safely experiment. Users don't learn to use software by reading the manual - they experiment and guess. Make it easy for them.


There's some guidelines (currently under development) in [[Moodle User Interface Guidelines|User Interface Guidelines]]
There's some guidelines (currently under development) in [[Moodle User Interface Guidelines|User Interface Guidelines]]
== Let the database do the grunt work ==
If there's a choice let the database do the work of searches. Especially if multiple tables are involved. It's what it was designed to do. It can be tempting, especially if your SQL knowledge isn't too good, to tie together multiple database queries with PHP loops and the like. Always consider using a single database call instead. Always try to use the basic Moodle database API functions before writing custom SQL (portability!).
Having said all that, optimising databases (especially when datasets get large) is a subject in itself. Nearly all web development involves database interactions so even basic db admin skills are very valuable and worthwhile acquiring.
== Generate helpful error messages ==
If you generate an error message, consider if it 'really' helps the user fix the problem. Be as specific as possible. If you can give information that will help resolve the problem rather than just say it happened then do so. BUT... you also have to consider security. Don't give away information that might help a hacker. You might want to consider debugging level (is it on?) and/or who the user is (you might give an administrator more information).
You should also try to trap as many possible errors as possible. If a function returns a fail condition then you would need to have a very good reason not to check it. This helps avoid the highly unpopular "white screen of death".
Add extra debugging code (call ''debugging()'' )if you think it might help. This is especially true for functions that have complex configuration or external dependencies (i.e. lots that can go wrong).
Never write an error message that looks something like "An unknown error occurred". You might as well not bother as this doesn't help anybody fix the problem.
== Don't make empty pages and blocks ==
If you write code that returns (typically) a block (but you can do it lots of places) think very carefully before returning nothing. An empty return for a block causes the block not to be displayed at all. Unless you have a very compelling reason to do this avoid it. It will confuse the user - they add a block and then nothing happens. If some capability or configuration is required consider displaying a message to help them. In a report or other pages that return variable data, be careful how you deal with empty data sets. Always display something like "no data found" rather than a blank page. Blank pages make users think something is broken.
== Turn on Debugging and fix those notices and warnings ==
If you get PHP warnings or notices when [[:en:Debugging|Debugging]] is switched on the problem is '''not''' that debugging has been left on, the problem is that there are bugs in your code. There is no excuse for not checking for and then fixing notices and warnings. To not do so is shoddy at best.
== Expand Moodle Docs ==
If something you want to do isn't documented (or isn't documented well or fully) and you figure it out - document it. Don't write it in your notebook or your company's closed Wiki, put it in the docs here. It's there for you next time and for everyone else as well.


== More tips please ==
== More tips please ==
(add your own!)
(add your own!)

Latest revision as of 06:51, 21 September 2011

Note: This page is a work-in-progress. Feedback and suggested improvements are welcome. Please join the discussion on moodle.org or use the page comments.


There is a great deal of development experience amongst the Moodle developers. This page is some general hints and tips that may help people starting out in PHP and Moodle development. These apply as much to people writing their own plugins as core developers.

Avoid writing code in the first place

Always take the trouble to find if there is another (existing) way to do what you need. Failing that, does a plugin or option already exist. Failing that, does something exist that you can modify. Failing that, is there a library (or libraries) that exist to reduce your effort. Lastly write the code yourself. Existing, tested code is always to be preferred - more so if it has an extensive user base.

Follow the Coding Guidelines

Moodle has a well developed set of Coding Guidelines. Read them and follow them. It's surprising how many custom plugins for Moodle do not. It instantly prevents your code from being incorporated in core Moodle.

Pay particular attention to the security information. A basic understanding of security in a web development environment is no longer optional. If you don't know what an XSS attack or an SQL injection are then you need to find out.

When in Rome, do like the Romans

The Coding Guidelines do not describe every possible situation. When you find yourself in that situation, try to follow the example of how things are done in other parts of Moodle. Just because Moodle is not written the way you would do it if you were starting from scratch does not matter. In a large project like Moodle, it is more important to keep the code consistent than it is to satisfy your personal prejudices about how code should be. That makes it easier to maintain the code, and if you start writing Moodle-style code, you will find it easier to understand the other bits of Moodle code you look at.

Of course, some parts of Moodle are just badly written. You should not copy what is done in those places. ;-) When looking for examples to follow, try to find code that has been written recently by one of the reliable core developers.

Getting involved in a large Open Source project can be a bit of a culture shock if you are not used to it. Lots of advice (and, sometimes, constructive criticism) is readily available. Don't be afraid to ask - that's what the General Developer Forum is for.

Use a Version Control system

If you are developing without a version control system then you are doing it wrong. The benefits run well beyond just being able to keep past versions of your code. Moodle uses Git for developing so it makes sense to learn it. This is a powerful distributed system and does take a bit of getting your head around but the effort is worth it.

Find an editor or IDE that works for you and learn it properly

There are many different development platforms from complex Integrated Development Environments (IDEs) to simple editors and command line tools. Choose something that works for you and then take the trouble to learn how to use it properly.

Find the editor's customisation options and make it fit in with Moodle's coding guidelines - example, most editors can be persuaded to use the correct number of spaces (4 in Moodle's case) rather than the tab character.

Comment effectively

Don't be shy about putting comments in code. If the code deserves a blank line it probably deserves a comment. It's obvious what the code does now but it won't be in six months.

KISS (Keep It Simple Stupid)

Albert Einstein didn't actually say "Everything should be made as simple as possible, but no simpler" but it would still have been good advice if he had. Take the trouble to come up with the simplest solution to the problem at hand. Resist the temptation to add code for things that you might need in the future or might be required one day. They usually never happen and you can always change the code later if requirements change. For example, don't use some insanely complex object factory when old-fashioned procedural programming will do. Don't use old-fashioned procedural programming when a class-hierarchy models the real-world problem more intuitively. Avoid complex abstractions where they are not actually needed to get the job done. Any additional code increases the risk of bugs, security problems and maintenance issues in the future.

Use good variable and function names

It should be easy and obvious to pick a name for a variable or a function. If it isn't you are either trying to make that function too complicated (simplify and break it up) or you haven't fully understood what you are trying to do (another cup of coffee?). Names should always say what they are for or what they do - plainly.

Pretty code is good code

Seriously! Code that is well laid out and easy to read is easy to debug and to modify. Make the effort to lay out code so it looks good and is easy to read through. Don't be afraid to break something nasty into several lines so that it reads well. It's tempting to make one line of code do something incredibly complex but you won't feel so clever when you can't remember how it works.

Write Plugins. Use APIs

Always, when developing custom features, write a standard plugin in preference to modifying core code. Even if you have to compromise the functionality a bit. Most Moodle plugin structures are able to easily create database structures, handle role capabilities, define language files and ease future updates. Furthermore, the end result can all be delivered in one simple zip file. It doesn't rely on one particular build of Moodle either. These are real and big advantages. A core code patch is only guaranteed to work with the exact build it was written with, it probably won't survive upgrades and patches are notoriously difficult to apply properly - even for experienced developers. If in doubt look at blocks - you can do an awful lot with a block (even if it's never actually added as a visible block). Blocks are reasonably easy to understand and to develop, too.

Similarly, take the trouble to investigate existing Moodle APIs and library calls. Your code will last longer and be more reliable.

Separate out functionality

Or... don't muddle up the user interface with the database access and other logic. For example, alarm bells should ring if you are writing functions like get_data_and_display(). It is a much better idea to write get_data() and then display_data(). The effort is little or no different, however, the end result is often easier to follow and (say) if someone asks you to dump the data to Excel rather than display it the latter method saves you a costly refactor. Even if you are not writing functions and your logic is all on one page try to split things into logical blocks - read the input, THEN do the calculations and database access, THEN display the output. It will be easier to refactor or to modify.

Don't Make Me Think

It's actually a title of a book by Steve Krug (and it should be obligatory reading for all web designers), however, the point is really about Usability. Usability is hard but you still have to try. Don't make your users have to think. Good documentation is important but it's hard to keep it up to date and it's a partial failure if someone has to resort to reading it. In particular, be quite clear that ordinary Moodle users don't care about clever implementation or super flexibility. Anything that complicates the job of getting effective learning materials to students is "a bad thing". Anything that in the name of adding flexibility or functionality makes an ordinary user's job more complex is a regression. If something must be done then the code must do it - do not burden the user.

Force yourself to think like a user and not a programmer. A clever, elegant solution to a programming problem is not guaranteed to result in a feature that is simple and intuitive to use. Look at the forums. If lots of people are having trouble using a feature then you need to consider if the feature is doing the job well enough.

It should be hard (or even better impossible) for users to break things. The greatest invention ever was the undo button - it doesn't only protect the user against mistakes it allows them to safely experiment. Users don't learn to use software by reading the manual - they experiment and guess. Make it easy for them.

There's some guidelines (currently under development) in User Interface Guidelines

Let the database do the grunt work

If there's a choice let the database do the work of searches. Especially if multiple tables are involved. It's what it was designed to do. It can be tempting, especially if your SQL knowledge isn't too good, to tie together multiple database queries with PHP loops and the like. Always consider using a single database call instead. Always try to use the basic Moodle database API functions before writing custom SQL (portability!).

Having said all that, optimising databases (especially when datasets get large) is a subject in itself. Nearly all web development involves database interactions so even basic db admin skills are very valuable and worthwhile acquiring.

Generate helpful error messages

If you generate an error message, consider if it 'really' helps the user fix the problem. Be as specific as possible. If you can give information that will help resolve the problem rather than just say it happened then do so. BUT... you also have to consider security. Don't give away information that might help a hacker. You might want to consider debugging level (is it on?) and/or who the user is (you might give an administrator more information).

You should also try to trap as many possible errors as possible. If a function returns a fail condition then you would need to have a very good reason not to check it. This helps avoid the highly unpopular "white screen of death".

Add extra debugging code (call debugging() )if you think it might help. This is especially true for functions that have complex configuration or external dependencies (i.e. lots that can go wrong).

Never write an error message that looks something like "An unknown error occurred". You might as well not bother as this doesn't help anybody fix the problem.

Don't make empty pages and blocks

If you write code that returns (typically) a block (but you can do it lots of places) think very carefully before returning nothing. An empty return for a block causes the block not to be displayed at all. Unless you have a very compelling reason to do this avoid it. It will confuse the user - they add a block and then nothing happens. If some capability or configuration is required consider displaying a message to help them. In a report or other pages that return variable data, be careful how you deal with empty data sets. Always display something like "no data found" rather than a blank page. Blank pages make users think something is broken.

Turn on Debugging and fix those notices and warnings

If you get PHP warnings or notices when Debugging is switched on the problem is not that debugging has been left on, the problem is that there are bugs in your code. There is no excuse for not checking for and then fixing notices and warnings. To not do so is shoddy at best.

Expand Moodle Docs

If something you want to do isn't documented (or isn't documented well or fully) and you figure it out - document it. Don't write it in your notebook or your company's closed Wiki, put it in the docs here. It's there for you next time and for everyone else as well.

More tips please

(add your own!)