Home / AI vs Complex Code: Why Software Engineers Still Matter in 2025

AI vs Complex Code: Why Software Engineers Still Matter in 2025

As developers increasingly turn to AI for coding assistance, my recent experience building a chart management tool revealed both the remarkable capabilities and critical limitations of today’s frontier AI models. What started as a seemingly straightforward project became an illuminating case study in AI-human collaboration, one that aligns closely with recent academic research highlighting the current boundaries of AI coding capabilities.

Recent research from Cornell University, MIT CSAIL, Stanford University, and UC Berkeley presented at the 2025 International Conference on Machine Learning offers crucial insights into why AI hasn’t yet achieved “full autonomy” in software development [1]. As MIT’s Armando Solar-Lezama notes, while AI-powered programming tools are “powerful and useful,” they haven’t reached “the point where you can really collaborate with these tools the way you can with a human programmer.”

Building a Chart Management Interface

My goal was to create a web application that could manipulate HTML files containing multiple interactive charts (built with libraries such as Chart.js and Plotly.js). Users needed to:

  • Browse charts from a source HTML file
  • Select specific charts to add to or replace in a target HTML file
  • Remove unwanted charts from the target file
  • Export the modified HTML with all functionality intact

Each chart came with accompanying notes and configurations. The charts were self-contained with embedded data and functions, seemingly perfect for manipulation.

The AI Odyssey: Multiple Models, Persistent Problems

I enlisted several leading frontier models for this task, including Gemini Flash 2.5 and Claude Opus 4.1. Initially, the AI responses were impressive, generating sophisticated code structures and demonstrating deep understanding of web technologies. The models confidently produced solutions that looked comprehensive and well-architected.

But reality had other plans.

The Static File Trap 

The first major hurdle surfaced when trying to extract user‑selected charts from an existing HTML file so they could be shown on the screen and then copied into another target html file. Each AI model offered tweaks, some charts rendered, others didn’t, creating a classic “AI revision loop.” These incremental fixes never fully addressed the core problem: isolating each chart’s data, configuration, and logic into a reusable, self‑contained format.

After numerous iterations across different models, I pivoted to a new strategy: restructuring the source HTML files to include explicit JSON chart configuration blocks embedded beneath each chart. This separation of data from presentation logic made the chart configurations easily identifiable and extractable for transfer to the target HTML file, and the AIs adapted quickly to this more structured approach.

The Unescaping Nightmare

Success felt within reach until subtle but critical issues began surfacing. Chart hover effects stopped working. Labels disappeared. Interactive features broke mysteriously. The root cause became clear through browser console errors:

Uncaught SyntaxError: Unexpected token '&'
exported_report (42).html:2748 Uncaught SyntaxError: Unexpected token '&'
exported_report (42).html:2894 Uncaught SyntaxError: Unexpected token ';'

The error Uncaught SyntaxError: Unexpected token '&' meant that the JavaScript interpreter encountered an ampersand character where it wasn’t expecting one. In the context of the createChartScript function, this occurred when chart data containing strings like “Projects & Reports” was being embedded directly into JavaScript without proper escaping. The ampersand, which is perfectly valid in data, was being misinterpreted as a JavaScript operator when embedded in code strings.

This represents a classic “meta-coding” challenge using JavaScript to dynamically generate JavaScript code. The problem involves multiple layers of string interpretation:

  1. Data layer: Chart configurations containing strings like “Q&A Sessions” or “Sales & Marketing”
  2. Template layer: JavaScript code that converts this data into executable JavaScript strings
  3. Execution layer: The browser’s JavaScript interpreter parsing the generated code

The AI models kept suggesting fixes, but they consistently mismanaged the multi‑layered escaping. They would generate code like:

javascript

// Problematic AI-generated code
const chartConfig = {
    title: "Sales & Marketing Report"  // This becomes problematic when stringified
};
const scriptContent = `
    const config = ${JSON.stringify(chartConfig)};
    new Chart(ctx, config);
`;

When JSON.stringify() processes data containing ampersands, and that string is later embedded in HTML, the ampersands can get double-encoded or incorrectly escaped, leading to syntax errors when the browser tries to execute the generated JavaScript.

The Circular Debugging Trap

What became particularly frustrating was watching the AI models get caught in circular debugging patterns. They would suggest a fix that resolved one issue but inadvertently broke something else. When I reported the new problem, they’d suggest another approach that would fix the new issue but reintroduce the original problem. Then they’d suggest going back to an earlier approach, one we had already tried, without any apparent memory that this path had already been explored and abandoned.

This circular behavior exposed a key limitation: AI models appear to lack persistent memory of what has already been tried in a debugging session. Each reply stands alone, failing to build on the accumulated knowledge of previous failures and their causes, especially after many attempts on a complex task.

The Human Intervention: Strategic Thinking Over Tactical Fixes

After watching multiple frontier AI models struggle with the same fundamental issue, I realized the limitation wasn’t in their coding ability. It was in their approach to the problem. They were trying to solve everything in the frontend, where JavaScript string manipulation and HTML parsing create complex escaping scenarios.

The solution required strategic thinking: move the HTML parsing and manipulation to Python on the backend, where robust libraries like BeautifulSoup could handle the escaping issues that were tripping up the frontend approach.

This wasn’t a coding problem. It was an architectural decision that required understanding the broader context and constraints.

Key Insights: The Current State of AI-Human Collaboration

What AI Models Excel At

  • Rapid prototyping: Generating initial code structures quickly
  • Pattern recognition: Identifying and implementing common programming patterns
  • Documentation and explanation: Providing clear explanations of complex concepts
  • Iteration speed: Making quick modifications based on feedback
  • Straightforward implementations: Building standard CRUD applications, API endpoints, or basic UI components work reliably
  • Well-defined problem domains: Tasks like data transformation, algorithm implementation, or following established frameworks perform excellently

Where AI Models Struggle

The limitations I encountered mirror those identified in the academic research [1]. According to the study, AI struggles with “sweeping scopes involving huge codebases, the extended context lengths of millions of lines of code, higher levels of logical complexity, and long-horizon or long-term planning.” My experience confirms these findings:

  • Meta-coding complexity: Problems that emerge when using JavaScript to generate JavaScript/HTML code, requiring careful escaping and string manipulation. AI models struggle with the multiple layers of interpretation, understanding that a string will later be executed as code, and properly escaping characters that have different meanings in different contexts (HTML entities vs. JavaScript operators vs. string literals)
  • Strategic architecture decisions: Knowing when to abandon an approach entirely
  • Context switching: Recognizing when a problem domain shift is needed
  • Debugging complex interdependencies: Tracing issues across multiple layers of abstraction, similar to the memory safety bug example cited by UC Berkeley’s Koushik Sen, where “you might have to not only fix that bug but change the entire memory management”
  • Circular debugging patterns: Getting trapped in loops of fixes that break and re-break the same issues, resulting in what the research describes as “hallucinations about where the bug is or its root cause, as well as irrelevant suggestions”
  • Persistent debugging memory: Remembering what approaches have already been tried and failed
  • Complex code modifications: When asked to modify code with intricate logic and many dependencies, AI often introduces regressions or fails to propagate changes throughout the codebase, requiring multiple attempts to achieve the desired outcome

The Power of Human Guidance

The breakthrough came not from better prompting or trying yet another AI model, but from human strategic thinking:

  1. Problem reframing: Recognizing that the issue wasn’t coding skill but architectural approach
  2. Domain expertise: Understanding that browser JavaScript has different constraints than server-side processing
  3. Pattern recognition: Seeing that multiple AI models were making the same category of error
  4. Strategic patience: Knowing when to stop iterating on tactical fixes and step back for strategic thinking

The Interface Problem: Beyond Prompt Engineering

The academic research highlights a crucial insight that became apparent in my experience: current AI coding interfaces are fundamentally limited. Solar-Lezama warns that if “it takes longer to explain to the system all the things you want to do and all the details of what you want to do, then all you have is just programming by another name” [1]

This resonates deeply with my chart management project. The amount of context and detail required to get AI models to understand the multi-layered JavaScript generation problem often exceeded the effort of solving it directly. As University of Notre Dame’s Shreya Kumar observes, “we’re adapting to the tool, so instead of the tool serving us, we’re serving the tool” [1].

The research suggests that future AI systems need to “learn to quantify uncertainty and communicate proactively, asking for clarification or more information when faced with vague instructions.” Sen adds that AI models are often “missing context that I have in my mind as a developer – hidden concepts that are embedded in the code but hard to decipher from it” [1].

The Spectrum of AI Coding Capability

It’s important to note that this experience doesn’t represent all AI-assisted coding scenarios. The same models that struggled with the HTML parsing and JavaScript escaping issues performed admirably on simpler, more straightforward tasks throughout the project:

  • UI components: Creating responsive layouts, form handling, and standard web components worked flawlessly
  • Data processing functions: Writing utilities to parse JSON configurations and transform chart data was handled excellently
  • API integration: Building REST endpoints and handling HTTP requests required minimal human intervention
  • Algorithm implementation: Standard sorting, filtering, and data manipulation functions were generated correctly on first try

The complexity threshold seems to emerge when multiple systems interact in unexpected ways, browser parsing behavior, JavaScript execution contexts, and HTML entity encoding created a perfect storm that exceeded current AI capabilities.

Lessons for AI-Assisted Development

For Developers

  • Use AI for rapid exploration, but be prepared to provide strategic direction
  • Watch for iteration loops – if multiple revisions aren’t converging on a solution, the approach may be fundamentally flawed
  • Maintain domain expertise – AI is a powerful tool, but human understanding of system constraints remains crucial
  • Don’t be afraid to change domains – sometimes the solution lies in a different technology stack
  • Design for modularity: Structure your code as modularly as possible, this makes it easier to maintain, enables isolated enhancements of specific components, and allows you to leverage multiple LLMs for different modules when one doesn’t perform well enough or when you need a fresh perspective on a particular piece

For the AI Development Community

This experience highlights areas where current models could improve:

  • Better error pattern recognition: Understanding when repeated similar errors indicate architectural rather than implementation problems
  • Cross-domain problem solving: Suggesting technology stack changes when hitting domain-specific limitations
  • Strategic vs. tactical thinking: Developing better instincts for when to abandon an approach entirely

The Evolution of AI-Human Coding

The research community is optimistic about addressing current limitations. Roychoudhury believes many challenges “would be solved relatively quickly” and sees promise in agentic AI approaches. Sen points to evolutionary algorithms and projects like AlphaEvolve that use genetic algorithms to continuously improve solutions [1].

However, the trust question remains paramount. As Kumar emphasizes, “if you want a trustworthy system, you do need to have humans in the loop”. Roychoudhury acknowledges that AI probably won’t gain developers’ “complete trust as a team member and thus might not be allowed to do its tasks fully autonomously” [1].

The future, as Solar-Lezama suggests, isn’t about replacing human developers but enabling them to “work at a different level of abstraction”^1. The question isn’t whether AI will become a “real coder,” but how it will integrate into development teams and what the human-AI boundary will look like.

The Future of AI-Human Collaboration

Rather than seeing AI limitations as failures, this experience reinforced the value of true collaboration. Current AI models, despite their impressive capabilities, cannot yet replace software engineers, they lack the strategic thinking, persistent problem-solving memory, and architectural intuition that complex software development requires.

The AI models provided incredible value in rapid prototyping and implementation, while human strategic thinking provided the architectural guidance needed to overcome fundamental constraints.

The most effective approach combined:

  • AI speed and pattern matching for implementation
  • Human strategic thinking for architecture and problem reframing
  • Iterative collaboration where each party contributes their strengths

As AI models continue to evolve, the sweet spot likely isn’t replacing human developers but creating more sophisticated collaboration patterns where both human and artificial intelligence contribute their unique capabilities to solving complex problems.

As Solar-Lezama notes, “a big part of software development is building a shared vocabulary and a shared understanding of what the problem is and how we want to describe these features” [1]. This collaborative aspect, the ability to create shared mental models and architectural metaphors, remains distinctly human.

The future of coding isn’t about AI versus humans. It’s about AI with humans, each bringing irreplaceable strengths to the development process. While AI excels at rapid implementation and pattern recognition, the human role in providing strategic direction, architectural oversight, and persistent problem-solving context remains not just valuable, but essential.


References:

  1. Caballar, R. D. (2025). “Will AI Ever Fully Replace Human Coders?” IEEE Spectrum. Retrieved from https://spectrum.ieee.org/ai-for-coding