ng scalability and resilience.
3. Matrix Computation Engine: A processing layer computes portfolio-level metrics. This engine generates the "Digital Asset Matrix," plotting assets across axes such as Cost vs. Reliability, or Value vs. Technical Debt.
4. Policy Enforcement Layer: Analytics drive actions. The system evaluates policies (e.g., "Decommission if cost > $500 and traffic < 10 req/min for 30 days") and triggers alerts or automated workflows.
Technical Implementation
The following TypeScript implementation demonstrates the core data models and the computation of a Portfolio Health Score and Matrix positioning.
1. Asset Domain Model
Define a strict schema for digital assets to ensure data consistency.
export interface DigitalAsset {
id: string;
name: string;
type: 'API' | 'MICROSERVICE' | 'FUNCTION' | 'DATABASE';
owner: string;
productLine: string;
lifecycleStage: 'DEV' | 'STAGING' | 'PROD' | 'DECOMMISSIONING';
metadata: Record<string, string>;
}
export interface AssetTelemetry {
assetId: string;
timestamp: Date;
metrics: {
latencyP99: number;
errorRate: number;
throughput: number;
costPerHour: number;
};
}
export interface DependencyEdge {
source: string;
target: string;
criticality: 'HIGH' | 'MEDIUM' | 'LOW';
}
2. Portfolio Analyzer Engine
This class aggregates telemetry and computes portfolio metrics, including a weighted health score and matrix coordinates.
export class PortfolioAnalyzer {
private registry: Map<string, DigitalAsset> = new Map();
private dependencies: DependencyEdge[] = [];
registerAsset(asset: DigitalAsset): void {
this.registry.set(asset.id, asset);
}
addDependency(edge: DependencyEdge): void {
this.dependencies.push(edge);
}
/**
* Computes the Portfolio Health Score (PHS).
* Weighted average based on throughput and criticality.
* Returns score 0-100.
*/
computePortfolioHealthScore(telemetry: AssetTelemetry[]): number {
if (telemetry.length === 0) return 100;
let weightedScore = 0;
let totalWeight = 0;
telemetry.forEach(t => {
const asset = this.registry.get(t.assetId);
if (!asset || asset.lifecycleStage === 'DECOMMISSIONING') return;
// Weight by throughput to prioritize high-traffic assets
const weight = t.metrics.throughput;
// Health calculation: penalize errors heavily, latency moderately
const errorPenalty = t.metrics.errorRate * 100; // 1% error = 100 penalty
const latencyPenalty = Math.max(0, (t.metrics.latencyP99 - 200) / 10); // Baseline 200ms
const assetHealth = Math.max(0, 100 - (errorPenalty + latencyPenalty));
weightedScore += assetHealth * weight;
totalWeight += weight;
});
return totalWeight > 0 ? weightedScore / totalWeight : 100;
}
/**
* Generates the Digital Asset Matrix.
* Returns assets plotted on Cost vs. Value/Reliability axes.
*/
generateAssetMatrix(telemetry: AssetTelemetry[]): AssetMatrixEntry[] {
return telemetry.map(t => {
const asset = this.registry.get(t.assetId);
if (!asset) throw new Error(`Asset ${t.assetId} not in registry`);
// Value proxy: Throughput normalized by cost efficiency
const costEfficiency = t.metrics.throughput / (t.metrics.costPerHour + 0.001);
// Reliability proxy: 1 - errorRate
const reliability = 1 - t.metrics.errorRate;
return {
assetId: t.assetId,
name: asset.name,
productLine: asset.productLine,
coordinates: {
x: t.metrics.costPerHour, // Cost axis
y: costEfficiency * reliability // Value/Reliability axis
},
quadrant: this.getQuadrant(t.metrics.costPerHour, costEfficiency * reliability)
};
});
}
private getQuadrant(cost: number, valueReliability: number): 'STAR' | 'CASH_COW' | 'QUESTION_MARK' | 'DOG' {
// Dynamic thresholds based on portfolio median could be used here
const medianCost = 5.0;
const medianValue = 1000;
if (cost > medianCost && valueReliability > medianValue) return 'STAR';
if (cost < medianCost && valueReliability > medianValue) return 'CASH_COW';
if (cost > medianCost && valueReliability < medianValue) return 'QUESTION_MARK';
return 'DOG';
}
}
export interface AssetMatrixEntry {
assetId: string;
name: string;
productLine: string;
coordinates: { x: number; y: number };
quadrant: 'STAR' | 'CASH_COW' | 'QUESTION_MARK' | 'DOG';
}
Rationale
The computePortfolioHealthScore uses throughput weighting to prevent low-traffic, perfectly healthy assets from skewing the score while critical, high-traffic assets degrade. The generateAssetMatrix implements a BCG-style matrix adapted for engineering, allowing teams to visualize the portfolio distribution. Assets in the "DOG" quadrant (high cost, low value/reliability) are immediate candidates for decommissioning. This logic integrates directly with CI/CD pipelines to enforce governance.
Pitfall Guide
Common Mistakes
-
Registry Drift: The asset registry becomes outdated as services evolve.
- Impact: Analytics engine analyzes non-existent assets or misses new ones.
- Mitigation: Integrate registry updates into the deployment pipeline. The analytics engine should validate telemetry against the registry and flag unknown assets as "Shadow IT."
-
Static Thresholds: Using fixed thresholds for health scores or cost alerts.
- Impact: False positives as traffic patterns change seasonally or with growth.
- Mitigation: Implement dynamic baselines using statistical modeling (e.g., moving averages, z-scores) to detect anomalies relative to historical behavior.
-
Ignoring Dependency Direction: Analyzing assets in isolation without dependency context.
- Impact: A "healthy" asset may be the root cause of failures in downstream consumers.
- Mitigation: Ingest dependency graphs from service mesh logs or API gateways. Propagate health scores upstream to calculate "Consumer Impact Score."
-
Cost Data Granularity Mismatch: Aggregating cost data at a level that doesn't match asset granularity.
- Impact: Inaccurate cost attribution leads to wrong decommissioning decisions.
- Mitigation: Use cloud provider tagging strategies to enforce cost allocation to specific asset IDs. Implement a cost-normalization layer to handle shared infrastructure costs.
-
Over-Engineering the Visualization: Building complex dashboards that no one reviews.
- Impact: Analytics become shelfware; decisions remain gut-based.
- Mitigation: Focus on actionable insights. Push alerts to Slack/Teams with direct links to remediation. Embed portfolio metrics in sprint planning tools.
-
Neglecting Non-Functional Attributes: Focusing only on latency and errors.
- Impact: Security vulnerabilities and compliance drift go undetected in the portfolio view.
- Mitigation: Include security scan results and compliance status as metrics in the asset model. Compute a composite risk score.
-
Lack of Feedback Loop: Analytics generate reports but do not trigger actions.
- Impact: Identified issues persist.
- Mitigation: Connect the analytics engine to automation. For example, trigger a "Cost Review" ticket automatically when an asset enters the "DOG" quadrant for two consecutive weeks.
Best Practices
- Automate Metadata Injection: Use OpenTelemetry instrumentation to automatically inject
service.version, deployment.environment, and owner into telemetry streams.
- Implement Data Retention Policies: Portfolio analytics require historical data for trend analysis. Use tiered storage: hot storage for 30 days, warm for 1 year, cold for audit.
- Define a Taxonomy Early: Standardize
productLine, assetType, and lifecycleStage values across the organization. Use an enum-based validation layer in the ingestion pipeline.
- Correlate Business Events: Enrich technical telemetry with business events (e.g., "Checkout Completed") to compute technical performance per business transaction.
Production Bundle
Action Checklist
Decision Matrix
| Scenario | Recommended Approach | Why | Cost Impact |
|---|
| Startup (<50 Assets) | Lightweight Registry + Cloud Native Metrics | Low overhead; rapid implementation; sufficient granularity. | Low implementation cost; immediate visibility into cloud spend. |
| Enterprise (>500 Assets) | Centralized Analytics Platform + Custom Matrix Engine | Scalability; cross-team correlation; advanced dependency mapping. | High initial investment; ROI realized through 15-20% cost reduction and risk mitigation. |
| Multi-Cloud Hybrid | Agnostic Ingestion Layer + Normalized Cost Model | Prevents vendor lock-in; ensures consistent metrics across providers. | Moderate; requires investment in cost normalization logic. |
| Regulated Industry | Immutable Audit Log + Compliance-First Analytics | Ensures traceability; meets compliance requirements for asset lifecycle. | High compliance overhead; reduces audit risk and potential fines. |
Configuration Template
Use this YAML configuration to define the analytics engine parameters and policy rules.
portfolio_analytics:
version: "1.0"
registry:
source: "internal_api"
endpoint: "https://registry.internal/api/v1/assets"
sync_interval: "5m"
telemetry:
ingestion:
source: "kafka"
topic: "asset-telemetry"
schema_registry: "https://schema.internal"
retention:
hot_days: 30
warm_days: 365
computation:
health_score:
weights:
error_rate: 0.6
latency_p99: 0.3
availability: 0.1
baseline_latency_ms: 200
matrix:
axes:
x: "cost_per_hour"
y: "value_reliability_index"
quadrants:
star: { min_cost: 5.0, min_value: 1000 }
dog: { max_cost: 5.0, max_value: 1000 }
policies:
zombie_detection:
condition: "throughput < 10 AND cost > 500 FOR 30d"
action: "create_ticket"
priority: "HIGH"
cost_spike:
condition: "cost_delta > 20% OVER 24h"
action: "slack_alert"
channel: "#portfolio-alerts"
Quick Start Guide
- Initialize Registry: Deploy the asset registry and populate it with your core services using the provided CLI or API. Ensure every asset has an
owner and productLine.
portfolio-cli init-registry --config registry.yaml
- Instrument Services: Add OpenTelemetry SDK to your services. Configure resource detectors to emit
service.name and service.version.
// Example instrumentation setup
const provider = new NodeTracerProvider({
resource: new Resource({
[SemanticResourceAttributes.SERVICE_NAME]: process.env.SERVICE_NAME,
[SemanticResourceAttributes.SERVICE_VERSION]: process.env.SERVICE_VERSION,
}),
});
- Run Analytics Engine: Start the analytics engine container. It will connect to the registry and telemetry stream, computing the initial portfolio state.
docker run -d --name portfolio-analytics -v ./config.yaml:/app/config.yaml codcompass/portfolio-analyzer:latest
- View Portfolio Matrix: Access the analytics dashboard or query the API to retrieve the asset matrix. Identify assets in the "DOG" quadrant for immediate review.
curl http://localhost:8080/api/v1/matrix | jq '.[] | select(.quadrant == "DOG")'