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.