Thursday, December 20, 2018

Transaction Script Pattern

Transaction script pattern

The short definition for the Transaction Script Pattern is: “Organizes business logic by procedures where each procedure handles a single request from the presentation.”
When the Transaction Script Pattern is used, we see a business application as consisted of a number of transactions. The transaction could be viewing or changing some data, and also some application logic might be in the interaction between the application and the data store. With the Transaction Script Pattern, we build each transaction as a single method, then use the method to interact with database or database wrapping layers.
One benefit of using the Transaction Script Pattern is its simplicity nature; a procedure can be dedicated with one task without worrying others. Transaction script can be placed at any location within an application, the best solution is to separate the transaction script from others and put it into its own layer. Several transaction scripts can be put into one class or we can use one class for each transaction script with using the Command pattern.

When To Use It

The Transaction Script Pattern should be used when the application itself does not have much logic, or it does not have much overhead in performance and understanding. As the business logic getting complex, other patterns such as Domain model pattern is a better choice.

Organizing Domain Logic: Transaction Script

This is first of several articles on representing domain logic in .NET applications and services, again taken from a course I developed on .NET patterns and architecture. I should mention that because one of the benefits of using patterns is to share a common nomenclature I'm using the pattern names as defined by Martin Fowler in his excellent book.


Since an application can usually be thought of as a series of transactions, one pattern for representing the transaction is called a Transaction Script. As the name implies each transaction, for example processing an order, is encapsulated in its own script housed in a method of a Business Component (a Business Component is a class or set of classes packaged in a Class Library assembly in .NET used to encapsulate business or domain logic). The benefit of this approach is that it is conceptually straightforward to design by looking at the actions that the application needs to perform.
The way the transaction script is packaged can vary in two basic ways:
Multiple Transactions per Component
This is the most common technique and involves factoring the transactions into higher-level groupings and then creating a Business Component for each grouping and a public or shared method for each transaction. For example, in a retail application the process of ordering a product involves several steps and can be encapsulated in an PlaceOrder method in the OrderProcessing component like so:
Public Class OrderProcessing    

  Public Shared Function PlaceOrder(ByVal order As OrderInfo) As Long        

        ' Start a transaction

        ' Check Inventory

        ' Retrieve customer information, check credit status

        ' Calculate price and tax

        ' Calculate shipping and total order

        ' Save Order to the database and commit transaction

        ' Send an email confirming the order

        ' Return the new order ID

    End Function

End Class

In this case the order information is passed to the PlaceOrder method in an OrderInfo structure defined as follows:
Public Structure OrderInfo    

   Public ProductID As Long    

   Public Quantity As Integer    

   Public CustomerId As Long    

   Public ShipVia As ShipType

End Structure



Public Enum ShipType    

  FedEx    

  UPS    

  Postal

End Enum

In a similar fashion the customer processing can be encapsulated in a CustomerProcessing component (class) like so:
Public Class CustomerProcessing    

  Public Shared Function SaveCustomer(ByVal customer As CustomerInfo) As Long        

        ' Validate Address

        ' Start a transaction

        ' Look for duplicate customers based on email address

        ' Save customer to database and commit transaction

        ' Return the new customer ID    

  End Function

End Class



Public Structure CustomerInfo    

  Public Name As String    

  Public Address As String    

  Public City As String    

  Public State As String    

  Public PostalCode As String    

  Public Email As String

End Structure

The user process or user or service interface components would be responsible for calling the SaveCustomer method, persisting the customer ID, creating the OrderInfo structure and then passing it to the PlaceOrder method. Note that here the product information would already be known since the UI would have called a method in the OrderProcessing class (or another Business Component) to retrieve products.

Of course, both the OrderProcessing and CustomerProcessing classes could inherit from a base class if there were any code that both could use (for example a base class constructor). In that case the methods would likely not be shared methods. Since these components have dependencies on each other they might well be packaged in the same assembly so they can be versioned and deployed as a unit.
Each Transaction is its own Component
Using this technique, each transaction script is implemented in its own class which uses implementation or interface inheritance in order to provide polymorphism. For example, the PlaceOrder and SaveCustomer scripts could be implemented as classes that inherit from the IProcessing interface like so:


The code to implement the PlaceOrder component would then look as follows:
Public Interface IProcessing    

  Function Execute() As Long

End Interface



Public Class PlaceOrder : Implements IProcessing

    Private _order As OrderInfo    

    Public Sub New(ByVal order As OrderInfo)        

       _order = order    

    End Sub

    Public Function Execute() As Long Implements IProcessing.Execute        

        ' Start a transaction

        ' Check Inventory

        ' Retrieve customer information, check credit status

        ' Calculate price and tax

        ' Calculate shipping and total order

        ' Save Order to the database and commit transaction

        ' Email a confirmation

        ' Return the new order ID

    End Function

End Class
This design is based on the Command Pattern documented by the GoF and allows the user or service interface and process components to treat the scripts polymorphically by calling the Execute method of the IProcessing interface. The UI components could rely on one of the Factory Patterns to create the appropriate object.

The logic to perform the various steps shown in these code snippets can be implemented either with inline managed code or through calls to stored procedures. Using stored procedures has the benefit of introducing a further layer of abstraction and taking advantage of database server performance optimizations. In either case the Transaction Script typically uses only the barest of data access layers or none at all.

No comments:

Post a Comment