Human Who Codes Newsletter - Static Analysis and AI


Static Analysis and AI

If you’re like me, the way you write code has changed significantly in the past year. December 2024 was the first time I decided to use AI to write code, and today it generates most of the code I work on. It also writes the tests and documentation. My job is now focused on reviewing code, and that can get tiring. How can I be confident that the code meets my standards, remains secure, and scales well? The answer is static analysis.

Static analysis tools inspect code without executing it, which removes the risk of side effects or security issues that can appear when running tests. This is why static analysis often runs before code execution in continuous integration systems. You may be thinking, “Wait a minute! Don't LLMs perform static analysis on my files to work on them?” The answer is not really.

LLMs read text and look for patterns. Because they have been trained on a large amount of code, they can identify patterns that appear desirable or undesirable. Their analysis is non-deterministic, which means you will not always get the same results even when asking the same question of the same code. LLMs also have no semantic understanding of the code they read. Without semantics, any evaluation becomes a guess.

Traditional static analysis tools are deterministic and understand semantics. For example, ESLint knows the difference between an identifier named foo and the string "foo". To an LLM, these are similar-looking tokens and the interpretation can shift based on context. This makes static analysis even more important for AI-generated code than for human-written code.

Here are some static analysis tools worth integrating, especially if you are deploying AI-generated code:

Linters. As the creator of ESLint, I am a strong supporter of using linters. They are especially important for languages that are not compiled before deployment, such as JSON, YAML, and CSS, because they catch syntax errors before production. As capable as LLMs are, I still encounter incorrect syntax in AI-generated code at least once a week. Many linters also flag problematic patterns even when syntax is valid, which makes them essential for AI-generated code.

Type checkers. Compiled languages include type checking, but others do not. If you are using a language with a type checker, such as TypeScript for JavaScript, make sure to use it to avoid runtime errors.

Accessibility checkers. When working with generated HTML, it is important to verify that the code meets accessibility standards. Accessibility checkers are available both as command line tools and as features built into browser developer tools.

Security scanners. Because LLMs are trained on large amounts of code that may not be verified as safe, AI-generated code often contains security vulnerabilities. Use a security scanner that supports your programming language so you do not deploy code that is open to attack.

Dependency checkers. You should never let AI select a dependency that has not been vetted. Since LLMs are trained on historical data, they often choose outdated dependencies with known security or licensing issues. Make sure your dependencies are automatically checked before deployment.

As AI becomes a larger part of how we write code, static analysis provides a reliable foundation that keeps our work consistent, secure, and maintainable. These tools do not replace the value of human judgment, but they give us confidence that the code we review is structurally sound before we ship it. By pairing AI-assisted development with a strong static analysis pipeline, you set yourself up for faster reviews and higher quality results.

Key Takeaways

  • AI can generate large amounts of code, but static analysis is essential to ensure that the code is secure, consistent, and reliable.
  • LLMs identify patterns but do not understand code semantics, so their output cannot replace deterministic static analysis tools.
  • Integrating linters, type checkers, accessibility tools, security scanners, and dependency checkers provides a safer path to deploying AI-generated code.

Understanding JavaScript Promises

My e-book, Understanding JavaScript Promises, now includes information about Promise.withResolvers() and a whole new chapter on using and creating abortable functions.


Stuff I've Enjoyed this Month

🎬 The line of code that took down the internet by ThePrimeTime
Unless you were offline in November, your work was probably impacted by the Cloudflare outage. This short video explains what happened.

📝 A complete guide to the HTML number input by Ollie Williams
There's a lot to the element that you may not be aware of. This article goes deep on how it works, how to style it, and more.

🎬 Learn the basics of Google Antigravity by Google Antigravity
When Google hired most of the Windsurf team, it was a clue that they were planning on building a code editor. Antigravity is that code editor, and it's a bold step away from the editing experience we're all used to.

💻 TOON Format by Johann Schopplich
Token-Oriented Object Notation (TOON) is an emerging data format designed specifically to minimize token usage by LLMs. It encodes the same data as JSON but with a more concise syntax.

📝 HTML's best kept secret: The tag by Den Odell
I knew about the element, but honestly, completely forgot about it. This is a nice reminder of how semantically useful can be.

🎬 Why Anthropic's AI Claude tried to contact the FBI by 60 Minutes
Anthropic allows Claude to run a vending machine in their building. This short video explains how it does that and what happened when it thought it was the victim of a scam.

📝 How to programmatically highlight text with the CSS Custom Highlight API by Joe Attardi
While researching adding highlights to Bredbox I discovered something called the CSS Custom Highlight API. The name is a bit of a misnomer because it is a JavaScript (DOM) API with CSS to style the highlights.

💻 VERT.sh
Just last week I was lamenting that all online image converters are terrible and sketchy. Enter VERT, a free and open source alternative that does all of the conversion in the browser. And the results are impressive.


What I'm Working On

🏠 Real Estate: I had a tenant unexpectedly leave this past month. It's never good to lose a tenant right at the start of winter because people tend not to want to move when it's cold out. However, my property manager thinks he can get it fixed up and rented out fairly quickly. Fingers crossed. Follow my Instagram for real estate photos.

🍞 Bredbox: Bredbox now gives users complete control over their data. You can import, export, clear data, and delete your account. Imports and exports can now be tracked on the new settings page and you'll get emails when operations complete to let you know if things worked. Plus, there's a new logo I'm pretty happy about.

💻 Open Source: I released several new npm packages with utilities that were extracted from Bredbox:

  • @humanwhocodes/safe-fetch is a drop-in replacement for fetch() that doesn't reject errors. You always get a Response object back and can use that to determine what to do. Forgetting to catch errors on fetch() has brought down some Bredbox services, so I made this to avoid the problem.
  • @humanwhocodes/guarded-fetch is another take on the same problem. Instead of a drop-in replacement, it returns a { response, error } tuple that lets you decide what to do.
  • @humanwhocodes/csv-tools is a small collection of utility functions for working with CSV files.

💻 ESLint:

  • v10.0.0 prereleases are now being published. This will continue until we feel v10.0.0 is fully baked and ready for prime time.
  • I fixed several bugs in ESLint's CSSTree fork to improve CSS parsing.

Coaching for Tech Leads and Staff+ Engineers

If you're a tech lead or staff+ engineer, chances are your manager has no experience in your role. While they may be well-intentioned, they may not know how to help you grow in such a challenging position.

That's where working with me can help. As a former tech lead and principal engineer at multiple companies, I learned firsthand the ins and outs of these roles. I work with my clients one-on-one to develop their leadership, communication, organization, and problem-solving skills to succeed in the upper ranks of the individual contributor track.

Human Who Codes Newsletter

A once-per-month newsletter discussing topics important to senior-level software engineers, with a particular focus on frontend technology and leadership.

Read more from Human Who Codes Newsletter

Working with Legacy Code The term “legacy code” often strikes fear into the hearts of software engineers. While there’s no single definition, IBM describes it as “code that still serves its purpose but was developed using now outdated technologies.” Any successful tech company has some amount of legacy code because that code worked well enough to attract and keep customers. When something is working, especially if it’s difficult to change, the logical choice is often to let it keep running...

npm Security For the past few weeks, an ongoing supply chain attack on npm packages has shaken the JavaScript community. It’s not that npm packages haven’t been compromised before, but this time, the targets were surprising. Attackers went after popular packages maintained by well-known authors, creating the potential for widespread damage. In late August, the popular monorepo tool Nx was compromised, leading to several malicious package versions. These included a postinstall script that...

Code portability If you’ve been following me recently, you’ve probably seen me mention Bredbox, my new application for saving bookmarks. This is the first time in years I’ve built a web application, so I put a lot of thought into the process. My philosophy is to leave as many options open as possible in case I need to change direction later. That’s why I recommend targeting Node.js for JavaScript applications, even if you plan to run them on Deno or Bun. Both Deno and Bun are largely...