https://raw.githubusercontent.com/dry-python/brand/master/logo/stories.png

travis codecov pyup codacy pypi docs gitter


The business transaction DSL

stories is a business transaction DSL. It provides a simple way to define a complex business transaction that includes processing over many steps and by many different objects. It makes error handling a primary concern by taking a “Railway Oriented Programming” approach to capturing and returning errors from any step in the transaction.

stories is based on the following ideas:

  • A business transaction is a series of operations where any can fail and stop the processing.
  • A business transaction can describe its steps on an abstract level without being coupled to any details about how individual operations work.
  • A business transaction doesn’t have any state.
  • Each operation shouldn’t accumulate state, instead it should receive an input and return an output without causing any side-effects.
  • The only interface of an operation is ctx.
  • Each operation provides a meaningful piece of functionality and can be reused.
  • Errors in any operation should be easily caught and handled as part of the normal application flow.

Example

stories provide a simple way to define a complex business scenario that include many processing steps.

from stories import story, argument, Success

class PurchaseProduct:

    @story
    @argument('user')
    @argument('product')
    @argument('shipment_details')
    def purchase(I):

        I.create_order
        I.calculate_price
        I.request_payment
        I.notify_user

    def create_order(self, ctx):

        order = Order.objects.create(
            user=ctx.user,
            product=ctx.product
        )
        return Success(order=order)

    def calculate_price(self, ctx):

        return Success(...

This code style allow you clearly separate actual business scenario from implementation details.

Note

stories library was heavily inspired by dry-transaction ruby gem.