Writing a custom Zikula module can be relatively fun and easy, provided you follow some basic guidelines and are prepared to invest some discipline. The more complex the module you are writing, the more you will benefit from the strategies laid out in this post.
It should be noted that this article is very much Zikula 1.2 based/focussed. Although the guiding principles remain the same, some of the details change in Zikula 1.3.
1) Plan ahead: before you start coding, sit down and think about what you wish to achiev in detail. Make sure you understand the requirements your module has to fulfill and develop a strategy for storing and handling your module's data. Time spent planning is well-invested since it tends to pay for itself during the course of development and maintainance.
2) Consistently format your code: Zikula suggests a 4-space indention in your PHP code. Whether you use 4-spaces, 8-spaces or tabs doesn't really matter as long as you use the same formatting on *all* your code. Make sure your code is properly indented and that it is easily readable. There is nothing worth than trying to make sense of code which is a mess to look at. If I can't read your code I can't understand it which in turn means that it's pretty useless to me. Remember: just because your editor displays your code in an orderly manner doesn't mean other editors will. If you are not sure, open your code in a different editor to check if your code is properly indented.
3) Comment your code: commenting your code can be in important help in order for someone else to understand the intention of your code. The important thing to remember for code comments is that you should comment *why* you are doing something, not *what* you are doing. What you are doing should be readily understandable from the code itself. Why you are doing whatever it is you are doing is an improtant prerequisite for understand what you are doing. For complex pieces of code a short description of *what* you are doing may be a good idea, but generally this should not be needed often.
4) Write modular code: there is nothing worse than a function which runs on for several pages and does lots of complex things. If you have such a function, split it up into smaller sub-functions whose purpose is then more easily understood. This is also an important tool to allow code re-use since chances are that if you are performing a series of complex steps, some of these steps may be of use in other parts of your module.
5) Group common functions into a utility class: common functions which are frequently used by your module should be grouped into a utility class (or equivalent package structure). This makes it easy to locate such common code and allows you to have a central repository of code which can easily be updated in a single place. When writing code, try to identify common pieces of functionality which you use a lot and define such functionality as utility methods. If done consistently, it creates a smaller and more maintainable codebase.
6) Use the architecture: Zikula provides you with rich architecture which allows you to let the system take care of many common tasks. Use the architecture to it's fullest extent. Even if you're tempted to implement something yourself, spend the extra few minutes to see if the architecture does not already provide the feature you need. Doing so ensures compatibility with future Zikula releases and allows you to offload maintainance of that piece of code to the Zikula team.
7) Separate functions by scope: Zikula lets you group functions into scope groups. At the simplest level, this is results in the pnadmin/pnuser and pnadminapi/pnuserapi distinction. However, if your module is complex, why stop there. For example, have your display code reside in pnuser.php and the code which processes user input in pnuserform.php. Once you start separating your code into components, you will find that the code structure becomes clearer and that you have and easier time managing your code.
8) Avoid shortcuts and hacks: No matter how tempting, avoid shortcuts and hacks. A lot of times you may think that it's easier to just hack something in quickly rather than spending the extra hour to code a proper solution. If you plan for your module to be around for a while and to be maintainable, avoid such hacks at all costs because they *always* come back to bite you in the rear at a later date and cause you to waste time and get gray hairs. In addition to this, coding a proper solution will usually result in cleaner, more maintainable code which in the long run will save you time, effort and gray hairs.
9) Use an object/component model: related to #4, #5 and #6, use a component model. My suggestion is to use PNObject/PNObjectArray component model which, under Zikula 1.2, is the most advanced component model available. Under Zikula 1.3 there will be additional options to choose from, but if you choose PNObject your code will run without issues under Zikula 1.3. Using a component model has numerous benefits: it forces you to separate your code into distinct units while also forcing a great degree of consistency on your code. In addition, PNObject allows you to define an object which knows how to select/insert/update/delete it's data with about 5 lines of code. If you have the need for more complex behaviour, PNObject provides all the hooks you could ever want and need in order to implement even the most complex object behaviour. Using a component model can evolve into the single biggest code and time saving device of all the points discussed above. Note that in 1.3 PNObject changes to DBObject and we also added the possibility to define/use Doctrine objects. The underlying idea though is the same and using it consistently will save you lots of repetitive typing.
10) When tired, take a break: If you've been sitting at your computer all day long and things do go they way you'd like them to go, take a break and do something which has nothing to do with the task of coding. Go for a walk, go for coffee, play a game, rock out on your guitar, paint your house, etc. You will find that when you return that you may have new ideas or insights which may allow you to solve the problem at hand with surprising ease. If all else fails, don't be afraid to ask for help on the forums; we're all human and we all make mistakes and sometimes an extra pair of eyes is just what you need to solve a stubborn problem.
These points hopefully give you some ideas on what you can do to improve y or code. I try to use them consistently and am convinced that I would be more frustrated and less productive if I didn't do so.