home-lab/packages/lab-tool/REFACTOR_PLAN.md
Geir O. Jerstad 646c8bbc20 refactor: apply functional programming to SSH module
- Split complex nested functions into focused, single-responsibility helpers
- Created io/ directory with pure command builders and impure executors
- Eliminated parentheses complexity that was causing compilation errors
- SSH module now compiles and runs successfully with cleaner architecture

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-07-04 17:09:49 +02:00

2.9 KiB

Lab Tool Refactoring Plan - Functional Programming Approach

Current Problems

  • Deep nested parentheses causing syntax errors
  • Functions doing too many things
  • Hard to debug and maintain
  • Mixed pure/impure logic

New Structure

lab-tool/
├── core/
│   ├── config.scm          # Pure config access
│   ├── machine.scm         # Pure machine data structures
│   └── commands.scm        # Pure command building
├── io/
│   ├── ssh.scm             # Pure SSH command building
│   ├── rsync.scm           # Pure rsync command building
│   └── shell.scm           # Impure shell execution
├── deploy/
│   ├── ssh-strategy.scm    # Pure deployment strategy
│   ├── deploy-rs-strategy.scm # Pure deploy-rs strategy
│   └── executor.scm        # Impure deployment execution
├── health/
│   ├── checks.scm          # Pure health check logic
│   └── monitor.scm         # Impure health monitoring
└── main/
    ├── cli.scm             # Pure CLI parsing
    ├── dispatcher.scm      # Pure command dispatch
    └── runner.scm          # Impure main execution

Functional Principles

1. Single Responsibility Functions

;; Instead of one complex function doing everything:
(define (deploy-complex machine options) ...)

;; Break into focused functions:
(define (build-rsync-command source dest ssh-config) ...)
(define (build-nixos-rebuild-command flake-path machine mode) ...)
(define (execute-command command) ...)
(define (compose-ssh-deployment rsync-cmd rebuild-cmd) ...)

2. Pure vs Impure Separation

;; Pure: No side effects, testable
(define (make-ssh-target user hostname) 
  (format #f "~a@~a" user hostname))

;; Impure: Clear side effects
(define (execute-ssh-command ssh-config command)
  (system (build-ssh-command ssh-config command)))

3. Function Composition

;; Instead of deep nesting:
(let ((config (get-ssh-config machine))
      (command (build-command ...))
      (result (execute (format ...))))
  (if (success? result) ...))

;; Use composition:
(-> machine
    get-ssh-config
    (build-deployment-commands flake-path)
    execute-deployment
    handle-result)

4. Error Handling as Values

;; Instead of exceptions in nested calls:
(catch #t (lambda () (complex-nested-operation)) error-handler)

;; Return result types:
(define (safe-ssh-connect machine)
  (if (valid-config? machine)
      `(success . ,(make-connection machine))
      `(error . "Invalid SSH config")))

Implementation Steps

  1. Extract SSH utilities (no more parentheses hell)
  2. Create pure command builders
  3. Separate execution layer
  4. Build composable deployment strategies
  5. Clean CLI interface

This will make debugging much easier - each small function can be tested independently!