A
A
alex4answ2020-09-09 21:36:55
Express.js
alex4answ, 2020-09-09 21:36:55

How to deal with template code, redundant decomposition?

Good evening, one of the main problems of my projects is repetition and template code, which violates DRY, I strive for maximum decomposition, but in my opinion this is often redundant and complicates the project.

For example, there is a middleware Multer (file upload):

// categoryRouter.js
const fileFilter = (req, file, cb) => {
  const allowedMimeType = ['image/png', 'image/jpeg', 'image/jpg'];
  if (allowedMimeType.includes(file.mimetype) {
    cb(null, true);
  } else {
    cb(new Error('Invalid file type'));
  }
};

const storage = multer.diskStorage({
  destination: (req, file, cb) => {
    cb(null, path.resolve('public/uploads/categories'));
  },
  filename: (req, file, cb) => {
    cb(null, `${uuidv4()}${path.extname(file.originalname)}`);
  }
});

router.post('/:slug/uploadImage', multer({ storage, fileFilter }).single('image'), (req, res) => {
  // сохранить путь в бд
});


This piece is repeated from module to module, only the destination (path) of saving and fileFilter (file validator) change, it seems logical to me to decompose this code like this:
fileHelper.js

Проверка на MimeType, генерация уникального имени файла уходят в отдельный модуль-хелпер
// fileHelper.js
exports.isImage = ({ mimetype }) => ['image/png', 'image/jpeg', 'image/jpg'].includes(mimetype);

exports.getUniqueFileName = (originalName) => `${uuidv4()}${path.extname(originalName)}`;


fileFilter

fileFilter уходит в отдельный модуль - utils
// fileFilter.js
module.exports = (fileValidation) => {
  return (req, file, cb) => {
    if (fileValidation(file)) {
      cb(null, true);
    } else {
      cb(new Error('Invalid file type'));
    }
  };
};


Factory multer (uploadImage)

storage не вижу смысла выносить отдельно-
module.exports = (destination) => {
  const filter = fileFilter(fileHelper.isImage);
  const storage = multer.diskStorage({
    destination: (req, file, cb) => {
      cb(null, destination);
    },
    filename: (req, file, cb) => {
      cb(null, fileHelper.getUniqueFileName(file.originalname));
    }
  });

  return multer({ storage, fileFilter });
};



And in the end, instead of copying, we have a "generator" middleware:
const uploadImage = require('./multerFactory')('public/uploads/category');

router.post('/:slug/uploadImage', uploadImage.single('image'), (req, res) => {
  // сохранить ссылку на файл в бд
});


1. To what extent is such an approach justified and necessary?
2. What is usually done in such cases?
3. Have I over-decomposed everything? (or can it be even better, how?)

PS I can't find a "combat", real example of a full-fledged application on express / node, hence a bunch of "philosophical" questions to which it is difficult to find an unambiguous answer.

Answer the question

In order to leave comments, you need to log in

1 answer(s)
D
Dmitry Belyaev, 2020-09-09
@alex4answ

1. To what extent is such an approach justified and necessary?
Quite justified. Imagine that a month after the launch, you are faced with the task “the disk space is running out quickly, let’s store it in a different way, and don’t forget to change the download”, how will it be easier, fix one place or wherever you accumulated pastilles?
2. What is usually done in such cases?
If some part of the code is repeated more than 1 time, then it is taken out into a separate function. So you have chosen the right direction.
3. Have I over-decomposed everything? (or even better, how?)
Show a colleague if he can figure out what is happening without explanation?
Well, if you use VSCode, then this can also help: https://marketplace.visualstudio.com/items?itemNam...

Didn't find what you were looking for?

Ask your question

Ask a Question

731 491 924 answers to any question