Fundamentals 21 min read

Reflections on Transaction System Design: Principles, Patterns, and Evolution

This article reflects on the redesign of a large‑scale transaction system, describing a decision‑making routine that starts from purpose and goals, discusses programming paradigms, SOLID principles, domain‑driven design, bounded contexts, component splitting, layering, and the trade‑offs of patterns such as State and CQRS to achieve a flexible, maintainable backend architecture.

Architecture Digest
Architecture Digest
Architecture Digest
Reflections on Transaction System Design: Principles, Patterns, and Evolution

Reflections on Transaction System Design

The piece originates from a post‑restructuring review of a transaction system, focusing on the mindset behind design decisions rather than formal "architecture" terminology.

Design routine: purpose → goal → core design → design principles → detailed sub‑system design.

It emphasizes that a clear purpose and measurable goals are the first step for any system redesign.

"Soft" ware

The author notes that the original system was built in Python for rapid MVP delivery, later migrated to Java, with occasional use of Go for specific services, highlighting the trade‑offs of flexibility versus language ergonomics.

Programming Paradigms

From OOP to functional programming, the article argues that the chosen paradigm should match the problem domain, advocating a mixed OOP‑centric approach for complex transaction logic while using functional style for isolated calculations.

Principles and Patterns

"The difference between a bad programmer and a good one is whether he considers his code or his data structures more important." – Linus Torvalds

Key quality attributes identified are rigidity, fragility, robustness, and unnecessary complexity.

SOLID

SRP (single responsibility) is illustrated with the example of separating delivery‑type logic for different merchant scenarios. DIP (dependency inversion) is shown through a simplified order‑state transition example, and OCP (open‑closed) is discussed as the ultimate goal of the design routine.

public class Order {
    // States
    public static final int ACCEPT = 5;
    public static final int SETTLED = 9;
    // Events
    public static final int ARRIVED = 1; // 订单送达
    public void event(int event) {
        switch (state) {
            case ACCEPT:
                switch (event) {
                    case ARRIVED:
                        state = SETTLED;
                        // to do action
                        break;
                }
        }
    }
}

A state‑machine implementation using a transition table is also presented, demonstrating a more maintainable alternative to nested switch statements.

# 完结订单
add_transition(trigger=ARRIVED,
               src=ACCEPT,
               dest=SETTLED,
               on_start=_set_order_settled_at,
               set_state=_set_state_with_record,
               on_end=_push_to_transcore)

def event_fire(event, current_state):
    for transition in transitions:
        if transition.on_start == current_state && transition.trigger == event:
            transition.on_start()
            current_state = transition.dest
            transition.on_end()

Domain‑Driven Design and Bounded Contexts

The article introduces a ubiquitous language and bounded contexts to isolate different meanings of the same entity (e.g., User from personal, public, and admin perspectives), applying DDD to split the transaction domain into membership and core transaction contexts.

Component Splitting and Layering

Four logical packages are defined: Extension (custom plugins), Domain (core business), Business (specific use‑case logic), and Infra (infrastructure). Classic layered architecture and CQRS are compared, with diagrams illustrating proper dependency direction.

Evolution and Final Thoughts

Four major decisions—paradigm choice, component modularization, layered decomposition, and pattern application—are summarized as steps toward a flexible, reliable system. The author concludes that there is no "silver bullet" for building adaptable transaction systems; continuous reflection and team collaboration remain essential.

Original Source

Signed-in readers can open the original source through BestHub's protected redirect.

Sign in to view source
Republication Notice

This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactadmin@besthub.devand we will review it promptly.

Design PatternsSoftware ArchitectureSystem DesignDomain-Driven DesignSOLID
Architecture Digest
Written by

Architecture Digest

Focusing on Java backend development, covering application architecture from top-tier internet companies (high availability, high performance, high stability), big data, machine learning, Java architecture, and other popular fields.

0 followers
Reader feedback

How this landed with the community

Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.