Development hints and tips
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!)