Design Patterns & Architectural Principles¶
Core Design Patterns¶
1. Finite State Machine (FSM) Pattern {#fsm-patterns}¶
O(1) FSM Implementation¶
The ABS Platform implements mathematically optimized FSMs with precomputed transition maps for constant-time lookups.
// FSM transition function: f:(S,Σ)→(S′,P(Λ))
interface FSMTransition {
currentState: State;
input: Signal;
targetState: State;
outputs: Set<Output>;
}
// Precomputed transition map for O(1) performance
class OptimizedFSM {
private transitionMap: Map<string, FSMTransition>;
getTransition(state: State, input: Signal): FSMTransition | null {
const key = `${state.id}:${input.type}`;
return this.transitionMap.get(key) || null;
}
}
Signal Compression Pattern¶
Complex external events are compressed into fundamental FSM inputs to maintain performance and simplicity.
// External event compression
export class SignalCompressor {
compressExternalEvent(event: ExternalEvent): FSMSignal[] {
// Complex business logic reduced to fundamental signals
switch (event.type) {
case 'CUSTOMER_PAYMENT_PROCESSED':
return [{ type: 'DEPOSIT_PAID', data: event.paymentData }];
case 'BATTERY_SWAP_COMPLETED':
return [
{ type: 'BATTERY_RETURNED', data: event.returnData },
{ type: 'BATTERY_ISSUED', data: event.issueData }
];
}
}
}
2. Data-Driven Agent Pattern¶
Functional Agent Design¶
Agents are pure functions that receive context and return state updates and outputs.
// Agent function signature
export type AgentFunction = (
request: AgentRequest,
servicePlan: ServicePlan,
context: AgentContext
) => Promise<AgentResult>;
// Example agent implementation
export const batterySwapAgent: AgentFunction = async (request, servicePlan, context) => {
// 1. Validate business rules
const validation = await validateServiceAccess(request, servicePlan, context);
// 2. Process business logic
const result = await processBatterySwap(request, servicePlan, context);
// 3. Update agent state
const updatedState = updateAgentState(context.state, result);
// 4. Generate FSM signals
const fsmSignals = generateFSMSignals(result);
return {
success: true,
updatedState,
outputs: result.outputs,
fsmSignals
};
};
Context Injection Pattern¶
Rich execution context provides utilities and dependencies without tight coupling.
interface AgentContext {
state: AgentState;
utilities: AgentUtilities;
services: ServiceRegistry;
logger: Logger;
metrics: MetricsCollector;
}
// Context injection enables testing and modularity
export const executeAgent = async (
agentFunction: AgentFunction,
request: AgentRequest,
servicePlan: ServicePlan,
context: AgentContext
): Promise<AgentResult> => {
return await agentFunction(request, servicePlan, context);
};
3. Template-Driven Configuration Pattern¶
Immutable Template Design¶
ServicePlanTemplates provide immutable configuration that ServicePlans inherit.
interface ServicePlanTemplate {
readonly id: string;
readonly country: string; // Immutable after creation
readonly jurisdiction: string; // Immutable after creation
readonly currency: string; // Inherited by all derived objects
readonly agent_config: AgentConfig;
readonly fsm_definitions: FSMDefinitions;
}
// Template inheritance ensures consistency
export class ServicePlanFactory {
createFromTemplate(
template: ServicePlanTemplate,
customData: ServicePlanCustomData
): ServicePlan {
return {
...customData,
// Inherited immutable properties
country: template.country,
jurisdiction: template.jurisdiction,
currency: template.currency,
// Template references
templateId: template.id,
agent_config: template.agent_config,
fsm_definitions: template.fsm_definitions
};
}
}
4. Event-Driven Messaging Pattern¶
MQTT Topic Hierarchy¶
Structured topic patterns enable efficient message routing and filtering.
/dirac/{component}/{domain}/{entity_id}/{event_type}
Examples:
/dirac/abs/service/plan-001/state_changed
/dirac/arm/asset/battery-123/status_updated
/dirac/bro/coordination/system/health_check
Message Criticality Patterns¶
Different message patterns based on criticality and coordination requirements.
// High criticality: call/return pattern
export const callReturnPattern = {
call: '/call/abs/service/{plan_id}/asset_allocation',
return: '/return/abs/service/{plan_id}/asset_allocated'
};
// Medium criticality: emit/echo pattern
export const emitEchoPattern = {
emit: '/emit/abs/service/{plan_id}/service_signal',
echo: '/echo/abs/service/{plan_id}/signal_received'
};
// Low criticality: stat/meta pattern
export const statMetaPattern = {
stat: '/stat/abs/metrics/service_usage',
meta: '/meta/abs/system/configuration'
};
Architectural Principles¶
1. Separation of Concerns¶
Domain Boundaries¶
Clear boundaries between different platform concerns:
- FSM Layer: Pure state management without business logic
- Agent Layer: Business logic without state management
- Service Layer: Coordination without implementation details
- API Layer: Interface without business rules
Model Confinement¶
Agent-specific types and state confined to agent modules:
// Agent state interface (confined to agent module)
interface BSSAgentState {
quotaUsage: QuotaUsage;
paymentStatus: PaymentStatus;
// Agent-specific state properties
}
// Generic platform interface (shared)
interface ServicePlan {
id: string;
agent_state: Record<string, unknown>; // Generic storage
}
2. Single Responsibility Principle¶
Component Responsibilities¶
Each component has a single, well-defined responsibility:
- FED (Federated API): API coordination and schema federation
- BRO (Messaging Broker): Asynchronous event coordination
- ABS (Asset Services): Service orchestration and business logic
- ARM (Asset Relations): Asset management and IoT coordination
3. Open/Closed Principle¶
Extensible Agent System¶
New agents can be added without modifying existing code:
// Agent registry is open for extension
export const agentRegistry = new Map<string, AgentFunction>([
['bss-service-agent', bssServiceAgent],
['fleet-charging-agent', fleetChargingAgent],
// New agents added here without modification
]);
// Agent factory creates agents based on configuration
export class AgentFactory {
createAgent(agentType: string): AgentFunction {
const agentFunction = this.agentRegistry.get(agentType);
if (!agentFunction) {
throw new Error(`Unknown agent type: ${agentType}`);
}
return agentFunction;
}
}
4. Dependency Inversion Principle¶
Interface-Based Dependencies¶
High-level modules depend on abstractions, not concretions:
// Abstract interface
interface PaymentProcessor {
processPayment(amount: number, currency: string): Promise<PaymentResult>;
}
// Service depends on abstraction
export class ServicePlanService {
constructor(private paymentProcessor: PaymentProcessor) {}
async processSubscriptionPayment(plan: ServicePlan): Promise<void> {
await this.paymentProcessor.processPayment(plan.amount, plan.currency);
}
}
// Concrete implementation
export class OdooPaymentProcessor implements PaymentProcessor {
async processPayment(amount: number, currency: string): Promise<PaymentResult> {
// Odoo-specific implementation
}
}
Performance Patterns¶
1. Caching Strategies¶
Multi-Level Caching¶
Strategic caching at different architectural levels:
// Application-level caching
export class ServicePlanService {
private templateCache = new LRUCache<string, ServicePlanTemplate>(100);
async getTemplate(templateId: string): Promise<ServicePlanTemplate> {
// Check cache first
if (this.templateCache.has(templateId)) {
return this.templateCache.get(templateId)!;
}
// Load from database and cache
const template = await this.repository.findById(templateId);
this.templateCache.set(templateId, template);
return template;
}
}
// Database-level caching
export class FSMEngine {
private transitionCache = new Map<string, CompiledTransitionMap>();
getCompiledFSM(fsmId: string): CompiledTransitionMap {
if (!this.transitionCache.has(fsmId)) {
const fsm = this.loadAndCompileFSM(fsmId);
this.transitionCache.set(fsmId, fsm);
}
return this.transitionCache.get(fsmId)!;
}
}
2. Lazy Loading Pattern¶
On-Demand Resource Loading¶
Load expensive resources only when needed:
export class AgentExecutor {
private agentInstances = new Map<string, AgentFunction>();
async executeAgent(agentType: string, ...args: unknown[]): Promise<AgentResult> {
// Lazy load agent function
if (!this.agentInstances.has(agentType)) {
const agentFunction = await this.loadAgentFunction(agentType);
this.agentInstances.set(agentType, agentFunction);
}
const agent = this.agentInstances.get(agentType)!;
return await agent(...args);
}
}
Security Patterns¶
1. Defense in Depth¶
Multi-Layer Security¶
Security controls at multiple architectural layers:
- Network Layer: VPC, subnets, security groups
- Application Layer: Authentication, authorization, input validation
- Data Layer: Encryption at rest, encrypted connections
- Code Layer: Secure coding practices, dependency scanning
2. Principle of Least Privilege¶
Role-Based Access Control¶
Granular permissions based on actual requirements:
interface UserPermissions {
canCreateServicePlan: boolean;
canModifyServicePlan: boolean;
canViewCustomerData: boolean;
allowedCountries: string[];
allowedServiceTypes: string[];
}
export class AuthorizationService {
async checkPermission(
user: User,
action: string,
resource: Resource
): Promise<boolean> {
const permissions = await this.getUserPermissions(user);
return this.evaluatePermission(permissions, action, resource);
}
}
These patterns collectively create a robust, scalable, and maintainable architecture that supports complex multi-stakeholder coordination while maintaining high performance and reliability.