Take Stock of Your Application With Static Code Analysis Tools
Whether you’re joining a team to work on an existing application, or just want to get a better idea of the status of the application you’ve been working on for a while, static analysis tools can help.
These tools can provide you with a better sense of the size and scope of your application, its architecture, and provide insight into areas of importance, high complexity, low test coverage or poor testability, and more.
Of course, these tools are no substitute for human review and team discussion, but they certainly can be used to expedite that process.
cloc
(Count Lines of Code)
cloc
is a
command-line tool that counts lines of code (LOC) in a given directory or file.
It can be used to get an idea of the size of a codebase and to track changes in code size over time. It will also identify what languages are used in each file and separate out blank lines, comments, and actual “source lines of code” (SLOC ).
LOC statistics can give you an idea of how large your application is, as well as find large files or directories that could be an indicator of places that could use refactoring.
cloc
is a very powerful tool that can do many things, including running a diff
between directories or tarballs, etc, to tell you how the LOC stats differ.
Here is an example of running cloc
on the Express codebase:
$ npx cloc ./
228 text files.
214 unique files.
15 files ignored.
github.com/AlDanial/cloc v 1.96 T=0.38 s (567.2 files/s, 75935.9 lines/s)
--------------------------------------------------------------------------------
Language files blank comment code
--------------------------------------------------------------------------------
JavaScript 153 4251 2497 16409
Markdown 12 848 0 3764
YAML 3 41 28 259
EJS 19 27 0 214
JSON 1 0 0 99
Handlebars 3 5 0 71
CSS 4 1 0 44
HTML 7 2 0 42
make 1 2 0 15
Bourne Again Shell 1 5 0 13
Text 10 0 0 13
--------------------------------------------------------------------------------
SUM: 214 5182 2525 20943
--------------------------------------------------------------------------------
We can see that the application is written almost entirely in JavaScript, with supporting documentation, configuration, scripts, and front-end templates and code.
At roughly 16.5K SLOC, it’s not as large of a code base as I might have expected. Let’s get a sense of how the code is structured.
Next I’d like to see what some of the largest JavaScript files are, so I will run:
$ npx cloc --include-lang=JavaScript --by-file ./
228 text files.
214 unique files.
76 files ignored.
github.com/AlDanial/cloc v 1.96 T=0.41 s (369.1 files/s, 55859.6 lines/s)
----------------------------------------------------------------------
File blank comment code
----------------------------------------------------------------------
./test/res.sendFile.js 262 0 1150
./test/express.urlencoded.js 134 0 732
./test/express.static.js 122 6 686
./test/express.json.js 119 1 670
./test/app.router.js 255 312 544
...
I’m truncating the full report as it’s pretty long. But I can quickly see that
a large portion of the JavaScript code is in the test
and examples
. This
seems good - we likely have a well-tested codebase with many examples of
how to use it!
Now I’m interested in the actual application code, so I will filter out those two directories:
$ npx cloc --exclude-dir=test,examples --include-lang=Javascript --by-file ./
33 text files.
29 unique files.
21 files ignored.
github.com/AlDanial/cloc v 1.96 T=0.02 s (835.4 files/s, 267381.1 lines/s)
----------------------------------------------------------------------------------------
File blank comment code
----------------------------------------------------------------------------------------
./lib/response.js 157 475 537
./lib/router/index.js 124 160 389
./lib/application.js 109 275 277
./lib/request.js 72 287 166
./lib/utils.js 51 126 126
./lib/router/route.js 48 72 110
./lib/router/layer.js 34 58 89
./lib/view.js 38 68 76
./lib/express.js 20 33 63
./lib/middleware/query.js 9 16 22
./lib/middleware/init.js 9 20 14
./benchmarks/middleware.js 6 1 13
./index.js 2 7 2
----------------------------------------------------------------------------------------
SUM: 679 1598 1884
----------------------------------------------------------------------------------------
Wow! It looks like the whole Express framework is less than 2,000 lines of code. That’s pretty impressive for the amount of work this framework does in so many production applications.
Now we’ve got a pretty good sense of the size of this codebase, the languages used, and the amount of test and example code. That’s good to know, and we may be curious to open some of the largest files and see what they look like.
But there are more tools we can use to glean more “big picture” knowledge about the state of this application before we even dig into code and code quality analysis.
First, let’s see if the package.json
declares what versions of Node it supports:
$ npm view ./ engines
{ node: '>= 0.10.0' }
We can see that it is quite backwards compatible, supporting all the way back to
version 0.10.0
of Node. That’s great. I wonder how many of its dependencies
support that far back.
With our open source tool ,
depngn
we can check this!
depngn
(Node Compatibility)
We can run depngn
with this command:
$ npx depngn 0.10.0
╔═════════════════════════════════════════════════════════════════════╗
| |
| Node version: 0.10.0 |
| |
|=====================┬============┬==================================|
package │ compatible │ range
|=====================┼============┼==================================|
accepts │ true │ >= 0.6
|=====================┼============┼==================================|
after │ undefined │ n/a
|=====================┼============┼==================================|
array-flatten │ undefined │ n/a
|=====================┼============┼==================================|
body-parser │ true │ >= 0.8
|=====================┼============┼==================================|
connect-redis │ true │ *
|=====================┼============┼==================================|
content-disposition │ true │ >= 0.6
|=====================┼============┼==================================|
content-type │ true │ >= 0.6
|=====================┼============┼==================================|
cookie-parser │ true │ >= 0.8.0
|=====================┼============┼==================================|
cookie-session │ true │ >= 0.10
|=====================┼============┼==================================|
...
It looks like most of the critical dependencies are quite backwards compatible.
The few that failed were devDependencies
like ESLint
and mocha
. So that’s
encouraging.
npm audit
(Known Security Issues)
We should also run npm audit
to see if any dependencies have known
vulnerabilities:
$ npm audit
# npm audit report
marked <=4.0.9
Severity: high
Inefficient Regular Expression Complexity in marked - https://github.com/advisories/GHSA-5v2h-r2cx-5xgj
Inefficient Regular Expression Complexity in marked - https://github.com/advisories/GHSA-rrrm-qjm4-v8hf
fix available via `npm audit fix --force`
Will install marked@4.2.12, which is a breaking change
node_modules/marked
redis 2.6.0 - 3.1.0
Severity: high
Node-Redis potential exponential regex in monitor mode - https://github.com/advisories/GHSA-35q2-47q7-3pc3
fix available via `npm audit fix --force`
Will install connect-redis@7.0.1, which is a breaking change
node_modules/redis
connect-redis 3.4.0 - 4.0.1
Depends on vulnerable versions of redis
node_modules/connect-redis
3 high severity vulnerabilities
To address all issues (including breaking changes), run:
npm audit fix --force
Hmm, looks like 3 packages have vulnerabilities, with the root causes being
the marked
and redis
packages. But the recommended patched versions also
contain breaking changes. This will likely require some exploration.
npm-check
(Known Security Issues)
While we’re looking at dependencies’ versions, we can get an idea of how up-to-date they are. Are we using recent versions, or are we way behind?
npm-check
is a great tool for this.
Seems like there are definitely some outdated packages in there, though this
also pointed out that redis
is only used in an example file, and not in the
main codebase, so we can probably ignore that for now!
Conclusion
All these tools have given us a pretty good bird’s eye view of how large our application is, and how healthy its dependencies are.
But there is more we can find out! In subsequent posts we will take a look at how we can gain insight into the quality and complexity of the code, the architecture, and testability and coverage!
Did I miss any tools you love? Share this article in Reddit and we can start a discussion about it! ❤️