Raid: A Tool for Orchestrating Distributed Application Development
by Alex Salerno
As modern software development evolves, teams often work with multiple repositories, complex environments, and numerous services running in parallel. Managing this complexity can become a daunting task. That's why I'm excited to unveil my design proposal for Raid, a tool designed to orchestrate distributed application development with a focus on simplifying the management of multiple repositories, environments, configurations, and their testing.
In this post, I’ll walk through the key features and high-level design of Raid, and how it aims to streamline workflows for developers working with multi-repository and containerized applications.
TLDR; Raid is a configurable command-line application that orchestrates common development tasks, environments, and dependencies across distributed code repositories.
The Problem: Managing Complexity in Distributed Systems
When working on large-scale applications, it's common to have code split across multiple repositories, each with its own set of dependencies, environments, and configurations. As applications grow in size, keeping track of these dependencies and ensuring that all parts of the system work in harmony can be overwhelming.
Traditional approaches often rely on manual processes, scripts, tribal knowledge, or complex configuration management tools. However, these solutions can be cumbersome and difficult to maintain, especially when developers need to switch between different environments, run tests across services, or apply patches to multiple repositories or systems simultaneously.
The Solution: Raid - A Unified Orchestration Tool
Raid is designed to solve these challenges by providing a unified platform for managing distributed development workflows. It integrates multiple repositories, environments, and testing processes into one easy-to-use tool, making it easier to build, test, and maintain modern applications. Built in Go, Raid is fast, concurrent by design, and powered by portable, declarative configurations.
Key Features
- Repository Management:
Raid simplifies working with multiple repositories by automating the process of onboarding, syncing, cloning, and managing dependencies between them. Developers can easily track which branches or commits need to be worked on and ensure that all related repositories are updated accordingly. - Environment Management:
Local development environments can vary widely depending on the tech stack and dependencies of each repository. Raid automates the setup of local environments (e.g., variables, virtual environments, containers) and ensures consistency across repositories. It supports various configuration formats like.envfiles for injecting environment variables and Docker for managing complex containerized environments. - Automated Testing:
Running tests across multiple repositories can be a tedious and error-prone task. With Raid, you can define test commands for each repository in a centralized configuration file. It can run tests in parallel, aggregate results, and provide detailed feedback on any failures, all from a single command. - Highly Configurable: At the heart of Raid is its flexibility. All configurations for repositories, environments, and services are defined through easy-to-read YAML files. Developers can group distributed applications into Profiles and customize settings for each repository, define specific testing workflows, and fine-tune environment configurations.
- Custom Commands: In large projects it's very common to have scripts packaged in the code to automate common tasks. It's also common for developers to create their own scripts and forget to share them out. Raid fixes this gap by supporting custom commands that can be run anywhere from the command line. Scripts can then be packaged with the raid configuration in a single well-defined location and run anywhere anytime. Developers no longer have to rely on tribal knowledge to accomplish bespoke tasks.
High-Level Design
Core Components
The core of Raid consists of several key components that work together to manage the orchestration:
-
Profile Manager: Profiles define a grouping of repositories, dependencies, environments, and commands. Profiles are highly configurable, portable, and self-documenting.
-
Configuration Specification: The configuration specification defines the YAML schema and related components for building a profile.
-
Repository Manager: This component handles cloning, updating, and managing the state of multiple repositories. It tracks dependencies and ensures that all repositories are aligned.
-
Environment Manager: The environment manager ensures that each repository is running in the correct environment, whether that's setting up a local database, creating a virtual environment for Python, or spinning up Docker containers for microservices.
-
Command Executor: Run native and arbitrary custom commands reducing common developer toil. Native commands, such as 'test', are optimized for performance and readability. Custom commands are user-defined tasks adapting to the needs of any project.
-
Test Execution: The test execution interfaces with various testing frameworks (e.g., Jest, PyTest, GoTest) and runs tests across repositories. It aggregates results and provides feedback, all while running tests in parallel to speed up the process.
Configuration Files
The core configuration of Raid is defined using YAML files, which provide flexibility and ease of use.
There are two types of configuration files:
-
Profile Configuration: A file with the name pattern
*.raid.yamlthat defines the properties of a raid profile (group of repositories and their dependencies). -
Repository Configuration: A file with the name
raid.yamlthat defines the properties of an individual repository. Located in the root folder of a git repository.
Here's an example of what a profile configuration might look like:
---
name: raid profile
repositories:
- name: repo1
path: /local/path/to/repo
url: https://github.com/user/repo1.git
- name: repo2
path: /local/path/to/repo
url: git@github.com:user/repo2.git
dependencies:
- name: Database
install:
mac:
tasks:
- shell:
cmd: 'brew install mysql'
execute:
mac:
tasks:
- shell:
dir: /path/to/run
cmd: 'mysql -u root'
verify:
mac:
tasks:
- shell:
cmd: "brew services list | grep mysql | awk '{ print $2}' | grep 'started'"
executor: /bin/bash
environments:
- name: development
default: true
variables:
- KEY=VALUE
- DB_USER=root
tasks:
- script:
path: /path/to/script
executor: bash
- name: testing
variables:
- KEY=VALUE
- DB_USER=root
commands:
- name: fetch
usage: 'Retrieve frequently accessed resources'
sub-commands:
- name: logs
usage: 'Fetch service logs'
tasks:
- script:
path: /path/to/script
executor: python
options:
- flag: o
usage: 'Set output file path'
parameter:
required: true
name: output
variable: $outfile
out:
stdout: true
stderr: false
file: $outfile
...
This configuration file allows you to specify raid profile details including repositories, dependencies, environments, and custom commands. It’s highly extensible, allowing you to add new services or repositories with ease.
Here's an example of what a repository configuration might look like:
name: repo1
main branch: main
environments:
- name: development
variables:
- KEY=VALUE
- name: testing
variables:
- KEY=VALUE
build:
mac:
tasks:
- shell
cmd: './gradle clean build'
test:
parser: Gradle
mac:
tasks:
- shell
cmd: './gradle test'
User Interface
Raid is controlled via a simple and intuitive CLI, which allows developers to trigger actions like managing repositories, running tests, or switching environments. The tool is built using Go’s cobra package, which provides flexibility in defining commands and flags.
Here are some example commands:
- install: Clones all required repos, builds dependencies, and configures the environment.
- environment, env: Switch and manage environments.
- test: Runs tests across all repositories.
- health: Shows profile status like repo & dependency state, current environment, and last run test status.
Concurrency and Performance
Raid takes advantage of Go’s concurrency model to run tasks in parallel. Whether it's syncing repositories, building containers, or running tests, tasks are executed concurrently to maximize performance and minimize development time.
Conclusion
Raid aims to simplify the complexity of distributed application development by automating key processes such as repository management, environment setup, testing, and (eventually) container orchestration. Raid simplifies the grind so you can focus on what matters most—writing great software.
Stay tuned for updates and feel free check out the Raid repo, GitHub - 8bitAlex/raid, if you’re interested in contributing or using it for your projects!