docs: update transaction script

This commit is contained in:
Ilkka Seppälä committed 2024-05-22 18:24:00 +03:00
1 parent b3abdb3341
commit 8ed580018c
3 files changed
+60 -47

No files matched your search

+53 -30
View File
@@ -1,28 +1,40 @@
--- ---
title: Transaction Script title: Transaction Script
category: Behavioral category: Data access
language: en language: en
tag: tag:
- Data access - Business
- Data access
- Domain
- Persistence
- Transactions
--- ---
## Also known as
* Scripted Transactions
## Intent ## Intent
Transaction Script organizes business logic by procedures where each procedure handles a single Organize business logic by procedures where each procedure handles a single request from the presentation.
request from the presentation.
## Explanation ## Explanation
Real world example Real-world example
> You need to create a hotel room booking system. Since the requirements are quite simple we intend > An analogous real-world example of the Transaction Script design pattern can be seen in a bank teller's daily operations. Imagine a bank where each transaction, such as depositing money, withdrawing cash, or transferring funds between accounts, is handled by a specific script-like procedure. Each procedure takes in the necessary details (e.g., account numbers, amounts) and performs the transaction in a straightforward, step-by-step manner. This ensures that each transaction is processed correctly and independently, without the need for a complex system of rules and interactions. This simple, organized approach allows bank tellers to efficiently manage a variety of transactions throughout the day.
> to use the Transaction Script pattern here.
In plain words In plain words
> Transaction Script organizes business logic into transactions that the system needs to carry out. > Transaction Script organizes business logic into transactions that the system needs to carry out.
Programmatic example Wikipedia says
> The Transaction Script design pattern is a straightforward way to organize business logic in applications, particularly suitable for scenarios where each request from the presentation layer can be handled by a single procedure. This pattern is often used in simple applications or in systems where rapid development and ease of understanding are crucial. Each transaction script is responsible for a particular task, such as processing an order or calculating a result, and typically interacts directly with the database.
**Programmatic example**
Our programmatic example is about booking hotel rooms.
The `Hotel` class takes care of booking and cancelling room reservations. The `Hotel` class takes care of booking and cancelling room reservations.
@@ -76,42 +88,53 @@ public class Hotel {
} }
``` ```
The `Hotel` class has two methods, one for booking and cancelling a room respectively. Each one of The `Hotel` class has two methods, one for booking and cancelling a room respectively. Each one of them handles a single transaction in the system, making `Hotel` implement the Transaction Script pattern.
them handles a single transaction in the system, making `Hotel` implement the Transaction Script
pattern.
The `bookRoom` method consolidates all the needed steps like checking if the room is already booked The `bookRoom` method consolidates all the needed steps like checking if the room is already booked or not, if not booked then books the room and updates the database by using the DAO.
or not, if not booked then books the room and updates the database by using the DAO.
The `cancelRoom` method consolidates steps like checking if the room is booked or not, The `cancelRoom` method consolidates steps like checking if the room is booked or not, if booked then calculates the refund amount and updates the database using the DAO.
if booked then calculates the refund amount and updates the database using the DAO.
## Class diagram ## Class diagram
![alt text](./etc/transaction-script.png "Transaction script model") ![Transaction Script](./etc/transaction-script.png "Transaction Script")
## Applicability ## Applicability
Use the Transaction Script pattern when the application has only a small amount of logic and that * Use when business logic is simple and can be easily organized into individual procedures.
logic won't be extended in the future. * Suitable for applications with simple transaction requirements or where the logic doesn't justify complex architectures like Domain Model.
## Tutorials
* [Transaction Script Pattern - DZone](https://dzone.com/articles/transaction-script-pattern#:~:text=Transaction%20Script%20(TS)%20is%20the,need%20big%20architecture%20behind%20them.)
* [Transaction Script](https://www.informit.com/articles/article.aspx?p=1398617)
### Known Uses
* Early-stage startups and small-scale applications where rapid development is crucial.
* Enterprise applications with well-defined procedures like banking transactions or e-commerce order processing.
* Legacy systems where business logic is already written as scripts.
## Consequences ## Consequences
* As the business logic gets more complicated, Benefits:
it gets progressively harder to keep the transaction script
in a well-designed state. * Simple and straightforward to implement.
* Code duplication between transaction scripts can occur. * Easy to understand and maintain for straightforward business logic.
* Normally not easy to refactor transactions script to other domain logic * Fast development cycle for small applications.
patterns.
Trade-offs:
* Can lead to duplicated code if not carefully managed.
* Not suitable for complex business logic; can become unmanageable as the application grows.
* Harder to test in isolation compared to more structured approaches like Domain Model.
## Related patterns ## Related patterns
* Domain Model * [Domain Model](https://java-design-patterns.com/patterns/domain-model/): Unlike Transaction Script, Domain Model organizes business logic around the data model and is better suited for complex business rules.
* Table Module * [Service Layer](https://java-design-patterns.com/patterns/service-layer/): Often used together with Transaction Script to define an application's boundary and encapsulate the business logic.
* Service Layer * [Table Module](https://java-design-patterns.com/patterns/table-module/): Similar to Transaction Script but organizes logic using a single class per table rather than a procedure per request.
## Credits ## Credits
* [Transaction Script Pattern](https://dzone.com/articles/transaction-script-pattern#:~:text=Transaction%20Script%20(TS)%20is%20the,need%20big%20architecture%20behind%20them.) * [Enterprise Integration Patterns: Designing, Building, and Deploying Messaging Solutions](https://amzn.to/3WcFVui)
* [Transaction Script](https://www.informit.com/articles/article.aspx?p=1398617) * [Patterns of Enterprise Application Architecture](https://amzn.to/3WfKBPR)
* [Patterns of Enterprise Application Architecture](https://www.amazon.com/gp/product/0321127420/ref=as_li_qf_asin_il_tl?ie=UTF8&tag=javadesignpat-20&creative=9325&linkCode=as2&creativeASIN=0321127420&linkId=18acc13ba60d66690009505577c45c04)
@@ -32,7 +32,7 @@ import org.slf4j.LoggerFactory;
/** /**
* Transaction Script (TS) is one of the simplest domain logic pattern. * Transaction Script (TS) is one of the simplest domain logic pattern.
* It needs less work to implement than other domain logic patterns and therefore * It needs less work to implement than other domain logic patterns, and therefore
* it’s perfect fit for smaller applications that don't need big architecture behind them. * it’s perfect fit for smaller applications that don't need big architecture behind them.
* *
* <p>In this example we will use the TS pattern to implement booking and cancellation * <p>In this example we will use the TS pattern to implement booking and cancellation
@@ -88,7 +88,7 @@ class HotelDaoImplTest {
} }
/** /**
* Represents the scenario when DAO operations are being performed on a non existing room. * Represents the scenario when DAO operations are being performed on a non-existing room.
*/ */
@Nested @Nested
class NonExistingRoom { class NonExistingRoom {
@@ -209,16 +209,12 @@ class HotelDaoImplTest {
@Test @Test
void addingARoomFailsWithExceptionAsFeedbackToClient() { void addingARoomFailsWithExceptionAsFeedbackToClient() {
assertThrows(Exception.class, () -> { assertThrows(Exception.class, () -> dao.add(new Room(2, "Double", 80, false)));
dao.add(new Room(2, "Double", 80, false));
});
} }
@Test @Test
void deletingARoomFailsWithExceptionAsFeedbackToTheClient() { void deletingARoomFailsWithExceptionAsFeedbackToTheClient() {
assertThrows(Exception.class, () -> { assertThrows(Exception.class, () -> dao.delete(existingRoom));
dao.delete(existingRoom);
});
} }
@Test @Test
@@ -226,23 +222,17 @@ class HotelDaoImplTest {
final var newRoomType = "Double"; final var newRoomType = "Double";
final var newPrice = 80; final var newPrice = 80;
final var newBookingStatus = false; final var newBookingStatus = false;
assertThrows(Exception.class, () -> { assertThrows(Exception.class, () -> dao.update(new Room(existingRoom.getId(), newRoomType, newPrice, newBookingStatus)));
dao.update(new Room(existingRoom.getId(), newRoomType, newPrice, newBookingStatus));
});
} }
@Test @Test
void retrievingARoomByIdFailsWithExceptionAsFeedbackToClient() { void retrievingARoomByIdFailsWithExceptionAsFeedbackToClient() {
assertThrows(Exception.class, () -> { assertThrows(Exception.class, () -> dao.getById(existingRoom.getId()));
dao.getById(existingRoom.getId());
});
} }
@Test @Test
void retrievingAllRoomsFailsWithExceptionAsFeedbackToClient() { void retrievingAllRoomsFailsWithExceptionAsFeedbackToClient() {
assertThrows(Exception.class, () -> { assertThrows(Exception.class, () -> dao.getAll());
dao.getAll();
});
} }
} }