1. Hash is the best form of data representation for Puppet. So, try to adjust your hiera data to the concepth "Everything is a Hash" ( XaaH ).
2. All configuration files must be divided into 2 parts: the one that is calculated dynamically by Puppet server and another one that is generated from Hiera.
3. Configuration files must be generated from manifests without templates ( use inline templates, Luke :) ). Templates are only allowed either for very complicated configs when 1 file uses a number of multiple formats inside of itself, or for the config part that uses dynamically calculated values that are not common for all servers that run that service.
4. Use either built-in or stdlib function for config generation. If there is no appropriate function that satisfies requirements of your module - write your own function and extend the exsting stdlib snap. it is easier to write necessary function and spend time once than constantly change configuration files.
5. There is no place for scripts and programs inside puppet modules - use packaging capabilities of your distribution and manage those programs via package versions. All changeable parts of the script or the program must be separated into configuration files and handled according to statemets 2-4 above.
6. If rule 1 is not respected - something is wrong with design of your module.
7.Follow the standard module hierarchy. Inside init manifest of your module transform hashes from hiera into configuration files and strings into package versions and service attributes.
8. Do not try to puppetize smething that is not supposed to be. E.g. if some configuration is stored somehow what puppet cannot handle natively via its resources - don't creat crutches from "exec" resources. Puppet is for state description, not for the orchestration.