Real-time feedback, faster iteration, zero context-switching
Working together with PairSpaces is different from how you've collaborated in the past. There is no passing a keyboard from one person to another and there is no screen-sharing. Instead, you code in parallel and share diffs from the same workspace. If what you've done before is like a turn-based, roll-the-dice kind of game, PairSpaces is multiplayer programming.
To demonstrate multiplayer programming we're going to show how two engineers, Alice and Bob, work together to create an API endpoint using FastAPI. Alice is focused on the endpoint /users
that creates a new user and Bob is focused on the logic that will validate requests to the endpoint.
To follow along in your Space, you need to install the following dependencies.
> sudo yum -y install git
> curl -O https://bootstrap.pypa.io/get-pip.py
> python3 get-pip.py --user
> pip install "fastapi[standard]"
Each Space has its own storage volume available from /space
.
> cd /space
> mkdir api-application
> mkdir worktrees
> cd api-application
This is the initial state of the repository:
api-application/
├── main.py
├── users/
│ ├── __init__.py
│ ├── routes.py
│ └── validators.py
worktrees/
Both Alice and Bob have the following files checked out.
# main.py
from fastapi import FastAPI
from users.routes import router as user_router
app = FastAPI()
app.include_router(user_router)
# users/routes.py
from fastapi import APIRouter
router = APIRouter()
@router.post("/users")
async def create_user():
return {"message": "User created"}
# users/validators.py
def validate_user(data: dict) -> bool:
return "name" in data and "email" in data
From their Space, Alice and Bob create worktrees in their Git repository.
# Alice
> git worktree add -b feat/users-endpoint ../worktrees/users-endpoint
Preparing worktree (new branch 'feat/users-endpoint')
HEAD is now at 89ca1a0 feat: initial commit
> cd ../worktrees/users-endpoint
# Bob
> git worktree add -b feat/users-validation ../worktrees/users-validation
Preparing worktree (new branch 'feat/users-validation')
HEAD is now at 89ca1a0 feat: initial commit
> cd ../worktrees/users-validation
POST /users
EndpointFrom her worktree, Alice completes the route for POST /users
...
from fastapi import APIRouter, Request, HTTPException
from users.validators import validate_user
router = APIRouter()
@router.post("/users")
async def create_user(request: Request):
data = await request.json()
if not validate_user(data):
raise HTTPException(status_code=400, detail="Invalid user data")
return {"message": f"User {data['name']} created"}
...and then commits her change...
> git add users/routes.py
> git commit -m "feat: implemented post users with request body and validation"
1 file changed, 7 insertions(+), 4 deletions(-)
From his worktree, Bob improves the validation logic for the POST /users
endpoint...
import re
def validate_user(data: dict) -> bool:
if not isinstance(data.get("name"), str):
return False
email = data.get("email", "")
if not isinstance(email, str) or not re.match(r"[^@]+@[^@]+\.[^@]+", email):
return False
return True
...and then commits his change...
> git add users/validators.py
> git commit -m "feat: improved user validation with type and format checks"
1 file changed, 8 insertions(+), 2 deletions(-)
Now, without pushing code and waiting for it to build, test, and lint, Alice and Bob can review a pull request from their Space.
Alice reviews Bob's work...
> git fetch ../users-validation feat/users-validation:bob-review
From ../users-validation
* [new branch] feat/users-validation -> bob-review
> git diff bob-review
...
...and Bob reviews Alice's work...
> git fetch ../users-endpoint feat/users-endpoint:alice-review
From ../users-endpoint
* [new branch] feat/users-endpoint -> alice-review
> git diff alice-review
...
Both can make changes based on feedback.
When ready, Alice and Bob merge their branches into a new branch that's ready to pushed.
> cd ../../api-application
> git worktree add ../worktrees/users-api -b users-api main
Preparing worktree (new branch 'users-api')
HEAD is now at 89ca1a0 feat: initial commit
> cd ../worktrees/users-api
# Merge Alice's endpoint
> git fetch ../users-endpoint feat/users-endpoint
From ../users-endpoint
* branch feat/users-endpoint -> FETCH_HEAD
> git merge FETCH_HEAD -m "feat: created user endpoint"
Updating 89ca1a0..45b6200
Fast-forward (no commit created; -m option ignored)
users/routes.py | 11 +++++++----
1 file changed, 7 insertions(+), 4 deletions(-)
# Merge Bob's validation
> git fetch ../users-validation feat/users-validation
From ../users-validation
* branch feat/users-validation -> FETCH_HEAD
> git merge FETCH_HEAD -m "feat: improved validation logic"
Merge made by the 'ort' strategy.
users/validators.py | 10 ++++++++--
1 file changed, 8 insertions(+), 2 deletions(-)
And now the code has been reviewed without any delays waiting for a CI build process to complete.
You can also share your work with other members of your team, for example, a Product Manager, QA engineer, or a stakeholder.
To do this, Alice uses the PairSpaces CLI from her local machine to open a port from the Space:
> pair space SPACE_ID --port 8000
Your Space is now available on port 8000, however, you must be authenticated in PairSpaces to access. Visit https://pairspaces.com/pairs/SPACE_ID to access your Space from this port.
Bob starts the FastAPI development server from the Space:
> fastapi dev main.py --host 0.0.0.0
And any team member that Alice and Bob shared their Space with can view their work.
PairSpaces is the first collaboration platform for software engineers that brings that in-the-moment sense of collaboration to their work. Using Git Worktrees, PairSpaces eliminates the cost of waiting for building, testing, and linting before getting feedback on work.
This is what we call multiplayer programming and can scale to 3, 4, or more users all from a single Space.
Try PairSpaces now.