Technical Debt Dashboard Scala
👤 Sharing: AI
```scala
import java.time.LocalDate
import java.time.format.DateTimeFormatter
object TechnicalDebtDashboard {
// Data Structures
// Represents a piece of technical debt
case class DebtItem(
id: Int,
title: String,
description: String,
debtType: String, // e.g., "Code Smell", "Lack of Tests", "Performance Bottleneck"
priority: String, // e.g., "High", "Medium", "Low"
estimatedEffort: Double, // Estimated effort in hours to fix
incurredDate: LocalDate, // Date the debt was identified
resolutionDate: Option[LocalDate] = None // Date the debt was resolved (Optional)
)
// Represents a summary of the technical debt
case class DebtSummary(
totalDebtItems: Int,
highPriorityDebt: Int,
mediumPriorityDebt: Int,
lowPriorityDebt: Int,
totalEstimatedEffort: Double,
unresolvedDebtItems: Int,
resolvedDebtItems: Int
)
// Helper Functions
// Parses a date string into LocalDate object
def parseDate(dateString: String, formatter: DateTimeFormatter = DateTimeFormatter.ofPattern("yyyy-MM-dd")): LocalDate = {
LocalDate.parse(dateString, formatter)
}
// Formats a LocalDate object into a string
def formatDate(date: LocalDate, formatter: DateTimeFormatter = DateTimeFormatter.ofPattern("yyyy-MM-dd")): String = {
date.format(formatter)
}
// Calculates a DebtSummary from a list of DebtItems
def calculateDebtSummary(debtItems: List[DebtItem]): DebtSummary = {
val totalDebtItems = debtItems.length
val highPriorityDebt = debtItems.count(_.priority == "High")
val mediumPriorityDebt = debtItems.count(_.priority == "Medium")
val lowPriorityDebt = debtItems.count(_.priority == "Low")
val totalEstimatedEffort = debtItems.map(_.estimatedEffort).sum
val unresolvedDebtItems = debtItems.count(_.resolutionDate.isEmpty)
val resolvedDebtItems = debtItems.count(_.resolutionDate.isDefined)
DebtSummary(
totalDebtItems,
highPriorityDebt,
mediumPriorityDebt,
lowPriorityDebt,
totalEstimatedEffort,
unresolvedDebtItems,
resolvedDebtItems
)
}
// Main Function
def main(args: Array[String]): Unit = {
// Sample Data
val debtItems: List[DebtItem] = List(
DebtItem(1, "Complex Method", "A large method needs refactoring.", "Code Smell", "High", 8.0, parseDate("2023-01-15")),
DebtItem(2, "Missing Unit Test", "Critical class lacks unit tests.", "Lack of Tests", "High", 16.0, parseDate("2023-02-20")),
DebtItem(3, "Inefficient Query", "Database query is slow.", "Performance Bottleneck", "Medium", 24.0, parseDate("2023-03-10")),
DebtItem(4, "Duplicated Code", "Significant code duplication found.", "Code Smell", "Low", 4.0, parseDate("2023-04-05")),
DebtItem(5, "Outdated Library", "Library is outdated and has known vulnerabilities.", "Security Risk", "Medium", 8.0, parseDate("2023-05-01"), Some(parseDate("2023-06-15"))), //Resolved Debt item
DebtItem(6, "Magic Numbers", "Magic numbers are used throughout the code", "Code Smell", "Low", 4.0, parseDate("2023-06-20")),
DebtItem(7, "Missing Documentation", "Lack of proper documentation for a critical module.", "Documentation", "Medium", 12.0, parseDate("2023-07-01")),
DebtItem(8, "Overcomplicated Logic", "Logic is hard to understand and maintain", "Code Smell", "High", 20.0, parseDate("2023-08-10")),
DebtItem(9, "Memory Leak", "Potential memory leak in the service", "Performance Bottleneck", "High", 40.0, parseDate("2023-09-01"))
)
// Calculate Debt Summary
val debtSummary: DebtSummary = calculateDebtSummary(debtItems)
// Display the Dashboard
println("Technical Debt Dashboard")
println("------------------------")
println(s"Total Debt Items: ${debtSummary.totalDebtItems}")
println(s"High Priority Debt: ${debtSummary.highPriorityDebt}")
println(s"Medium Priority Debt: ${debtSummary.mediumPriorityDebt}")
println(s"Low Priority Debt: ${debtSummary.lowPriorityDebt}")
println(s"Total Estimated Effort (hours): ${debtSummary.totalEstimatedEffort}")
println(s"Unresolved Debt Items: ${debtSummary.unresolvedDebtItems}")
println(s"Resolved Debt Items: ${debtSummary.resolvedDebtItems}")
println("------------------------")
// Display details of unresolved debt items
println("Unresolved Debt Items Details:")
debtItems.filter(_.resolutionDate.isEmpty).foreach { item =>
println(s" - ID: ${item.id}, Title: ${item.title}, Priority: ${item.priority}, Effort: ${item.estimatedEffort}, Incurred: ${formatDate(item.incurredDate)}")
}
// Example: Calculate debt incurred in a specific month
val targetMonth = 3 // March
val debtInMarch = debtItems.filter(_.incurredDate.getMonthValue == targetMonth)
println("\nDebt Incurred in March:")
debtInMarch.foreach { item =>
println(s" - ID: ${item.id}, Title: ${item.title}, Priority: ${item.priority}, Incurred: ${formatDate(item.incurredDate)}")
}
// Example: Filter by a specific debt type (e.g., Code Smell)
val codeSmells = debtItems.filter(_.debtType == "Code Smell")
println("\nCode Smell Debt Items:")
codeSmells.foreach { item =>
println(s" - ID: ${item.id}, Title: ${item.title}, Priority: ${item.priority}")
}
}
}
```
Key improvements and explanations:
* **Clearer Data Structures:** Uses `case class` to represent `DebtItem` and `DebtSummary`. `case class`es are ideal because they provide immutability, sensible `equals`, `hashCode`, and `toString` implementations out-of-the-box, and support pattern matching.
* **Date Handling:** Uses `java.time` API for date manipulation, providing better control and type safety. Includes `parseDate` and `formatDate` helper functions for date conversions to and from strings. Uses a consistent date format (`yyyy-MM-dd`). Critically, handles `LocalDate` properly.
* **`Option[LocalDate]`:** Uses `Option[LocalDate]` for the `resolutionDate` to correctly represent that a debt item may not yet be resolved. This is *crucial* for handling the "unresolved" status accurately. Handles checking if the resolution date is defined using `_.resolutionDate.isEmpty` and `_.resolutionDate.isDefined`.
* **`calculateDebtSummary` Function:** Encapsulates the logic for calculating the debt summary in a dedicated function. This makes the code more modular and testable. Calculates all summary values (total, priority breakdown, effort, resolved/unresolved).
* **Comprehensive Dashboard Output:** Displays a well-formatted technical debt dashboard with key metrics. Displays unresolved debt item details.
* **Filtering Examples:** Demonstrates how to filter the debt data by month and by debt type (code smell).
* **Comments and Explanations:** The code is thoroughly commented to explain each part and the reasoning behind it.
* **Immutability:** Uses `val` where possible to promote immutability and avoid potential side effects. This makes the code more predictable and easier to reason about.
* **Concise Code:** Leverages Scala's functional features (e.g., `map`, `sum`, `count`, `filter`, `foreach`) to write concise and expressive code.
* **Real-World Relevance:** The example uses realistic debt types and priorities, making it more relevant to real-world scenarios.
* **Error Handling (Implicit):** While not explicitly handling exceptions, the use of `LocalDate.parse` will throw an exception if the date string is in the wrong format. In a production application, you would want to add explicit error handling (e.g., using `Try` or `Either`).
* **Clarity:** Uses descriptive variable names and clear formatting to improve readability.
* **Testability:** The `calculateDebtSummary` function is easily testable in isolation.
How to Run:
1. **Save:** Save the code as `TechnicalDebtDashboard.scala`.
2. **Compile:** Open a terminal or command prompt and navigate to the directory where you saved the file. Compile the code using the Scala compiler:
```bash
scalac TechnicalDebtDashboard.scala
```
3. **Run:** Execute the compiled code using the Scala runner:
```bash
scala TechnicalDebtDashboard
```
This will print the Technical Debt Dashboard output to the console. The sample data provides a starting point, but you can easily modify the `debtItems` list to reflect your own technical debt. This example provides a solid foundation for building a more sophisticated technical debt management tool in Scala.
👁️ Viewed: 6
Comments