This framework grew over several years in the hands of several programmers. Though we haven't always made bumper sticker mottos, some come to mind which might help you understand what we do and why.
Once upon a time our do_* methods queried our databases directly and produced HTML output. The flow of our modules was hard to follow. The markup was hard to work on. Worst of all much of the sql and markup was repeated over and over again with cp or cut and paste.
Instead of hand writing each select, we rejoice in the simplicity of Class::DBI, but we need some Sweet features, like order_by on retrieve_all.
Yes, we used to have an in house templating system. It was simple, so simple that do_* methods had to produce almost the final form of our html output. Only wrappers and simple substitutions were applied. We want more, but there's no need to write it here.
At first, we thought that we might need a template for each do_* method. Then we coded and realized that we need only a few templates which can be shared widely. For instance, there is only one form template in the Billing sample app and it is very similar to the one we use for our production applications.
Even though Template Toolkit allows you to write raw Perl in the template, please don't. This just opens up too many problems, including security problems. But primarily, it defeats the separation of concerns which is so useful for people to keep track of a project. Our minds work better if things are separated into manageable pieces.
Following on the previous principle, avoid putting any sort of display markup in your code. Rather, build a data structure which the template can unpack into marked up form.
In some frameworks, extreme magic is employed so that only one Location directive is needed for each application. This has two problems. First, it requires the urls to exactly match the modules which handle them. This immediately defeats our naming convention. We place all of our apps in the Apps:: name space, but we never include 'apps' in the url. Second, and more importantly, it baffles new people who can't immediately determine dispatch from the httpd.conf alone.
When converting to a new version of mod_perl, not all apps will move at once. Hence the framework provides a plugin scheme for different mod_perl engines.
Plugins add a bit of complexity to a framework. We've chosen to use them for specifying things like which version of mod_perl you have and what templating system you use. For other things that only some modules even care about, we just use the standard or CPAN module directly. The rule is this: if Gantry.pm calls the methods, there will be plugins, otherwise not.
Since our CDBI model packages are typically only 10-15 lines, we put all of them in the same file for easy access.
There is a lot of data in any application which should not be hard coded. In particular, this allows development and production code to be identical, but have different effects on the outside world.
The following would be better advice if Apache2::Reload wasn't broken.
If you develop with the same architechture as you deploy, you must reinstall the app on each change, then restart the server. It is better to leave the app in a development directory, use lib and Apache::Reload or Apache2::Reload. These ensure that the app is reloaded as needed. Note that changes to the CDBI modules usually require a server restart.