Scalable Workflow Architecture: Multi-UI Support

by Square 49 views
Iklan Headers

Hey guys! Today, we're diving deep into implementing a scalable workflow architecture that supports multiple user interfaces. This is all about making our lives easier by decoupling core logic from the UI layer. Let's break it down and see how we can make this happen!

Context and Vision

The main goal here is to support both a Command-Line Interface (@stackcode/cli) and a native VS Code Extension UI (@stackcode/vscode). To achieve this, we need a scalable architecture. The vision is to create a generalized pattern where any command can be driven by multiple, distinct user interfaces without duplicating the same logic. Think of it as having one brain that can talk to many faces!

The key is to decouple the core business logic and command orchestration from the UI layer. Currently, the UI is tightly coupled with the inquirer terminal library, which isn't ideal for our multi-UI vision. We want the core logic to be independent, so it can be used by any UI, whether it's a CLI, a VS Code extension, or even a web interface in the future.

To achieve this, we will introduce a Workflow Layer within the @stackcode/core package. This layer will act as the central processing unit, handling all the heavy lifting while the UI layers simply serve as input/output interfaces. This approach ensures that changes to the UI don't affect the underlying logic, and vice versa.

The New Architecture: A Workflow Layer

We're introducing a Workflow Layer within the @stackcode/core package. This layer will be the heart of our new architecture, making sure everything runs smoothly regardless of the UI being used. For each user-facing command (e.g., init, commit), we'll create a corresponding workflow function in core (e.g., runInitWorkflow, runCommitWorkflow).

These workflow functions are the central "brains". They'll accept a simple options object and be responsible for orchestrating all the low-level logic (scaffolding, git operations, etc.). This means all the complex stuff happens here, neatly tucked away from the UI.

The UI packages (@stackcode/cli and @stackcode/vscode) become simple "frontends." Their only job is to collect input from the user (via inquirer or VS Code APIs) and call the appropriate workflow function in @stackcode/core. This makes the UI packages lightweight and focused on what they do best: providing a user-friendly interface.

Imagine it like this: the UI is the waiter taking your order, and the workflow function is the chef preparing your meal. The waiter (UI) takes your order (input) and passes it to the chef (workflow function), who then cooks the meal (processes the logic) and sends it back to you. The waiter doesn't need to know how to cook; they just need to know how to take orders and deliver food.

This Issue's Scope: Implementing the Pattern for the init Command

For this particular issue, we're focusing on implementing this pattern for the init command. Think of this as our proof-of-concept to ensure the architecture works as expected. We'll start by refactoring the init command to use the new Workflow Layer, and then we'll expand it to other commands later.

Here’s what we’re aiming for:

  • A new workflows.ts module is created in @stackcode/core. This module will house all our workflow functions.
  • A runInitWorkflow(options) function is implemented in this module, containing the step-by-step logic currently in the cli/init.ts handler. This function will be the new brain for the init command.
  • The @stackcode/cli init command is refactored to be a thin UI layer that only gathers input and calls runInitWorkflow. This makes the CLI a simple frontend, focused on collecting user input.
  • The @stackcode/vscode extension uses native VS Code APIs (showInputBox, showQuickPick) to gather input for the init command. This allows the VS Code extension to provide a native, integrated experience.
  • The extension then calls the same runInitWorkflow function to execute the process, reporting progress via VS Code notifications. This ensures that both the CLI and the VS Code extension use the same core logic.

Acceptance Criteria

To make sure we're on the right track, here are the acceptance criteria we'll be using:

  • [ ] A new workflows.ts module is created in @stackcode/core.
  • [ ] A runInitWorkflow(options) function is implemented in this module, containing the step-by-step logic currently in the cli/init.ts handler.
  • [ ] The @stackcode/cli init command is refactored to be a thin UI layer that only gathers input and calls runInitWorkflow.
  • [ ] The @stackcode/vscode extension uses native VS Code APIs (showInputBox, showQuickPick) to gather input for the init command.
  • [ ] The extension then calls the same runInitWorkflow function to execute the process, reporting progress via VS Code notifications.

Let's walk through each of these criteria in a bit more detail.

Creating the workflows.ts Module

First up, we need to create a new workflows.ts module inside the @stackcode/core package. This module will be the home for all our workflow functions. Think of it as the central command center where all the action happens. To create this, simply navigate to the @stackcode/core directory and create a new file named workflows.ts. Make sure it's properly integrated into the project's build process so it can be imported and used by other modules.

Implementing the runInitWorkflow(options) Function

Next, we need to implement the runInitWorkflow(options) function within the workflows.ts module. This function is where the magic happens. It encapsulates all the step-by-step logic that's currently in the cli/init.ts handler. This includes things like:

  • Validating input options
  • Creating necessary directories
  • Initializing configuration files
  • Setting up Git repositories
  • Installing dependencies

The function should accept an options object as input, which contains all the necessary parameters for the init command. This allows us to pass in different configurations depending on the UI being used. For example, the CLI might pass in command-line arguments, while the VS Code extension might pass in values obtained from input boxes and quick picks.

Refactoring the @stackcode/cli init Command

Now, let's refactor the @stackcode/cli init command to be a thin UI layer. This means we need to strip out all the business logic and leave only the code that's responsible for gathering input from the user. The refactored command should:

  • Prompt the user for necessary input using inquirer or similar tools
  • Create an options object containing the user's input
  • Call the runInitWorkflow(options) function in @stackcode/core
  • Handle any errors or exceptions that might occur

By doing this, we're making the CLI a simple frontend that's focused on collecting user input and passing it to the core logic. This makes the CLI more maintainable and easier to test.

Using VS Code APIs in the @stackcode/vscode Extension

For the @stackcode/vscode extension, we want to provide a native, integrated experience. This means we need to use VS Code APIs like showInputBox and showQuickPick to gather input from the user. These APIs allow us to create input fields and dropdown menus that look and feel like they're part of VS Code.

The extension should:

  • Use showInputBox to prompt the user for text-based input, such as project names and descriptions
  • Use showQuickPick to present the user with a list of options, such as project templates and programming languages
  • Create an options object containing the user's input
  • Call the runInitWorkflow(options) function in @stackcode/core
  • Report progress to the user via VS Code notifications

Executing the Process and Reporting Progress

Finally, we need to make sure that both the CLI and the VS Code extension call the same runInitWorkflow function to execute the process. This ensures that the same core logic is used regardless of the UI being used. Additionally, the VS Code extension should report progress to the user via VS Code notifications.

This can be done using the vscode.window.withProgress API, which allows us to display a progress bar in the VS Code status bar. This provides the user with feedback on the progress of the init command and helps them understand what's happening behind the scenes.

By following these steps, we can ensure that our init command is scalable, maintainable, and easy to use across multiple UIs. And remember, this is just the beginning. Once we've successfully implemented this pattern for the init command, we can expand it to other commands as well.

This new architecture not only supports multiple UIs but also enhances the maintainability and scalability of our codebase. By decoupling the UI layer from the core logic, we create a more modular and flexible system. This makes it easier to add new features, fix bugs, and adapt to changing requirements. Plus, it opens the door for supporting even more UIs in the future, such as web interfaces or mobile apps.