Indiana Jones and the Temple of Legacy Code - William Brander - NDC Oslo 2026
Summary
This talk uses the metaphor of Indiana Jones and ancient traps to guide developers through the process of safely modernizing legacy codebases. The core argument is that dealing with legacy systems requires a structured approach focused on improving 'Supportability' (tooling and safety nets) and 'Understanding' (archaeology and history). Key strategies include establishing reproducible builds, implementing comprehensive testing (including mutation testing), adding observability, and using advanced source control analysis (like `git log` queries) to map hidden dependencies and understand historical decisions.
Key takeaways
-
The Legacy System Quadrant
21:00
Assess the system's state using two axes: Understanding (how well you know the code) and Supportability (the tooling around the code, e.g., tests, CI, observability). The goal is to move the system from the low-understanding/low-supportability quadrant to the high-understanding/high-supportability ideal state. (Timestamp: 1260)
-
Improving Supportability
27:10
To make changes safely, establish reproducible builds, pin specific dependency versions, remove machine-specific build requirements, and integrate the system into a CI pipeline with rollback capabilities. (Timestamp: 1630)
-
Advanced Code Archaeology
34:10
Use source control tools (like `git log` queries) to analyze historical data. Look for files with high change counts, frequent bug fixes, or high churn percentage to identify critical, yet poorly understood, components. (Timestamp: 2050)
-
Life Cycle Determines Technique
45:00
The appropriate refactoring technique depends on the system's life cycle: Critical Support Only (prefer adding new behavior, e.g., `getSortedItemValueNames`), General Maintenance (change at the edge), or Active Development (slice by capability). (Timestamp: 2700)
Technical details
-
Legacy System Analysis Framework
1260s
The system state is defined by: 1) Understanding (predicting impact of changes); 2) Supportability (builds, tests, CI, observability, rollbacks); and 3) Life Cycle (Critical Support, General Maintenance, Active Development). (Timestamp: 1260)
-
Testing and AI Integration
1800s
Implement unit, integration, and acceptance tests. Use mutation testing (e.g., Striker.net for .NET) to ensure tests are meaningful by having the framework intentionally break the code to prove test coverage. AI agents can assist in generating these tests. (Timestamp: 1800)
-
Observability and Mapping
2150s
Add observability (e.g., using OpenTelemetry) for simple flows first (like user login) to establish telemetry in production. This allows developers to create a visual map of the system's flow and understand component interactions. (Timestamp: 2150)
-
Source Control Querying
2050s
Treat the Git repository as a database. Use `git log` queries to select and group data (e.g., files changed most often, files with the highest churn percentage) to identify areas needing investigation. (Timestamp: 2050)
-
Refactoring Techniques
2700s
When making changes, prioritize non-invasive techniques: 'Adding' new functionality (e.g., `getSortedItemValueNames`) over modifying existing methods. Alternatively, 'Change at the Edge' or 'Slice by Capability' can isolate changes to minimize risk. (Timestamp: 2700)
Mentioned resources
- Jellyfin
- CodeScene
- CodeMart
- Striker.net
Channel & topics
Watch on YouTube · Back to latest
This independent, AI-assisted summary is provided for commentary and informational purposes. It may contain errors or omit important context. Please watch the original video for the creator's complete presentation. Video, thumbnail, and related copyrights belong to their respective owners.