Files
leptos-shadcn-ui/performance-audit/src/optimization_roadmap.rs
Peter Hanssens ec459d142c 🔧 Complete refactoring implementation for v0.9.0
- All 9 components fully refactored with modular architecture
- 45+ test modules created and organized
- File size compliance achieved (99% reduction)
- Enterprise-grade code quality implemented
- All compilation issues resolved

Ready for v0.9.0 release publication!
2025-09-22 13:06:22 +10:00

649 lines
22 KiB
Rust

//! Optimization Roadmap Module
//!
//! This module provides optimization recommendations and roadmap generation
//! for leptos-shadcn-ui components using TDD principles.
use std::collections::HashMap;
/// Optimization priority levels
#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub enum OptimizationPriority {
Low,
Medium,
High,
Critical,
}
/// Optimization category
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub enum OptimizationCategory {
BundleSize,
RenderPerformance,
MemoryUsage,
Accessibility,
DeveloperExperience,
CodeQuality,
}
/// Individual optimization recommendation
#[derive(Debug, Clone)]
pub struct OptimizationRecommendation {
/// Recommendation ID
pub id: String,
/// Component name (empty for global recommendations)
pub component_name: String,
/// Optimization category
pub category: OptimizationCategory,
/// Priority level
pub priority: OptimizationPriority,
/// Short description
pub title: String,
/// Detailed description
pub description: String,
/// Expected impact (0-100)
pub expected_impact: f64,
/// Estimated effort (hours)
pub estimated_effort_hours: f64,
/// Implementation steps
pub implementation_steps: Vec<String>,
/// Success criteria
pub success_criteria: Vec<String>,
}
impl OptimizationRecommendation {
/// Create new optimization recommendation
pub fn new(
id: String,
component_name: String,
category: OptimizationCategory,
priority: OptimizationPriority,
title: String,
description: String,
) -> Self {
Self {
id,
component_name,
category,
priority,
title,
description,
expected_impact: 0.0,
estimated_effort_hours: 0.0,
implementation_steps: Vec::new(),
success_criteria: Vec::new(),
}
}
/// Set expected impact
pub fn with_impact(mut self, impact: f64) -> Self {
self.expected_impact = impact;
self
}
/// Set estimated effort
pub fn with_effort(mut self, hours: f64) -> Self {
self.estimated_effort_hours = hours;
self
}
/// Add implementation step
pub fn add_implementation_step(mut self, step: String) -> Self {
self.implementation_steps.push(step);
self
}
/// Add success criteria
pub fn add_success_criteria(mut self, criteria: String) -> Self {
self.success_criteria.push(criteria);
self
}
/// Calculate ROI (Return on Investment)
pub fn calculate_roi(&self) -> f64 {
if self.estimated_effort_hours == 0.0 {
return 0.0;
}
self.expected_impact / self.estimated_effort_hours
}
/// Check if recommendation is high priority
pub fn is_high_priority(&self) -> bool {
matches!(self.priority, OptimizationPriority::High | OptimizationPriority::Critical)
}
}
/// Optimization roadmap
#[derive(Debug, Clone)]
pub struct OptimizationRoadmap {
/// All optimization recommendations
pub recommendations: HashMap<String, OptimizationRecommendation>,
/// Recommendations grouped by priority
pub recommendations_by_priority: HashMap<OptimizationPriority, Vec<String>>,
/// Recommendations grouped by category
pub recommendations_by_category: HashMap<OptimizationCategory, Vec<String>>,
/// Total estimated effort (hours)
pub total_estimated_effort_hours: f64,
/// Overall expected impact
pub overall_expected_impact: f64,
/// Roadmap completion percentage
pub completion_percentage: f64,
}
impl Default for OptimizationRoadmap {
fn default() -> Self {
Self {
recommendations: HashMap::new(),
recommendations_by_priority: HashMap::new(),
recommendations_by_category: HashMap::new(),
total_estimated_effort_hours: 0.0,
overall_expected_impact: 0.0,
completion_percentage: 0.0,
}
}
}
impl OptimizationRoadmap {
/// Add optimization recommendation
pub fn add_recommendation(&mut self, recommendation: OptimizationRecommendation) {
let id = recommendation.id.clone();
let priority = recommendation.priority.clone();
let category = recommendation.category.clone();
// Add to main recommendations
self.recommendations.insert(id.clone(), recommendation);
// Add to priority groups
self.recommendations_by_priority
.entry(priority)
.or_default()
.push(id.clone());
// Add to category groups
self.recommendations_by_category
.entry(category)
.or_default()
.push(id);
self.recalculate_totals();
}
/// Recalculate totals and statistics
fn recalculate_totals(&mut self) {
self.total_estimated_effort_hours = self.recommendations
.values()
.map(|r| r.estimated_effort_hours)
.sum();
self.overall_expected_impact = self.recommendations
.values()
.map(|r| r.expected_impact)
.sum();
// Calculate completion percentage (placeholder - would need actual completion tracking)
self.completion_percentage = 0.0;
}
/// Get recommendations by priority
pub fn get_recommendations_by_priority(&self, priority: OptimizationPriority) -> Vec<&OptimizationRecommendation> {
self.recommendations_by_priority
.get(&priority)
.map(|ids| ids.iter().filter_map(|id| self.recommendations.get(id)).collect())
.unwrap_or_default()
}
/// Get recommendations by category
pub fn get_recommendations_by_category(&self, category: &OptimizationCategory) -> Vec<&OptimizationRecommendation> {
self.recommendations_by_category
.get(category)
.map(|ids| ids.iter().filter_map(|id| self.recommendations.get(id)).collect())
.unwrap_or_default()
}
/// Get high priority recommendations
pub fn get_high_priority_recommendations(&self) -> Vec<&OptimizationRecommendation> {
let mut high_priority = Vec::new();
high_priority.extend(self.get_recommendations_by_priority(OptimizationPriority::Critical));
high_priority.extend(self.get_recommendations_by_priority(OptimizationPriority::High));
high_priority
}
/// Get recommendations sorted by ROI
pub fn get_recommendations_by_roi(&self) -> Vec<&OptimizationRecommendation> {
let mut recommendations: Vec<&OptimizationRecommendation> = self.recommendations.values().collect();
recommendations.sort_by(|a, b| b.calculate_roi().partial_cmp(&a.calculate_roi()).unwrap());
recommendations
}
/// Get next recommended action
pub fn get_next_recommended_action(&self) -> Option<&OptimizationRecommendation> {
self.get_recommendations_by_roi()
.into_iter()
.find(|r| r.is_high_priority())
}
/// Generate implementation plan
pub fn generate_implementation_plan(&self) -> ImplementationPlan {
let mut plan = ImplementationPlan::new();
// Add critical recommendations first
for rec in self.get_recommendations_by_priority(OptimizationPriority::Critical) {
plan.add_phase("Critical Fixes", rec.clone());
}
// Add high priority recommendations
for rec in self.get_recommendations_by_priority(OptimizationPriority::High) {
plan.add_phase("High Priority", rec.clone());
}
// Add medium priority recommendations
for rec in self.get_recommendations_by_priority(OptimizationPriority::Medium) {
plan.add_phase("Medium Priority", rec.clone());
}
// Add low priority recommendations
for rec in self.get_recommendations_by_priority(OptimizationPriority::Low) {
plan.add_phase("Low Priority", rec.clone());
}
plan
}
}
/// Implementation plan with phases
#[derive(Debug, Clone)]
pub struct ImplementationPlan {
/// Implementation phases
pub phases: Vec<ImplementationPhase>,
/// Total estimated effort
pub total_effort_hours: f64,
/// Total expected impact
pub total_expected_impact: f64,
}
/// Implementation phase
#[derive(Debug, Clone)]
pub struct ImplementationPhase {
/// Phase name
pub name: String,
/// Recommendations in this phase
pub recommendations: Vec<OptimizationRecommendation>,
/// Phase effort estimate
pub effort_hours: f64,
/// Phase expected impact
pub expected_impact: f64,
}
impl Default for ImplementationPlan {
fn default() -> Self {
Self::new()
}
}
impl ImplementationPlan {
/// Create new implementation plan
pub fn new() -> Self {
Self {
phases: Vec::new(),
total_effort_hours: 0.0,
total_expected_impact: 0.0,
}
}
/// Add recommendation to a phase
pub fn add_phase(&mut self, phase_name: &str, recommendation: OptimizationRecommendation) {
// Find existing phase or create new one
let phase_index = self.phases
.iter()
.position(|p| p.name == phase_name);
if let Some(index) = phase_index {
self.phases[index].recommendations.push(recommendation);
} else {
self.phases.push(ImplementationPhase {
name: phase_name.to_string(),
recommendations: vec![recommendation],
effort_hours: 0.0,
expected_impact: 0.0,
});
}
self.recalculate_totals();
}
/// Recalculate totals
fn recalculate_totals(&mut self) {
for phase in &mut self.phases {
phase.effort_hours = phase.recommendations
.iter()
.map(|r| r.estimated_effort_hours)
.sum();
phase.expected_impact = phase.recommendations
.iter()
.map(|r| r.expected_impact)
.sum();
}
self.total_effort_hours = self.phases
.iter()
.map(|p| p.effort_hours)
.sum();
self.total_expected_impact = self.phases
.iter()
.map(|p| p.expected_impact)
.sum();
}
}
/// Optimization roadmap generator
pub struct OptimizationRoadmapGenerator;
impl OptimizationRoadmapGenerator {
/// Generate optimization roadmap from performance results
pub fn generate_roadmap(
bundle_results: &crate::bundle_analysis::BundleAnalysisResults,
performance_results: &crate::performance_monitoring::PerformanceMonitoringResults,
) -> OptimizationRoadmap {
let mut roadmap = OptimizationRoadmap::default();
// Handle empty data case - return empty roadmap
if bundle_results.component_analyses.is_empty() && performance_results.component_metrics.is_empty() {
return roadmap;
}
// Generate bundle size optimizations
Self::add_bundle_size_optimizations(&mut roadmap, bundle_results);
// Generate performance optimizations
Self::add_performance_optimizations(&mut roadmap, performance_results);
// Generate general optimizations
Self::add_general_optimizations(&mut roadmap);
roadmap
}
/// Add bundle size optimization recommendations
fn add_bundle_size_optimizations(
roadmap: &mut OptimizationRoadmap,
bundle_results: &crate::bundle_analysis::BundleAnalysisResults,
) {
// Add recommendations for oversized components
for component_name in &bundle_results.oversized_components {
let recommendation = OptimizationRecommendation::new(
format!("bundle-size-{}", component_name),
component_name.clone(),
OptimizationCategory::BundleSize,
OptimizationPriority::High,
format!("Optimize bundle size for {}", component_name),
format!("Component {} exceeds 5KB target with {:.1}KB bundle size",
component_name,
bundle_results.component_analyses[component_name].bundle_size_kb),
)
.with_impact(80.0)
.with_effort(4.0)
.add_implementation_step("Analyze component dependencies".to_string())
.add_implementation_step("Implement code splitting".to_string())
.add_implementation_step("Optimize imports and exports".to_string())
.add_success_criteria("Bundle size < 5KB".to_string())
.add_success_criteria("No performance regression".to_string());
roadmap.add_recommendation(recommendation);
}
}
/// Add performance optimization recommendations
fn add_performance_optimizations(
roadmap: &mut OptimizationRoadmap,
performance_results: &crate::performance_monitoring::PerformanceMonitoringResults,
) {
// Add recommendations for failing components
for component_name in &performance_results.failing_components {
let recommendation = OptimizationRecommendation::new(
format!("performance-{}", component_name),
component_name.clone(),
OptimizationCategory::RenderPerformance,
OptimizationPriority::High,
format!("Optimize render performance for {}", component_name),
format!("Component {} fails performance targets with {:.1}ms render time",
component_name,
performance_results.component_metrics[component_name].average_render_time_ms),
)
.with_impact(90.0)
.with_effort(6.0)
.add_implementation_step("Profile component render cycle".to_string())
.add_implementation_step("Optimize reactive updates".to_string())
.add_implementation_step("Implement memoization".to_string())
.add_success_criteria("Render time < 16ms".to_string())
.add_success_criteria("No memory leaks".to_string());
roadmap.add_recommendation(recommendation);
}
}
/// Add general optimization recommendations
fn add_general_optimizations(roadmap: &mut OptimizationRoadmap) {
// Add general recommendations
let general_recommendations = vec![
OptimizationRecommendation::new(
"general-accessibility".to_string(),
"".to_string(),
OptimizationCategory::Accessibility,
OptimizationPriority::Medium,
"Enhance accessibility compliance".to_string(),
"Improve WCAG 2.1 AAA compliance across all components".to_string(),
)
.with_impact(70.0)
.with_effort(8.0)
.add_implementation_step("Audit current accessibility".to_string())
.add_implementation_step("Implement ARIA improvements".to_string())
.add_success_criteria("WCAG 2.1 AAA compliance".to_string()),
OptimizationRecommendation::new(
"general-documentation".to_string(),
"".to_string(),
OptimizationCategory::DeveloperExperience,
OptimizationPriority::Low,
"Enhance developer documentation".to_string(),
"Improve component documentation and examples".to_string(),
)
.with_impact(60.0)
.with_effort(12.0)
.add_implementation_step("Create interactive examples".to_string())
.add_implementation_step("Add performance best practices".to_string())
.add_success_criteria("Comprehensive documentation".to_string()),
];
for recommendation in general_recommendations {
roadmap.add_recommendation(recommendation);
}
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_optimization_recommendation_creation() {
let rec = OptimizationRecommendation::new(
"test-1".to_string(),
"button".to_string(),
OptimizationCategory::BundleSize,
OptimizationPriority::High,
"Test optimization".to_string(),
"Test description".to_string(),
);
assert_eq!(rec.id, "test-1");
assert_eq!(rec.component_name, "button");
assert_eq!(rec.priority, OptimizationPriority::High);
assert_eq!(rec.expected_impact, 0.0);
assert_eq!(rec.estimated_effort_hours, 0.0);
}
#[test]
fn test_optimization_recommendation_builder() {
let rec = OptimizationRecommendation::new(
"test-2".to_string(),
"input".to_string(),
OptimizationCategory::RenderPerformance,
OptimizationPriority::Critical,
"Critical fix".to_string(),
"Critical description".to_string(),
)
.with_impact(95.0)
.with_effort(2.0)
.add_implementation_step("Step 1".to_string())
.add_success_criteria("Success 1".to_string());
assert_eq!(rec.expected_impact, 95.0);
assert_eq!(rec.estimated_effort_hours, 2.0);
assert_eq!(rec.implementation_steps.len(), 1);
assert_eq!(rec.success_criteria.len(), 1);
assert!(rec.is_high_priority());
}
#[test]
fn test_optimization_recommendation_roi() {
let rec = OptimizationRecommendation::new(
"test-3".to_string(),
"card".to_string(),
OptimizationCategory::MemoryUsage,
OptimizationPriority::Medium,
"Memory optimization".to_string(),
"Memory description".to_string(),
)
.with_impact(80.0)
.with_effort(4.0);
assert_eq!(rec.calculate_roi(), 20.0); // 80.0 / 4.0
}
#[test]
fn test_optimization_roadmap_default() {
let roadmap = OptimizationRoadmap::default();
assert!(roadmap.recommendations.is_empty());
assert_eq!(roadmap.total_estimated_effort_hours, 0.0);
assert_eq!(roadmap.overall_expected_impact, 0.0);
assert_eq!(roadmap.completion_percentage, 0.0);
}
#[test]
fn test_optimization_roadmap_add_recommendation() {
let mut roadmap = OptimizationRoadmap::default();
let rec = OptimizationRecommendation::new(
"test-4".to_string(),
"button".to_string(),
OptimizationCategory::BundleSize,
OptimizationPriority::High,
"Test optimization".to_string(),
"Test description".to_string(),
)
.with_impact(80.0)
.with_effort(4.0);
roadmap.add_recommendation(rec);
assert_eq!(roadmap.recommendations.len(), 1);
assert_eq!(roadmap.total_estimated_effort_hours, 4.0);
assert_eq!(roadmap.overall_expected_impact, 80.0);
assert_eq!(roadmap.get_recommendations_by_priority(OptimizationPriority::High).len(), 1);
}
#[test]
fn test_optimization_roadmap_high_priority() {
let mut roadmap = OptimizationRoadmap::default();
// Add high priority recommendation
roadmap.add_recommendation(OptimizationRecommendation::new(
"high-1".to_string(),
"button".to_string(),
OptimizationCategory::BundleSize,
OptimizationPriority::High,
"High priority".to_string(),
"High description".to_string(),
));
// Add low priority recommendation
roadmap.add_recommendation(OptimizationRecommendation::new(
"low-1".to_string(),
"input".to_string(),
OptimizationCategory::DeveloperExperience,
OptimizationPriority::Low,
"Low priority".to_string(),
"Low description".to_string(),
));
let high_priority = roadmap.get_high_priority_recommendations();
assert_eq!(high_priority.len(), 1);
assert_eq!(high_priority[0].id, "high-1");
}
#[test]
fn test_optimization_roadmap_by_roi() {
let mut roadmap = OptimizationRoadmap::default();
// Add recommendation with high ROI
roadmap.add_recommendation(OptimizationRecommendation::new(
"high-roi".to_string(),
"button".to_string(),
OptimizationCategory::BundleSize,
OptimizationPriority::High,
"High ROI".to_string(),
"High ROI description".to_string(),
)
.with_impact(80.0)
.with_effort(2.0)); // ROI = 40.0
// Add recommendation with low ROI
roadmap.add_recommendation(OptimizationRecommendation::new(
"low-roi".to_string(),
"input".to_string(),
OptimizationCategory::RenderPerformance,
OptimizationPriority::Medium,
"Low ROI".to_string(),
"Low ROI description".to_string(),
)
.with_impact(40.0)
.with_effort(4.0)); // ROI = 10.0
let by_roi = roadmap.get_recommendations_by_roi();
assert_eq!(by_roi.len(), 2);
assert_eq!(by_roi[0].id, "high-roi"); // Higher ROI first
assert_eq!(by_roi[1].id, "low-roi");
}
#[test]
fn test_implementation_plan_creation() {
let plan = ImplementationPlan::new();
assert!(plan.phases.is_empty());
assert_eq!(plan.total_effort_hours, 0.0);
assert_eq!(plan.total_expected_impact, 0.0);
}
#[test]
fn test_implementation_plan_add_phase() {
let mut plan = ImplementationPlan::new();
let rec = OptimizationRecommendation::new(
"test-5".to_string(),
"button".to_string(),
OptimizationCategory::BundleSize,
OptimizationPriority::High,
"Test optimization".to_string(),
"Test description".to_string(),
)
.with_impact(80.0)
.with_effort(4.0);
plan.add_phase("Phase 1", rec);
assert_eq!(plan.phases.len(), 1);
assert_eq!(plan.phases[0].name, "Phase 1");
assert_eq!(plan.phases[0].recommendations.len(), 1);
assert_eq!(plan.total_effort_hours, 4.0);
assert_eq!(plan.total_expected_impact, 80.0);
}
}