in reply to MVC in Dancer

MVC architecture is triangular: the view sends updates to the controller, the controller updates the model, and the view gets updated directly from the model

Mmmmmm… no, and weird. The View doesn’t send anything anywhere. The View, AKA the presentation layer, may provide instructions or a structure like WSDL or JS or a web form for a browser to send data to the Controller layer but the browser, AKA the client/agent, is the actor, not the View.

MVC is a bit agnostic, and some might say broken, with regards to business layer. Some say Controller, some say Model, some say hybrid. In Catalyst/DBIx::Class circles, at least, the term fat model started being used a decade ago to mean the Model contains the business logic; validation, bookkeeping, data integrity, data relations, restrictions, and such.

This, to me, makes the most sense by quite a lot. A Controller that does business logic is useless outside the web application (without serious contortions or having to write a backend API beside or on top of the frontend API; bad form). Having to duplicate biz logic for new code would be a nightmare. If the Model contains all the business logic, doing a one-off script to migrate things is trivial and cannot break anything because the Model knows what’s allowed and what’s not. With a fat model the only thing the Controller really is is a dispatcher and authn/authz/role sentry.

The Model is given to the View in discreet packets properly, like a flattened, or mostly flattened, user or shopping cart, but some folks use the View, much like PHP apps usually do, to be the Controller too and manipulate and render the Model within it. It’s not what MVC is supposed to look like. If a View changes state or data directly, it’s not a (pure) View.

For a 5+ item cart to trigger a discount, I’d probably try to put the logic in a Role consumed by the Model. The Role can be swapped in and out, like a promotion or a sale, without changing the Model at all, but operate on totals and messages and such. I’ve never tried this but that feels correct and non-spaghetti to me, off the cuff. So any non-permanent business logic could reside in Roles; easy to name or version by date and such.