Conquering Complexity: Refactoring JavaScript Projects

Rate this content
Bookmark

One of the most common issues in JavaScript code bases is that our code is too complex. As projects and their requirements evolve, complexity creeps in. Excess complexity slows progress, frustrating us as we try to keep large chunks of a program in our heads just to understand what is happening.


To conquer complexity, we must refactor! In this talk, we'll investigate how to identify unnecessary complexity in our code base using cognitive complexity as a measure, how to approach refactoring complex code, and what tools are available to help us refactor. We'll put it all into practice through a live example. By the end of the talk, you'll be excited to tackle that 1000-line monstrosity of a function in your own code base (you know the one).

This talk has been presented at JSNation 2024, check out the latest edition of this JavaScript Conference.

FAQ

Phil Nash is a developer relations engineer at Datastacks.

Datastacks is a company behind AstroDB, a serverless vector database used for building generative AI applications.

You can find Phil Nash on various social networks like Twitter, Mastodon, and LinkedIn.

Complexity in coding refers to the inherent difficulty in modeling real-world scenarios in programming languages such as JavaScript or TypeScript. It involves managing the complexity to keep codebases understandable and maintainable.

Cyclomatic complexity, invented in 1976, is a metric that scores a function based on the number of breaks in the flow, such as loops or conditionals. It helps in determining the number of tests needed to cover a function.

Cognitive complexity, introduced by Sona in 2016, measures how human-readable and understandable code is. It scores breaks in flow and nesting levels to reflect the mental effort required to read and understand the code.

You can reduce complexity in code by understanding where the complexity is, inverting conditions, exiting early, collapsing structures, extracting helper methods, and using modern language features like optional chaining and nullish coalescing operators.

Tools like Sona cloud, Sona cube, Sona lint, and the ESLint plugin Sona JS can help measure cognitive complexity in your code.

Test coverage is important when refactoring code to ensure that the refactored code still behaves the same way as before. Tests should cover what the function does, not how it does it.

If a complex piece of code doesn't need to be changed, it's best to do nothing. Changing code that doesn't need it can introduce risks without providing benefits.

Phil Nash
Phil Nash
21 min
17 Jun, 2024

Comments

Sign in or register to post your comment.

Video Summary and Transcription

Today's Talk explores the complexity in code and its impact. It discusses different methods of measuring complexity, such as cyclomatic complexity and cognitive complexity. The importance of understanding and conquering complexity is emphasized, with a demo showcasing complexity in a codebase. The Talk also delves into the need for change and the role of refactoring in dealing with complexity. Tips and techniques for refactoring are shared, including the use of language features and tools to simplify code. Overall, the Talk provides insights into managing and reducing complexity in software development.

1. Introduction to Complexity

Short description:

Today, I want to talk about complexity in our code. Our jobs are complex as we have to model real-life things in programming languages. Let's explore what complexity means and how it affects our code.

What's up, everybody? My name is Phil Nash, and I'm a developer relations engineer at Datastacks. Datastacks is a company behind AstroDB, which is a serverless vector database that you can use to build your generative AI applications. Again, my name's Phil Nash. If you need to find me anywhere on the internet, I will be Phil Nash, and Twitter, Mastodon, whatever social network you're using at the moment, even LinkedIn, my goodness. Anyway, what I want to talk to you about today is complexity, complexity in our code. So let's start by talking about what I mean by complexity. You see, our jobs are complex. We often have to model real-life, real-world things the medium of JavaScript or TypeScript or any other kind of language. And the world itself is inherently complex, and then we just add to that by trying to turn it into code. And code, therefore, itself is inherently complex.

2. Measuring Complexity and Cyclomatic Complexity

Short description:

Our job is managing complexity, and we need a method of measuring it in our code. Let's examine the complexity of functions through examples. Cyclomatic complexity, invented in 1976, gives a score to a function based on its flow breaks, such as loops and conditionals.

What we want to avoid doing is actually just adding any more complexity to our applications than the problem that we're trying to solve demands itself. And ultimately, this means that our job becomes managing complexity. As long as we can keep on top of this complexity, then our codebases stay sane, easy to understand, and easy to work on over time and over changes of team and all sorts of things like that.

So our job is managing complexity. However, last year at some other conferences, I gave a talk in which I looked into the top five issues in JavaScript projects that could be discovered by static analysis, and in at number two was the fact that the complexity of functions in our projects was just too high. And so that's a problem. That's why I wanted to give this talk to get over that. And so really the question is, what is too high? We need a method of measuring our complexity in our code. And so how might we go about that? How do we measure complexity?

Well, first of all, let me, if I showed you a piece of code, if I showed you a function like this, a sum of prime numbers, and asked you how complex is it, just have a think about what you might answer and how useful that would be. There is obviously some complexity here. We've got some loops. We've got some conditionals. We're dealing with prime numbers. That's going to be complex. And then we've got this other function. This is a get words function. We pass in a number and it returns words like one, a couple, a few, many, or lots. It's a big switch statement. How complex is this? Well, there have been ways to measure complexity that have come, been invented over the years. Back in 1976, cyclomatic complexity was invented. Cyclomatic complexity gives a score to a function based on a couple of things. Mainly it adds scores for when a function has a break in flow. That is, when there is a loop or a conditional for the most part. And so if we look at our sum of prime numbers function, cyclomatic complexity actually scores one for being a function. Everything starts as one. So it starts up there. And then we score one for this first four loop. There's a second four loop which scores one. There's a conditional. And then there's another conditional at the bottom.

Check out more articles and videos

We constantly think of articles and videos that might spark Git people interest / skill us up or help building a stellar career

The Future of Performance Tooling
JSNation 2022JSNation 2022
21 min
The Future of Performance Tooling
Top Content
Today's Talk discusses the future of performance tooling, focusing on user-centric, actionable, and contextual approaches. The introduction highlights Adi Osmani's expertise in performance tools and his passion for DevTools features. The Talk explores the integration of user flows into DevTools and Lighthouse, enabling performance measurement and optimization. It also showcases the import/export feature for user flows and the collaboration potential with Lighthouse. The Talk further delves into the use of flows with other tools like web page test and Cypress, offering cross-browser testing capabilities. The actionable aspect emphasizes the importance of metrics like Interaction to Next Paint and Total Blocking Time, as well as the improvements in Lighthouse and performance debugging tools. Lastly, the Talk emphasizes the iterative nature of performance improvement and the user-centric, actionable, and contextual future of performance tooling.
Rome, a Modern Toolchain!
JSNation 2023JSNation 2023
31 min
Rome, a Modern Toolchain!
Top Content
Rome is a toolchain built in Rust that aims to replace multiple tools and provide high-quality diagnostics for code maintenance. It simplifies tool interactions by performing all operations once, generating a shared structure for all tools. Rome offers a customizable format experience with a stable formatter and a linter with over 150 rules. It integrates with VCS and VLSP, supports error-resilient parsing, and has exciting plans for the future, including the ability to create JavaScript plugins. Rome aims to be a top-notch toolchain and welcomes community input to improve its work.
Improving Developer Happiness with AI
React Summit 2023React Summit 2023
29 min
Improving Developer Happiness with AI
Watch video: Improving Developer Happiness with AI
GitHub Copilot is an auto-completion tool that provides suggestions based on context. Research has shown that developers using Copilot feel less frustrated, spend less time searching externally, and experience less mental effort on repetitive tasks. Copilot can generate code for various tasks, including adding modals, testing, and refactoring. It is a useful tool for improving productivity and saving time, especially for junior developers and those working in unfamiliar domains. Security concerns have been addressed with optional data sharing and different versions for individuals and businesses.
Static Analysis in JavaScript: What’s Easy and What’s Hard
JSNation 2023JSNation 2023
23 min
Static Analysis in JavaScript: What’s Easy and What’s Hard
Static analysis in JavaScript involves analyzing source code without executing it, producing metrics, problems, or warnings. Data flow analysis aims to determine the values of data in a program. Rule implementation in JavaScript can be straightforward or require extensive consideration of various cases and parameters. JavaScript's dynamic nature and uncertainty make static analysis challenging, but it can greatly improve code quality.
Automate the Browser With Workers Browser Rendering API
JSNation 2024JSNation 2024
20 min
Automate the Browser With Workers Browser Rendering API
The Talk discusses browser automation using the Worker's Browser Rendering API, which allows tasks like navigating websites, taking screenshots, and creating PDFs. Cloudflare integrated Puppeteer with their workers to automate browser tasks, and their browser rendering API combines remote browser isolation with Puppeteer. Use cases for the API include taking screenshots, generating PDFs, automating web applications, and gathering performance metrics. The Talk also covers extending sessions and performance metrics using Durable Objects. Thank you for attending!
How I Automated Code Changes for 100 Repositories: Getting Started With Codemods
React Day Berlin 2022React Day Berlin 2022
28 min
How I Automated Code Changes for 100 Repositories: Getting Started With Codemods
This Talk discusses automating code changes for Android repositories, utilizing tools like JSCodeShift and Abstract Syntax Tree. The speaker shares a real use case example of maintaining a design system library and making changes to a component. The talk emphasizes the importance of automating repetitive tasks and using the power of abstract syntax tree for code changes. The Q&A session covers topics like source code formatting, TypeScript support, and cultural embedding of code mods. The talk concludes with insights on when automation is worth it and the limitations of code mods for monorepo changes.

Workshops on related topic

Solve 100% Of Your Errors: How to Root Cause Issues Faster With Session Replay
JSNation 2023JSNation 2023
44 min
Solve 100% Of Your Errors: How to Root Cause Issues Faster With Session Replay
WorkshopFree
Ryan Albrecht
Ryan Albrecht
You know that annoying bug? The one that doesn’t show up locally? And no matter how many times you try to recreate the environment you can’t reproduce it? You’ve gone through the breadcrumbs, read through the stack trace, and are now playing detective to piece together support tickets to make sure it’s real.
Join Sentry developer Ryan Albrecht in this talk to learn how developers can use Session Replay - a tool that provides video-like reproductions of user interactions - to identify, reproduce, and resolve errors and performance issues faster (without rolling your head on your keyboard).