3 ms·
At Replicon, a SaaS timesheet provider, we started supporting Python scripting a couple years ago. At first, it was a component of the application we called "p
by mfenniak 11y ago
At Replicon, a SaaS timesheet provider, we started supporting Python scripting a couple years ago. At first, it was a component of the application we called "pay rules", which are basically the rules that determine how much regular time, over time, double time, etc. an individual is being paid based upon their timesheets. These rules are very different from locale to locale, and at times can be very complex.
The scripting started pretty simple; one script type. It has access to all of our web services, and runs "as the user" but under a specific fixed permission set. The permission set limits the script to read-only services. It is passed simple data: a timesheet reference, and a user. It returns simple data: an array of dates, pay codes, and amounts to be paid. The scripts run under IronPython, so we're able to use .NET's security to prevent the script from accessing the file-system, network, etc. As an additional precaution, the scripts are run on isolated servers that are firewalled to only have network access to the web services servers, and importantly not the database servers or the Internet. Whenever a timesheet is updated, the pay output for that timesheet is marked as "needs recalculation", and the script is executed in a background task.
It was an ugly roll-out. Our first large customer ran into a ton of intermittent errors, which resulted in stale data calculations being used in actual payroll runs. But we fixed these problems quickly, and it's been incredibly smooth after that first month of hell.
And it was very successful. Its success lead to using scripts more and more for other parts of our application, which gives us some incredible per-tenant flexibility while maintaining a single core application. We've followed a few major rules that have helped:
(a) Scripts always do read-only operations; they can never access services that write data. This makes development of the scripts simple because they can be executed with no side-effects, which we leverage in the form of a script simulator that we provide in the UI.
(b) Scripts always have simple inputs, simple outputs. This is tricky every time we create a new type of script. We've found that the less we feed into the script as an input, the more it has to use services to retrieve data, which is actually a fantastically flexible approach. And the same with data output; it needs to contain the results of a calculation, which the script host then does stuff with.
(c) Background execution is far better than interactive execution. We design for background calculations now, making the UI show that "this is being calculated", and preventing certain operations while data is stale. This makes it easy to scale up and down our script servers, and the occasional badly written script doesn't have much of an impact outside of the specific tenant trying to use it.
Overall, the approach IS somewhat crazy. It's a lot more work than just implementing your product the way you want it to work. But for "enterprise customizability", it rocks.