Mutations is a Python package I just released for handling, validating, and executing complex business logic in web applications. I’ve used it in a large Django codebase to shrink large models and move complex logic into independent, testable, and reusable command classes. It’s based on the Ruby eponym, Jonathan Novak’s excellent mutations gem.
Check it out on GitHub and PyPi.
dict, and essentially any other sort of field. Expecting an email address? There’s a validator for that.
Business logic: rules and conditions that run your app/business and make the user’s experience predictable and streamlined.
As an example (in a web application): when a user signs up, send them a welcome email, except if they signed up with their Twitter account, in which case send them a twitter DM. Lots of these small decisions and policies add up and sometimes lead to very large models.
This logic is simple in the beginning, but can quickly grow as your business needs evolve, your previously simple logic gets complex, very quickly. For example, if the new user comes through a partner’s channel, make an API request to that partner’s backend and see if they should get an email or not. Sometimes, the partner’s backend is down, in which case enqueue the request and try again in five minutes.
Complexity increases quickly, and suddenly you find yourself enqueueing retry requests to your partner’s backend in a class that also handles storing the user’s email and password. With this we face a new question: where should this code live?
I wrote Mutations as an answer to this question: store the business logic in separate, reusable, and testable classes. Classes with fewer responsibilities are generally easier to maintain, test, and debug, and pulling transaction logic out of models and into something else keeps your models focused on what they do best: defining and persisting data.
Here’s an example of how you could use it to handle the aforementioned example:
You can then call the command like this:
Say, for example, you need to run this command one-off, or on a batch of users on their behalf. With mutations, you can run the signup command in a regular console, instead of having to sign users up through the web application on their behalf.
Moreover, you can validate against any condition. Any method inside a Mutation class that’s prefixed with
validate_ will be treated as a validation method and will be run before the command can be executed. For example:
Mutations helps you split out your business logic and run it in separate, reusable, testable command classes. It keeps your models thin, key commands testable, is modular, and extensible. Give it a try — it’s available on GitHub and PyPi, and tweet @omarish with any feedback/suggestions.