Validation & Linting
Use Sruja's validator to catch errors, orphan elements, and bad references. Includes troubleshooting guide.
Validation & Linting
Sruja ships with a validation engine that helps keep architectures healthy. This tutorial covers how to use it effectively and troubleshoot common issues.
Quick Start
# Lint a single file
sruja lint architecture.sruja
# Lint all .sruja files in a directory
sruja lint ./architectures/
# Get detailed output
sruja lint --verbose architecture.sruja
# Export validation report as JSON (for CI/CD)
sruja lint --json architecture.sruja > lint-report.json
Common Validation Checks
Sruja validates:
- Unique IDs: No duplicate element IDs
- Valid references: Relations must connect existing elements
- Cycle detection: Informational (cycles are valid for many patterns)
- Orphan detection: Elements not used by any relation
- Simplicity guidance: Suggests simpler syntax when appropriate
- Constraint violations: Policy and constraint rule violations
Real-World Example: E-Commerce Platform
Let’s validate a real architecture:
import { * } from 'sruja.ai/stdlib'
Customer = person "Customer"
ECommerce = system "E-Commerce Platform" {
WebApp = container "Web Application" {
technology "React"
}
API = container "REST API" {
technology "Go"
}
ProductDB = database "Product Database" {
technology "PostgreSQL"
}
OrderDB = database "Order Database" {
technology "PostgreSQL"
}
}
Customer -> ECommerce.WebApp "Browses products"
ECommerce.WebApp -> ECommerce.API "Calls API"
ECommerce.API -> ECommerce.ProductDB "Reads products"
ECommerce.API -> ECommerce.OrderDB "Writes orders"
view index {
include *
}
Validation output:
✅ Valid architecture
✅ All references valid
✅ No orphan elements
ℹ️ Cycle detected: ECommerce.WebApp ↔ ECommerce.API (this is valid for request/response)
Troubleshooting Common Errors
Error 1: Invalid Reference
Error message:
❌ Invalid reference: ECommerce.API -> ECommerce.NonExistent "Calls"
Element 'NonExistent' not found in system 'ECommerce'
Problem: You’re referencing an element that doesn’t exist.
Fix:
// ❌ Wrong
ECommerce.API -> ECommerce.NonExistent "Calls"
// ✅ Correct - element exists
ECommerce.API -> ECommerce.ProductDB "Reads"
Real-world scenario: You renamed a service but forgot to update all references.
Error 2: Duplicate ID
Error message:
❌ Duplicate ID: 'API' found in system 'ECommerce'
First occurrence: line 5
Second occurrence: line 12
Problem: Two elements have the same ID in the same scope.
Fix:
import { * } from 'sruja.ai/stdlib'
// EXPECTED_FAILURE: unexpected token
// ❌ Wrong
ECommerce = system "E-Commerce" {
API = container "REST API"
API = container "GraphQL API" // Duplicate ID!
}
// ✅ Correct - use unique IDs
ECommerce = system "E-Commerce" {
RESTAPI = container "REST API"
GraphQLAPI = container "GraphQL API"
}
Real-world scenario: You added a new API type but used the same ID.
Error 3: Orphan Element
Warning message:
⚠️ Orphan element: ECommerce.Cache
This element is not referenced by any relation
Problem: An element exists but nothing connects to it.
Fix options:
- Add a relation (if the element should be used):
// Add relation to use the cache
ECommerce.API -> ECommerce.Cache "Reads cache"
- Remove the element (if it’s not needed):
// Remove if not part of current architecture
// datastore Cache "Cache" { ... }
- Document why it’s isolated (if intentional):
datastore Cache "Cache" {
description "Future: Will be used for product catalog caching"
metadata {
status "planned"
}
}
Real-world scenario: You added a component for future use but haven’t integrated it yet.
Error 4: Constraint Violation
Error message:
❌ Constraint violation: 'NoDirectDB' violated
ECommerce.WebApp -> ECommerce.ProductDB "Direct database access"
Constraint: Frontend containers cannot access databases directly
Problem: A constraint rule is being violated.
Fix:
// EXPECTED_FAILURE: Invalid reference
// ❌ Wrong - violates constraint
ECommerce.WebApp -> ECommerce.ProductDB "Direct access"
// ✅ Correct - go through API
ECommerce.WebApp -> ECommerce.API "Calls API"
ECommerce.API -> ECommerce.ProductDB "Reads products"
Real-world scenario: Enforcing architectural standards (e.g., “no direct database access from frontend”).
Understanding Validation Messages
Cycles Are Valid
Sruja detects cycles but doesn’t block them - cycles are valid architectural patterns:
- Feedback loops: User ↔ System interactions
- Event-driven: Service A ↔ Service B via events
- Mutual dependencies: Microservices that call each other
- Bidirectional flows: API ↔ Database (read/write)
import { * } from 'sruja.ai/stdlib'
// ✅ Valid - feedback loop
User = person "User"
Platform = system "Platform"
User -> Platform "Makes request"
Platform -> User "Sends response"
// ✅ Valid - event-driven pattern
ServiceA = system "Service A"
ServiceB = system "Service B"
ServiceA -> ServiceB "Publishes event"
ServiceB -> ServiceA "Publishes response event"
// ✅ Valid - mutual dependencies
PaymentService = system "Payment Service"
OrderService = system "Order Service"
PaymentService -> OrderService "Updates order status"
OrderService -> PaymentService "Requests payment"
view index {
include *
}
The validator will inform you about cycles but won’t prevent compilation, as they’re often intentional.
Simplicity Guidance
Sruja suggests simpler syntax when appropriate:
Example:
ℹ️ Simplicity suggestion: Consider using 'system' instead of nested 'container'
Current: system App { container Web { ... } }
Simpler: system Web { ... }
This is informational only - use the level of detail that matches your modeling goal.
CI/CD Integration
GitHub Actions Example
Add validation to your CI pipeline:
name: Validate Architecture
on: [push, pull_request]
jobs:
validate:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Install Sruja
run: |
curl -fsSL https://raw.githubusercontent.com/sruja-ai/sruja/main/scripts/install.sh | bash
export PATH="$HOME/go/bin:$PATH"
- name: Lint Architecture
run: |
sruja lint architecture.sruja
- name: Export Validation Report
if: always()
run: |
sruja lint --json architecture.sruja > lint-report.json
- name: Upload Report
if: always()
uses: actions/upload-artifact@v3
with:
name: lint-report
path: lint-report.json
GitLab CI Example
validate-architecture:
image: golang:1.21
script:
- curl -fsSL https://raw.githubusercontent.com/sruja-ai/sruja/main/scripts/install.sh | bash
- export PATH="$HOME/go/bin:$PATH"
- sruja lint architecture.sruja
only:
- merge_requests
- main
Pre-commit Hook
Validate before every commit:
#!/bin/sh
# .git/hooks/pre-commit
sruja lint architecture.sruja
if [ $? -ne 0 ]; then
echo "❌ Architecture validation failed. Fix errors before committing."
exit 1
fi
Advanced: Custom Validation Rules
Use constraints and conventions for custom validation:
import { * } from 'sruja.ai/stdlib'
// Define constraints
constraints {
"Frontend cannot access databases directly"
}
// Apply conventions
conventions {
"Layered Architecture: Frontend → API → Database"
}
Platform = system "Platform" {
Frontend = container "React App"
API = container "REST API"
DB = database "PostgreSQL"
// ✅ Valid
Frontend -> API "Calls API"
API -> DB "Reads/Writes"
// ❌ Will be caught by validator
// Frontend -> DB "Direct access" // Violates constraint
}
view index {
include *
}
Real-World Workflow
Step 1: Write Architecture
import { * } from 'sruja.ai/stdlib'
App = system "App" {
Web = container "Web"
DB = datastore "Database"
}
view index {
include *
}
Step 2: Validate
sruja lint architecture.sruja
Step 3: Fix Errors
Address any validation errors or warnings.
Step 4: Commit to CI/CD
Once validation passes locally, commit. CI/CD will validate again.
Step 5: Monitor in Production
Use validation in CI/CD to catch issues before they reach production.
Key Takeaways
- Validate early and often: Run
sruja lintfrequently during development - Fix errors immediately: Don’t accumulate validation debt
- Integrate with CI/CD: Catch issues before they reach production
- Understand cycles: They’re often valid patterns, not errors
- Use constraints: Enforce architectural standards automatically
Exercise: Fix Validation Errors
Scenario: You have an architecture file with several validation errors.
Tasks:
- Run
sruja linton a file - Identify all errors and warnings
- Fix each error
- Re-validate to confirm fixes
Time: 10 minutes
Further Reading
- Docs: Validation Concepts
- Tutorial: CLI Basics
- Course: System Design 101 - Module 4: Production Readiness