Skip to content

Latest commit

 

History

History

README.md

Split Code

This document was created to define clear criteria and ways to refactor code.
Although the principles described are universal in themselves,
the absolute meanings described in them may be adapted
depending on the context of the project and development.

Also remember that due to development time constraints and constantly changing business requirements,
you will not be able to achieve a perfect result.
But keeping 80% of your code clean is more than great and will allow you to save in a project:

Cognitive Complexity

An objective metric for identifying refactoring sites can be "Cognitive Complexity". Its high scores clearly indicate files that need improvement. All approaches described here are aimed at reducing the overall complexity in each file.
CodeClimate - Cognitive Complexity
G. Ann Campbell - SonarSource - Cognitive Complexity
eslint-plugin-sonarjs - cognitive-complexity
JetBrains - plugin - CognitiveComplexity


Move Out Nested callbacks

Move Out Nested callbacks - read more
It is recommended to allow only 1 level of nesting. Deeper nesting can be fixed by Dependency injection through Higher-order function.


Reduce Heavy nesting

Reduce Heavy nesting - read more
It is recommended to allow only 2 level of nesting,
move the logic into separate new functions and methods.


Remove Duplicates

Remove Duplicates - read more
It is recommended to immediately move duplicated blocks into separate functions.
And strive to reduce the metric indicating the number of duplicates.


Shorten Files

Shorten Files - read more
The number of lines of code can serve as a trigger for the need to split a file.
It is recommended to shorten files to a maximum length of 250 lines.
To do this, you can turn larger files into folders,
moving all independent functions into new small files.


Slice Long Functions

Slice Long Functions - read more
It can be difficult to understand the long chain of sequential instructions. It is recommended to separate sequential instructions into logical blocks
and bring them into separate functions.


Use One "third party API" per file

Use One "third party API" per file - read more
Transferring the direct use of third-party libraries and APIs into separate modules (Adapters)
helps to isolate the business logic from the implementation details of the tools.


Sustain Single Responsibility

Sustain Single Responsibility - read more
By creating and dedicating one simple and clear task to each function, you simultaneously:

  • Make it easier to understand
  • Make it reusable in the future
  • Facilitate refactoring and collaboration

❌ BAD
const compareTwoPages = async ({pageOneId, pageTwoId}) => {
    console.log(`Start read pages: ${pageOneId}; ${pageTwoId}`);

    const fileOnePromise = fsPromises.readFile(
        `pagesDir/${pageOneId}.html`,
        {encoding: 'utf8'}
    ).then((fileContent) => {
        console.log(`File read: pagesDir/${pageOneId}.html`);
        return fileContent;
    }).catch((error) => {
        console.error(`Cant read file: pagesDir/${pageOneId}.html`, error)
        throw new Error(`Cant read page: ${pageOneId}`);
    });

    const fileTwoPromise = fsPromises.readFile(
        `pagesDir/${pageTwoId}.html`,
        {encoding: 'utf8'}
    ).then((fileContent) => {
        console.log(`File read: pagesDir/${pageTwoId}.html`);
        return fileContent;
    }).catch((error) => {
        console.error(`Cant read file: pagesDir/${pageTwoId}.html`, error)
        throw new Error(`Cant read page: ${pageTwoId}`);
    });

    return (await fileOnePromise) === (await fileTwoPromise);
};
✔ GOOD
// logger
const writeLog = ({message, data}) => (
    console.log(message, data)
);

const writeError = ({message, error}) => (
    console.log(message, error)
);
// array helpers
const isAllInArrayAreEqual = (arr) => (
    arr.every((element) => element === arr[0])
);
// file service
const DEFAULT_FILE_PARAMS = {encoding: 'utf8'};

const createFilePath = ({directory, fileName}) => (
    `${directory}/${fileName}`
);

const readFileContent = async (filePath) => (
    await fsPromises.readFile(
        filePath,
        DEFAULT_FILE_PARAMS
    )
);
// pages service
const PAGES_DIRECTORY = 'pageDir';
const PAGES_FILE_FORMAT = 'html';

const createPageFilePath = (pageId) => (
    createFilePath({
        directory: PAGES_DIRECTORY,
        fileName: `${pageId}.${PAGES_FILE_FORMAT}`
    })
);
// compareTwoPages resolver
const handlePageReadError = ({filePath, error}) => {
    writeError({message: `Cant read file: pagesDir/${filePath}.html`, error})
    throw new Error(`Cant read page: ${filePath}`);
};

const readPageContent = (pageId) => {
    const filePath = createPageFilePath(pageId);

    writeLog(`File read: ${filePath}`);

    return readFileContent(filePath).catch((error) => {
        handlePageReadError({filePath, error});
    });
};

const compareTwoPages = async ({pageOneId, pageTwoId}) => {
    const pagesArray = [pageOneId, pageTwoId];

    writeLog({message: `Start read pages: ${pagesArray.join('; ')}`});

    return await isAllInArrayAreEqual(
        await Promise.all(
            pagesArray.map(readPageContent)
        )
    );
}

Back to Code Guide - Readme


Copyright © 2017 Stanislav Kochenkov