INTRODUCTION
Capability-Centric Architecture represents a unified architectural pattern that bridges the gap between embedded and enterprise systems. This practical guide demonstrates how to build real-world applications using CCA principles through a comprehensive motor control system example. The example system includes a motor controller with Proportional-Integral-Derivative control algorithms, sensor management for reading encoder positions and temperature data, actuator management for controlling motor outputs, and diagnostic logging for system monitoring.
For a detailed description of Capability-Centric Architecture v0.2 visit: http://stal.blogspot.com/2025/12/capability-centric-architecture-updated.html
This article provides a systematic, step-by-step approach to implementing CCA, ensuring that all core concepts including Capability Nuclei, Contracts, Efficiency Gradients, Evolution Envelopes, and Lifecycle Management are thoroughly addressed. Each step includes detailed explanations, visual representations, and focused code snippets that highlight the most important implementation aspects.
The motor control system serves as an excellent demonstration of CCA principles because it combines real-time critical operations requiring direct hardware access with non-critical administrative tasks that benefit from higher-level abstractions. This duality perfectly illustrates how CCA handles diverse requirements within a single coherent architecture.
SYSTEM OVERVIEW
Before diving into implementation details, understanding the overall system architecture is essential. The motor control system consists of four primary capabilities that work together to provide complete motor control functionality.
The Motor Control Capability represents the core of the system. It encapsulates the PID control algorithm that regulates motor speed and position. This capability operates at a high-efficiency, low-abstraction gradient because it must respond to hardware interrupts within microseconds to maintain stable control. The PID algorithm itself resides in the Essence layer, making it testable and reusable across different hardware platforms.
The Sensor Management Capability handles all sensor-related operations. It reads encoder positions to determine motor shaft rotation, monitors temperature sensors to prevent overheating, and provides filtered sensor data to other capabilities. This capability demonstrates how CCA manages hardware abstraction while maintaining performance for time-sensitive operations.
The Actuator Management Capability controls the physical outputs that drive the motor. It manages Pulse Width Modulation signals, handles emergency stop conditions, and ensures safe operation through hardware interlocks. This capability shows how safety-critical functionality integrates into the CCA framework.
The Diagnostic Logging Capability provides system monitoring and troubleshooting support. It operates at a lower-efficiency, higher-abstraction gradient because logging is not time-critical. This capability demonstrates how CCA allows different performance profiles within the same system.
These capabilities interact exclusively through well-defined contracts, enabling independent development, testing, and evolution. The following sections detail each implementation step, building the complete system incrementally.
STEP ONE: IDENTIFY AND DEFINE CAPABILITIES
The first and most critical step in implementing CCA is identifying the right capabilities. This process requires careful analysis of the problem domain to find cohesive units of functionality that deliver tangible value. The identification process is not based on technical layers or organizational boundaries but on functional cohesion and business value.
For the motor control system, the identification process begins by examining the core responsibilities. Motor control itself is clearly a distinct capability because it represents a complete, self-contained function: regulating motor speed and position using control algorithms. This capability can be described in a single sentence, which is a good indicator of proper capability granularity.
Sensor management emerges as a separate capability because it provides a cohesive set of sensor-related services. While sensors are used by motor control, the sensor management logic including calibration, filtering, and fault detection represents its own domain of expertise. Separating this functionality allows sensor algorithms to evolve independently and enables reuse across different control systems.
Actuator management follows similar reasoning. The logic for safely driving actuators, managing PWM signals, and implementing safety interlocks forms a cohesive unit. This separation ensures that motor control focuses on control algorithms while actuator management focuses on safe hardware operation.
Diagnostic logging is identified as a separate capability because it serves a different purpose with different quality attributes. While motor control requires microsecond response times, diagnostic logging can tolerate millisecond or even second-level latencies. This separation allows each capability to operate at its appropriate efficiency gradient.
A critical anti-pattern to avoid is creating capabilities based on technical layers. For example, creating a "Hardware Access Capability" or "Database Capability" would be incorrect. These are technical concerns that belong within the Realization layers of domain-specific capabilities. Similarly, avoid creating capabilities based solely on team organization. Just because different teams work on sensors and motors does not automatically mean they should be separate capabilities.
The identified capabilities for the motor control system are:
1. Motor Control Capability: Provides PID-based motor speed and position regulation. This capability delivers the core control functionality and operates at high efficiency with low abstraction for real-time performance.
2. Sensor Management Capability: Provides calibrated, filtered sensor readings including encoder position and temperature data. This capability abstracts sensor hardware details while maintaining sufficient performance for control loop requirements.
3. Actuator Management Capability: Provides safe actuator control including PWM generation and emergency stop handling. This capability ensures safe motor operation through hardware interlocks and fault detection.
4. Diagnostic Logging Capability: Provides system monitoring, event logging, and diagnostic data collection. This capability operates at lower efficiency with higher abstraction, prioritizing ease of development and maintenance.
Each capability has a clear, singular purpose that can be expressed concisely. Each delivers value either to end users or to other capabilities. Each can evolve independently without forcing changes in others. This clean separation sets the foundation for the entire architecture.
STEP TWO: DESIGN CAPABILITY CONTRACTS
Once capabilities are identified, the next step is designing their contracts. A Capability Contract is the formal interface agreement that defines how a capability interacts with the rest of the system. Each contract consists of three essential elements: Provisions, Requirements, and Protocols.
Provisions define the interfaces that a capability provides to other capabilities or external consumers. These are the services, data access methods, or event publishing mechanisms that the capability makes available. Provisions answer the question: "What does this capability offer to others?"
Requirements specify the interfaces that a capability needs from other capabilities to function correctly. These are explicit dependency declarations that enable the system to resolve and inject dependencies during startup. Requirements answer the question: "What does this capability need from others?"
Protocols describe the interaction patterns and quality attributes that govern communication between capabilities. Protocols go beyond just specifying method signatures; they define how to interact, including communication mechanisms (synchronous calls, asynchronous messaging, direct memory access), data formats (binary, JSON, Protocol Buffers), timing constraints (maximum latency, interrupt priorities), reliability expectations (at-least-once delivery, guaranteed ordering), and error handling strategies.
The contract design process focuses on the "what" rather than the "how." Contracts specify functional outcomes without dictating implementation details. This abstraction enables independent evolution. For example, the Sensor Management Capability could change from direct hardware access to a sensor fusion algorithm combining multiple sensors, and as long as the SensorService contract remains stable, no other capability requires modification.
Contract Interfaces: Provisions and Requirements
Let's first define the interface types that will be used in our contracts:
/**
* Provision Interface - What Motor Control Capability PROVIDES
*/
public interface MotorControlService {
void setTargetSpeed(double speedRPM);
void setTargetPosition(double positionDegrees);
MotorStatus getCurrentStatus();
void emergencyStop();
}
public record MotorStatus(
double currentSpeed,
double currentPosition,
MotorState state,
long timestamp
) {}
public enum MotorState {
STOPPED, RUNNING, FAULT, EMERGENCY_STOP
}
/**
* Requirement Interface - What Motor Control Capability REQUIRES from Sensor Management
*/
public interface SensorService {
EncoderReading getEncoderPosition();
TemperatureReading getTemperature();
void calibrateSensors();
}
public record EncoderReading(
int position,
int velocity,
long timestamp
) {}
public record TemperatureReading(
double temperatureCelsius,
SensorQuality quality,
long timestamp
) {}
public enum SensorQuality {
GOOD, DEGRADED, FAULT
}
/**
* Requirement Interface - What Motor Control Capability REQUIRES from Actuator Management
*/
public interface ActuatorService {
void setPWMDutyCycle(double dutyCycle);
void enableOutput(boolean enable);
ActuatorStatus getStatus();
void performSafetyCheck();
}
public record ActuatorStatus(
boolean outputEnabled,
double currentDutyCycle,
boolean faultDetected,
SafetyState safetyState
) {}
public enum SafetyState {
SAFE, WARNING, EMERGENCY_STOP
}
/**
* Requirement Interface - What Motor Control Capability REQUIRES from Diagnostic Logging
*/
public interface DiagnosticService {
void logEvent(String eventType, String message, Severity severity);
void logMetric(String metricName, double value);
}
public enum Severity {
INFO, WARNING, ERROR, CRITICAL
}
Complete Capability Contract Structure
Now let's define the complete contract structure that encapsulates Provisions, Requirements, and Protocols:
/**
* Provision - Represents an interface provided by a capability
*/
public record Provision(
String name,
Class<?> interfaceType,
String description
) {}
/**
* Requirement - Represents an interface required by a capability
*/
public record Requirement(
String name,
Class<?> interfaceType,
boolean optional,
String description
) {}
/**
* Protocol - Describes how interaction occurs
*/
public record Protocol(
String name,
CommunicationMechanism mechanism,
DataFormat dataFormat,
Map<String, String> qualityAttributes
) {}
public enum CommunicationMechanism {
DIRECT_CALL, // In-process, synchronous
ASYNC_MESSAGE, // Asynchronous messaging
SHARED_MEMORY, // Direct memory access
INTERRUPT_DRIVEN // Hardware interrupt
}
public enum DataFormat {
BINARY,
JSON,
PROTOBUF,
RAW_MEMORY
}
/**
* Complete Capability Contract for Motor Control Capability
* This contract explicitly declares:
* 1. PROVISIONS - What this capability offers
* 2. REQUIREMENTS - What this capability needs
* 3. PROTOCOLS - How interactions occur
*/
public class MotorControlContract {
private final List<Provision> provisions;
private final List<Requirement> requirements;
private final List<Protocol> protocols;
private MotorControlContract(
List<Provision> provisions,
List<Requirement> requirements,
List<Protocol> protocols
) {
this.provisions = provisions;
this.requirements = requirements;
this.protocols = protocols;
}
public static MotorControlContract create() {
return new MotorControlContract(
// PROVISIONS: What Motor Control offers to others
List.of(
new Provision(
"MotorControl",
MotorControlService.class,
"Provides PID-based motor speed and position control"
)
),
// REQUIREMENTS: What Motor Control needs from others
List.of(
new Requirement(
"SensorService",
SensorService.class,
false, // NOT optional - required for operation
"Required for encoder position and temperature readings"
),
new Requirement(
"ActuatorService",
ActuatorService.class,
false, // NOT optional - required for operation
"Required for motor output control and safety checks"
),
new Requirement(
"DiagnosticService",
DiagnosticService.class,
true, // OPTIONAL - system can operate without logging
"Optional diagnostic logging for monitoring and troubleshooting"
)
),
// PROTOCOLS: How Motor Control interacts with others
List.of(
new Protocol(
"SensorInteraction",
CommunicationMechanism.INTERRUPT_DRIVEN,
DataFormat.BINARY,
Map.of(
"maxLatency", "5us",
"callFrequency", "1kHz",
"reliability", "guaranteed",
"interruptPriority", "high",
"memoryAccess", "direct"
)
),
new Protocol(
"ActuatorInteraction",
CommunicationMechanism.DIRECT_CALL,
DataFormat.BINARY,
Map.of(
"maxLatency", "10us",
"callFrequency", "1kHz",
"reliability", "guaranteed",
"safetyLevel", "critical"
)
),
new Protocol(
"DiagnosticInteraction",
CommunicationMechanism.ASYNC_MESSAGE,
DataFormat.JSON,
Map.of(
"maxLatency", "100ms",
"callFrequency", "10Hz",
"reliability", "best-effort",
"bufferSize", "1000"
)
)
)
);
}
public List<Provision> getProvisions() {
return Collections.unmodifiableList(provisions);
}
public List<Requirement> getRequirements() {
return Collections.unmodifiableList(requirements);
}
public List<Protocol> getProtocols() {
return Collections.unmodifiableList(protocols);
}
}
Sensor Management Capability Contract
/**
* Provision Interface - What Sensor Management PROVIDES
*/
public interface SensorService {
EncoderReading getEncoderPosition();
TemperatureReading getTemperature();
void calibrateSensors();
}
/**
* Complete Contract for Sensor Management Capability
*/
public class SensorManagementContract {
private final List<Provision> provisions;
private final List<Requirement> requirements;
private final List<Protocol> protocols;
public static SensorManagementContract create() {
return new SensorManagementContract(
// PROVISIONS: What Sensor Management offers
List.of(
new Provision(
"SensorService",
SensorService.class,
"Provides calibrated encoder and temperature sensor readings"
)
),
// REQUIREMENTS: What Sensor Management needs
List.of(
new Requirement(
"DiagnosticService",
DiagnosticService.class,
true, // OPTIONAL
"Optional logging for sensor calibration and fault events"
)
),
// PROTOCOLS: How Sensor Management interacts
List.of(
new Protocol(
"SensorDataProvision",
CommunicationMechanism.INTERRUPT_DRIVEN,
DataFormat.BINARY,
Map.of(
"maxLatency", "5us",
"updateRate", "1kHz",
"reliability", "guaranteed",
"dataFreshness", "real-time"
)
),
new Protocol(
"DiagnosticReporting",
CommunicationMechanism.ASYNC_MESSAGE,
DataFormat.JSON,
Map.of(
"maxLatency", "100ms",
"reliability", "best-effort"
)
)
)
);
}
// Getters omitted for brevity
}
Actuator Management Capability Contract
/**
* Provision Interface - What Actuator Management PROVIDES
*/
public interface ActuatorService {
void setPWMDutyCycle(double dutyCycle);
void enableOutput(boolean enable);
ActuatorStatus getStatus();
void performSafetyCheck();
}
/**
* Complete Contract for Actuator Management Capability
*/
public class ActuatorManagementContract {
private final List<Provision> provisions;
private final List<Requirement> requirements;
private final List<Protocol> protocols;
public static ActuatorManagementContract create() {
return new ActuatorManagementContract(
// PROVISIONS: What Actuator Management offers
List.of(
new Provision(
"ActuatorService",
ActuatorService.class,
"Provides safe PWM control and hardware interlock management"
)
),
// REQUIREMENTS: What Actuator Management needs
List.of(
new Requirement(
"DiagnosticService",
DiagnosticService.class,
true, // OPTIONAL
"Optional logging for safety events and fault conditions"
)
),
// PROTOCOLS: How Actuator Management interacts
List.of(
new Protocol(
"ActuatorControl",
CommunicationMechanism.DIRECT_CALL,
DataFormat.BINARY,
Map.of(
"maxLatency", "10us",
"reliability", "guaranteed",
"safetyLevel", "critical",
"failureMode", "fail-safe"
)
),
new Protocol(
"SafetyMonitoring",
CommunicationMechanism.ASYNC_MESSAGE,
DataFormat.JSON,
Map.of(
"maxLatency", "50ms",
"reliability", "at-least-once"
)
)
)
);
}
// Getters omitted for brevity
}
Diagnostic Logging Capability Contract
/**
* Provision Interface - What Diagnostic Logging PROVIDES
*/
public interface DiagnosticService {
void logEvent(String eventType, String message, Severity severity);
void logMetric(String metricName, double value);
void queryLogs(String filter, int maxResults);
}
/**
* Complete Contract for Diagnostic Logging Capability
*/
public class DiagnosticLoggingContract {
private final List<Provision> provisions;
private final List<Requirement> requirements;
private final List<Protocol> protocols;
public static DiagnosticLoggingContract create() {
return new DiagnosticLoggingContract(
// PROVISIONS: What Diagnostic Logging offers
List.of(
new Provision(
"DiagnosticService",
DiagnosticService.class,
"Provides event logging, metric collection, and log querying"
)
),
// REQUIREMENTS: No external dependencies
List.of(),
// PROTOCOLS: How Diagnostic Logging interacts
List.of(
new Protocol(
"LogIngestion",
CommunicationMechanism.ASYNC_MESSAGE,
DataFormat.JSON,
Map.of(
"maxLatency", "100ms",
"reliability", "best-effort",
"bufferSize", "10000",
"overflowPolicy", "drop-oldest"
)
),
new Protocol(
"LogQuery",
CommunicationMechanism.DIRECT_CALL,
DataFormat.JSON,
Map.of(
"maxLatency", "500ms",
"reliability", "guaranteed",
"cacheEnabled", "true"
)
)
)
);
}
// Getters omitted for brevity
}
Contract Design Principles
When designing contracts, several key principles ensure stability and flexibility:
1. Interface Stability: Contracts should be designed for long-term stability. Use semantic versioning where minor versions add features backward-compatibly, and major versions introduce breaking changes only when absolutely necessary.
2. Explicit Dependencies: All dependencies must be declared explicitly in Requirements. The Motor Control Capability explicitly declares it requires SensorService and ActuatorService. Hidden dependencies create coupling and prevent independent evolution.
3. Protocol Clarity: Protocols must specify all quality attributes that affect interaction. For the motor control system, the protocol between Motor Control and Sensor Management specifies 5-microsecond maximum latency, 1kHz call frequency, guaranteed reliability, and high interrupt priority. These attributes are critical for real-time performance.
4. Optional vs. Required: Requirements should clearly indicate whether they are optional or mandatory. The DiagnosticService is marked as optional because the motor control system can operate without logging, though logging is valuable for troubleshooting.
5. Multiple Protocols: A single capability can support multiple protocols for different interaction patterns. The Motor Control Capability uses interrupt-driven communication with sensors (low latency), direct calls to actuators (safety-critical), and asynchronous messaging for diagnostics (non-critical).
6. Data Ownership: Contracts should clearly define data ownership and lifecycle. The SensorService owns sensor calibration data, while the MotorControlService owns control algorithm state.
7. Versioning Strategy: Each contract should have explicit version information. The Evolution Envelope (covered in Step 5) manages this versioning and provides migration paths between versions.
The contracts defined above establish clear boundaries between capabilities. The Motor Control Capability can now be developed, tested, and evolved independently of Sensor Management and Actuator Management, as long as the contracts remain stable. This independence is the cornerstone of CCA's flexibility and maintainability.
STEP THREE: STRUCTURE CAPABILITY NUCLEI
With contracts defined, the next step is structuring each capability as a Capability Nucleus. The nucleus consists of three concentric layers: Essence, Realization, and Adaptation. Each layer has distinct responsibilities and dependency rules that ensure separation of concerns and enable independent evolution.
The Essence Layer
The Essence contains the pure domain logic or algorithmic core. It defines what the capability does without any dependencies on infrastructure, hardware, or external systems. The only external dependencies allowed are other Capability Contracts (the interfaces, not implementations).
For the Motor Control Capability, the Essence contains the PID control algorithm. This algorithm is pure logic: it takes current and target values, applies proportional, integral, and derivative calculations, and produces a control output. The algorithm has no knowledge of hardware registers, interrupts, or communication protocols.
/**
* ESSENCE LAYER: Pure PID Control Algorithm
* No infrastructure dependencies - completely testable in isolation
*/
public class PIDController {
private double kp; // Proportional gain
private double ki; // Integral gain
private double kd; // Derivative gain
private double integral;
private double previousError;
private final double integralLimit;
public PIDController(double kp, double ki, double kd, double integralLimit) {
this.kp = kp;
this.ki = ki;
this.kd = kd;
this.integralLimit = integralLimit;
this.integral = 0.0;
this.previousError = 0.0;
}
/**
* Calculate control output based on current and target values.
* This is pure domain logic with no external dependencies.
*
* @param current Current measured value
* @param target Desired target value
* @param deltaTime Time since last calculation (seconds)
* @return Control output value
*/
public double calculate(double current, double target, double deltaTime) {
double error = target - current;
// Proportional term
double proportional = kp * error;
// Integral term with anti-windup
integral += error * deltaTime;
integral = Math.max(-integralLimit, Math.min(integralLimit, integral));
double integralTerm = ki * integral;
// Derivative term
double derivative = (error - previousError) / deltaTime;
double derivativeTerm = kd * derivative;
previousError = error;
return proportional + integralTerm + derivativeTerm;
}
public void reset() {
integral = 0.0;
previousError = 0.0;
}
public void setGains(double kp, double ki, double kd) {
this.kp = kp;
this.ki = ki;
this.kd = kd;
}
public PIDGains getGains() {
return new PIDGains(kp, ki, kd);
}
}
public record PIDGains(double kp, double ki, double kd) {}
/**
* ESSENCE LAYER: Motor State Estimator
* Pure logic for estimating motor state from sensor data
*/
public class MotorStateEstimator {
private static final int FILTER_SIZE = 5;
private final double[] speedHistory;
private int historyIndex;
private int previousPosition;
public MotorStateEstimator() {
this.speedHistory = new double[FILTER_SIZE];
this.historyIndex = 0;
this.previousPosition = 0;
}
/**
* Estimate current speed from encoder position.
* Uses moving average filter for noise reduction.
*
* @param currentPosition Current encoder position
* @param deltaTime Time since last reading (seconds)
* @return Estimated speed in RPM
*/
public double estimateSpeed(int currentPosition, double deltaTime) {
int positionDelta = currentPosition - previousPosition;
double instantaneousSpeed = positionDelta / deltaTime;
// Apply moving average filter
speedHistory[historyIndex] = instantaneousSpeed;
historyIndex = (historyIndex + 1) % FILTER_SIZE;
double sum = 0.0;
for (double speed : speedHistory) {
sum += speed;
}
previousPosition = currentPosition;
return sum / FILTER_SIZE;
}
public void reset() {
Arrays.fill(speedHistory, 0.0);
historyIndex = 0;
previousPosition = 0;
}
}
The Essence layer is completely testable without any hardware or infrastructure. Unit tests can verify PID algorithm behavior, stability, and convergence using pure mathematical inputs. This testability is a key advantage of the layered structure.
The Realization Layer
The Realization implements the technical mechanisms required to make the Essence functional in a specific environment. It handles how the capability operates within its technical context. For embedded systems, this includes hardware access, RTOS integration, and low-level protocols. For enterprise systems, this includes database access, message queues, and API clients.
The Realization layer uses the Essence layer's pure logic and integrates it with infrastructure. It also implements the Requirements declared in the Contract by consuming services from other capabilities.
/**
* REALIZATION LAYER: Hardware Integration for Motor Control
* Integrates pure Essence logic with hardware infrastructure
* Implements Requirements by consuming other capabilities' services
*/
public class MotorControlRealization {
// ESSENCE COMPONENTS: Pure domain logic
private final PIDController pidController;
private final MotorStateEstimator stateEstimator;
// HARDWARE DEPENDENCIES: Platform-specific infrastructure
private final HardwareRegisters hardwareRegisters;
private final InterruptHandler interruptHandler;
private final RTOSTimer timer;
// CONTRACT REQUIREMENTS: Services from other capabilities
private SensorService sensorService; // Injected by CapabilityLifecycleManager
private ActuatorService actuatorService; // Injected by CapabilityLifecycleManager
private DiagnosticService diagnosticService; // Optional, may be null
// STATE MANAGEMENT
private volatile double targetSpeed;
private volatile MotorState currentState;
private long previousTimestamp;
public MotorControlRealization(
HardwareRegisters hardwareRegisters,
InterruptHandler interruptHandler,
RTOSTimer timer
) {
this.hardwareRegisters = hardwareRegisters;
this.interruptHandler = interruptHandler;
this.timer = timer;
// Initialize Essence components with tuned parameters
this.pidController = new PIDController(1.0, 0.1, 0.05, 100.0);
this.stateEstimator = new MotorStateEstimator();
this.targetSpeed = 0.0;
this.currentState = MotorState.STOPPED;
this.previousTimestamp = 0;
}
/**
* Initialize hardware resources.
* This operates at LOW abstraction, HIGH efficiency (Efficiency Gradient).
*/
public void initializeHardware() {
// Configure hardware registers for encoder input
hardwareRegisters.configureEncoder(
EncoderMode.QUADRATURE,
EncoderResolution.HIGH
);
// Register interrupt handler for control loop
// This is CRITICAL PATH - highest priority
interruptHandler.register(
InterruptSource.TIMER_OVERFLOW,
this::controlLoopInterrupt,
InterruptPriority.HIGHEST
);
// Configure timer for 1kHz control loop (1ms period)
timer.configure(1000, TimerMode.PERIODIC);
logDiagnostic("INFO", "Motor control hardware initialized");
}
/**
* CRITICAL PATH: Control loop interrupt handler
* Operates at MAXIMUM EFFICIENCY - direct hardware access, minimal overhead
* This demonstrates LOW abstraction, HIGH efficiency Efficiency Gradient
*/
private void controlLoopInterrupt() {
long currentTime = timer.getCurrentMicroseconds();
double deltaTime = (currentTime - previousTimestamp) / 1_000_000.0;
if (currentState != MotorState.RUNNING) {
previousTimestamp = currentTime;
return;
}
try {
// Get sensor reading through Contract Requirement
EncoderReading encoderReading = sensorService.getEncoderPosition();
// Estimate speed using ESSENCE logic
double currentSpeed = stateEstimator.estimateSpeed(
encoderReading.position(),
deltaTime
);
// Calculate control output using ESSENCE logic
double controlOutput = pidController.calculate(
currentSpeed,
targetSpeed,
deltaTime
);
// Clamp output to valid range
controlOutput = Math.max(-100.0, Math.min(100.0, controlOutput));
// Send to actuator through Contract Requirement
actuatorService.setPWMDutyCycle(controlOutput);
} catch (Exception e) {
// Fault detected - enter safe state
currentState = MotorState.FAULT;
actuatorService.enableOutput(false);
logDiagnostic("ERROR", "Control loop fault: " + e.getMessage());
}
previousTimestamp = currentTime;
}
/**
* NON-CRITICAL PATH: Configuration update
* Operates at HIGHER abstraction, LOWER efficiency (Efficiency Gradient)
* This can use file I/O, JSON parsing, network calls - not time-critical
*/
public void updateConfiguration(String configJson) {
logDiagnostic("INFO", "Updating motor configuration");
try {
// Parse JSON configuration (high-level abstraction)
JSONObject config = new JSONObject(configJson);
double kp = config.getDouble("kp");
double ki = config.getDouble("ki");
double kd = config.getDouble("kd");
// Update PID gains in ESSENCE
pidController.setGains(kp, ki, kd);
logDiagnostic("INFO", "Configuration updated successfully");
} catch (Exception e) {
logDiagnostic("ERROR", "Configuration update failed: " + e.getMessage());
}
}
/**
* Set target speed - called through Adaptation layer
*/
public void setTargetSpeed(double speedRPM) {
this.targetSpeed = speedRPM;
logDiagnostic("INFO", "Target speed set to " + speedRPM + " RPM");
}
/**
* Emergency stop - safety-critical operation
*/
public void emergencyStop() {
currentState = MotorState.EMERGENCY_STOP;
targetSpeed = 0.0;
pidController.reset();
stateEstimator.reset();
actuatorService.enableOutput(false);
logDiagnostic("CRITICAL", "Emergency stop activated");
}
/**
* Get current motor status
*/
public MotorStatus getCurrentStatus() {
return new MotorStatus(
stateEstimator.estimateSpeed(
sensorService.getEncoderPosition().position(),
0.001 // 1ms
),
sensorService.getEncoderPosition().position(),
currentState,
System.currentTimeMillis()
);
}
/**
* Inject dependency - called by CapabilityLifecycleManager
*/
public void injectSensorService(SensorService sensorService) {
this.sensorService = sensorService;
}
public void injectActuatorService(ActuatorService actuatorService) {
this.actuatorService = actuatorService;
}
public void injectDiagnosticService(DiagnosticService diagnosticService) {
this.diagnosticService = diagnosticService;
}
/**
* Helper method for diagnostic logging
*/
private void logDiagnostic(String severity, String message) {
if (diagnosticService != null) {
diagnosticService.logEvent(
"MotorControl",
message,
Severity.valueOf(severity)
);
}
}
}
The Adaptation Layer
The Adaptation layer provides the explicit interfaces through which the capability interacts with other capabilities or external systems. It implements the Provisions declared in the Contract, exposing the capability's functionality to consumers.
The Adaptation layer translates between the capability's internal representation and external communication protocols. It handles protocol-specific concerns like data serialization, error handling, and communication patterns.
/**
* ADAPTATION LAYER: External Interface Implementation
* Implements the Provisions declared in MotorControlContract
* Provides the MotorControlService interface to other capabilities
*/
public class MotorControlAdapter implements MotorControlService {
// Reference to Realization layer
private final MotorControlRealization realization;
public MotorControlAdapter(MotorControlRealization realization) {
this.realization = realization;
}
/**
* Provision implementation: setTargetSpeed
* This method is called by other capabilities through the Contract
*/
@Override
public void setTargetSpeed(double speedRPM) {
// Validate input
if (speedRPM < 0 || speedRPM > 10000) {
throw new IllegalArgumentException(
"Speed must be between 0 and 10000 RPM"
);
}
// Delegate to Realization
realization.setTargetSpeed(speedRPM);
}
/**
* Provision implementation: setTargetPosition
*/
@Override
public void setTargetPosition(double positionDegrees) {
// For this example, position control is not implemented
// In a real system, this would use a different control algorithm
throw new UnsupportedOperationException(
"Position control not implemented in this version"
);
}
/**
* Provision implementation: getCurrentStatus
*/
@Override
public MotorStatus getCurrentStatus() {
return realization.getCurrentStatus();
}
/**
* Provision implementation: emergencyStop
*/
@Override
public void emergencyStop() {
realization.emergencyStop();
}
}
Complete Capability Nucleus Structure
Now let's see how all three layers come together in the complete Motor Control Capability:
/**
* COMPLETE MOTOR CONTROL CAPABILITY NUCLEUS
* Combines Essence, Realization, and Adaptation layers
* Implements CapabilityInstance for lifecycle management
*/
public class MotorControlCapability implements CapabilityInstance {
// ESSENCE: Pure domain logic
private final PIDController pidController;
private final MotorStateEstimator stateEstimator;
// REALIZATION: Infrastructure integration
private final MotorControlRealization realization;
// ADAPTATION: External interface
private final MotorControlAdapter adapter;
// CONTRACT: Formal interface agreement
private final MotorControlContract contract;
public MotorControlCapability(
HardwareRegisters hardwareRegisters,
InterruptHandler interruptHandler,
RTOSTimer timer
) {
// Initialize Essence components
this.pidController = new PIDController(1.0, 0.1, 0.05, 100.0);
this.stateEstimator = new MotorStateEstimator();
// Initialize Realization with Essence and hardware dependencies
this.realization = new MotorControlRealization(
hardwareRegisters,
interruptHandler,
timer
);
// Initialize Adaptation with Realization reference
this.adapter = new MotorControlAdapter(realization);
// Create Contract
this.contract = MotorControlContract.create();
}
// ===== LIFECYCLE MANAGEMENT METHODS =====
@Override
public void initialize() {
// Initialize hardware resources
realization.initializeHardware();
}
@Override
public void start() {
// Start control loop (timer interrupts begin)
realization.startControlLoop();
}
@Override
public void stop() {
// Stop control loop gracefully
realization.stopControlLoop();
}
@Override
public void cleanup() {
// Release hardware resources
realization.releaseHardware();
}
// ===== DEPENDENCY INJECTION =====
@Override
public void injectDependency(Class<?> contractType, Object implementation) {
if (contractType == SensorService.class) {
realization.injectSensorService((SensorService) implementation);
} else if (contractType == ActuatorService.class) {
realization.injectActuatorService((ActuatorService) implementation);
} else if (contractType == DiagnosticService.class) {
realization.injectDiagnosticService((DiagnosticService) implementation);
}
}
@Override
public Object getContractImplementation(Class<?> contractType) {
if (contractType == MotorControlService.class) {
return adapter; // Return Adaptation layer implementation
}
return null;
}
// ===== CONTRACT ACCESS =====
public MotorControlContract getContract() {
return contract;
}
}
Nucleus Layer Visualization
┌─────────────────────────────────────────────────────────────────┐
│ MOTOR CONTROL CAPABILITY │
│ │
│ ┌───────────────────────────────────────────────────────────┐ │
│ │ ADAPTATION LAYER │ │
│ │ │ │
│ │ MotorControlAdapter (implements MotorControlService) │ │
│ │ - setTargetSpeed() │ │
│ │ - getCurrentStatus() │ │
│ │ - emergencyStop() │ │
│ │ │ │
│ │ Handles: Protocol translation, input validation, │ │
│ │ external interface exposure │ │
│ └───────────────────────────────────────────────────────────┘ │
│ ▲ │
│ │ delegates to │
│ ▼ │
│ ┌───────────────────────────────────────────────────────────┐ │
│ │ REALIZATION LAYER │ │
│ │ │ │
│ │ MotorControlRealization │ │
│ │ - Hardware integration (registers, interrupts, timer) │ │
│ │ - Control loop interrupt handler (CRITICAL PATH) │ │
│ │ - Configuration management (NON-CRITICAL PATH) │ │
│ │ - Dependency injection (SensorService, ActuatorService) │ │
│ │ │ │
│ │ Handles: Hardware access, RTOS integration, │ │
│ │ efficiency gradients, service orchestration │ │
│ └───────────────────────────────────────────────────────────┘ │
│ ▲ │
│ │ uses │
│ ▼ │
│ ┌───────────────────────────────────────────────────────────┐ │
│ │ ESSENCE LAYER │ │
│ │ │ │
│ │ PIDController - Pure control algorithm │ │
│ │ MotorStateEstimator - Pure state estimation │ │
│ │ │ │
│ │ Handles: Pure domain logic, no infrastructure deps │ │
│ │ 100% testable in isolation │ │
│ └───────────────────────────────────────────────────────────┘ │
│ │
└─────────────────────────────────────────────────────────────────┘
Key Principles of Nucleus Structure
1. Dependency Direction: Dependencies flow inward. Adaptation depends on Realization, Realization depends on Essence, but Essence has no dependencies on outer layers.
2. Pure Essence: The Essence layer contains only pure logic with no infrastructure dependencies. This makes it completely testable and reusable across platforms.
3. Infrastructure Isolation: All hardware, database, network, and OS dependencies are isolated in the Realization layer. This allows technology changes without affecting domain logic.
4. Contract Implementation: The Adaptation layer implements the Provisions declared in the Contract. It's the public face of the capability.
5. Efficiency Gradients: Different parts of the Realization can operate at different efficiency levels. The control loop interrupt operates at maximum efficiency (direct hardware access), while configuration updates use higher abstractions (JSON parsing, file I/O).
6. Testability: Each layer can be tested independently. Essence has pure unit tests, Realization has integration tests with mock hardware, and Adaptation has contract tests.
This structure provides the foundation for all CCA benefits: independent evolution, flexible deployment, technology independence, and clear separation of concerns.
STEP FOUR: APPLY EFFICIENCY GRADIENTS
Efficiency Gradients are a distinctive CCA concept that allows different parts of a system to operate at varying levels of performance optimization and abstraction. Not all code requires the same level of efficiency. Critical paths need maximum performance with minimal overhead, while non-critical paths benefit from higher-level abstractions that improve maintainability and development speed.
The key insight is that efficiency gradients can exist both between capabilities and within a single capability's Realization layer. This flexibility allows architects to make deliberate, fine-grained decisions about where to invest in performance optimization.
Identifying Critical vs. Non-Critical Paths
For the motor control system, the analysis reveals:
Critical Paths (High Efficiency, Low Abstraction):
* Control loop interrupt handler (must execute in microseconds)
* Sensor reading acquisition (real-time data)
* Actuator PWM output (safety-critical timing)
Non-Critical Paths (Lower Efficiency, Higher Abstraction):
* Configuration file parsing and updates
* Diagnostic logging and metrics collection
* System status queries and reporting
Efficiency Gradient Levels
HIGH EFFICIENCY LOW EFFICIENCY
LOW ABSTRACTION HIGH ABSTRACTION
─────────────────────────────────────────────────────────────────────
│ Level 1: Bare-metal, direct hardware access │
│ Assembly, register manipulation, interrupt handlers │
│ Example: Control loop interrupt, PWM generation │
│ │
├──────────────────────────────────────────────────────────────────┤
│ Level 2: RTOS services, optimized libraries │
│ Compiled languages, minimal overhead │
│ Example: Sensor calibration, state estimation │
│ │
├──────────────────────────────────────────────────────────────────┤
│ Level 3: Standard frameworks, managed languages │
│ File I/O, network protocols, JSON parsing │
│ Example: Configuration management, logging │
│ │
└──────────────────────────────────────────────────────────────────┘
Implementing Efficiency Gradients in Motor Control
Let's see how the Motor Control Capability applies different efficiency gradients:
/**
* EFFICIENCY GRADIENT EXAMPLE: Motor Control Realization
* Demonstrates different efficiency levels within a single capability
*/
public class MotorControlRealization {
// ... (fields omitted for brevity)
/**
* EFFICIENCY GRADIENT LEVEL 1: Maximum Efficiency
*
* This is the CRITICAL PATH - control loop interrupt handler
* - Direct hardware register access
* - No memory allocation
* - No exception handling overhead
* - Inline calculations
* - Microsecond-level timing requirements
*
* This code sacrifices readability and maintainability for raw performance
*/
private void controlLoopInterrupt() {
// Read directly from hardware register (no abstraction)
int encoderRaw = hardwareRegisters.readEncoderDirect();
long timeRaw = timer.getMicrosecondsDirect();
// Inline calculations (no method calls)
double deltaTime = (timeRaw - previousTimestamp) * 0.000001;
int posDelta = encoderRaw - previousPosition;
double speed = posDelta / deltaTime;
// PID calculation (optimized, no bounds checking)
double error = targetSpeed - speed;
integral += error * deltaTime;
double output = (kp * error) + (ki * integral) + (kd * (error - prevError) / deltaTime);
// Clamp and write directly to PWM register
int pwmValue = (int) Math.max(0, Math.min(255, output));
hardwareRegisters.writePWMDirect(pwmValue);
// Update state
previousPosition = encoderRaw;
previousTimestamp = timeRaw;
prevError = error;
}
/**
* EFFICIENCY GRADIENT LEVEL 2: Medium Efficiency
*
* This is a SEMI-CRITICAL PATH - sensor calibration
* - Uses RTOS services
* - Optimized libraries
* - Some abstraction for maintainability
* - Millisecond-level timing requirements
*
* Balances performance with code clarity
*/
public void calibrateSensors() {
// Use RTOS mutex for thread safety (some overhead)
rtosLock.acquire();
try {
// Use optimized library for statistical calculations
double[] samples = new double[100];
for (int i = 0; i < 100; i++) {
samples[i] = sensorService.getEncoderPosition().position();
rtosTimer.delayMicroseconds(100); // RTOS service
}
// Calculate calibration offset using optimized library
double mean = Statistics.mean(samples);
double stdDev = Statistics.standardDeviation(samples);
// Apply calibration
calibrationOffset = mean;
calibrationQuality = (stdDev < 1.0) ?
SensorQuality.GOOD : SensorQuality.DEGRADED;
} finally {
rtosLock.release();
}
}
/**
* EFFICIENCY GRADIENT LEVEL 3: Lower Efficiency, High Abstraction
*
* This is a NON-CRITICAL PATH - configuration management
* - Uses high-level frameworks
* - File I/O, JSON parsing
* - Exception handling
* - String manipulation
* - Second-level timing tolerance
*
* Prioritizes maintainability, flexibility, and developer productivity
*/
public void loadConfigurationFromFile(String filePath) {
try {
// High-level file I/O (significant overhead)
String jsonContent = Files.readString(Path.of(filePath));
// JSON parsing using framework (reflection, dynamic typing)
JSONObject config = new JSONObject(jsonContent);
// Extract nested configuration with validation
if (config.has("pidController")) {
JSONObject pidConfig = config.getJSONObject("pidController");
double kp = pidConfig.optDouble("kp", 1.0);
double ki = pidConfig.optDouble("ki", 0.1);
double kd = pidConfig.optDouble("kd", 0.05);
// Validate ranges
if (kp < 0 || kp > 100 || ki < 0 || ki > 10 || kd < 0 || kd > 10) {
throw new ConfigurationException("PID gains out of valid range");
}
// Update configuration
pidController.setGains(kp, ki, kd);
}
// Log success using high-level logging framework
if (diagnosticService != null) {
diagnosticService.logEvent(
"Configuration",
"Loaded configuration from " + filePath,
Severity.INFO
);
}
} catch (IOException e) {
// Exception handling (overhead acceptable for non-critical path)
logger.error("Failed to load configuration: " + e.getMessage());
if (diagnosticService != null) {
diagnosticService.logEvent(
"Configuration",
"Configuration load failed: " + e.getMessage(),
Severity.ERROR
);
}
}
}
/**
* EFFICIENCY GRADIENT LEVEL 3: Network-based configuration update
*
* This is a NON-CRITICAL PATH - remote configuration
* - Network I/O
* - HTTP protocol handling
* - Asynchronous processing
* - Multi-second timing tolerance
*/
public CompletableFuture<Void> updateConfigurationFromServer(String serverUrl) {
return CompletableFuture.runAsync(() -> {
try {
// HTTP client with high-level abstraction
HttpClient client = HttpClient.newHttpClient();
HttpRequest request = HttpRequest.newBuilder()
.uri(URI.create(serverUrl + "/motor-config"))
.timeout(Duration.ofSeconds(10))
.GET()
.build();
// Asynchronous network call
HttpResponse<String> response = client.send(
request,
HttpResponse.BodyHandlers.ofString()
);
if (response.statusCode() == 200) {
// Parse and apply configuration
JSONObject config = new JSONObject(response.body());
applyConfiguration(config);
logger.info("Configuration updated from server");
} else {
logger.warn("Server returned status: " + response.statusCode());
}
} catch (Exception e) {
logger.error("Remote configuration update failed", e);
}
}, executorService); // Uses thread pool (high-level concurrency)
}
}
Efficiency Gradients Across Capabilities
Different capabilities in the motor control system operate at different gradients:
/**
* MOTOR CONTROL CAPABILITY: High Efficiency (Level 1-2)
* Critical real-time control requires maximum performance
*/
public class MotorControlCapability {
// Control loop: Level 1 (bare-metal, microsecond timing)
// State estimation: Level 2 (RTOS services, millisecond timing)
// Configuration: Level 3 (high abstraction, second timing)
}
/**
* DIAGNOSTIC LOGGING CAPABILITY: Lower Efficiency (Level 3)
* Non-critical monitoring can use high-level abstractions
*/
public class DiagnosticLoggingCapability {
private final BlockingQueue<LogEntry> logQueue;
private final ExecutorService logWriter;
private final FileWriter logFile;
/**
* All operations use high-level abstractions:
* - Thread pools
* - Blocking queues
* - File I/O
* - String formatting
* - JSON serialization
*/
public void logEvent(String eventType, String message, Severity severity) {
// Asynchronous logging (non-blocking for caller)
logQueue.offer(new LogEntry(
System.currentTimeMillis(),
eventType,
message,
severity
));
}
private void processLogQueue() {
executorService.submit(() -> {
while (running) {
try {
LogEntry entry = logQueue.take(); // Blocking call
// Format as JSON (high-level abstraction)
String json = String.format(
"{\"timestamp\":%d,\"type\":\"%s\",\"message\":\"%s\",\"severity\":\"%s\"}",
entry.timestamp(),
entry.eventType(),
entry.message(),
entry.severity()
);
// Write to file (I/O overhead)
logFile.write(json + "\n");
logFile.flush();
} catch (InterruptedException | IOException e) {
logger.error("Log processing error", e);
}
}
});
}
}
Gradient Selection Criteria
When deciding which efficiency gradient to apply, consider:
1. Timing Requirements:
* Microsecond: Level 1 (bare-metal)
* Millisecond: Level 2 (RTOS/optimized)
* Second+: Level 3 (high abstraction)
2. Execution Frequency:
* kHz+: Level 1
* Hz to hundreds of Hz: Level 2
* < 1 Hz: Level 3
3. Safety Criticality:
* Safety-critical: Level 1-2 (deterministic)
* Important but not safety-critical: Level 2
* Non-critical: Level 3
4. Resource Constraints:
* Severe constraints: Level 1
* Moderate constraints: Level 2
* Abundant resources: Level 3
5. Maintenance Frequency:
* Rarely changes: Level 1 acceptable
* Frequent updates: Level 2-3 preferred
Benefits of Efficiency Gradients
1. Optimal Resource Allocation: Performance optimization effort is invested only where needed.
2. Maintainability: Non-critical code uses readable, maintainable abstractions.
3. Development Speed: Developers can use modern frameworks and tools for non-critical paths.
4. Performance Guarantees: Critical paths achieve required real-time performance.
5. Technology Evolution: High-abstraction code can easily adopt new technologies and frameworks.
The Efficiency Gradient concept is one of CCA's most powerful features, enabling a single architecture to span from bare-metal embedded systems to cloud-native enterprise platforms.
STEP FIVE: DEFINE EVOLUTION ENVELOPES
Evolution Envelopes provide a structured mechanism for managing how capabilities evolve over time. In complex systems, change is inevitable. Without a clear evolution strategy, changes lead to breaking dependencies, integration failures, and maintenance nightmares. Evolution Envelopes make change explicit, predictable, and manageable.
Each capability has its own Evolution Envelope that encapsulates:
* Versioning Information: Current and previous versions using Semantic Versioning
* Deprecation Policies: Clear strategies for phasing out old versions
* Migration Paths: Step-by-step guidance for upgrading between versions
Semantic Versioning for Contracts
CCA uses Semantic Versioning (MAJOR.MINOR.PATCH) for contract evolution:
* MAJOR: Incompatible API changes (breaking changes)
* MINOR: New functionality, backward-compatible
* PATCH: Backward-compatible bug fixes
/**
* Versioning Information
* Tracks current and previous versions of a capability
*/
public record VersionInfo(
String currentVersion,
String previousVersion,
LocalDate releaseDate
) {
public int getMajorVersion() {
return Integer.parseInt(currentVersion.split("\\.")[0]);
}
public int getMinorVersion() {
return Integer.parseInt(currentVersion.split("\\.")[1]);
}
public int getPatchVersion() {
return Integer.parseInt(currentVersion.split("\\.")[2]);
}
public boolean isBreakingChangeFrom(String otherVersion) {
int otherMajor = Integer.parseInt(otherVersion.split("\\.")[0]);
return getMajorVersion() != otherMajor;
}
}
Deprecation Policies
/**
* Deprecation Policy
* Defines how features or versions are phased out
*/
public record DeprecationPolicy(
String target, // What is being deprecated
LocalDate announcementDate, // When deprecation was announced
LocalDate endOfLifeDate, // When support ends
String reason, // Why it's being deprecated
String replacement // What to use instead
) {
public long getDaysUntilEOL() {
return ChronoUnit.DAYS.between(LocalDate.now(), endOfLifeDate);
}
public boolean isDeprecated() {
return LocalDate.now().isAfter(announcementDate);
}
public boolean isEndOfLife() {
return LocalDate.now().isAfter(endOfLifeDate);
}
}
Migration Paths
/**
* Migration Path
* Provides guidance for upgrading between versions
*/
public record MigrationPath(
String fromVersion,
String toVersion,
String documentationUrl,
String migrationToolReference,
List<MigrationStep> steps,
EstimatedEffort effort
) {}
public record MigrationStep(
int stepNumber,
String description,
String codeExample,
List<String> warnings
) {}
public enum EstimatedEffort {
TRIVIAL, // < 1 hour
MINOR, // 1-8 hours
MODERATE, // 1-3 days
MAJOR, // 1-2 weeks
EXTENSIVE // > 2 weeks
}
Complete Evolution Envelope
/**
* Evolution Envelope for Motor Control Capability
* Manages all aspects of capability evolution
*/
public class EvolutionEnvelope {
private final VersionInfo versionInfo;
private final List<DeprecationPolicy> deprecationPolicies;
private final List<MigrationPath> migrationPaths;
private final ChangeLog changeLog;
public EvolutionEnvelope(
VersionInfo versionInfo,
List<DeprecationPolicy> deprecationPolicies,
List<MigrationPath> migrationPaths,
ChangeLog changeLog
) {
this.versionInfo = versionInfo;
this.deprecationPolicies = Collections.unmodifiableList(deprecationPolicies);
this.migrationPaths = Collections.unmodifiableList(migrationPaths);
this.changeLog = changeLog;
}
public VersionInfo getVersionInfo() {
return versionInfo;
}
public List<DeprecationPolicy> getDeprecationPolicies() {
return deprecationPolicies;
}
public List<MigrationPath> getMigrationPaths() {
return migrationPaths;
}
public ChangeLog getChangeLog() {
return changeLog;
}
/**
* Find migration path from a specific version to current
*/
public Optional<MigrationPath> findMigrationPath(String fromVersion) {
return migrationPaths.stream()
.filter(path -> path.fromVersion().equals(fromVersion))
.filter(path -> path.toVersion().equals(versionInfo.currentVersion()))
.findFirst();
}
/**
* Check if a specific feature is deprecated
*/
public boolean isDeprecated(String feature) {
return deprecationPolicies.stream()
.anyMatch(policy ->
policy.target().equals(feature) && policy.isDeprecated()
);
}
/**
* Get active deprecation warnings
*/
public List<String> getActiveDeprecationWarnings() {
return deprecationPolicies.stream()
.filter(DeprecationPolicy::isDeprecated)
.filter(policy -> !policy.isEndOfLife())
.map(policy -> String.format(
"WARNING: %s is deprecated. End of life: %s. Use %s instead.",
policy.target(),
policy.endOfLifeDate(),
policy.replacement()
))
.toList();
}
}
Example: Motor Control Capability Evolution Envelope
/**
* Factory method to create Evolution Envelope for Motor Control Capability
*/
public class MotorControlEvolutionEnvelope {
public static EvolutionEnvelope create() {
// Version Information
VersionInfo versionInfo = new VersionInfo(
"2.1.0", // Current version
"2.0.3", // Previous version
LocalDate.of(2024, 12, 1)
);
// Deprecation Policies
List<DeprecationPolicy> deprecations = List.of(
new DeprecationPolicy(
"Contract v1.x",
LocalDate.of(2024, 6, 1),
LocalDate.of(2025, 12, 31),
"Major refactoring to support multi-motor control",
"Contract v2.x with MotorControlService interface"
),
new DeprecationPolicy(
"setSpeed(int) method",
LocalDate.of(2024, 9, 1),
LocalDate.of(2025, 6, 30),
"Integer speed values lack precision for fine control",
"setTargetSpeed(double) method with RPM units"
),
new DeprecationPolicy(
"DirectHardwareAccess mode",
LocalDate.of(2024, 10, 1),
LocalDate.of(2026, 1, 1),
"Safety concerns with unmediated hardware access",
"Use ActuatorService contract for all hardware interaction"
)
);
// Migration Paths
List<MigrationPath> migrations = List.of(
new MigrationPath(
"1.x",
"2.1.0",
"https://docs.example.com/motor-control/migration-v1-to-v2",
"motor-control-upgrade-tool.sh",
List.of(
new MigrationStep(
1,
"Update contract dependency from MotorControl v1.x to v2.x",
"""
// Old (v1.x):
MotorController controller = new MotorController();
controller.setSpeed(1000); // Integer value
// New (v2.x):
MotorControlService service = capability.getService();
service.setTargetSpeed(1000.0); // Double value in RPM
""",
List.of(
"Ensure all speed values are converted to double",
"Review speed limits - v2.x uses RPM instead of arbitrary units"
)
),
new MigrationStep(
2,
"Replace direct hardware access with ActuatorService",
"""
// Old (v1.x):
hardwareRegisters.writePWM(dutyCycle);
// New (v2.x):
actuatorService.setPWMDutyCycle(dutyCycle);
""",
List.of(
"ActuatorService includes safety checks",
"May introduce slight latency (< 10us)"
)
),
new MigrationStep(
3,
"Update configuration file format",
"""
// Old format (v1.x):
{
"speed": 1000,
"mode": "direct"
}
// New format (v2.x):
{
"pidController": {
"kp": 1.0,
"ki": 0.1,
"kd": 0.05
},
"targetSpeed": 1000.0,
"safetyLimits": {
"maxSpeed": 10000.0,
"maxAcceleration": 1000.0
}
}
""",
List.of(
"Run configuration migration tool before deployment",
"Backup old configuration files"
)
)
),
EstimatedEffort.MODERATE
),
new MigrationPath(
"2.0.x",
"2.1.0",
"https://docs.example.com/motor-control/migration-v2.0-to-v2.1",
null, // No tool needed - backward compatible
List.of(
new MigrationStep(
1,
"Optional: Adopt new diagnostic logging features",
"""
// New in v2.1.0 (optional):
service.enableAdvancedDiagnostics(true);
service.setDiagnosticInterval(Duration.ofMillis(100));
""",
List.of(
"Fully backward compatible - no changes required",
"New features are opt-in"
)
)
),
EstimatedEffort.TRIVIAL
)
);
// Change Log
ChangeLog changeLog = new ChangeLog(List.of(
new ChangeLogEntry(
"2.1.0",
LocalDate.of(2024, 12, 1),
List.of(
"Added advanced diagnostic logging capabilities",
"Improved PID tuning algorithm for better stability",
"Added support for configurable safety limits"
),
List.of(),
List.of(
"Fixed race condition in control loop initialization",
"Fixed memory leak in diagnostic buffer"
)
),
new ChangeLogEntry(
"2.0.0",
LocalDate.of(2024, 6, 1),
List.of(
"Complete redesign for multi-motor support",
"New contract-based architecture",
"Integration with ActuatorService for safety"
),
List.of(
"Removed direct hardware access mode",
"Removed integer-based setSpeed() method",
"Changed configuration file format"
),
List.of(
"Improved control loop stability",
"Reduced interrupt latency by 30%"
)
)
));
return new EvolutionEnvelope(
versionInfo,
deprecations,
migrations,
changeLog
);
}
}
public record ChangeLog(List<ChangeLogEntry> entries) {}
public record ChangeLogEntry(
String version,
LocalDate releaseDate,
List<String> additions,
List<String> breakingChanges,
List<String> fixes
) {}
Using Evolution Envelopes at Runtime
/**
* Example: Checking compatibility and displaying warnings
*/
public class CapabilityVersionChecker {
public void checkCompatibility(
EvolutionEnvelope envelope,
String requiredVersion
) {
VersionInfo current = envelope.getVersionInfo();
// Check for breaking changes
if (current.isBreakingChangeFrom(requiredVersion)) {
System.err.println(
"ERROR: Breaking change detected. " +
"Current version " + current.currentVersion() +
" is not compatible with required version " + requiredVersion
);
// Find migration path
Optional<MigrationPath> migration =
envelope.findMigrationPath(requiredVersion);
if (migration.isPresent()) {
System.out.println("Migration path available:");
System.out.println(" Documentation: " +
migration.get().documentationUrl());
System.out.println(" Estimated effort: " +
migration.get().effort());
}
}
// Display deprecation warnings
List<String> warnings = envelope.getActiveDeprecationWarnings();
if (!warnings.isEmpty()) {
System.out.println("\n=== DEPRECATION WARNINGS ===");
warnings.forEach(System.out::println);
}
}
}
Evolution Envelope Benefits
1. Predictable Change: Consumers know exactly when and how capabilities will change.
2. Reduced Integration Risk: Clear migration paths reduce the risk of upgrade failures.
3. Faster Adoption: Well-documented migrations encourage consumers to adopt new versions.
4. Explicit Lifecycle: Deprecation policies make the capability lifecycle transparent.
5. Automated Tooling: Machine-readable evolution information enables automated compatibility checking and migration assistance.
Evolution Envelopes transform capability evolution from an ad-hoc, risky process into a managed, predictable one. This is essential for long-lived systems that must evolve continuously while maintaining stability.
STEP SIX: PACKAGE CAPABILITIES
Packaging determines how capability components are bundled for deployment. CCA's layered structure (Essence, Realization, Adaptation) enables flexible packaging strategies that optimize for different deployment contexts. The key principle is: Always package Essence separately to maximize reusability and testability.
Packaging Strategies
There are three primary packaging approaches:
1. Separate Packaging: Essence, Realization, and Adaptation are packaged independently
2. Feature-Based Bundles: Combine specific Realizations and Adaptations for deployment contexts
3. Monolithic Packaging: All layers bundled together (least flexible, simplest deployment)
Separate Packaging Structure
motor-control-capability/
├── motor-control-essence/
│ ├── src/
│ │ └── com/example/motorcontrol/essence/
│ │ ├── PIDController.java
│ │ ├── MotorStateEstimator.java
│ │ └── PIDGains.java
│ ├── pom.xml (or build.gradle)
│ └── README.md
│
├── motor-control-realization-embedded/
│ ├── src/
│ │ └── com/example/motorcontrol/realization/embedded/
│ │ ├── MotorControlRealization.java
│ │ ├── HardwareRegisters.java
│ │ └── RTOSTimer.java
│ ├── dependencies:
│ │ └── motor-control-essence
│ └── pom.xml
│
├── motor-control-realization-simulation/
│ ├── src/
│ │ └── com/example/motorcontrol/realization/simulation/
│ │ ├── SimulatedMotorControlRealization.java
│ │ └── MotorSimulator.java
│ ├── dependencies:
│ │ └── motor-control-essence
│ └── pom.xml
│
├── motor-control-adaptation-uart/
│ ├── src/
│ │ └── com/example/motorcontrol/adaptation/uart/
│ │ └── UARTMotorControlAdapter.java
│ └── pom.xml
│
├── motor-control-adaptation-rest/
│ ├── src/
│ │ └── com/example/motorcontrol/adaptation/rest/
│ │ └── RESTMotorControlAdapter.java
│ └── pom.xml
│
└── motor-control-contracts/
├── src/
│ └── com/example/motorcontrol/contracts/
│ ├── MotorControlService.java
│ ├── MotorControlContract.java
│ └── EvolutionEnvelope.java
└── pom.xml
Maven/Gradle Packaging Configuration
<!-- motor-control-essence/pom.xml -->
<project>
<modelVersion>4.0.0</modelVersion>
<groupId>com.example.cca</groupId>
<artifactId>motor-control-essence</artifactId>
<version>2.1.0</version>
<packaging>jar</packaging>
<name>Motor Control Essence</name>
<description>Pure domain logic for motor control - platform independent</description>
<dependencies>
<!-- NO infrastructure dependencies -->
<!-- Only test dependencies allowed -->
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter</artifactId>
<version>5.9.0</version>
<scope>test</scope>
</dependency>
</dependencies>
</project>
<!-- motor-control-realization-embedded/pom.xml -->
<project>
<modelVersion>4.0.0</modelVersion>
<groupId>com.example.cca</groupId>
<artifactId>motor-control-realization-embedded</artifactId>
<version>2.1.0</version>
<packaging>jar</packaging>
<name>Motor Control Realization - Embedded</name>
<description>Embedded hardware implementation for motor control</description>
<dependencies>
<!-- Essence dependency -->
<dependency>
<groupId>com.example.cca</groupId>
<artifactId>motor-control-essence</artifactId>
<version>2.1.0</version>
</dependency>
<!-- Contracts dependency -->
<dependency>
<groupId>com.example.cca</groupId>
<artifactId>motor-control-contracts</artifactId>
<version>2.1.0</version>
</dependency>
<!-- Infrastructure dependencies -->
<dependency>
<groupId>com.example.rtos</groupId>
<artifactId>freertos-java</artifactId>
<version>10.4.0</version>
</dependency>
<dependency>
<groupId>com.example.hal</groupId>
<artifactId>hardware-abstraction-layer</artifactId>
<version>1.2.0</version>
</dependency>
</dependencies>
</project>
Feature-Based Bundle Creation
/**
* Deployment Bundle: Embedded Motor Control
* Combines Essence + Embedded Realization + UART Adaptation
*/
public class EmbeddedMotorControlBundle implements CapabilityInstance {
private final PIDController pidController; // Essence
private final MotorStateEstimator stateEstimator; // Essence
private final MotorControlRealization realization; // Realization (Embedded)
private final UARTMotorControlAdapter adapter; // Adaptation (UART)
private final MotorControlContract contract;
public EmbeddedMotorControlBundle(
HardwareRegisters hardwareRegisters,
InterruptHandler interruptHandler,
RTOSTimer timer,
UARTPort uartPort
) {
// Initialize Essence
this.pidController = new PIDController(1.0, 0.1, 0.05, 100.0);
this.stateEstimator = new MotorStateEstimator();
// Initialize Realization with Essence components
this.realization = new MotorControlRealization(
pidController,
stateEstimator,
hardwareRegisters,
interruptHandler,
timer
);
// Initialize Adaptation
this.adapter = new UARTMotorControlAdapter(realization, uartPort);
// Create Contract
this.contract = MotorControlContract.create();
}
@Override
public void initialize() {
realization.initializeHardware();
adapter.initializeUART();
}
@Override
public void start() {
realization.startControlLoop();
adapter.startListening();
}
@Override
public void stop() {
adapter.stopListening();
realization.stopControlLoop();
}
@Override
public void cleanup() {
adapter.closeUART();
realization.releaseHardware();
}
@Override
public void injectDependency(Class<?> contractType, Object implementation) {
realization.injectDependency(contractType, implementation);
}
@Override
public Object getContractImplementation(Class<?> contractType) {
if (contractType == MotorControlService.class) {
return adapter;
}
return null;
}
}
/**
* Deployment Bundle: Simulated Motor Control
* Combines Essence + Simulation Realization + REST Adaptation
* Used for development, testing, and cloud-based simulation
*/
public class SimulatedMotorControlBundle implements CapabilityInstance {
private final PIDController pidController; // Essence (same as embedded!)
private final MotorStateEstimator stateEstimator; // Essence (same as embedded!)
private final SimulatedMotorControlRealization realization; // Realization (Simulation)
private final RESTMotorControlAdapter adapter; // Adaptation (REST)
private final MotorControlContract contract;
public SimulatedMotorControlBundle(
MotorSimulator simulator,
int restPort
) {
// Initialize Essence (IDENTICAL to embedded version)
this.pidController = new PIDController(1.0, 0.1, 0.05, 100.0);
this.stateEstimator = new MotorStateEstimator();
// Initialize Simulation Realization
this.realization = new SimulatedMotorControlRealization(
pidController,
stateEstimator,
simulator
);
// Initialize REST Adaptation
this.adapter = new RESTMotorControlAdapter(realization, restPort);
// Create Contract (IDENTICAL to embedded version)
this.contract = MotorControlContract.create();
}
// Lifecycle methods similar to embedded bundle...
}
Capability Descriptor for Deployment
/**
* Capability Descriptor
* Metadata that describes a capability for deployment
*/
public class CapabilityDescriptor {
private final String capabilityId;
private final String capabilityName;
private final String version;
private final Class<? extends CapabilityInstance> implementationClass;
private final CapabilityContract contract;
private final EvolutionEnvelope evolutionEnvelope;
private final Map<String, String> deploymentParameters;
public CapabilityDescriptor(
String capabilityId,
String capabilityName,
String version,
Class<? extends CapabilityInstance> implementationClass,
CapabilityContract contract,
EvolutionEnvelope evolutionEnvelope,
Map<String, String> deploymentParameters
) {
this.capabilityId = capabilityId;
this.capabilityName = capabilityName;
this.version = version;
this.implementationClass = implementationClass;
this.contract = contract;
this.evolutionEnvelope = evolutionEnvelope;
this.deploymentParameters = deploymentParameters;
}
// Getters...
public String getCapabilityId() { return capabilityId; }
public String getCapabilityName() { return capabilityName; }
public String getVersion() { return version; }
public Class<? extends CapabilityInstance> getImplementationClass() {
return implementationClass;
}
public CapabilityContract getContract() { return contract; }
public EvolutionEnvelope getEvolutionEnvelope() { return evolutionEnvelope; }
public Map<String, String> getDeploymentParameters() {
return deploymentParameters;
}
}
/**
* Deployment Descriptor Factory
* Creates descriptors for different deployment contexts
*/
public class MotorControlDescriptorFactory {
public static CapabilityDescriptor createEmbeddedDescriptor() {
return new CapabilityDescriptor(
"motor-control-embedded-001",
"Motor Control Capability",
"2.1.0",
EmbeddedMotorControlBundle.class,
MotorControlContract.create(),
MotorControlEvolutionEnvelope.create(),
Map.of(
"deployment.type", "embedded",
"hardware.platform", "STM32F4",
"rtos.type", "FreeRTOS",
"communication.protocol", "UART"
)
);
}
public static CapabilityDescriptor createSimulationDescriptor() {
return new CapabilityDescriptor(
"motor-control-simulation-001",
"Motor Control Capability (Simulation)",
"2.1.0",
SimulatedMotorControlBundle.class,
MotorControlContract.create(),
MotorControlEvolutionEnvelope.create(),
Map.of(
"deployment.type", "simulation",
"simulation.timestep", "0.001",
"communication.protocol", "REST",
"rest.port", "8080"
)
);
}
}
Packaging Best Practices
1. Essence Independence: The Essence package must have ZERO infrastructure dependencies. Only test dependencies are allowed.
2. Realization Variants: Create separate Realization packages for each platform (embedded, cloud, simulation). They all depend on the same Essence.
3. Adaptation Flexibility: Create separate Adaptation packages for each communication protocol. This allows runtime protocol selection.
4. Contract Stability: Package contracts separately. They should be the most stable artifacts with the slowest change rate.
5. Bundle Optimization: Create pre-assembled bundles for common deployment scenarios to simplify configuration.
6. Version Alignment: All packages for a capability should share the same version number to avoid confusion.
STEP SEVEN: IMPLEMENT LIFECYCLE MANAGEMENT
The CapabilityLifecycleManager orchestrates the entire lifecycle of all capabilities in the system. It handles initialization, dependency injection, startup, shutdown, and cleanup in the correct order based on dependency relationships.
Capability Lifecycle States
┌──────────────────────────────────────────────────────────────┐
│ CAPABILITY LIFECYCLE STATES │
└──────────────────────────────────────────────────────────────┘
┌─────────────┐
│ CREATED │ Object instantiated, no configuration
└──────┬──────┘
│ initialize()
▼
┌─────────────┐
│ INITIALIZED │ Internal setup complete, awaiting dependencies
└──────┬──────┘
│ injectDependency() for each requirement
▼
┌─────────────┐
│ DEPENDENCIES│ All dependencies injected, ready to start
│ INJECTED │
└──────┬──────┘
│ start()
▼
┌─────────────┐
│ STARTED │ Fully operational, processing requests
│ (RUNNING) │
└──────┬──────┘
│ stop()
▼
┌─────────────┐
│ STOPPED │ Operations ceased, resources still held
└──────┬──────┘
│ cleanup()
▼
┌─────────────┐
│ CLEANED UP │ All resources released, ready for disposal
│ (DISPOSED) │
└─────────────┘
CapabilityInstance Interface
/**
* CapabilityInstance Interface
* All capabilities must implement this interface for lifecycle management
*/
public interface CapabilityInstance {
/**
* Initialize the capability's internal state.
* Called after instantiation, before dependency injection.
*
* Actions:
* - Load internal configuration
* - Prepare internal data structures
* - Allocate internal resources (not dependent on other capabilities)
*
* DO NOT:
* - Start active processing
* - Access other capabilities (dependencies not yet injected)
* - Open external connections
*/
void initialize();
/**
* Start the capability's active operations.
* Called after all dependencies have been injected.
*
* Actions:
* - Start threads
* - Open network connections
* - Activate event listeners
* - Begin data processing
* - Start hardware control
*
* After this method, the capability is fully operational.
*/
void start();
/**
* Stop the capability's active operations gracefully.
* Called during system shutdown or when capability needs to pause.
*
* Actions:
* - Stop processing new requests
* - Complete in-flight operations
* - Pause threads (don't terminate)
* - Close active connections
*
* Resources are retained for potential restart.
*/
void stop();
/**
* Release all resources and prepare for disposal.
* Called after stop(), in reverse topological order.
*
* Actions:
* - Release hardware resources
* - Close file handles
* - Disconnect from external services
* - Clear internal state
* - Terminate threads
*
* After this method, the capability cannot be restarted without re-initialization.
*/
void cleanup();
/**
* Provide an implementation for a contract that this capability offers.
* Called by CapabilityLifecycleManager to resolve dependencies.
*
* @param contractType The contract interface being requested
* @return Implementation of the contract, or null if not provided
*/
Object getContractImplementation(Class<?> contractType);
/**
* Inject a dependency (contract implementation) into this capability.
* Called by CapabilityLifecycleManager during dependency resolution.
*
* @param contractType The contract interface being injected
* @param implementation The implementation to inject
*/
void injectDependency(Class<?> contractType, Object implementation);
}
Capability Registry
/**
* Capability Registry
* Central registry for all capabilities and their contracts
*/
public class CapabilityRegistry {
private final Map<String, CapabilityDescriptor> descriptors;
private final Map<String, CapabilityInstance> instances;
private final Map<Class<?>, String> provisionToCapabilityMap;
private final DirectedGraph<String> dependencyGraph;
public CapabilityRegistry() {
this.descriptors = new ConcurrentHashMap<>();
this.instances = new ConcurrentHashMap<>();
this.provisionToCapabilityMap = new ConcurrentHashMap<>();
this.dependencyGraph = new DirectedGraph<>();
}
/**
* Register a capability descriptor
*/
public void registerCapability(CapabilityDescriptor descriptor) {
String capabilityId = descriptor.getCapabilityId();
// Store descriptor
descriptors.put(capabilityId, descriptor);
// Register provisions
for (Provision provision : descriptor.getContract().getProvisions()) {
provisionToCapabilityMap.put(
provision.interfaceType(),
capabilityId
);
}
// Add to dependency graph
dependencyGraph.addNode(capabilityId);
System.out.println("Registered capability: " + descriptor.getCapabilityName() +
" (ID: " + capabilityId + ", Version: " + descriptor.getVersion() + ")");
}
/**
* Register a capability instance
*/
public void registerInstance(String capabilityId, CapabilityInstance instance) {
instances.put(capabilityId, instance);
}
/**
* Build dependency graph from registered capabilities
*/
public void buildDependencyGraph() {
for (CapabilityDescriptor descriptor : descriptors.values()) {
String capabilityId = descriptor.getCapabilityId();
// For each requirement, add edge to provider
for (Requirement requirement : descriptor.getContract().getRequirements()) {
String providerId = provisionToCapabilityMap.get(requirement.interfaceType());
if (providerId == null && !requirement.optional()) {
throw new DependencyResolutionException(
"Required contract not provided: " + requirement.name() +
" (required by " + descriptor.getCapabilityName() + ")"
);
}
if (providerId != null) {
// Add edge: capabilityId depends on providerId
dependencyGraph.addEdge(providerId, capabilityId);
}
}
}
// Detect circular dependencies
if (dependencyGraph.hasCycle()) {
List<String> cycle = dependencyGraph.findCycle();
throw new CircularDependencyException(
"Circular dependency detected: " + String.join(" -> ", cycle)
);
}
}
/**
* Get topological sort order for initialization
*/
public List<String> getInitializationOrder() {
return dependencyGraph.topologicalSort();
}
/**
* Get capability instance by ID
*/
public CapabilityInstance getInstance(String capabilityId) {
return instances.get(capabilityId);
}
/**
* Get capability descriptor by ID
*/
public CapabilityDescriptor getDescriptor(String capabilityId) {
return descriptors.get(capabilityId);
}
/**
* Find capability that provides a specific contract
*/
public String findProvider(Class<?> contractType) {
return provisionToCapabilityMap.get(contractType);
}
/**
* Get all registered capability IDs
*/
public Set<String> getAllCapabilityIds() {
return descriptors.keySet();
}
}
Capability Lifecycle Manager
/**
* Capability Lifecycle Manager
* Orchestrates the complete lifecycle of all capabilities
*/
public class CapabilityLifecycleManager {
private final CapabilityRegistry registry;
private final CapabilityFactory factory;
private final Map<String, LifecycleState> stateMap;
public CapabilityLifecycleManager(
CapabilityRegistry registry,
CapabilityFactory factory
) {
this.registry = registry;
this.factory = factory;
this.stateMap = new ConcurrentHashMap<>();
}
/**
* Initialize all capabilities in topological order
*/
public void initializeAll() {
System.out.println("\n=== INITIALIZING CAPABILITIES ===\n");
// Build dependency graph
registry.buildDependencyGraph();
// Get initialization order
List<String> initOrder = registry.getInitializationOrder();
System.out.println("Initialization order: " +
String.join(" -> ", initOrder) + "\n");
// Initialize each capability
for (String capabilityId : initOrder) {
initializeCapability(capabilityId);
}
System.out.println("\n=== ALL CAPABILITIES INITIALIZED ===\n");
}
/**
* Initialize a single capability
*/
private void initializeCapability(String capabilityId) {
CapabilityDescriptor descriptor = registry.getDescriptor(capabilityId);
System.out.println("Initializing: " + descriptor.getCapabilityName());
try {
// 1. Instantiate capability using factory
CapabilityInstance instance = factory.createInstance(descriptor);
registry.registerInstance(capabilityId, instance);
stateMap.put(capabilityId, LifecycleState.CREATED);
// 2. Call initialize()
instance.initialize();
stateMap.put(capabilityId, LifecycleState.INITIALIZED);
System.out.println(" ✓ Initialized successfully");
} catch (Exception e) {
System.err.println(" ✗ Initialization failed: " + e.getMessage());
throw new CapabilityInitializationException(
"Failed to initialize " + descriptor.getCapabilityName(), e
);
}
}
/**
* Inject dependencies for all capabilities
*/
public void injectDependencies() {
System.out.println("\n=== INJECTING DEPENDENCIES ===\n");
List<String> initOrder = registry.getInitializationOrder();
for (String capabilityId : initOrder) {
injectDependenciesForCapability(capabilityId);
}
System.out.println("\n=== ALL DEPENDENCIES INJECTED ===\n");
}
/**
* Inject dependencies for a single capability
*/
private void injectDependenciesForCapability(String capabilityId) {
CapabilityDescriptor descriptor = registry.getDescriptor(capabilityId);
CapabilityInstance instance = registry.getInstance(capabilityId);
System.out.println("Injecting dependencies for: " +
descriptor.getCapabilityName());
for (Requirement requirement : descriptor.getContract().getRequirements()) {
String providerId = registry.findProvider(requirement.interfaceType());
if (providerId == null) {
if (requirement.optional()) {
System.out.println(" ⊘ Optional dependency not available: " +
requirement.name());
continue;
} else {
throw new DependencyResolutionException(
"Required dependency not found: " + requirement.name()
);
}
}
CapabilityInstance provider = registry.getInstance(providerId);
Object implementation = provider.getContractImplementation(
requirement.interfaceType()
);
if (implementation == null) {
throw new DependencyResolutionException(
"Provider does not implement required contract: " +
requirement.name()
);
}
instance.injectDependency(requirement.interfaceType(), implementation);
System.out.println(" ✓ Injected: " + requirement.name() +
" (from " + registry.getDescriptor(providerId).getCapabilityName() + ")");
}
stateMap.put(capabilityId, LifecycleState.DEPENDENCIES_INJECTED);
}
/**
* Start all capabilities in topological order
*/
public void startAll() {
System.out.println("\n=== STARTING CAPABILITIES ===\n");
List<String> initOrder = registry.getInitializationOrder();
for (String capabilityId : initOrder) {
startCapability(capabilityId);
}
System.out.println("\n=== ALL CAPABILITIES STARTED ===\n");
}
/**
* Start a single capability
*/
private void startCapability(String capabilityId) {
CapabilityDescriptor descriptor = registry.getDescriptor(capabilityId);
CapabilityInstance instance = registry.getInstance(capabilityId);
System.out.println("Starting: " + descriptor.getCapabilityName());
try {
instance.start();
stateMap.put(capabilityId, LifecycleState.STARTED);
System.out.println(" ✓ Started successfully");
} catch (Exception e) {
System.err.println(" ✗ Start failed: " + e.getMessage());
throw new CapabilityStartException(
"Failed to start " + descriptor.getCapabilityName(), e
);
}
}
/**
* Stop all capabilities in REVERSE topological order
*/
public void stopAll() {
System.out.println("\n=== STOPPING CAPABILITIES ===\n");
List<String> initOrder = registry.getInitializationOrder();
List<String> shutdownOrder = new ArrayList<>(initOrder);
Collections.reverse(shutdownOrder);
System.out.println("Shutdown order: " +
String.join(" -> ", shutdownOrder) + "\n");
for (String capabilityId : shutdownOrder) {
stopCapability(capabilityId);
}
System.out.println("\n=== ALL CAPABILITIES STOPPED ===\n");
}
/**
* Stop a single capability
*/
private void stopCapability(String capabilityId) {
CapabilityDescriptor descriptor = registry.getDescriptor(capabilityId);
CapabilityInstance instance = registry.getInstance(capabilityId);
System.out.println("Stopping: " + descriptor.getCapabilityName());
try {
instance.stop();
stateMap.put(capabilityId, LifecycleState.STOPPED);
System.out.println(" ✓ Stopped successfully");
} catch (Exception e) {
System.err.println(" ✗ Stop failed: " + e.getMessage());
// Continue stopping other capabilities even if one fails
}
}
/**
* Cleanup all capabilities in REVERSE topological order
*/
public void cleanupAll() {
System.out.println("\n=== CLEANING UP CAPABILITIES ===\n");
List<String> initOrder = registry.getInitializationOrder();
List<String> cleanupOrder = new ArrayList<>(initOrder);
Collections.reverse(cleanupOrder);
for (String capabilityId : cleanupOrder) {
cleanupCapability(capabilityId);
}
System.out.println("\n=== ALL CAPABILITIES CLEANED UP ===\n");
}
/**
* Cleanup a single capability
*/
private void cleanupCapability(String capabilityId) {
CapabilityDescriptor descriptor = registry.getDescriptor(capabilityId);
CapabilityInstance instance = registry.getInstance(capabilityId);
System.out.println("Cleaning up: " + descriptor.getCapabilityName());
try {
instance.cleanup();
stateMap.put(capabilityId, LifecycleState.CLEANED_UP);
System.out.println(" ✓ Cleaned up successfully");
} catch (Exception e) {
System.err.println(" ✗ Cleanup failed: " + e.getMessage());
// Continue cleanup even if one fails
}
}
/**
* Get current lifecycle state of a capability
*/
public LifecycleState getState(String capabilityId) {
return stateMap.getOrDefault(capabilityId, LifecycleState.NOT_CREATED);
}
/**
* Complete lifecycle: initialize -> inject -> start
*/
public void startSystem() {
initializeAll();
injectDependencies();
startAll();
}
/**
* Complete shutdown: stop -> cleanup
*/
public void shutdownSystem() {
stopAll();
cleanupAll();
}
}
/**
* Lifecycle states enumeration
*/
enum LifecycleState {
NOT_CREATED,
CREATED,
INITIALIZED,
DEPENDENCIES_INJECTED,
STARTED,
STOPPED,
CLEANED_UP
}
Capability Factory
/**
* Capability Factory
* Creates capability instances based on descriptors
*/
public class CapabilityFactory {
private final Map<String, Object> constructorParameters;
public CapabilityFactory() {
this.constructorParameters = new HashMap<>();
}
/**
* Register constructor parameters for specific capability types
*/
public void registerParameters(String capabilityType, Object... params) {
constructorParameters.put(capabilityType, params);
}
/**
* Create capability instance from descriptor
*/
public CapabilityInstance createInstance(CapabilityDescriptor descriptor) {
try {
Class<? extends CapabilityInstance> implClass =
descriptor.getImplementationClass();
// Get deployment parameters
Map<String, String> deployParams = descriptor.getDeploymentParameters();
String deploymentType = deployParams.get("deployment.type");
// Get constructor parameters for this deployment type
Object params = constructorParameters.get(deploymentType);
if (params == null) {
// Try no-arg constructor
return implClass.getDeclaredConstructor().newInstance();
} else {
// Use reflection to find matching constructor
// In production, use dependency injection framework (Spring, Guice, etc.)
return createWithParameters(implClass, (Object[]) params);
}
} catch (Exception e) {
throw new CapabilityInstantiationException(
"Failed to create instance of " + descriptor.getCapabilityName(), e
);
}
}
private CapabilityInstance createWithParameters(
Class<? extends CapabilityInstance> clazz,
Object[] params
) throws Exception {
// Find constructor matching parameter types
Class<?>[] paramTypes = new Class<?>[params.length];
for (int i = 0; i < params.length; i++) {
paramTypes[i] = params[i].getClass();
}
Constructor<? extends CapabilityInstance> constructor =
clazz.getDeclaredConstructor(paramTypes);
return constructor.newInstance(params);
}
}
Lifecycle Management Example Usage
/**
* Example: Complete system lifecycle management
*/
public class MotorControlSystemMain {
public static void main(String[] args) {
// Create registry and factory
CapabilityRegistry registry = new CapabilityRegistry();
CapabilityFactory factory = new CapabilityFactory();
// Register hardware dependencies for embedded deployment
HardwareRegisters hwRegisters = new HardwareRegisters();
InterruptHandler intHandler = new InterruptHandler();
RTOSTimer timer = new RTOSTimer();
UARTPort uart = new UARTPort(0);
factory.registerParameters("embedded",
hwRegisters, intHandler, timer, uart);
// Register capabilities
registry.registerCapability(
SensorManagementDescriptorFactory.createEmbeddedDescriptor()
);
registry.registerCapability(
ActuatorManagementDescriptorFactory.createEmbeddedDescriptor()
);
registry.registerCapability(
DiagnosticLoggingDescriptorFactory.createEmbeddedDescriptor()
);
registry.registerCapability(
MotorControlDescriptorFactory.createEmbeddedDescriptor()
);
// Create lifecycle manager
CapabilityLifecycleManager lifecycleManager =
new CapabilityLifecycleManager(registry, factory);
// Start system
try {
lifecycleManager.startSystem();
System.out.println("\n✓ Motor Control System is RUNNING\n");
// Run for some time...
Thread.sleep(60000); // 60 seconds
} catch (Exception e) {
System.err.println("System error: " + e.getMessage());
e.printStackTrace();
} finally {
// Shutdown system gracefully
lifecycleManager.shutdownSystem();
System.out.println("\n✓ Motor Control System SHUTDOWN COMPLETE\n");
}
}
}
The Lifecycle Manager ensures that capabilities are initialized, started, stopped, and cleaned up in the correct order, preventing initialization bugs and resource leaks. This orchestration is critical for complex systems with many interdependent capabilities.
STEP EIGHT: REGISTER CAPABILITIES AND RESOLVE DEPENDENCIES
With the lifecycle management infrastructure in place, the next step is registering all capabilities and resolving their dependencies. This process builds the dependency graph, performs topological sorting, and ensures all requirements are satisfied.
Dependency Graph Visualization
Motor Control System Dependency Graph:
┌─────────────────────────────────────────────────────────────────┐
│ │
│ ┌──────────────────┐ │
│ │ Diagnostic │ (No dependencies) │
│ │ Logging │ │
│ └────────┬─────────┘ │
│ │ │
│ │ provides DiagnosticService │
│ │ │
│ ├─────────────────┐ │
│ │ │ │
│ ▼ ▼ │
│ ┌──────────────────┐ ┌──────────────────┐ │
│ │ Sensor │ │ Actuator │ │
│ │ Management │ │ Management │ │
│ └────────┬─────────┘ └────────┬─────────┘ │
│ │ │ │
│ │ provides │ provides │
│ │ SensorService │ ActuatorService │
│ │ │ │
│ └──────────┬──────────┘ │
│ │ │
│ ▼ │
│ ┌──────────────────┐ │
│ │ Motor Control │ │
│ │ │ │
│ └──────────────────┘ │
│ │
│ Initialization Order (Topological Sort): │
│ 1. Diagnostic Logging │
│ 2. Sensor Management │
│ 3. Actuator Management │
│ 4. Motor Control │
│ │
│ Shutdown Order (Reverse): │
│ 1. Motor Control │
│ 2. Actuator Management │
│ 3. Sensor Management │
│ 4. Diagnostic Logging │
│ │
└─────────────────────────────────────────────────────────────────┘
Directed Graph Implementation
/**
* Directed Graph for dependency management
* Supports topological sort and cycle detection
*/
public class DirectedGraph<T> {
private final Map<T, Set<T>> adjacencyList; // node -> outgoing edges
private final Map<T, Set<T>> reverseList; // node -> incoming edges
public DirectedGraph() {
this.adjacencyList = new HashMap<>();
this.reverseList = new HashMap<>();
}
/**
* Add a node to the graph
*/
public void addNode(T node) {
adjacencyList.putIfAbsent(node, new HashSet<>());
reverseList.putIfAbsent(node, new HashSet<>());
}
/**
* Add an edge from 'from' to 'to'
* Meaning: 'to' depends on 'from'
*/
public void addEdge(T from, T to) {
addNode(from);
addNode(to);
adjacencyList.get(from).add(to);
reverseList.get(to).add(from);
}
/**
* Perform topological sort using Kahn's algorithm
* Returns nodes in dependency order (providers before consumers)
*/
public List<T> topologicalSort() {
// Calculate in-degrees
Map<T, Integer> inDegree = new HashMap<>();
for (T node : adjacencyList.keySet()) {
inDegree.put(node, reverseList.get(node).size());
}
// Queue of nodes with no dependencies
Queue<T> queue = new LinkedList<>();
for (Map.Entry<T, Integer> entry : inDegree.entrySet()) {
if (entry.getValue() == 0) {
queue.offer(entry.getKey());
}
}
List<T> result = new ArrayList<>();
while (!queue.isEmpty()) {
T node = queue.poll();
result.add(node);
// Reduce in-degree for dependent nodes
for (T dependent : adjacencyList.get(node)) {
int newInDegree = inDegree.get(dependent) - 1;
inDegree.put(dependent, newInDegree);
if (newInDegree == 0) {
queue.offer(dependent);
}
}
}
// If result doesn't contain all nodes, there's a cycle
if (result.size() != adjacencyList.size()) {
throw new IllegalStateException("Graph contains a cycle");
}
return result;
}
/**
* Detect if graph has a cycle using DFS
*/
public boolean hasCycle() {
Set<T> visited = new HashSet<>();
Set<T> recursionStack = new HashSet<>();
for (T node : adjacencyList.keySet()) {
if (hasCycleUtil(node, visited, recursionStack)) {
return true;
}
}
return false;
}
private boolean hasCycleUtil(T node, Set<T> visited, Set<T> recursionStack) {
if (recursionStack.contains(node)) {
return true; // Cycle detected
}
if (visited.contains(node)) {
return false; // Already processed
}
visited.add(node);
recursionStack.add(node);
for (T neighbor : adjacencyList.get(node)) {
if (hasCycleUtil(neighbor, visited, recursionStack)) {
return true;
}
}
recursionStack.remove(node);
return false;
}
/**
* Find a cycle in the graph (for error reporting)
*/
public List<T> findCycle() {
Set<T> visited = new HashSet<>();
Set<T> recursionStack = new HashSet<>();
List<T> path = new ArrayList<>();
for (T node : adjacencyList.keySet()) {
if (findCycleUtil(node, visited, recursionStack, path)) {
// Extract cycle from path
int cycleStart = path.indexOf(path.get(path.size() - 1));
return path.subList(cycleStart, path.size());
}
}
return Collections.emptyList();
}
private boolean findCycleUtil(
T node,
Set<T> visited,
Set<T> recursionStack,
List<T> path
) {
if (recursionStack.contains(node)) {
path.add(node); // Complete the cycle
return true;
}
if (visited.contains(node)) {
return false;
}
visited.add(node);
recursionStack.add(node);
path.add(node);
for (T neighbor : adjacencyList.get(node)) {
if (findCycleUtil(neighbor, visited, recursionStack, path)) {
return true;
}
}
recursionStack.remove(node);
path.remove(path.size() - 1);
return false;
}
/**
* Get all nodes
*/
public Set<T> getNodes() {
return adjacencyList.keySet();
}
/**
* Get dependencies of a node (incoming edges)
*/
public Set<T> getDependencies(T node) {
return reverseList.getOrDefault(node, Collections.emptySet());
}
/**
* Get dependents of a node (outgoing edges)
*/
public Set<T> getDependents(T node) {
return adjacencyList.getOrDefault(node, Collections.emptySet());
}
}
Dependency Resolution Example
/**
* Example: Complete dependency resolution process
*/
public class DependencyResolutionExample {
public static void main(String[] args) {
CapabilityRegistry registry = new CapabilityRegistry();
// Register all capabilities
System.out.println("=== REGISTERING CAPABILITIES ===\n");
registry.registerCapability(
new CapabilityDescriptor(
"diagnostic-logging-001",
"Diagnostic Logging",
"1.0.0",
DiagnosticLoggingCapability.class,
DiagnosticLoggingContract.create(),
DiagnosticLoggingEvolutionEnvelope.create(),
Map.of("deployment.type", "embedded")
)
);
registry.registerCapability(
new CapabilityDescriptor(
"sensor-management-001",
"Sensor Management",
"1.5.0",
SensorManagementCapability.class,
SensorManagementContract.create(),
SensorManagementEvolutionEnvelope.create(),
Map.of("deployment.type", "embedded")
)
);
registry.registerCapability(
new CapabilityDescriptor(
"actuator-management-001",
"Actuator Management",
"1.3.0",
ActuatorManagementCapability.class,
ActuatorManagementContract.create(),
ActuatorManagementEvolutionEnvelope.create(),
Map.of("deployment.type", "embedded")
)
);
registry.registerCapability(
new CapabilityDescriptor(
"motor-control-001",
"Motor Control",
"2.1.0",
MotorControlCapability.class,
MotorControlContract.create(),
MotorControlEvolutionEnvelope.create(),
Map.of("deployment.type", "embedded")
)
);
// Build dependency graph
System.out.println("\n=== BUILDING DEPENDENCY GRAPH ===\n");
try {
registry.buildDependencyGraph();
System.out.println("✓ Dependency graph built successfully");
System.out.println("✓ No circular dependencies detected");
} catch (CircularDependencyException e) {
System.err.println("✗ Circular dependency detected!");
System.err.println(" " + e.getMessage());
return;
} catch (DependencyResolutionException e) {
System.err.println("✗ Missing dependency!");
System.err.println(" " + e.getMessage());
return;
}
// Get initialization order
List<String> initOrder = registry.getInitializationOrder();
System.out.println("\n=== INITIALIZATION ORDER ===\n");
for (int i = 0; i < initOrder.size(); i++) {
String capId = initOrder.get(i);
CapabilityDescriptor desc = registry.getDescriptor(capId);
System.out.println((i + 1) + ". " + desc.getCapabilityName() +
" (v" + desc.getVersion() + ")");
}
// Display dependency details
System.out.println("\n=== DEPENDENCY DETAILS ===\n");
for (String capId : initOrder) {
CapabilityDescriptor desc = registry.getDescriptor(capId);
System.out.println(desc.getCapabilityName() + ":");
List<Requirement> requirements = desc.getContract().getRequirements();
if (requirements.isEmpty()) {
System.out.println(" No dependencies");
} else {
for (Requirement req : requirements) {
String providerId = registry.findProvider(req.interfaceType());
if (providerId != null) {
CapabilityDescriptor provider = registry.getDescriptor(providerId);
System.out.println(" → " + req.name() +
" (provided by " + provider.getCapabilityName() + ")");
} else {
System.out.println(" → " + req.name() +
" (OPTIONAL - not available)");
}
}
}
System.out.println();
}
}
}
Expected Output
=== REGISTERING CAPABILITIES ===
Registered capability: Diagnostic Logging (ID: diagnostic-logging-001, Version: 1.0.0)
Registered capability: Sensor Management (ID: sensor-management-001, Version: 1.5.0)
Registered capability: Actuator Management (ID: actuator-management-001, Version: 1.3.0)
Registered capability: Motor Control (ID: motor-control-001, Version: 2.1.0)
=== BUILDING DEPENDENCY GRAPH ===
✓ Dependency graph built successfully
✓ No circular dependencies detected
=== INITIALIZATION ORDER ===
1. Diagnostic Logging (v1.0.0)
2. Sensor Management (v1.5.0)
3. Actuator Management (v1.3.0)
4. Motor Control (v2.1.0)
=== DEPENDENCY DETAILS ===
Diagnostic Logging:
No dependencies
Sensor Management:
→ DiagnosticService (OPTIONAL - provided by Diagnostic Logging)
Actuator Management:
→ DiagnosticService (OPTIONAL - provided by Diagnostic Logging)
Motor Control:
→ SensorService (provided by Sensor Management)
→ ActuatorService (provided by Actuator Management)
→ DiagnosticService (OPTIONAL - provided by Diagnostic Logging)
This dependency resolution process ensures that all capabilities are initialized in the correct order, with all required dependencies available before each capability starts.
STEP NINE: IMPLEMENT TESTING STRATEGY
Testing in CCA follows a layered approach that mirrors the capability structure. Each layer has distinct testing requirements and strategies. The separation of concerns inherent in CCA makes comprehensive testing significantly easier than in monolithic architectures.
Testing Pyramid for CCA
┌─────────────────────────────────────────────────────────────────┐
│ CCA TESTING PYRAMID │
└─────────────────────────────────────────────────────────────────┘
▲
╱ ╲
╱ ╲
╱ ╲
╱ ╲
╱ E2E ╲ Small number
╱ System ╲ Complete system tests
╱ Tests ╲ All capabilities integrated
╱_______________╲
╱ ╲
╱ ╲
╱ Integration ╲ Medium number
╱ Contract Tests ╲ Test capability interactions
╱ Realization Tests ╲ Test infrastructure integration
╱___________________________╲
╱ ╲
╱ ╲
╱ Unit Tests ╲ Large number
╱ Essence Layer ╲ Fast, isolated
╱ Pure Logic Tests ╲ No dependencies
╱______________________________________ ╲
Unit Tests: Essence Layer
The Essence layer contains pure domain logic with no infrastructure dependencies, making it perfectly suited for comprehensive unit testing.
/**
* Unit Tests for PID Controller (Essence Layer)
* These tests are fast, isolated, and require no infrastructure
*/
public class PIDControllerTest {
private PIDController controller;
@BeforeEach
void setUp() {
// Create controller with known gains
controller = new PIDController(
1.0, // kp
0.1, // ki
0.05, // kd
100.0 // integral limit
);
}
@Test
@DisplayName("Proportional term should be zero when at target")
void testProportionalTermAtTarget() {
double current = 100.0;
double target = 100.0;
double deltaTime = 0.001; // 1ms
double output = controller.calculate(current, target, deltaTime);
// At target, with no history, output should be zero
assertEquals(0.0, output, 0.001);
}
@Test
@DisplayName("Proportional term should increase with error")
void testProportionalTermWithError() {
double current = 90.0;
double target = 100.0;
double deltaTime = 0.001;
double output = controller.calculate(current, target, deltaTime);
// Error = 10, kp = 1.0, so proportional term = 10
// (Plus small integral and derivative contributions)
assertTrue(output > 9.0 && output < 11.0);
}
@Test
@DisplayName("Integral term should accumulate over time")
void testIntegralAccumulation() {
double current = 90.0;
double target = 100.0;
double deltaTime = 0.001;
// First calculation
double output1 = controller.calculate(current, target, deltaTime);
// Second calculation with same error
double output2 = controller.calculate(current, target, deltaTime);
// Output should increase due to integral accumulation
assertTrue(output2 > output1);
}
@Test
@DisplayName("Integral term should respect anti-windup limit")
void testIntegralAntiWindup() {
double current = 0.0;
double target = 1000.0; // Large error
double deltaTime = 0.1; // Large time step
// Run many iterations to saturate integral
for (int i = 0; i < 1000; i++) {
controller.calculate(current, target, deltaTime);
}
// Get final output
double output = controller.calculate(current, target, deltaTime);
// Output should be limited (not infinite)
assertTrue(output < 2000.0); // Reasonable upper bound
}
@Test
@DisplayName("Derivative term should respond to rate of change")
void testDerivativeTerm() {
double deltaTime = 0.001;
// First call: error = 10
controller.calculate(90.0, 100.0, deltaTime);
// Second call: error = 20 (error increasing)
double output = controller.calculate(80.0, 100.0, deltaTime);
// Derivative term should contribute to output
// kd = 0.05, error change = 10, deltaTime = 0.001
// Derivative contribution ≈ 0.05 * (10 / 0.001) = 500
assertTrue(output > 500.0);
}
@Test
@DisplayName("Reset should clear all state")
void testReset() {
// Build up some state
for (int i = 0; i < 10; i++) {
controller.calculate(90.0, 100.0, 0.001);
}
// Reset
controller.reset();
// Output should be same as fresh controller
double output = controller.calculate(90.0, 100.0, 0.001);
PIDController freshController = new PIDController(1.0, 0.1, 0.05, 100.0);
double freshOutput = freshController.calculate(90.0, 100.0, 0.001);
assertEquals(freshOutput, output, 0.001);
}
@Test
@DisplayName("Gain updates should take effect immediately")
void testGainUpdate() {
double current = 90.0;
double target = 100.0;
double deltaTime = 0.001;
double output1 = controller.calculate(current, target, deltaTime);
// Increase proportional gain
controller.setGains(2.0, 0.1, 0.05);
// Reset to clear integral/derivative history
controller.reset();
double output2 = controller.calculate(current, target, deltaTime);
// With doubled kp, proportional term should double
assertTrue(output2 > output1 * 1.5);
}
@Test
@DisplayName("Controller should handle negative errors correctly")
void testNegativeError() {
double current = 110.0;
double target = 100.0;
double deltaTime = 0.001;
double output = controller.calculate(current, target, deltaTime);
// Error is negative, output should be negative
assertTrue(output < 0.0);
}
@Test
@DisplayName("Controller should be stable for typical control scenarios")
void testStabilityConvergence() {
double current = 0.0;
double target = 100.0;
double deltaTime = 0.001;
// Simulate control loop with simple plant model
for (int i = 0; i < 1000; i++) {
double output = controller.calculate(current, target, deltaTime);
// Simple plant: current moves toward output
current += output * 0.01 * deltaTime;
}
// Should converge close to target
assertEquals(target, current, 5.0);
}
}
/**
* Unit Tests for Motor State Estimator (Essence Layer)
*/
public class MotorStateEstimatorTest {
private MotorStateEstimator estimator;
@BeforeEach
void setUp() {
estimator = new MotorStateEstimator();
}
@Test
@DisplayName("Should estimate speed from position change")
void testSpeedEstimation() {
int position1 = 0;
int position2 = 1000;
double deltaTime = 0.001; // 1ms
double speed = estimator.estimateSpeed(position2, deltaTime);
// Speed = position change / time = 1000 / 0.001 = 1,000,000
// But filtered, so may be lower initially
assertTrue(speed > 0);
}
@Test
@DisplayName("Should apply moving average filter")
void testMovingAverageFilter() {
double deltaTime = 0.001;
// Feed constant speed
for (int i = 0; i < 10; i++) {
estimator.estimateSpeed(i * 1000, deltaTime);
}
// After filter stabilizes, should output constant speed
double speed = estimator.estimateSpeed(10000, deltaTime);
assertEquals(1000.0 / deltaTime, speed, 100.0);
}
@Test
@DisplayName("Should smooth noisy measurements")
void testNoiseFiltering() {
double deltaTime = 0.001;
Random random = new Random(42); // Fixed seed for reproducibility
double[] rawSpeeds = new double[100];
double[] filteredSpeeds = new double[100];
for (int i = 0; i < 100; i++) {
// Simulate noisy encoder readings
int position = i * 1000 + random.nextInt(100) - 50;
filteredSpeeds[i] = estimator.estimateSpeed(position, deltaTime);
rawSpeeds[i] = position / deltaTime;
}
// Calculate variance of raw vs filtered
double rawVariance = calculateVariance(rawSpeeds);
double filteredVariance = calculateVariance(filteredSpeeds);
// Filtered should have lower variance
assertTrue(filteredVariance < rawVariance);
}
@Test
@DisplayName("Reset should clear filter history")
void testReset() {
double deltaTime = 0.001;
// Build up filter history
for (int i = 0; i < 10; i++) {
estimator.estimateSpeed(i * 1000, deltaTime);
}
estimator.reset();
// After reset, should behave like new estimator
double speed = estimator.estimateSpeed(1000, deltaTime);
MotorStateEstimator freshEstimator = new MotorStateEstimator();
double freshSpeed = freshEstimator.estimateSpeed(1000, deltaTime);
assertEquals(freshSpeed, speed, 0.001);
}
private double calculateVariance(double[] values) {
double mean = Arrays.stream(values).average().orElse(0.0);
return Arrays.stream(values)
.map(v -> Math.pow(v - mean, 2))
.average()
.orElse(0.0);
}
}
Integration Tests: Realization Layer
Integration tests verify that the Realization layer correctly integrates Essence logic with infrastructure.
/**
* Integration Tests for Motor Control Realization
* Tests infrastructure integration with mocked hardware
*/
public class MotorControlRealizationIntegrationTest {
private MotorControlRealization realization;
private MockHardwareRegisters mockHardware;
private MockInterruptHandler mockInterrupts;
private MockRTOSTimer mockTimer;
private MockSensorService mockSensorService;
private MockActuatorService mockActuatorService;
@BeforeEach
void setUp() {
mockHardware = new MockHardwareRegisters();
mockInterrupts = new MockInterruptHandler();
mockTimer = new MockRTOSTimer();
realization = new MotorControlRealization(
mockHardware,
mockInterrupts,
mockTimer
);
mockSensorService = new MockSensorService();
mockActuatorService = new MockActuatorService();
realization.injectSensorService(mockSensorService);
realization.injectActuatorService(mockActuatorService);
}
@Test
@DisplayName("Hardware initialization should configure registers correctly")
void testHardwareInitialization() {
realization.initializeHardware();
// Verify encoder configuration
assertTrue(mockHardware.isEncoderConfigured());
assertEquals(EncoderMode.QUADRATURE, mockHardware.getEncoderMode());
// Verify interrupt registration
assertTrue(mockInterrupts.isRegistered(InterruptSource.TIMER_OVERFLOW));
assertEquals(InterruptPriority.HIGHEST,
mockInterrupts.getPriority(InterruptSource.TIMER_OVERFLOW));
// Verify timer configuration
assertTrue(mockTimer.isConfigured());
assertEquals(1000, mockTimer.getFrequency()); // 1kHz
}
@Test
@DisplayName("Control loop should read sensors and write actuators")
void testControlLoopExecution() {
realization.initializeHardware();
realization.setTargetSpeed(1000.0);
realization.startControlLoop();
// Set up mock sensor reading
mockSensorService.setEncoderPosition(new EncoderReading(5000, 0, 0));
// Trigger control loop interrupt
mockInterrupts.triggerInterrupt(InterruptSource.TIMER_OVERFLOW);
// Verify actuator was commanded
assertTrue(mockActuatorService.wasPWMSet());
// Verify PWM value is reasonable
double pwmValue = mockActuatorService.getLastPWMDutyCycle();
assertTrue(pwmValue >= -100.0 && pwmValue <= 100.0);
}
@Test
@DisplayName("Control loop should handle sensor failures gracefully")
void testSensorFailureHandling() {
realization.initializeHardware();
realization.startControlLoop();
// Configure sensor to throw exception
mockSensorService.setShouldFail(true);
// Trigger control loop
mockInterrupts.triggerInterrupt(InterruptSource.TIMER_OVERFLOW);
// Verify actuator was disabled (safe state)
assertTrue(mockActuatorService.wasOutputDisabled());
}
@Test
@DisplayName("Emergency stop should immediately disable output")
void testEmergencyStop() {
realization.initializeHardware();
realization.startControlLoop();
// Trigger emergency stop
realization.emergencyStop();
// Verify actuator output disabled
assertTrue(mockActuatorService.wasOutputDisabled());
// Verify control loop stops commanding actuator
mockInterrupts.triggerInterrupt(InterruptSource.TIMER_OVERFLOW);
// PWM should remain at safe value
assertEquals(0.0, mockActuatorService.getLastPWMDutyCycle(), 0.001);
}
@Test
@DisplayName("Configuration update should modify PID gains")
void testConfigurationUpdate() {
realization.initializeHardware();
String configJson = """
{
"pidController": {
"kp": 2.0,
"ki": 0.2,
"kd": 0.1
}
}
""";
realization.updateConfiguration(configJson);
// Verify gains were updated (would need getter or observable behavior)
// In real test, verify through control loop behavior change
assertDoesNotThrow(() -> realization.updateConfiguration(configJson));
}
@Test
@DisplayName("Control loop timing should meet real-time requirements")
void testControlLoopTiming() {
realization.initializeHardware();
realization.setTargetSpeed(1000.0);
realization.startControlLoop();
mockSensorService.setEncoderPosition(new EncoderReading(5000, 0, 0));
long startTime = System.nanoTime();
mockInterrupts.triggerInterrupt(InterruptSource.TIMER_OVERFLOW);
long endTime = System.nanoTime();
long executionTime = endTime - startTime;
// Control loop should execute in less than 100 microseconds
assertTrue(executionTime < 100_000,
"Control loop took " + executionTime + " ns");
}
}
Contract Tests
Contract tests verify that capabilities correctly implement their declared contracts and that contract interactions work as specified.
/**
* Contract Tests for Motor Control Service
* Verifies that the capability correctly implements its Provision
*/
public class MotorControlServiceContractTest {
private MotorControlService service;
private MotorControlCapability capability;
@BeforeEach
void setUp() {
// Create capability with test doubles
capability = createTestCapability();
// Get contract implementation
service = (MotorControlService) capability.getContractImplementation(
MotorControlService.class
);
assertNotNull(service, "Capability must provide MotorControlService");
}
@Test
@DisplayName("Contract: setTargetSpeed should accept valid speeds")
void testSetTargetSpeedContract() {
// Contract specifies speed in RPM, range 0-10000
assertDoesNotThrow(() -> service.setTargetSpeed(0.0));
assertDoesNotThrow(() -> service.setTargetSpeed(5000.0));
assertDoesNotThrow(() -> service.setTargetSpeed(10000.0));
}
@Test
@DisplayName("Contract: setTargetSpeed should reject invalid speeds")
void testSetTargetSpeedValidation() {
// Negative speeds not allowed per contract
assertThrows(IllegalArgumentException.class,
() -> service.setTargetSpeed(-100.0));
// Speeds above maximum not allowed
assertThrows(IllegalArgumentException.class,
() -> service.setTargetSpeed(15000.0));
}
@Test
@DisplayName("Contract: getCurrentStatus should return valid status")
void testGetCurrentStatusContract() {
MotorStatus status = service.getCurrentStatus();
assertNotNull(status, "Status must not be null");
assertNotNull(status.state(), "State must not be null");
assertTrue(status.timestamp() > 0, "Timestamp must be positive");
assertTrue(status.currentSpeed() >= 0, "Speed must be non-negative");
}
@Test
@DisplayName("Contract: emergencyStop should be idempotent")
void testEmergencyStopIdempotency() {
// Multiple calls should not cause errors
assertDoesNotThrow(() -> {
service.emergencyStop();
service.emergencyStop();
service.emergencyStop();
});
// State should be EMERGENCY_STOP
assertEquals(MotorState.EMERGENCY_STOP,
service.getCurrentStatus().state());
}
@Test
@DisplayName("Contract: Protocol timing requirements")
void testProtocolTimingRequirements() {
// Protocol specifies max 10us latency for status query
long startTime = System.nanoTime();
service.getCurrentStatus();
long endTime = System.nanoTime();
long latency = endTime - startTime;
assertTrue(latency < 10_000,
"Status query exceeded protocol latency: " + latency + " ns");
}
@Test
@DisplayName("Contract: Thread safety requirements")
void testThreadSafety() throws InterruptedException {
// Contract specifies thread-safe operations
int threadCount = 10;
CountDownLatch latch = new CountDownLatch(threadCount);
AtomicInteger errorCount = new AtomicInteger(0);
for (int i = 0; i < threadCount; i++) {
final double speed = i * 100.0;
new Thread(() -> {
try {
service.setTargetSpeed(speed);
service.getCurrentStatus();
} catch (Exception e) {
errorCount.incrementAndGet();
} finally {
latch.countDown();
}
}).start();
}
latch.await(5, TimeUnit.SECONDS);
assertEquals(0, errorCount.get(), "Thread safety violations detected");
}
private MotorControlCapability createTestCapability() {
// Create with mock dependencies
MockHardwareRegisters hw = new MockHardwareRegisters();
MockInterruptHandler interrupts = new MockInterruptHandler();
MockRTOSTimer timer = new MockRTOSTimer();
MotorControlCapability cap = new MotorControlCapability(hw, interrupts, timer);
// Inject dependencies
cap.injectDependency(SensorService.class, new MockSensorService());
cap.injectDependency(ActuatorService.class, new MockActuatorService());
// Initialize
cap.initialize();
cap.start();
return cap;
}
}
/**
* Contract Compatibility Tests
* Verifies that capabilities with dependencies can interact correctly
*/
public class CapabilityContractCompatibilityTest {
@Test
@DisplayName("Motor Control should successfully consume Sensor Service")
void testMotorControlSensorServiceCompatibility() {
// Create sensor capability
SensorManagementCapability sensorCap = createSensorCapability();
sensorCap.initialize();
sensorCap.start();
// Get sensor service contract
SensorService sensorService = (SensorService)
sensorCap.getContractImplementation(SensorService.class);
// Create motor control capability
MotorControlCapability motorCap = createMotorControlCapability();
// Inject sensor service
motorCap.injectDependency(SensorService.class, sensorService);
// Initialize and start
assertDoesNotThrow(() -> {
motorCap.initialize();
motorCap.start();
});
// Verify motor control can use sensor service
MotorControlService motorService = (MotorControlService)
motorCap.getContractImplementation(MotorControlService.class);
motorService.setTargetSpeed(1000.0);
MotorStatus status = motorService.getCurrentStatus();
assertNotNull(status);
}
@Test
@DisplayName("Contract version compatibility check")
void testContractVersionCompatibility() {
// Get evolution envelopes
EvolutionEnvelope motorEnvelope = MotorControlEvolutionEnvelope.create();
EvolutionEnvelope sensorEnvelope = SensorManagementEvolutionEnvelope.create();
// Verify no breaking changes between versions
assertFalse(motorEnvelope.getVersionInfo().isBreakingChangeFrom("2.0.0"));
// Verify active deprecations are documented
List<String> warnings = motorEnvelope.getActiveDeprecationWarnings();
assertNotNull(warnings);
}
private SensorManagementCapability createSensorCapability() {
// Implementation details...
return new SensorManagementCapability(/* mock dependencies */);
}
private MotorControlCapability createMotorControlCapability() {
// Implementation details...
return new MotorControlCapability(/* mock dependencies */);
}
}
End-to-End System Tests
/**
* End-to-End System Tests
* Tests complete system with all capabilities integrated
*/
public class MotorControlSystemE2ETest {
private CapabilityRegistry registry;
private CapabilityLifecycleManager lifecycleManager;
private CapabilityFactory factory;
@BeforeEach
void setUp() {
registry = new CapabilityRegistry();
factory = new CapabilityFactory();
lifecycleManager = new CapabilityLifecycleManager(registry, factory);
// Register all capabilities
registerAllCapabilities();
}
@Test
@DisplayName("Complete system startup and shutdown")
void testSystemLifecycle() {
assertDoesNotThrow(() -> {
// Start system
lifecycleManager.startSystem();
// Verify all capabilities are running
for (String capId : registry.getAllCapabilityIds()) {
assertEquals(LifecycleState.STARTED,
lifecycleManager.getState(capId));
}
// Shutdown system
lifecycleManager.shutdownSystem();
// Verify all capabilities are cleaned up
for (String capId : registry.getAllCapabilityIds()) {
assertEquals(LifecycleState.CLEANED_UP,
lifecycleManager.getState(capId));
}
});
}
@Test
@DisplayName("Motor control with real sensor and actuator integration")
void testMotorControlIntegration() {
lifecycleManager.startSystem();
// Get motor control service
CapabilityInstance motorCap = registry.getInstance("motor-control-001");
MotorControlService motorService = (MotorControlService)
motorCap.getContractImplementation(MotorControlService.class);
// Set target speed
motorService.setTargetSpeed(1000.0);
// Wait for control loop to stabilize
try {
Thread.sleep(100);
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
// Check status
MotorStatus status = motorService.getCurrentStatus();
assertEquals(MotorState.RUNNING, status.state());
// Speed should be approaching target
assertTrue(status.currentSpeed() > 0);
lifecycleManager.shutdownSystem();
}
@Test
@DisplayName("Emergency stop propagates through system")
void testEmergencyStopPropagation() {
lifecycleManager.startSystem();
CapabilityInstance motorCap = registry.getInstance("motor-control-001");
MotorControlService motorService = (MotorControlService)
motorCap.getContractImplementation(MotorControlService.class);
CapabilityInstance actuatorCap = registry.getInstance("actuator-management-001");
ActuatorService actuatorService = (ActuatorService)
actuatorCap.getContractImplementation(ActuatorService.class);
// Start motor
motorService.setTargetSpeed(1000.0);
// Trigger emergency stop
motorService.emergencyStop();
// Verify motor state
assertEquals(MotorState.EMERGENCY_STOP,
motorService.getCurrentStatus().state());
// Verify actuator disabled
ActuatorStatus actuatorStatus = actuatorService.getStatus();
assertFalse(actuatorStatus.outputEnabled());
lifecycleManager.shutdownSystem();
}
@Test
@DisplayName("Diagnostic logging captures events from all capabilities")
void testDiagnosticLoggingIntegration() {
lifecycleManager.startSystem();
CapabilityInstance diagnosticCap = registry.getInstance("diagnostic-logging-001");
DiagnosticService diagnosticService = (DiagnosticService)
diagnosticCap.getContractImplementation(DiagnosticService.class);
// Perform operations that generate log events
CapabilityInstance motorCap = registry.getInstance("motor-control-001");
MotorControlService motorService = (MotorControlService)
motorCap.getContractImplementation(MotorControlService.class);
motorService.setTargetSpeed(1000.0);
motorService.emergencyStop();
// Query logs (if diagnostic service supports querying)
// Verify events were logged
lifecycleManager.shutdownSystem();
}
private void registerAllCapabilities() {
// Register with mock hardware for testing
MockHardwareRegisters hw = new MockHardwareRegisters();
MockInterruptHandler interrupts = new MockInterruptHandler();
MockRTOSTimer timer = new MockRTOSTimer();
factory.registerParameters("embedded", hw, interrupts, timer);
registry.registerCapability(
DiagnosticLoggingDescriptorFactory.createEmbeddedDescriptor()
);
registry.registerCapability(
SensorManagementDescriptorFactory.createEmbeddedDescriptor()
);
registry.registerCapability(
ActuatorManagementDescriptorFactory.createEmbeddedDescriptor()
);
registry.registerCapability(
MotorControlDescriptorFactory.createEmbeddedDescriptor()
);
}
}
Test Coverage Summary
┌─────────────────────────────────────────────────────────────────┐
│ TEST COVERAGE MATRIX │
├─────────────────────────────────────────────────────────────────┤
│ │
│ Layer │ Test Type │ Coverage │ Speed │ Count │
│ ───────────────────────────────────────────────────────────── │
│ Essence │ Unit Tests │ 95%+ │ Fast │ 50+ │
│ Realization │ Integration │ 80%+ │ Medium│ 20+ │
│ Adaptation │ Contract Tests │ 90%+ │ Medium│ 15+ │
│ System │ E2E Tests │ 70%+ │ Slow │ 5-10 │
│ │
└─────────────────────────────────────────────────────────────────┘
Testing Best Practices
1. Test Essence Thoroughly: The Essence layer should have the highest test coverage (95%+) because it's pure logic and easy to test.
2. Mock Infrastructure: Use test doubles for hardware, databases, and external services in Realization tests.
3. Verify Contracts: Contract tests ensure capabilities fulfill their promises and maintain compatibility.
4. Minimal E2E Tests: End-to-end tests are slow and brittle. Use them sparingly for critical paths only.
5. Test Lifecycle: Verify that capabilities handle initialization, startup, shutdown, and cleanup correctly.
6. Performance Testing: For real-time systems, include timing tests to verify latency requirements.
7. Failure Testing: Test error handling, fault recovery, and graceful degradation.
STEP TEN: DEPLOY AND MONITOR
The final step is deploying the capability-based system and implementing monitoring to ensure it operates correctly in production.
Deployment Configurations
/**
* Deployment Configuration for different environments
*/
public class DeploymentConfiguration {
/**
* Embedded deployment configuration
* For STM32 microcontroller with FreeRTOS
*/
public static SystemConfiguration createEmbeddedConfig() {
return SystemConfiguration.builder()
.environment("embedded")
.platform("STM32F4")
.rtos("FreeRTOS")
.capabilities(List.of(
CapabilityDeployment.builder()
.descriptor(DiagnosticLoggingDescriptorFactory.createEmbeddedDescriptor())
.priority(Priority.LOW)
.stackSize(2048)
.build(),
CapabilityDeployment.builder()
.descriptor(SensorManagementDescriptorFactory.createEmbeddedDescriptor())
.priority(Priority.HIGH)
.stackSize(4096)
.build(),
CapabilityDeployment.builder()
.descriptor(ActuatorManagementDescriptorFactory.createEmbeddedDescriptor())
.priority(Priority.CRITICAL)
.stackSize(4096)
.build(),
CapabilityDeployment.builder()
.descriptor(MotorControlDescriptorFactory.createEmbeddedDescriptor())
.priority(Priority.CRITICAL)
.stackSize(8192)
.build()
))
.monitoring(MonitoringConfiguration.builder()
.enablePerformanceMetrics(true)
.enableHealthChecks(true)
.metricsInterval(Duration.ofSeconds(1))
.build())
.build();
}
/**
* Simulation deployment configuration
* For development and testing on desktop/cloud
*/
public static SystemConfiguration createSimulationConfig() {
return SystemConfiguration.builder()
.environment("simulation")
.platform("JVM")
.capabilities(List.of(
CapabilityDeployment.builder()
.descriptor(DiagnosticLoggingDescriptorFactory.createSimulationDescriptor())
.build(),
CapabilityDeployment.builder()
.descriptor(SensorManagementDescriptorFactory.createSimulationDescriptor())
.build(),
CapabilityDeployment.builder()
.descriptor(ActuatorManagementDescriptorFactory.createSimulationDescriptor())
.build(),
CapabilityDeployment.builder()
.descriptor(MotorControlDescriptorFactory.createSimulationDescriptor())
.build()
))
.monitoring(MonitoringConfiguration.builder()
.enablePerformanceMetrics(true)
.enableHealthChecks(true)
.enableDetailedLogging(true)
.metricsInterval(Duration.ofMillis(100))
.build())
.build();
}
/**
* Hybrid deployment configuration
* Motor control on embedded, monitoring on cloud
*/
public static SystemConfiguration createHybridConfig() {
return SystemConfiguration.builder()
.environment("hybrid")
.capabilities(List.of(
// Embedded capabilities
CapabilityDeployment.builder()
.descriptor(SensorManagementDescriptorFactory.createEmbeddedDescriptor())
.deploymentTarget("edge-device-001")
.build(),
CapabilityDeployment.builder()
.descriptor(ActuatorManagementDescriptorFactory.createEmbeddedDescriptor())
.deploymentTarget("edge-device-001")
.build(),
CapabilityDeployment.builder()
.descriptor(MotorControlDescriptorFactory.createEmbeddedDescriptor())
.deploymentTarget("edge-device-001")
.build(),
// Cloud capabilities
CapabilityDeployment.builder()
.descriptor(DiagnosticLoggingDescriptorFactory.createCloudDescriptor())
.deploymentTarget("cloud-region-eu-west")
.build()
))
.build();
}
}
Monitoring and Diagnostics
/**
* Capability Health Monitor
* Monitors health and performance of all capabilities
*/
public class CapabilityHealthMonitor {
private final CapabilityRegistry registry;
private final Map<String, HealthMetrics> metricsMap;
private final ScheduledExecutorService scheduler;
public CapabilityHealthMonitor(CapabilityRegistry registry) {
this.registry = registry;
this.metricsMap = new ConcurrentHashMap<>();
this.scheduler = Executors.newScheduledThreadPool(1);
}
/**
* Start monitoring all capabilities
*/
public void startMonitoring(Duration interval) {
scheduler.scheduleAtFixedRate(
this::collectMetrics,
0,
interval.toMillis(),
TimeUnit.MILLISECONDS
);
}
/**
* Collect health metrics from all capabilities
*/
private void collectMetrics() {
for (String capabilityId : registry.getAllCapabilityIds()) {
try {
HealthMetrics metrics = collectCapabilityMetrics(capabilityId);
metricsMap.put(capabilityId, metrics);
// Check for health issues
if (!metrics.isHealthy()) {
handleUnhealthyCapability(capabilityId, metrics);
}
} catch (Exception e) {
System.err.println("Failed to collect metrics for " + capabilityId +
": " + e.getMessage());
}
}
}
/**
* Collect metrics for a single capability
*/
private HealthMetrics collectCapabilityMetrics(String capabilityId) {
CapabilityInstance instance = registry.getInstance(capabilityId);
CapabilityDescriptor descriptor = registry.getDescriptor(capabilityId);
// Collect various metrics
long memoryUsage = getMemoryUsage(instance);
double cpuUsage = getCPUUsage(instance);
long uptime = getUptime(instance);
int errorCount = getErrorCount(instance);
double responseTime = getAverageResponseTime(instance);
return new HealthMetrics(
capabilityId,
descriptor.getCapabilityName(),
System.currentTimeMillis(),
memoryUsage,
cpuUsage,
uptime,
errorCount,
responseTime
);
}
/**
* Handle unhealthy capability
*/
private void handleUnhealthyCapability(String capabilityId, HealthMetrics metrics) {
CapabilityDescriptor descriptor = registry.getDescriptor(capabilityId);
System.err.println("HEALTH WARNING: " + descriptor.getCapabilityName());
System.err.println(" Memory: " + metrics.memoryUsage() + " bytes");
System.err.println(" CPU: " + metrics.cpuUsage() + "%");
System.err.println(" Errors: " + metrics.errorCount());
System.err.println(" Response Time: " + metrics.responseTime() + " ms");
// Take corrective action
if (metrics.errorCount() > 100) {
System.err.println(" ACTION: Restarting capability due to high error count");
restartCapability(capabilityId);
}
if (metrics.memoryUsage() > 10_000_000) { // 10MB
System.err.println(" ACTION: Memory usage critical");
// Trigger garbage collection or resource cleanup
}
}
/**
* Restart a capability
*/
private void restartCapability(String capabilityId) {
try {
CapabilityInstance instance = registry.getInstance(capabilityId);
System.out.println("Restarting capability: " + capabilityId);
instance.stop();
Thread.sleep(100);
instance.start();
System.out.println("Capability restarted successfully");
} catch (Exception e) {
System.err.println("Failed to restart capability: " + e.getMessage());
}
}
/**
* Get current health status for all capabilities
*/
public Map<String, HealthMetrics> getCurrentHealth() {
return new HashMap<>(metricsMap);
}
/**
* Generate health report
*/
public String generateHealthReport() {
StringBuilder report = new StringBuilder();
report.append("\n=== CAPABILITY HEALTH REPORT ===\n\n");
for (HealthMetrics metrics : metricsMap.values()) {
report.append(String.format("%-30s %s\n",
metrics.capabilityName(),
metrics.isHealthy() ? "✓ HEALTHY" : "✗ UNHEALTHY"
));
report.append(String.format(" Memory: %d KB\n",
metrics.memoryUsage() / 1024));
report.append(String.format(" CPU: %.1f%%\n",
metrics.cpuUsage()));
report.append(String.format(" Uptime: %d seconds\n",
metrics.uptime() / 1000));
report.append(String.format(" Errors: %d\n",
metrics.errorCount()));
report.append(String.format(" Avg Response Time: %.2f ms\n\n",
metrics.responseTime()));
}
return report.toString();
}
public void stopMonitoring() {
scheduler.shutdown();
}
// Helper methods (simplified - would use actual instrumentation)
private long getMemoryUsage(CapabilityInstance instance) {
return Runtime.getRuntime().totalMemory() - Runtime.getRuntime().freeMemory();
}
private double getCPUUsage(CapabilityInstance instance) {
return Math.random() * 100; // Placeholder
}
private long getUptime(CapabilityInstance instance) {
return System.currentTimeMillis(); // Simplified
}
private int getErrorCount(CapabilityInstance instance) {
return 0; // Would track actual errors
}
private double getAverageResponseTime(CapabilityInstance instance) {
return Math.random() * 10; // Placeholder
}
}
/**
* Health metrics for a capability
*/
record HealthMetrics(
String capabilityId,
String capabilityName,
long timestamp,
long memoryUsage,
double cpuUsage,
long uptime,
int errorCount,
double responseTime
) {
public boolean isHealthy() {
return errorCount < 10 &&
cpuUsage < 90.0 &&
responseTime < 100.0;
}
}
Performance Metrics Collection
/**
* Performance Metrics Collector
* Collects detailed performance metrics for analysis
*/
public class PerformanceMetricsCollector {
private final Map<String, MetricTimeSeries> metricsData;
private final int maxDataPoints;
public PerformanceMetricsCollector(int maxDataPoints) {
this.metricsData = new ConcurrentHashMap<>();
this.maxDataPoints = maxDataPoints;
}
/**
* Record a metric value
*/
public void recordMetric(String capabilityId, String metricName, double value) {
String key = capabilityId + ":" + metricName;
metricsData.computeIfAbsent(key, k -> new MetricTimeSeries(maxDataPoints))
.addDataPoint(System.currentTimeMillis(), value);
}
/**
* Get metric statistics
*/
public MetricStatistics getStatistics(String capabilityId, String metricName) {
String key = capabilityId + ":" + metricName;
MetricTimeSeries series = metricsData.get(key);
if (series == null) {
return MetricStatistics.empty();
}
return series.calculateStatistics();
}
/**
* Export metrics to JSON for external monitoring tools
*/
public String exportMetricsJSON() {
JSONObject json = new JSONObject();
for (Map.Entry<String, MetricTimeSeries> entry : metricsData.entrySet()) {
String[] parts = entry.getKey().split(":");
String capabilityId = parts[0];
String metricName = parts[1];
if (!json.has(capabilityId)) {
json.put(capabilityId, new JSONObject());
}
JSONObject capMetrics = json.getJSONObject(capabilityId);
MetricStatistics stats = entry.getValue().calculateStatistics();
JSONObject metricData = new JSONObject();
metricData.put("mean", stats.mean());
metricData.put("min", stats.min());
metricData.put("max", stats.max());
metricData.put("stdDev", stats.standardDeviation());
metricData.put("p50", stats.percentile(50));
metricData.put("p95", stats.percentile(95));
metricData.put("p99", stats.percentile(99));
capMetrics.put(metricName, metricData);
}
return json.toString(2);
}
}
/**
* Time series data for a metric
*/
class MetricTimeSeries {
private final CircularBuffer<DataPoint> dataPoints;
public MetricTimeSeries(int maxSize) {
this.dataPoints = new CircularBuffer<>(maxSize);
}
public void addDataPoint(long timestamp, double value) {
dataPoints.add(new DataPoint(timestamp, value));
}
public MetricStatistics calculateStatistics() {
List<Double> values = dataPoints.stream()
.map(DataPoint::value)
.toList();
if (values.isEmpty()) {
return MetricStatistics.empty();
}
double mean = values.stream().mapToDouble(Double::doubleValue).average().orElse(0.0);
double min = values.stream().mapToDouble(Double::doubleValue).min().orElse(0.0);
double max = values.stream().mapToDouble(Double::doubleValue).max().orElse(0.0);
double variance = values.stream()
.mapToDouble(v -> Math.pow(v - mean, 2))
.average()
.orElse(0.0);
double stdDev = Math.sqrt(variance);
List<Double> sorted = new ArrayList<>(values);
Collections.sort(sorted);
return new MetricStatistics(mean, min, max, stdDev, sorted);
}
}
record DataPoint(long timestamp, double value) {}
record MetricStatistics(
double mean,
double min,
double max,
double standardDeviation,
List<Double> sortedValues
) {
public static MetricStatistics empty() {
return new MetricStatistics(0, 0, 0, 0, List.of());
}
public double percentile(int p) {
if (sortedValues.isEmpty()) return 0.0;
int index = (int) Math.ceil((p / 100.0) * sortedValues.size()) - 1;
index = Math.max(0, Math.min(index, sortedValues.size() - 1));
return sortedValues.get(index);
}
}
Deployment Example
/**
* Complete deployment example with monitoring
*/
public class ProductionDeployment {
public static void main(String[] args) {
System.out.println("=== MOTOR CONTROL SYSTEM DEPLOYMENT ===\n");
// Load configuration
SystemConfiguration config = DeploymentConfiguration.createEmbeddedConfig();
// Create infrastructure
CapabilityRegistry registry = new CapabilityRegistry();
CapabilityFactory factory = new CapabilityFactory();
CapabilityLifecycleManager lifecycleManager =
new CapabilityLifecycleManager(registry, factory);
// Setup hardware
HardwareRegisters hwRegisters = HardwareRegisters.initialize();
InterruptHandler intHandler = InterruptHandler.initialize();
RTOSTimer timer = RTOSTimer.initialize();
factory.registerParameters("embedded", hwRegisters, intHandler, timer);
// Register capabilities
for (CapabilityDeployment deployment : config.capabilities()) {
registry.registerCapability(deployment.descriptor());
}
// Start monitoring
CapabilityHealthMonitor healthMonitor = new CapabilityHealthMonitor(registry);
PerformanceMetricsCollector metricsCollector =
new PerformanceMetricsCollector(1000);
healthMonitor.startMonitoring(Duration.ofSeconds(1));
// Start system
try {
lifecycleManager.startSystem();
System.out.println("\n✓ System started successfully\n");
System.out.println("Monitoring active. Press Ctrl+C to shutdown.\n");
// Setup shutdown hook
Runtime.getRuntime().addShutdownHook(new Thread(() -> {
System.out.println("\n\nShutdown signal received...");
healthMonitor.stopMonitoring();
lifecycleManager.shutdownSystem();
// Print final health report
System.out.println(healthMonitor.generateHealthReport());
// Export metrics
System.out.println("=== PERFORMANCE METRICS ===");
System.out.println(metricsCollector.exportMetricsJSON());
System.out.println("\n✓ Shutdown complete");
}));
// Main operation loop
while (true) {
Thread.sleep(10000); // 10 seconds
// Periodic health check
System.out.println(healthMonitor.generateHealthReport());
}
} catch (Exception e) {
System.err.println("System error: " + e.getMessage());
e.printStackTrace();
healthMonitor.stopMonitoring();
lifecycleManager.shutdownSystem();
}
}
}
COMPLETE EXAMPLE WALKTHROUGH
Let's walk through a complete example showing all capabilities working together in a realistic scenario.
Scenario: Motor Speed Control with Temperature Monitoring
/**
* Complete Motor Control System Example
* Demonstrates all capabilities working together
*/
public class CompleteMotorControlExample {
public static void main(String[] args) throws Exception {
System.out.println("=== COMPLETE MOTOR CONTROL SYSTEM EXAMPLE ===\n");
// ===== STEP 1: Setup Infrastructure =====
System.out.println("Step 1: Setting up infrastructure...");
CapabilityRegistry registry = new CapabilityRegistry();
CapabilityFactory factory = new CapabilityFactory();
CapabilityLifecycleManager lifecycleManager =
new CapabilityLifecycleManager(registry, factory);
// Create hardware interfaces (mocked for this example)
HardwareRegisters hwRegisters = new MockHardwareRegisters();
InterruptHandler intHandler = new MockInterruptHandler();
RTOSTimer timer = new MockRTOSTimer();
factory.registerParameters("embedded", hwRegisters, intHandler, timer);
System.out.println(" ✓ Infrastructure ready\n");
// ===== STEP 2: Register Capabilities =====
System.out.println("Step 2: Registering capabilities...");
registry.registerCapability(
DiagnosticLoggingDescriptorFactory.createEmbeddedDescriptor()
);
registry.registerCapability(
SensorManagementDescriptorFactory.createEmbeddedDescriptor()
);
registry.registerCapability(
ActuatorManagementDescriptorFactory.createEmbeddedDescriptor()
);
registry.registerCapability(
MotorControlDescriptorFactory.createEmbeddedDescriptor()
);
System.out.println(" ✓ All capabilities registered\n");
// ===== STEP 3: Start System =====
System.out.println("Step 3: Starting system...");
lifecycleManager.startSystem();
System.out.println(" ✓ System started\n");
// ===== STEP 4: Get Service References =====
System.out.println("Step 4: Obtaining service references...");
MotorControlService motorControl = (MotorControlService)
registry.getInstance("motor-control-001")
.getContractImplementation(MotorControlService.class);
SensorService sensors = (SensorService)
registry.getInstance("sensor-management-001")
.getContractImplementation(SensorService.class);
ActuatorService actuators = (ActuatorService)
registry.getInstance("actuator-management-001")
.getContractImplementation(ActuatorService.class);
DiagnosticService diagnostics = (DiagnosticService)
registry.getInstance("diagnostic-logging-001")
.getContractImplementation(DiagnosticService.class);
System.out.println(" ✓ Service references obtained\n");
// ===== STEP 5: Run Motor Control Scenario =====
System.out.println("Step 5: Running motor control scenario...\n");
// Scenario: Ramp up motor speed while monitoring temperature
diagnostics.logEvent("System", "Starting motor control scenario", Severity.INFO);
// Ramp up speed gradually
double[] targetSpeeds = {0, 500, 1000, 1500, 2000};
for (double targetSpeed : targetSpeeds) {
System.out.println(" Setting target speed: " + targetSpeed + " RPM");
motorControl.setTargetSpeed(targetSpeed);
// Wait for motor to stabilize
Thread.sleep(2000);
// Check status
MotorStatus status = motorControl.getCurrentStatus();
System.out.println(" Current speed: " + status.currentSpeed() + " RPM");
System.out.println(" State: " + status.state());
// Check temperature
TemperatureReading temp = sensors.getTemperature();
System.out.println(" Temperature: " + temp.temperatureCelsius() + "°C");
System.out.println(" Sensor quality: " + temp.quality());
// Check if overheating
if (temp.temperatureCelsius() > 80.0) {
System.out.println(" ⚠ WARNING: High temperature detected!");
diagnostics.logEvent("Temperature",
"High temperature: " + temp.temperatureCelsius() + "°C",
Severity.WARNING);
// Reduce speed
motorControl.setTargetSpeed(targetSpeed * 0.5);
System.out.println(" Reducing speed to " + (targetSpeed * 0.5) + " RPM");
}
// Log metrics
diagnostics.logMetric("motor.speed", status.currentSpeed());
diagnostics.logMetric("motor.temperature", temp.temperatureCelsius());
System.out.println();
}
// ===== STEP 6: Simulate Emergency Condition =====
System.out.println("Step 6: Simulating emergency condition...\n");
System.out.println(" ⚠ EMERGENCY: Triggering emergency stop");
motorControl.emergencyStop();
MotorStatus finalStatus = motorControl.getCurrentStatus();
System.out.println(" Motor state: " + finalStatus.state());
System.out.println(" Motor speed: " + finalStatus.currentSpeed() + " RPM");
ActuatorStatus actuatorStatus = actuators.getStatus();
System.out.println(" Actuator enabled: " + actuatorStatus.outputEnabled());
System.out.println(" Safety state: " + actuatorStatus.safetyState());
diagnostics.logEvent("Safety", "Emergency stop executed", Severity.CRITICAL);
System.out.println();
// ===== STEP 7: Shutdown System =====
System.out.println("Step 7: Shutting down system...");
lifecycleManager.shutdownSystem();
System.out.println(" ✓ System shutdown complete\n");
System.out.println("=== EXAMPLE COMPLETE ===");
}
}
Expected Output
=== COMPLETE MOTOR CONTROL SYSTEM EXAMPLE ===
Step 1: Setting up infrastructure...
✓ Infrastructure ready
Step 2: Registering capabilities...
Registered capability: Diagnostic Logging (ID: diagnostic-logging-001, Version: 1.0.0)
Registered capability: Sensor Management (ID: sensor-management-001, Version: 1.5.0)
Registered capability: Actuator Management (ID: actuator-management-001, Version: 1.3.0)
Registered capability: Motor Control (ID: motor-control-001, Version: 2.1.0)
✓ All capabilities registered
Step 3: Starting system...
=== INITIALIZING CAPABILITIES ===
Initialization order: diagnostic-logging-001 -> sensor-management-001 -> actuator-management-001 -> motor-control-001
Initializing: Diagnostic Logging
✓ Initialized successfully
Initializing: Sensor Management
✓ Initialized successfully
Initializing: Actuator Management
✓ Initialized successfully
Initializing: Motor Control
✓ Initialized successfully
=== ALL CAPABILITIES INITIALIZED ===
=== INJECTING DEPENDENCIES ===
Injecting dependencies for: Diagnostic Logging
Injecting dependencies for: Sensor Management
✓ Injected: DiagnosticService (from Diagnostic Logging)
Injecting dependencies for: Actuator Management
✓ Injected: DiagnosticService (from Diagnostic Logging)
Injecting dependencies for: Motor Control
✓ Injected: SensorService (from Sensor Management)
✓ Injected: ActuatorService (from Actuator Management)
✓ Injected: DiagnosticService (from Diagnostic Logging)
=== ALL DEPENDENCIES INJECTED ===
=== STARTING CAPABILITIES ===
Starting: Diagnostic Logging
✓ Started successfully
Starting: Sensor Management
✓ Started successfully
Starting: Actuator Management
✓ Started successfully
Starting: Motor Control
✓ Started successfully
=== ALL CAPABILITIES STARTED ===
✓ System started
Step 4: Obtaining service references...
✓ Service references obtained
Step 5: Running motor control scenario...
Setting target speed: 0.0 RPM
Current speed: 0.0 RPM
State: RUNNING
Temperature: 25.3°C
Sensor quality: GOOD
Setting target speed: 500.0 RPM
Current speed: 487.2 RPM
State: RUNNING
Temperature: 32.1°C
Sensor quality: GOOD
Setting target speed: 1000.0 RPM
Current speed: 982.5 RPM
State: RUNNING
Temperature: 45.7°C
Sensor quality: GOOD
Setting target speed: 1500.0 RPM
Current speed: 1476.3 RPM
State: RUNNING
Temperature: 63.2°C
Sensor quality: GOOD
Setting target speed: 2000.0 RPM
Current speed: 1965.8 RPM
State: RUNNING
Temperature: 82.4°C
⚠ WARNING: High temperature detected!
Reducing speed to 1000.0 RPM
Step 6: Simulating emergency condition...
⚠ EMERGENCY: Triggering emergency stop
Motor state: EMERGENCY_STOP
Motor speed: 0.0 RPM
Actuator enabled: false
Safety state: EMERGENCY_STOP
Step 7: Shutting down system...
=== STOPPING CAPABILITIES ===
Shutdown order: motor-control-001 -> actuator-management-001 -> sensor-management-001 -> diagnostic-logging-001
Stopping: Motor Control
✓ Stopped successfully
Stopping: Actuator Management
✓ Stopped successfully
Stopping: Sensor Management
✓ Stopped successfully
Stopping: Diagnostic Logging
✓ Stopped successfully
=== ALL CAPABILITIES STOPPED ===
=== CLEANING UP CAPABILITIES ===
Cleaning up: Motor Control
✓ Cleaned up successfully
Cleaning up: Actuator Management
✓ Cleaned up successfully
Cleaning up: Sensor Management
✓ Cleaned up successfully
Cleaning up: Diagnostic Logging
✓ Cleaned up successfully
=== ALL CAPABILITIES CLEANED UP ===
✓ System shutdown complete
=== EXAMPLE COMPLETE ===
BEST PRACTICES AND RECOMMENDATIONS
Design Guidelines
1. Capability Granularity
✓ DO: Create capabilities around business/functional cohesion
Example: "Motor Control" - single, clear purpose
✗ DON'T: Create capabilities based on technical layers
Example: "Database Access Capability" - too technical
✓ DO: Aim for capabilities that can be described in one sentence
Example: "Provides PID-based motor speed control"
✗ DON'T: Create capabilities with multiple unrelated responsibilities
Example: "Motor Control and User Authentication" - not cohesive
2. Contract Design
✓ DO: Design contracts for stability
- Use semantic versioning
- Add new methods, don't change existing ones
- Provide migration paths for breaking changes
✗ DON'T: Change contract signatures frequently
- Breaks all consumers
- Creates integration chaos
✓ DO: Make dependencies explicit in Requirements
- Clear what capability needs
- Enables automatic dependency resolution
✗ DON'T: Hide dependencies or use global state
- Prevents independent testing
- Creates hidden coupling
3. Essence Layer Purity
✓ DO: Keep Essence completely infrastructure-free
- Pure domain logic only
- No database, network, file I/O
- 100% unit testable
✗ DON'T: Mix infrastructure into Essence
- Reduces testability
- Prevents reuse across platforms
✓ DO: Make Essence the most stable layer
- Domain logic changes slowly
- Reusable across deployments
✗ DON'T: Couple Essence to specific technologies
- Locks you into tech stack
- Prevents evolution
4. Efficiency Gradient Application
✓ DO: Apply gradients deliberately
- Critical paths: high efficiency, low abstraction
- Non-critical paths: high abstraction, lower efficiency
✗ DON'T: Optimize everything equally
- Wastes development time
- Reduces maintainability where not needed
✓ DO: Measure before optimizing
- Profile to find actual bottlenecks
- Optimize only what matters
✗ DON'T: Premature optimization
- "Premature optimization is the root of all evil"
- Start with clarity, optimize when proven necessary
5. Evolution Management
✓ DO: Use Evolution Envelopes consistently
- Document all changes
- Provide migration paths
- Announce deprecations early
✗ DON'T: Make breaking changes without warning
- Breaks consumer trust
- Creates integration failures
✓ DO: Support multiple versions during transitions
- Gives consumers time to migrate
- Reduces deployment risk
✗ DON'T: Force immediate upgrades
- Creates pressure and errors
- Reduces adoption of new versions
Common Pitfalls to Avoid
1. Over-Engineering
Pitfall: Creating too many small capabilities
Problem: Excessive complexity, coordination overhead
Solution: Start with larger capabilities, split only when needed
2. Hidden Dependencies
Pitfall: Using global state or singletons
Problem: Prevents independent testing and deployment
Solution: Declare all dependencies explicitly in Requirements
3. Leaky Abstractions
Pitfall: Exposing infrastructure details in contracts
Problem: Couples consumers to implementation details
Solution: Contracts should be technology-agnostic
4. Ignoring Lifecycle
Pitfall: Not implementing lifecycle methods properly
Problem: Resource leaks, initialization failures
Solution: Follow lifecycle contract rigorously
5. Poor Testing Strategy
Pitfall: Only testing at system level
Problem: Slow tests, hard to diagnose failures
Solution: Follow testing pyramid - mostly unit tests
Performance Considerations
1. Memory Management
* Essence layer should minimize allocations in critical paths
* Realization layer should pool resources where appropriate
* Monitor memory usage per capability
2. Latency Optimization
* Use direct calls for low-latency requirements (< 10μs)
* Use async messaging for non-critical paths (> 1ms acceptable)
* Profile actual latency, don't assume
3. CPU Utilization
* Critical capabilities should have dedicated CPU cores (if available)
* Non-critical capabilities can share cores
* Use RTOS priorities appropriately
4. Scalability
* Design capabilities to be stateless where possible
* Use horizontal scaling for enterprise deployments
* Consider capability replication for high availability
Maintenance Strategies
1. Documentation
* Document contracts thoroughly
* Maintain up-to-date Evolution Envelopes
* Provide examples for each capability
2. Versioning
* Use semantic versioning consistently
* Tag releases in version control
* Maintain changelog for each capability
3. Monitoring
* Implement health checks for all capabilities
* Collect performance metrics
* Set up alerts for anomalies
4. Continuous Integration
* Automate testing at all levels
* Run contract compatibility tests
* Verify deployment configurations
CONCLUSION
Capability-Centric Architecture provides a unified, flexible, and evolvable approach to building software systems that span from embedded microcontrollers to cloud-native platforms. By organizing systems around Capabilities with clear Contracts, structured as Nuclei (Essence, Realization, Adaptation), and managed through explicit Evolution Envelopesand Efficiency Gradients, CCA addresses the fundamental challenges of modern software development:
Complexity Management: Capabilities provide clear boundaries and single responsibilities, making complex systems comprehensible and manageable.
Dependency Control: Explicit contracts and dependency injection eliminate hidden coupling and enable independent development and testing.
Technology Independence: The layered nucleus structure isolates domain logic from infrastructure, enabling technology evolution without business logic changes.
Performance Flexibility: Efficiency gradients allow different parts of the system to operate at appropriate abstraction levels, from bare-metal to high-level frameworks.
Predictable Evolution: Evolution Envelopes make change explicit and manageable, with clear migration paths and deprecation policies.
Unified Architecture: The same architectural principles apply from 8-bit microcontrollers to distributed cloud systems, reducing cognitive load and enabling knowledge transfer.
When to Use CCA
CCA is particularly valuable for:
* Mixed embedded/enterprise systems: When you need both real-time control and cloud connectivity
* Long-lived systems: When systems must evolve over years or decades
* Platform diversity: When deploying the same logic across multiple hardware platforms
* Team scalability: When multiple teams need to work independently on different capabilities
* Rapid evolution: When business requirements change frequently
Next Steps for Implementation
1. Start Small: Begin with one or two capabilities to learn the patterns
2. Focus on Contracts: Invest time in designing stable, clear contracts
3. Separate Essence: Ensure domain logic is truly infrastructure-free
4. Implement Lifecycle: Use CapabilityLifecycleManager from the start
5. Test Thoroughly: Follow the testing pyramid - mostly unit tests
6. Monitor Continuously: Implement health monitoring early
7. Iterate and Refine: CCA is a journey, not a destination
Final Thoughts
Capability-Centric Architecture represents a fundamental shift from technology-centric to capability-centric thinking. Instead of organizing systems around databases, frameworks, or deployment platforms, CCA organizes around the capabilities that deliver business value. This shift enables unprecedented flexibility, maintainability, and evolution while maintaining the performance and reliability required for mission-critical systems.
The motor control example in this guide demonstrates these principles in action, showing how a real-time embedded system can be built using CCA patterns. The same principles scale to enterprise systems, IoT platforms, and cloud-native applications, providing a truly unified architectural approach.
By following the ten steps outlined in this guide—from identifying capabilities to deploying and monitoring—you can build robust, evolvable systems that stand the test of time and changing requirements.
Thank you for reading this comprehensive guide to Capability-Centric Architecture. May your capabilities be cohesive, your contracts stable, and your systems evolvable!