Introduction

In my current job, I was tasked with developing a large-scale approval process for a complex system. To demonstrate the feasibility and benefits of using a StateMachine for this purpose, I created a Proof of Concept (POC). Due to confidentiality reasons, I cannot reveal the specifics of my company's process. However, I can describe the approach and benefits using a code review approval process as an example. In this two-part blog post series, I will first discuss the approach of this type of requirement,  then the benefits of using a state machine for managing approval processes and illustrate the process using PlantUML diagrams. In the second part, we will implement the State Machine-based code review approval process in C#.

Requirement: The code review (PR) approval process

As a software development team, we require a streamlined and effective approach to handling the code review approval process, which encompasses stages such as open, approved, rejected, merged, and closed. The solution should be user-friendly and maintainable, as well as facilitate the addition or modification of states and transitions in the future. Moreover, we're utilizing the Azure DevOps approval process for pull requests.

Advantages of Using State Machine

Managing the code review approval process can be approached in various ways, such as using if-else statements, switch statements, or custom logic. However, these methods can become complex and hard to maintain as the number of states and transitions grows. State machines offer numerous benefits over these techniques:

  • Distinct separation of states and transitions: State machines deliver a clear and organized framework to define and handle states and transitions, resulting in more comprehensible code.
  • Scalability: State machines simplify the process of adding or modifying states and transitions, enabling easy scalability and maintainability.
  • Reduced complexity: State machines abstract the logic for state transitions, decreasing code complexity and making testing and debugging more accessible.

Why we do not use so much If-Else

Consider a simple code review approval process using if-else statements. While it might work for a few states, it can quickly become complex and difficult to maintain as the number of states and transitions increases. Here's an example:

public void ProcessPullRequest(string action)
{
    if (CurrentState == "Open")
    {
        if (action == "Approve")
        {
            CurrentState = "Approved";
        }
        else if (action == "Reject")
        {
            CurrentState = "Rejected";
        }
        else if (action == "Close")
        {
            CurrentState = "Closed";
        }
    }
    else if (CurrentState == "Approved")
    {
        if (action == "Complete")
        {
            CurrentState = "Completed";
        }
    }
    else if (CurrentState == "Rejected")
    {
        if (action == "Resubmit")
        {
            CurrentState = "Open";
        }
        else if (action == "Close")
        {
            CurrentState = "Closed";
        }
    }
}

In this example, we're using  to handle the transitions between states in the code review approval process. As the process becomes more complex with additional states and transitions, the nested if-else statements will become increasingly difficult to manage, understand, and maintain.

🤩
By using a State Machine, we can simplify the code and make it more scalable and maintainable, as well as easier to test and debug.

Identifying States and  Transitions

The code review approval process consists of various states and transitions that help manage the lifecycle of a Pull Request (PR).


Here's a brief overview of the states and transitions in the approval process:

States:

  1. Open: The PR is submitted and awaits review.
  2. Approved: The PR has been reviewed and meets the required standards.
  3. Rejected: The PR does not meet the required standards and needs revisions.
  4. Completed: The PR has been approved and integrated into the codebase.
  5. Closed: The PR is no longer needed or further revisions won't be made.

Transitions:

  1. Submit PR: A developer submits a PR, transitioning it from a non-existent state to the "Open" state.
  2. Approve: A reviewer approves the PR, transitioning it from the "Open" state to the "Approved" state.
  3. Reject: A reviewer rejects the PR, transitioning it from the "Open" state to the "Rejected" state.
  4. Revise and resubmit: The developer makes revisions and resubmits the PR, transitioning it from the "Rejected" state back to the "Open" state.
  5. Complete : The PR is merged into the target branch, transitioning it from the "Approved" state to the "Completed" state.
  6. Close: The PR is closed without merging, transitioning it from the "Open" or "Rejected" state to the "Closed" state.

These states and transitions form the backbone of the code review approval process, allowing teams to effectively manage PRs and ensure a smooth and efficient workflow.

Visualizing the Process with PlantUML

Before diving into the code implementation, it's helpful to visualize the approval process using PlantUML. By creating a state diagram with PlantUML, we can clearly represent the states and transitions in the code review approval process.

@startuml

hide empty description
title Code Review Approval Process

state "Open" as open
state "Approved" as approved
state "Rejected" as rejected
state "Completed" as completed
state "Closed" as closed

[*] --> open : SubmitPR()
note right of open : Awaiting review
open --> approved : Approve()
note right of approved : Meets standards
open --> rejected : Reject()
note left of rejected : Needs revisions
rejected --> open : Revise&resubmit()
approved --> completed : Complete()
note right of completed : Integrated into codebase
open --> closed : Close()
rejected --> closed : Close()
note left of closed : No further revisions
completed --> [*]
closed --> [*]

@enduml
code_review_approval_process.plantuml

Lets see generated process State Machine Image


Copy this PlantUML code and paste it into an online PlantUML editor such as PlantText or PlantUML Online Editor to generate a visual diagram of the code review approval process. This diagram illustrates the various states and transitions in the process, providing a clear understanding of the process.

🤩
To Be Continued..
In the second part of this blog post series, we will implement the StateMachine-based code review approval process in C# using the states and transitions visualized in the PlantUML diagram. This example will demonstrate the benefits and practicality of using a state machine for managing approval processes in real-world scenarios, like the one I encountered in my current job.

Resources

  1. Modelling Workflows With Finite State Machines in .NET
  2. State Machine Workflows
  3. State Machine and State Design Pattern
Share this post