How to use multi-language LOC counter CSV exports to identify technical debt in legacy codebases
The Friday Deadline and the Mystery Codebase
You're sitting in a conference room at 4:47 PM on a Wednesday. The VP of Engineering just slid a laptop across the table and said, "We acquired these three companies last quarter. Their codebases are now ours. I need a technical debt report by Friday for the board meeting."
You have approximately 400,000 lines of code across Java, Python, TypeScript, Go, and a surprising amount of Perl. You've never seen any of it before. The original developers are long gone, and the documentation is a single Confluence page that says "TODO: update this."
This is the scenario I found myself in last spring. And it's the scenario countless engineering leaders face during mergers, acquisitions, team transitions, and modernization initiatives. The question isn't whether technical debt exists. It's how much, where, and what's going to break first.
The answer starts with a multi-language LOC counter and a CSV export.
The Problem: Why Gut Feelings Don't Survive Board Meetings
Every experienced engineer has a sixth sense for technical debt. You open a file, see a 2,000-line function, and immediately know something is wrong. But when you're reporting to stakeholders who control budgets, "it feels bad" is not a deliverable.
The problem is twofold.
First, legacy codebases are almost always multi-language. That acquired company didn't write everything in clean, modern TypeScript. They have a React frontend, a Python backend, some shell scripts that nobody touches, and a Java service that one contractor wrote in 2019 and then disappeared. You cannot assess technical debt holistically if your tools only understand one language.
Second, raw numbers without structure are useless. Knowing that a codebase has "400,000 lines" tells you almost nothing. You need the data broken down by language, by directory, by file, and by type of code (source, comments, blanks). You need it in a format you can sort, filter, and cross-reference. That format is CSV.
What a Multi-Language LOC Counter Actually Gives You
A proper multi-language LOC counter scans your entire repository and produces a CSV export with per-file metrics. Each row typically contains the file path, language detected, total lines, code lines, comment lines, blank lines, and sometimes additional metadata like file size or last modified date.
This raw data is the foundation. But the technical debt signals are hidden in the patterns, not the individual rows.
The Cause: What LOC Distribution Reveals About Debt
Technical debt in legacy codebases doesn't distribute evenly. It clusters. And those clusters leave fingerprints in the LOC data if you know what to look for.
Let me walk through the specific patterns I've learned to identify after running this analysis on dozens of inherited codebases.
Pattern 1: The Monolith File
When you sort your CSV export by code lines descending, the top 10 files tell you a story. In a healthy codebase, the largest files are usually data models, generated code, or configuration files. In a debt-heavy codebase, the largest files are business logic.
In one codebase I audited, the top file was a Python module called utils.py with 4,847 lines of code. The second was handlers.py at 3,210 lines. Together, these two files represented 8% of the entire codebase's logic. They were also the source of 60% of the bug reports from the previous quarter, which I confirmed by cross-referencing with the issue tracker.
The calculation is simple but powerful: divide each file's code lines by the total code lines. Sort descending. Any file exceeding 2% of the total is a candidate for refactoring. Any file exceeding 5% is almost certainly a debt hotspot.
Pattern 2: The Language Graveyard
Multi-language LOC counters detect language by file extension and content analysis. When you group your CSV by language and sum the code lines, you'll often find languages that shouldn't be there.
I found 12,000 lines of Perl in one codebase. The team had no Perl developers. The code was from a legacy data pipeline that had been replaced two years ago but never deleted. It was dead weight that inflated the perceived complexity of the system and scared away potential new hires.
The same applies to abandoned shell scripts, old Ruby utilities, or prototype code in languages the team no longer uses. Group your CSV by language. Any language with fewer than 1,000 code lines that isn't actively part of the build process is likely a graveyard.
Pattern 3: Comment-to-Code Ratio Anomalies
This is one of the most underutilized signals in LOC data. A healthy codebase typically has a comment-to-code ratio between 10% and 25%, depending on the language and domain. When you calculate this ratio per file in your CSV, extremes on either end signal problems.
Files with zero comments and 500+ lines of code are either brilliantly written or, more likely, incomprehensible to anyone except the original author. Files with a 1:1 comment-to-code ratio often contain workarounds, hacks, and explanations that begin with phrases like "I know this is wrong but..."
In the acquired codebase I mentioned earlier, I found a Java file with 890 lines of code and 1,200 lines of comments. The comments were a running diary of a developer's frustration with a third-party API. That file was a debt time bomb.
The Solution: A Step-by-Step Workflow for Debt Identification
Here is the exact checklist I use when assessing a new codebase. You can run this entire process in under two hours on a codebase of moderate size.
Step 1: Run the Multi-Language LOC Counter
Choose a counter that supports all languages in your codebase and exports to CSV. Popular options include cloc, scc, and tokei. Run it against the root directory of your repository.
The command for cloc is straightforward:
cloc --by-file --csv --output=loc_report.csv ./repository-root
This produces a CSV with one row per file. The --by-file flag is critical. Without it, you only get aggregate summaries, which are nearly useless for debt analysis.
Step 2: Clean and Import the Data
Open the CSV in your tool of choice. I use a spreadsheet for quick analysis and Python with pandas for larger codebases. Remove generated files, vendor directories, and build artifacts from the dataset. These inflate numbers without representing actual debt.
Specifically, filter out:
- Any path containing
node_modules,vendor, ordist - Files with
.generated.or.min.in the name - Lock files (
package-lock.json,yarn.lock,Pipfile.lock) - Any directory explicitly marked as third-party
Step 3: Calculate the Debt Indicators
Create three calculated columns in your spreadsheet or script:
File Size Percentage = (file code lines / total code lines) × 100
Comment Ratio = (comment lines / code lines) × 100
Language Share = (language total code lines / total code lines) × 100
Sort by File Size Percentage descending. Flag any file above 2%. Sort by Comment Ratio. Flag any file below 5% with more than 200 code lines. Flag any file above 50% comment ratio. Group by language and flag any language with a share below 3% of the total.
Step 4: Cross-Reference with Git History
This is where the analysis moves from data to insight. For each flagged file, check the last modified date in your version control system. Files that are large, poorly documented, and haven't been touched in six months are the highest-priority debt targets. They represent code that nobody understands and nobody wants to touch.
Files that are large and frequently modified are different. They're not abandoned debt. They're active debt. These need refactoring before they grow further.
Step 5: Produce the Report
Create a summary document with three sections. First, the headline numbers: total code lines by language, file count, and average file size. Second, the top 10 debt hotspot files with their specific metrics. Third, recommended actions ranked by effort and impact.
When I presented the Friday report for those three acquired codebases, the headline was: "47% of the total codebase is concentrated in 23 files. These files represent the primary technical debt risk. We recommend a 6-week refactoring sprint focused exclusively on these files before integrating the codebases with our primary platform."
That number, 47% in 23 files, came directly from the CSV analysis. It was specific, defensible, and actionable. The board approved the refactoring sprint the following Monday.
Making This a Repeatable Practice
Technical debt assessment shouldn't be a one-time event triggered by an acquisition or crisis. The same CSV export workflow can run automatically as part of your CI pipeline, producing a monthly debt dashboard.
Set up a scheduled job that runs your LOC counter, processes the CSV through a script that calculates the indicators above, and outputs a trend report. Watch for files that are growing in size week over week. Watch for comment ratios that are declining. Watch for new languages appearing in the distribution.
The data is already there in your codebase. The CSV export is the bridge between raw files and engineering decisions. Once you build this workflow once, every future codebase assessment becomes a matter of running a script and reading a report. No more gut feelings. No more conference room panic. Just numbers, patterns, and a clear path forward.
Frequently Asked Questions
How can a multi-language LOC counter help identify technical debt in a legacy codebase?
A multi-language LOC counter provides a quantitative baseline of your codebase's size across different tech stacks, highlighting bloated modules. By analyzing these metrics, you can pinpoint areas with disproportionate amounts of code, which often correlate with high technical debt and maintenance bottlenecks.
What specific metrics in a LOC CSV export indicate technical debt?
In a LOC CSV export, sudden spikes in lines of code, high comment-to-code ratios, or large files with minimal recent changes are strong indicators of technical debt. These metrics suggest workarounds, complex patchwork fixes, or abandoned code that needs refactoring.
How do I analyze a CSV export from a multi-language codebase to find code smells?
You can import the CSV export into spreadsheet software like Excel or data visualization tools like Tableau to sort and filter by directory, language, or file size. Look for outliers—such as exceptionally large files or languages with high code churn—which typically signal legacy technical debt hotspots.
Why is it important to track LOC across multiple languages in legacy systems?
Legacy systems often consist of various languages stitched together over time, making it hard to see the total project scope. Tracking LOC across all languages ensures you don't miss hidden technical debt accumulating in older, auxiliary scripts or transitioning layers.
Can LOC counts alone accurately measure technical debt?
While LOC counts alone cannot measure technical debt with absolute precision, they serve as a highly effective proxy for identifying risk areas. Combining LOC data with complexity metrics and change frequency from your CSV export gives a much clearer picture of where debt resides.
How often should I export and analyze LOC data for technical debt tracking?
For active legacy codebases, exporting and analyzing LOC data on a monthly or quarterly basis is recommended to track trends over time. Regular analysis helps you catch new technical debt early and measure the impact of recent refactoring efforts.
What is the best way to visualize LOC CSV data for technical debt reporting?
The most effective way to visualize LOC CSV data for technical debt is by using treemaps to show file size distributions and scatter plots to compare code volume against complexity or bug rates. These visualizations make it easy to present technical debt hotspots to non-technical stakeholders.
How does high LOC in specific files relate to technical debt?
Files with exceptionally high LOC often violate the single-responsibility principle and are difficult to maintain, test, or debug. In legacy codebases, these massive files usually contain years of patched-together logic, making them prime targets for technical debt reduction.
What tools can generate multi-language LOC CSV exports for legacy code?
Tools like cloc, SonarQube, and various open-source code counters can scan multi-language legacy codebases and export the results directly to CSV. These tools automate the process of gathering code metrics, saving you from manually calculating lines of code across different languages.
How do I prioritize technical debt refactoring using LOC data?
Prioritize refactoring by cross-referencing your highest LOC files with metrics like bug frequency, cyclomatic complexity, and business criticality. Focus your cleanup efforts on the massive, high-LOC files that are actively being modified, as they pose the greatest risk of introducing new defects.