Unraveling the Transaction Script Pattern: A Deep Dive with Real-World Examples

[tr] Türkçe Oku

2023-06-11

The Transaction Script is an Enterprise application design pattern often used in transaction-based systems. This pattern is created by bringing together a series of procedures to perform a transaction. These procedures are typically used to initiate a transaction, run database queries, and process the results.

The Transaction Script pattern is suitable for applications with non-complex business logic. However, as the business logic becomes more complex and requires many transactions, using this pattern can make understanding and maintaining the code difficult.

Structure of the Transaction Script Pattern

A Transaction Script typically has the following components:

  1. Transaction Initiator: This is the component that initiates the transaction and waits to receive the transaction result. This is usually a user interface or an API call.

  2. Transaction Script: This is the sum of the procedures that perform the transaction and return the transaction result. This script runs database queries and processes the results.

  3. Database: This is where the transaction script queries and updates the data.

Real World Example

An online shopping system can be an example of the Transaction Script pattern. When a user wants to buy a product, the following transactions occur:

  1. The user makes a request to buy a product (Transaction Initiator).

  2. The Transaction Script checks if the user’s account has sufficient balance, checks if the product is in stock, if everything is appropriate, it deducts the fee from the user’s account and decreases the stock number of the product.

  3. All these transactions occur in the database.

Transaction Script Diagram

This diagram represents a product purchase transaction in an online shopping system. The user interface (transaction initiator) sends a purchase request. This request reaches the transaction script. The transaction script checks the user’s balance, checks the stock status of the product, deducts the fee, and decreases the stock number. All these transactions occur in the database. When the transaction is completed, the transaction script sends the result to the user interface.

Here is a simple C# code example representing a product purchase transaction in an online shopping system. In this example, we created a TransactionScript class and defined a method named PurchaseProduct in this class.

public class TransactionScript
{
    private readonly IAccountService _accountService;
    private readonly IProductService _productService;

    public TransactionScript(IAccountService accountService, IProductService productService)
    {
        _accountService = accountService;
        _productService = productService;
    }

    public async Task<bool> PurchaseProduct(int userId, int productId)
    {
        // Balance check
        var balance = await _accountService.GetBalance(userId);
        var product = await _productService.GetProduct(productId);

        if (balance < product.Price)
        {
            Console.WriteLine("Insufficient balance.");
            return false;
        }

        // Stock check
        if (product.Stock <= 0)
        {
            Console.WriteLine("Product out of stock.");
            return false;
        }

        // Fee deduction and stock decrease
        await _accountService.DeductBalance(userId, product.Price);
        await _productService.DecreaseStock(productId);

        Console.WriteLine("Product successfully purchased.");
        return true;
    }
}

In this example, we use two services named IAccountService and IProductService. Each of these services is used to check and deduct the user’s balance, get product information, and decrease the stock number.

This code example represents a simple application of the Transaction Script pattern. However, in real-world applications, additional features such as error control and transaction management may need to be added.

The same structure’s Go code example.

In this example, we created a struct named TransactionScript and defined a method named PurchaseProduct in this struct

package main

import (
	"fmt"
)

type AccountService interface {
	GetBalance(userId int) (float64, error)
	DeductBalance(userId int, amount float64) error
}

type ProductService interface {
	GetProduct(productId int) (*Product, error)
	DecreaseStock(productId int) error
}

type TransactionScript struct {
	accountService AccountService
	productService ProductService
}

func (ts *TransactionScript) PurchaseProduct(userId int, productId int) error {
	// Balance check
	balance, err := ts.accountService.GetBalance(userId)
	if err != nil {
		return err
	}

	product, err := ts.productService.GetProduct(productId)
	if err != nil {
		return err
	}

	if balance < product.Price {
		return fmt.Errorf("Insufficient balance")
	}

	// Stock check
	if product.Stock <= 0 {
		return fmt.Errorf("Product out of stock")
	}

	// Fee deduction and stock decrease
	err = ts.accountService.DeductBalance(userId, product.Price)
	if err != nil {
		return err
	}

	err = ts.productService.DecreaseStock(productId)
	if err != nil {
		return err
	}

	fmt.Println("Product successfully purchased")
	return nil
}

func main() {
	// Create and use TransactionScript instance
}

In this example, we use two interfaces named AccountService and ProductService. Each of these interfaces is used to check and deduct the user’s balance, get product information, and decrease the stock number.

This code example represents a simple application of the Transaction Script pattern. However, in real-world applications, additional features such as error control and transaction management may need to be added.

The use of this pattern depends on the complexity of the business logic. While it can be an excellent choice for applications with simple business logic, other patterns such as Domain Driven Design (DDD) may be more suitable for applications with complex business logic.



More posts like this

Decoding the Transaction Script Pattern: A Philosophical Dialogue with Epictetus

2023-06-11 | #domain-logic-patterns #enterprise-patterns #transaction-script

Murat: The Transaction Script pattern allows transactions to be carried out simply and smoothly. However, using this pattern can make understanding and maintaining the code difficult for applications with complex business logic. Epictetus: Yes, Murat. But we must not forget that everything depends on complexity. The Transaction Script pattern can be an excellent choice for applications with simple business logic. However, as the business logic becomes more complex and requires many transactions, other patterns such as Domain Driven Design (DDD) may be more suitable.

Continue reading 