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