One more small thing to consider, also: “sometimes the underlying data-structures are closely matched to the needs of the template, and sometimes they aren’t.” When the structure is complicated, or there are a number of alternatives for displaying it to the user, it might not be desirable to have code within the template be highly dependent on that structure. (It becomes something that now must be changed in many scattered places.)
So, in cases like that, you can define functions, or “closures,” which can be referenced from within the template, as variables that are provided to it by the caller of the template. Each time the template refers to it, the underlying function (in the Perl module, and/or in a common package referred-to by the same) does the work. Now, if the data structure changes or evolves, only the Perl module has to be modified or expanded.