Shine a light
Finding a job as a junior developer can be tough. There are only a few open positions and thanks to coding bootcamps we now have a lot of competition.
What can we do?
One option is to hustle harder. Another option is be smarter than the others.
Today I want to show you how you can use linting to improve the code quality of your portfolio projects. Interestingly enough, hardly anybody does it.
Imagine you alarm rings in the morning. You slept terribly because of that important job interview today. It’s winter, and it’s still dark outside. You turn the light on, but the bedroom stays dark. A power outage! There is no light in the bathroom and no light near your wardrobe either.
Now imagine you had to prepare and dress up for today’s job interview in total darkness without any light. Would you feel confident enough to go to that interview? Could you be sure that you’re presenting yourself from your best side? Probably not.
When it comes to our code we are facing a similar situation. Most of us did not shine a light on the code in order to check whether it is clean and readable.
Code is read much more often than it is written.
In a world of ever-changing requirements, we will almost certainly have to touch that code again. Therefore:
The simpler and cleaner the code, the better.
Everyone benefits from clean code. Changes are easier and faster to implement, end-users get features faster, your company saves money, and last but not least, your life as a developer will be so much more relaxed.
Being able to write clean code is an important skill, and the IT companies you really want to work for, look for that skill in their candidates (e.g. by scanning through your portfolio projects). So let’s shine a light.
Linting
A linter is a program that analyses the code without executing it in order to find potential issues. The process of running the linter regularly and fixing found issues is called linting or de-linting.
A linter can be configured to print a warning when the code is not written according to the agreed code conventions. A convention could be to prefer single quotes over double quotes.
Linting can also point out code that leads to common bugs. Using a function with a name that is not spelled like any defined function in the scope could be an indicator for a typo.
You can compare all these small code issues to real-life lint – small fibers or hair on your clothes.
A lint remover can be used to remove the lint and clean the surface of the cloth.
Complexity
Most teams that use a linter on a daily basis stick to a pre-configured linting setup that catches basic issues like violations of code conventions.
In this article, I want to show you how you can use a linter to go beyond what most developers do. I want to show you a couple of linting rules that can help you uncover the worst parts of your code. Once we identified these code sections, we can try improving them.
If you can’t measure it, you can’t improve it.
— Peter Drucker
Code that violates code conventions is harder to read. A more serious problem however, is complex code.
We will use simple and common metrics to measure the complexity of your code.
Lines of Code per File
One of these metrics is Lines of Code (LoC) per File.
The more lines of code a file contains, the more complex the code.
Over the last 20 years, I’ve worked for dozens of companies and clients and I’ve seen the code of hundreds of projects. From time to time, I am confronted with files that contain 500 lines of code or more. Just a few weeks ago, I saw a React component with 3,000 lines of code!
It was really hard for me to understand the code. It violated several principles of good software engineering. The component did all kind of things. It was incomprehensible. It was too complex.
The god of clean code once said:
Functions and classes should be small. Very small.
— Uncle Bob
We can apply the same principle to any file that contains code. I recommend to not allow more than 100 lines of regular JavaScript code.
No more than 100 LoC per JavaScript file
Lines of Code per File is a simple metric, but it is not perfect. That’s why we use multiple metrics in conjunction.
Statements per Function
Another useful metric is Statements per Function.
Every action in our code is represented by a statement. The following code segments has 3 statements:
let answer = 41
answer++
console.log(answer)
I recommend to not allow more than 10 statements per function.
No more than 10 Statements per Function
A file with a function can exceed both, the maximum allowed amount lines per file, and the maximum allowed amount of statements per function.
Overview
So let’s shine some light onto our code and start improving it.
In the following sections we will:
- Prepare the project
- Setup the linter
- Fine-tune the linting rules
- Check the code for problems
- Improve the code
Preparing the Project
First, we need to select a project.
I recommend you chose one of your bigger projects. I will use one of Edith’s portfolio projects. Edith is one of my mentees and agreed to play the guinea pig.
By the way, Edith is located in Berlin and wants to take her full stack career to the next level. Send me a message and I will get you in touch.
Edith’s project is a React project. The lessons from this article can of course be applied to any project. We will use ESLint in this article which is currently the most popular linter for all things JavaScript.
There is a linter for most languages. If your project is written in Java for instance, you might want consider SonarQube.
Before we start, we should check that everything works:
1. Verify app works as expected
Let’s run our test suite and verify that the app works as expected.
If you don’t have a suite of automated tests, start your app and test it manually.
Automated tests and test-driven development are beyond the scope of this article, but I will cover it in one of my upcoming newsletters.
2. Commit all changes
Now, let’s make sure that there are no uncommitted changes.
Once everything works as expected, we should commit all our changes. Should something go wrong, we are able to revert everything back to this state.
3. Verify app works after re-installing
Finally, let’s perform another check to see if our project is working.
Once, everything is committed, let’s pretend that we just cloned the project from GitHub. We can do that by deleting the node_modules
folder and re-installing all dependencies:
rm -rf node_modules
npm install
Make sure to execute these terminal commands in the root folder of your project.
Let’s verify again that the app works as expected.
We are now ready to set up the linter.
If something goes wrong during that process, we can easily go back to this state by:
- Reverting all changes (e.g. with
git checkout .
) - Deleting
node_modules
(rm -rf node_modules
) - Re-installing all dependencies (
npm i
)
Setting up the Linter
Setting up ESLint is usually straight forward. There are some differences depending on the type of project we have in front of us.
1. Check if ESLint is present
Some projects have ESLint already installed. If you have created your app with create-react-app
you will have ESLint installed almost certainly. Let’s check our project’s node_modules
folder for the eslint
dependency:
ls node_modules/eslint
If you see something like ls: node_modules/eslint: No such file or directory
it means ESLint is not installed. If you see something like CHANGELOG.md README.md conf ...
, ESLint is already present in your project.
2. (optional) Install ESLint as dev dependency
Obviously, we would only do that if ESLint is not already present in our project.
npm install --save-dev eslint
3. Add some NPM scripts
This will allow us to run the linter more easily. We open the project’s package.json
and add the follow linter scripts to the scripts
section:
{
"...": "...",
"scripts": {
"...": "...",
"lint": "eslint --ext=js,jsx --ignore-path=.gitignore --max-warnings=0 --color . || true"
}
}
If you’re working on a React app that was created with create-react-app
, you need to set the environment variable EXTEND_ESLINT
to true
(you can tell by whether there is an NPM script "eject": "react-scripts eject"
):
{
"...": "...",
"scripts": {
"...": "...",
"lint": "EXTEND_ESLINT=true eslint --ext=js,jsx --ignore-path=.gitignore --max-warnings=0 --color . || true"
}
}
And if you’re working on a Windows machine, you should use the following configuration:
{
"...": "...",
"scripts": {
"...": "...",
"lint": "set EXTEND_ESLINT=true && eslint --ext=js,jsx --ignore-path=.gitignore --max-warnings=0 --color ."
}
}
Make sure you have a .gitignore
file in your project and that it mentions node_modules
.
4. Run ESLint
Now it’s time to run the linter for the very first time.
On the terminal execute:
npm run lint
In case of Edith’s project, we get 9 linting issues:
> portfolio@1.0.0 lint ./portfolio
> EXTEND_ESLINT=true eslint --ext=js,jsx --ignore-path=.gitignore --max-warnings=0 --color . || true
Warning: React version not specified in eslint-plugin-react settings. See https://github.com/yannickcr/eslint-plugin-react#configuration .
...
./portfolio/src/projectthree.js
21:36 error `'` can be escaped with `'`, `‘`, `'`, `’` react/no-unescaped-entities
./portfolio/src/projecttwo.js
20:36 error `'` can be escaped with `'`, `‘`, `'`, `’` react/no-unescaped-entities
✕ 9 problems (9 errors, 0 warnings)
9 problems. That’s actually not too bad. Most of the above problems can be fixed by replacing the single quotes '
in the listed JSX files with the save HTML escape code '
.
It is common to get hundreds or even thousands of linting issues when setting up ESLint. Often, it is because ESLint tries to lint files that are not supposed to be linted or the configuration of the linting rules does not match the code conventions.
Fine-tuning the Linting Rules
Now that ESLint is set up and working, let’s fine-tune the linting rules. In order to do that, we need an ESLint configuration file.
1. Check ESLint configuration is present
First, let’s check if there is already an ESLint configuration file present in the project.
In the root directory of the project look for one of the following files:
.eslintrc.yml
.eslintrc.js
.eslintrc.json
Another possible location for the config is package.json
. Look for an entry called:
"eslintConfig": {
If you cannot find any ESLint configuration, let’s create one.
2. (optional) Create ESLint config
ESLint comes with a small Q&A-based helper tool to generate an initial ESLint configuration file. Let’s execute it with:
npx eslint --init
Depending on the version of ESLint, the questions and answers will vary a bit. Answer them based on what you know about your project. Don’t worry, if you got something wrong. You can abort and restart, or fix the mistake later in the config file itself.
Here is the Q&A protocol of the current ESLint version for a React app, created with create-react-app
:
✓ How would you like to use ESLint? · problems
✓ What type of modules does your project use? · esm
✓ Which framework does your project use? · react
✓ Does your project use TypeScript? · No / Yes
✓ Where does your code run? · browser, node
✓ What format do you want your config file to be in? · YAML
When being asked to install missing dependencies such as the eslint-plugin-react
, do so unless you are working on a React app, created with create-react-app
. In the later case skip that step.
Here is the Q&A protocol of a slightly older version of ESLint for a React app, created without create-react-app
:
? How would you like to configure ESLint? Answer questions about your style
? Are you using ECMAScript 6 features? Yes
? Are you using ES6 modules? Yes
? Where will your code run? Browser, Node
? Do you use CommonJS? No
? Do you use JSX? Yes
? Do you use React? Yes
? What style of indentation do you use? Spaces
? What quotes do you use for strings? Single
? What line endings do you use? Unix
? Do you require semicolons? No
? What format do you want your config file to be in? YAML
I prefer YAML over JSON when it comes to config files because the syntax is shorter and more readable and YAML supports comments.
Here is a configuration file for a React app, created with create-react-app
:
env:
browser: true
es6: true
node: true
extends:
- react-app
- eslint:recommended
- plugin:react/recommended
globals:
Atomics: readonly
SharedArrayBuffer: readonly
parserOptions:
ecmaFeatures:
jsx: true
ecmaVersion: 2018
sourceType: module
plugins:
- react
rules: {}
Make sure that the first entry of extends
(line 6) is - react-app
. Add it if necessary and remember:
Whitespace for indentation in YAML files matters!
Here is another configuration file for a React app, created without create-react-app
:
env:
browser: true
es6: true
node: true
extends:
- eslint:recommended
- plugin:react/recommended
globals:
Atomics: readonly
SharedArrayBuffer: readonly
parserOptions:
ecmaFeatures:
jsx: true
ecmaVersion: 2018
sourceType: module
plugins:
- react
settings:
react:
version: detect
rules: {}
3. Turn off rules temporarily
Let’s turn off the other rules that cause the current linting issues temporarily.
Today, we want to focus on a couple of linting rules that can help us reduce the complexity of our code.
And in my case I see errors unrelated to complexity, but related to the following two rules: no-unused-vars
and react/no-unescaped-entities
. So let’s turn these rules temporarily off by adding the following rule statements to .eslintrc.yml
:
# ...
rules:
no-unused-vars: off # TODO: remove this line before committing
react/no-unescaped-entities: off # TODO: remove this line before committing
If your configuration is JSON-based, it will look more like this:
{
"...": "...",
"rules": {
"no-unused-vars": "off",
"react/no-unescaped-entities": "off"
}
}
4. Run ESLint again
Finally, let’s run the linter again to see if everything is configured correctly.
npm run lint
We expect to see no linting issues for the time being.
Max Statements
One rule that can help us reduce the complexity of our code and thus make it more readable and maintainable is max-statements
.
Let’s add a rule that limits the maximum amount of allowed statements in a function to 10:
# ...
rules:
# ...
max-statements: [ error, 10 ]
Or in JSON:
{
"...": "...",
"rules": {
"...": "...",
"max-statements": [ "error", 10 ]
}
}
Executing the linter reveals one issue in Edith’s project:
./portfolio/src/cube.js
11:22 error Method 'componentDidMount' has too many statements (17). Maximum allowed is 10 max-statements
The problem is located in line 11 of the file cube.js
:
// ...
export default class Cube extends React.Component {
// ...
componentDidMount() {
// === THREE.JS CODE START ===
var scene = new THREE.Scene()
scene.background = new THREE.Color(0xFFFFFF)
var camera = new THREE.PerspectiveCamera(50, window.innerWidth / window.innerHeight, 0.1, 1000)
var renderer = new THREE.WebGLRenderer()
// renderer.setClearColor(0x000000, 0.5)
renderer.setSize(700, 300)
this.mount.appendChild(renderer.domElement)
var geometry = new THREE.BoxGeometry(1, 1, 1)
var material = new THREE.MeshBasicMaterial({ color: 0x00ff00 })
var cube = new THREE.Mesh(geometry, material)
scene.add(cube)
// cube.position.set(0, 0, 0)
scene.add(cube)
cube.scale.x = 2.5 // SCALE
cube.scale.y = 2.5 // SCALE
cube.scale.z = 2.5 // SCALE
camera.position.z = 5
var animate = function () {
requestAnimationFrame(animate)
cube.rotation.x += 0.01
cube.rotation.y += 0.01
renderer.render(scene, camera)
}
animate()
// === THREE.JS EXAMPLE CODE END ===
}
render() {
return <div className="cube" ref={ref => (this.mount = ref)} />
}
}
How do you feel when you are looking at that code for the first time?
It is a bit overwhelming, isn’t it? It looks complicated, doesn’t it? We also say “it 💩 smells”!
Some developers might even get a bit scared – especially if their task involves changing that code.
Now imagine how a hiring tech lead feels like, when they see this kind of code in your portfolio projects.
The function componentDidMount
violates the Small Function Principle.
The good news:
Thanks to linting, do we know now that this code needs improvement.
Complexity linting rules such as max-statements
are like little 💩 detectors.
What does the above code actually do?
It uses the three.js
library to create and render a 3D animation of a cube:
Let’s reduce the complexity of this code and make it more readable.
In our first iteration, let’s remove all unnecessary comments:
// ...
export default class Cube extends React.Component {
// ...
componentDidMount() {
let scene = new THREE.Scene()
scene.background = new THREE.Color(0xFFFFFF)
let camera = new THREE.PerspectiveCamera(50, window.innerWidth / window.innerHeight, 0.1, 1000)
let renderer = new THREE.WebGLRenderer()
renderer.setSize(700, 300)
this.mount.appendChild(renderer.domElement)
let geometry = new THREE.BoxGeometry(1, 1, 1)
let material = new THREE.MeshBasicMaterial({ color: 0x00ff00 })
let cube = new THREE.Mesh(geometry, material)
scene.add(cube)
scene.add(cube)
cube.scale.x = 2.5
cube.scale.y = 2.5
cube.scale.z = 2.5
camera.position.z = 5
let animate = function () {
requestAnimationFrame(animate)
cube.rotation.x += 0.01
cube.rotation.y += 0.01
renderer.render(scene, camera)
}
animate()
}
render() {
return <div className="cube" ref={ref => (this.mount = ref)} />
}
}
I also replaced var
with the more secure let
.
In general, the majority of comments are not necessary if we write clean code. Good variable and function names as well as short functions and classes usually provide enough context to understand what is happening.
Commenting out code and not deleting it is also a bad practice.
But what if we need that code later on?
We use git version control and are able to retrieve any deleted code at any time. No need to leave commented out code in our files.
It looks like the first half of the function deals with setting up a scene
, a camera
, a renderer
and a cube
. Let’s extract the creation of these entities into helper functions:
// ...
const createScene = () => {
let scene = new THREE.Scene()
scene.background = new THREE.Color(0xFFFFFF)
return scene
}
const createCamera = () => {
let camera = new THREE.PerspectiveCamera(50, window.innerWidth / window.innerHeight, 0.1, 1000)
camera.position.z = 5
return camera
}
const createRenderer = () => {
let renderer = new THREE.WebGLRenderer()
renderer.setSize(700, 300)
return renderer
}
const createCube = () => {
let geometry = new THREE.BoxGeometry(1, 1, 1)
let material = new THREE.MeshBasicMaterial({ color: 0x00ff00 })
let cube = new THREE.Mesh(geometry, material)
cube.scale.x = 2.5
cube.scale.y = 2.5
cube.scale.z = 2.5
return cube
}
export default class Cube extends React.Component {
// ...
componentDidMount() {
const scene = createScene()
const camera = createCamera()
const renderer = createRenderer()
const cube = createCube()
scene.add(cube)
scene.add(cube)
this.mount.appendChild(renderer.domElement)
let animate = function () {
requestAnimationFrame(animate)
cube.rotation.x += 0.01
cube.rotation.y += 0.01
renderer.render(scene, camera)
}
animate()
}
render() {
return <div className="cube" ref={ref => (this.mount = ref)} />
}
}
Let’s look at the code again. How do you feel now? Better?
I do feel better. The code is not perfect and there is more we could do, but reading the first few lines of componentDidMount
is not so overwhelming anymore. It creates a scene, then a camera, the a create renderer, then a cube, then adds the cube to the scene, …
Even if I do not fully understand what a scene is or how it is created, I can get the idea of what’s happening here. If I need to know more, I can look into the corresponding function (e.g. createCube
) and dig deeper into the details. On the higher level of componentDidMount
it doesn’t matter that the camera’s z
coordinate is set to 5
.
The cognitive load onto my brain is lower now. I might even have some capacity left to question why the cube is added twice to the scene (it’s indeed a copy-paste artifact and not necessary).
Let’s run the linter again.
npm run lint
The problem is gone. We successfully reduced the complexity of the code. Our future self and other developers will be thankful.
Max Lines
Another rule that can help make our code cleaner is max-lines
.
Let’s add a rule that limits the maximum amount of lines in a file to 100:
# ...
rules:
# ...
max-lines: [ error, 100 ]
Or in JSON:
{
"...": "...",
"rules": {
"...": "...",
"max-lines": [ "error", 100 ]
}
}
JSX code is a bit different when compared to vanilla JavaScript code, and usually I allow a few more lines in React component files (up to 150). In one of my upcoming newsletters I will cover how to override rule configurations for different file types.
Executing the linter reveals another issue in the project:
./portfolio/src/otherprojects.js
101:1 error File has too many lines (117). Maximum allowed is 100 max-lines
This time the problem is located in file otherprojects.js
.
import React from 'react'
export default class OtherProjects extends React.Component {
// ...
render() {
return (
<React.Fragment>
<div className="op-btm">
<img src="/raccoon.png" className="header-logo" alt="logo" width="45px" height="45px" background="none" />
<a className="op-back " href="http://www.edith....com/" > back to main </a>
</div>
<div className="op-container">
<div className="op-card">
<img src="/connectfourDemo.gif" className="op-img" alt="logo" width="250px" height="150px" />
<div className="op-text">
<h1 className="op-title">connect 4</h1>
<br></br>
<h3 className="op-tech">technologies:</h3>
<p className="op-tech-text">Javascript // HTML// CSS// JSON </p>
<br></br>
<h3 className="op-description">project's description:</h3>
<p className="op-description-text"> sweet 2D connect four!</p>
<br></br>
<a className="op-demo" href="https://edith....github.io/connect-four/" rel="noopener noreferrer" target='_blank'>Demo</a>
<br></br>
<a className="op-github" href="https://github.com/Edith.../connect-four" rel="noopener noreferrer" target='_blank'>Github</a>
</div>
</div>
<div className="op-card">
<img src="/spotifyAPI.gif" className="op-img" alt="logo" width="250px" height="150px" />
<div className="op-text">
<h1 className="op-title" >spotify API</h1>
<br></br>
<h3 className="op-tech">technologies:</h3>
<p className="op-tech-text">Javascript // HTML// CSS// JSON// Spotify API// proxy </p>
<br></br>
<h3 className="op-description">project's description:</h3>
<p className="op-description-text"> search and find the artists you love!</p>
<br></br>
<a className="op-github" href=" https://github.com/Edith.../spotify-API" rel="noopener noreferrer" target='_blank'>Github</a>
</div>
</div>
<div className="op-card">
<img src="/TwickerDemo.gif" className="op-img" alt="logo" width="250px" height="150px" />
<div className="op-text">
<h1 className="op-title">twitter API</h1>
<br></br>
<h3 className="op-tech">technologies:</h3>
<p className="op-tech-text">Javascript // HTML// CSS// JSON// Twitter API</p>
<br></br>
<h3 className="op-description">project's description:</h3>
<p className="op-description-text"> keep track of the hottest news via ticker displaying twitter tweets!</p>
<br></br>
<a className="op-github" href="https://github.com/Edith.../Twicker" rel="noopener noreferrer" target='_blank'>Github</a>
</div>
{/* ... */}
</div>
</div>
<p className="copyright-project">Copyright © 2020 Edith</p>
</React.Fragment >
)
}
}
How do feel when looking at (what is actually only half of) the code?
It is possible to grasp what’s going on, but it is a lot of code.
Let’s do the Squint Test. What do you notice when squinting your eyes and looking at the code?
A repeating structure. Every project listed in this file is represented by what seems to be a card:
{/* ... */}
<div className="op-card">
<img src="/spotifyAPI.gif" className="op-img" alt="logo" width="250px" height="150px" />
<div className="op-text">
<h1 className="op-title" >spotify API</h1>
<br></br>
<h3 className="op-tech">technologies:</h3>
<p className="op-tech-text">Javascript // HTML// CSS// JSON// Spotify API// proxy </p>
<br></br>
<h3 className="op-description">project's description:</h3>
<p className="op-description-text"> search and find the artists you love!</p>
<br></br>
<a className="op-github" href=" https://github.com/Edith.../spotify-API" rel="noopener noreferrer" target='_blank'>Github</a>
</div>
</div>
{/* ... */}
Every card has the same structure:
- image
- title
- technologies
- description
- links
Now imagine, we had to change the order of description and technologies on all cards. We would have to change that for every project. 7 times!
This markup violates the principle of DRY – Don’t Repeat Yourself.
The good news:
ESLint – the 💩 detector – helped us once again spotting the problem. Let’s fix it!
In the previous example we used sub functions to reduce the complexity and make the code more readable. When it comes to React components we can often use sub components to achieve a similar result.
Let’s create a helper component Project
:
import React from "react"
import PropTypes from "prop-types"
const Project = ({ title, imageUrl, technologies, description, links }) => (
<div className="op-card">
<img src={imageUrl} className="op-img" alt="logo" width="250px" height="150px" />
<div className="op-text">
<h1 className="op-title">{title}</h1>
<br />
<h3 className="op-tech">technologies:</h3>
<p className="op-tech-text">{technologies.join(" // ")}</p>
<br />
<h3 className="op-description">project's description:</h3>
<p className="op-description-text">{description}</p>
{links.map(link => (
<>
<br />
<a className="op-demo" href={link.url} rel="noopener noreferrer" target='_blank'>{link.title}</a>
</>
))}
</div>
</div>
)
Project.propTypes = {
title: PropTypes.string.isRequired,
imageUrl: PropTypes.string.isRequired,
technologies: PropTypes.arrayOf(PropTypes.string).isRequired,
description: PropTypes.string.isRequired,
links: PropTypes.arrayOf(PropTypes.shape({
title: PropTypes.string.isRequired,
url: PropTypes.string.isRequired,
})).isRequired,
}
export default Project
The Project
component is a stateless component, and we decided to use the shorter functional component style.
The property technologies
is an array of strings and we join it in line 11 into a single string where all listed technologies are separated with a double slash //
.
The property links
is an array of small objects. Each object has a title
and a url
. We use the map
function to convert each link
into an <a>
tag (prepended with a <br>
tag).
A good practice is to provide a PropType definition (line 25) to describe the type of each property and whether a property is required or optional.
Now let’s use the new Project
component in otherprojects.js
:
import React from 'react'
import Project from './project'
export default class OtherProjects extends React.Component {
// ...
render() {
return (
<React.Fragment>
<div className="op-btm">
<img src="/raccoon.png" className="header-logo" alt="logo" width="45px" height="45px" background="none" />
<a className="op-back " href="http://www.edith....com/" > back to main </a>
</div>
<div className="op-container">
<Project
title="connect 4"
imageUrl="/connectfourDemo.gif"
technologies={[ "Javascript", "HTML", "CSS", "JSON" ]}
description="sweet 2D connect four!"
links={[
{ title: "Demo", url: "https://edith....github.io/connect-four/" },
{ title: "Github", url: "https://github.com/edith.../connect-four" },
]}
/>
<Project
title="spotify API"
imageUrl="/spotifyAPI.gif"
technologies={[ "Javascript", "HTML", "CSS", "JSON", "Spotify API", "proxy" ]}
description="search and find the artists you love!"
links={[ { title: "Github", url: "https://github.com/edith.../spotify-API" } ]}
/>
<Project
title="twitter API"
imageUrl="/TwickerDemo.gif"
technologies={[ "Javascript", "HTML", "CSS", "JSON", "Twitter API" ]}
description="keep track of the hottest news via ticker displaying twitter tweets!"
links={[ { title: "Github", url: "https://github.com/edith.../Twicker" } ]}
/>
{/* ... */}
</div>
<p className="copyright-project">Copyright © 2020 Edith</p>
</React.Fragment >
)
}
}
Let’s look at otherprojects.js
again. How do you feel now?
I feel that the intention of the file is more obvious. It contains a list of projects. And I can immediately grasp what a project is made of.
The code is again not perfect and there is more we could do, but it is more readable now.
Changing the order of description and technology is now a quick and easy task, performed by swapping a few lines in project.js
. It will automatically be applied to all projects.
First make the change easy, then make the easy change.
— Kent Beck
Let’s run the linter again.
npm run lint
The problem is gone. We reduced the size of otherprojects.js
from 117 to 75 lines of code.
Cleanup
It’s time to re-enable the temporarily disabled linting rules by deleting the lines we added earlier.
We should also commit our changes.
Summary
Here are the steps that brought us here today:
- Prepare project – First, we prepared the project by making sure that there are no uncommitted changes.
- Setup linter – Then, we installed ESLint and added convenient NPM scripts to execute it regularly.
- Fine-tune linting rules – Next, we fine-tuned the linting rules by adding rules that measure the complexity.
- Check code for problems – Then, we ran the linter in order to find problematic code.
- Improve code – And finally, we refactored the code in order to reduce its complexity.
The big takeaway is that static code analysis tools such as ESLint can be used to measure the complexity of code, and to enforce simpler and cleaner code in your projects.
Utilize static code analysis tools to enforce writing simpler code
I recommend continuing improving your project code and running the linter regularly. It’s a great opportunity to practice refactoring, and you can train the habit of writing clean code.
Your (future) employer will appreciate it.
And don’t forget to mention ESLint on your list of skills!
What’s next?
There is obviously much more to linting and static code analysis. We covered only two of hundreds of rules, and you might have further questions like:
- Is there a way to automatically fix linting issues? (yes, there is)
- How often should I run the linter?
- How do I introduce linting in my team?
- Can I automate running the linter? (yes, you can)
- How do I exclude certain code sections from the linting process?
- What to do when I don’t have time to fix hundreds of issues now? (there’s a technique called ratcheting)
I will cover answers to all these questions and much more in my Test-first newsletters. So if you liked this article and if you are interested in learning more about smart software engineering skills, feel free to sign up here.
See you around,
-David