Все статьи | Код

Совершенный код: нормализация данных

Совершенный код: нормализация данных главное изображение

Нормализация данных — подход, с помощью которого можно не только упростить логику кода, но и сделать сам код короче. Его принцип работы состоит в приведении данных к общему виду перед основным алгоритмом обработки этих данных. Посмотрим, как это работает на простом примере.

Представьте себе такую задачу: нужно извлечь из HTML все ссылки и загрузить их содержимое. Для простоты допустим, что HTML уже проанализирован, а ссылки собраны в массив. Кроме самих ссылок понадобится имя домена, на котором был расположен этот HTML. Это нужно для загрузки относительных ссылок, то есть тех ссылок, у которых не указан домен в HTML, например, /about. Ниже пример кода, решающего задачу в лоб:

// Кода здесь мало и код можно было бы оставить так,
// но именно на таких маленьких примерах и нужно отрабатывать хорошие практики

import axios from 'axios'; // http-клиент

// Эта функция анализирует HTML и извлекает ссылки
const getLinksFromHTML = /* определение функции */;
const domainName = /* тут имя домена на котором расположен HTML */;
const html = /* сам html */;

// Подготовка данных
const links = getLinksFromHTML(html);

// Здесь основной алгоритм работы
const promises = links.map((link) => {
  // Определяем тип ссылки. Если домена нет, значит используем текущий 
  // Сама проверка упрощена. Для правильного анализа придется попотеть
  if (link.startsWith('/')) {
    return axios.get(`${domainName}/${link}`);
  }

  return axios.get(link);
});
// Выполняем запросы параллельно
const responses = await Promise.all(promises);

Обратите внимание на чёткое разделение двух этапов. У нас есть место, где готовятся данные, а есть место, где выполняется основная логика. В данном случае обе эти части предельно маленькие, но в реальных приложениях они могут содержать десятки строк, множество условных конструкций и циклов. Большую часть кода можно разделить как минимум на эти два этапа.

Самое примечательное в этом коде — условие, проверяющее относительность ссылки. Посмотрите внимательно на код, который внутри. Он не выполняет какую-то другую особую логику. Всё, что он делает — приводит данные к нужному для обработки виду. Именно здесь и подходит нормализация данных. Вместо того, чтобы строить ссылку по условию, код можно изменить так, чтобы ссылки были полными ещё до попадания в эту часть программы.

import axios from 'axios';
import { URL } from 'url';

const getLinksFromHTML = /* определение функции */;
const domainName = /* тут имя домена на котором расположен HTML */;
const html = /* сам html */;

const links = getLinksFromHTML(html);
// Возможно эту логику имеет смысл поместить в getLinksFromHTML
const urls = links.map((link) => new URL(link, domainName));

// toString преобразует объект обратно в строку
const promises = urls.map((url) => axios.get(url.toString()));
const responses = await Promise.all(promises);

В чём хитрость этого решения? Встроенный модуль url в JavaScript содержит специальную функцию-конструктор URL, с помощью которой создается объект, описывающий конкретный url. Внутри этого объекта есть информация о всех частях адреса. Так их удобнее извлекать и даже менять. У этой функции есть второй параметр — базовый адрес, хост, который будет использоваться в том случае, когда ссылка относительная:

(new URL('/pages/about', 'https://ru.hexlet.io')).toString();
// 'https://ru.hexlet.io/pages/about'

// Если адрес абсолютный то ничего не ломается!
(new URL('https://yandex.ru/pages/about', 'https://ru.hexlet.io')).toString();
// 'https://yandex.ru/pages/about'

Использование готовых инструментов — идеальное решение задачи. Даже если бы у нас не было такого модуля, как url, все равно имело бы смысл делать предварительную нормализацию данных. Как правило, в живых проектах обработка — это больше чем одна условная конструкция. Одни и те же данные могут использоваться много раз и по-разному. Такой код очень легко обрастает условиями и дублированием.

Кстати, в примере выше мы получили дополнительное преимущество — убрали прямое использование строк.

Аватар пользователя Kirill Mokevnin
Kirill Mokevnin 03 марта 2020
Рекомендуемые программы

С нуля до разработчика. Возвращаем деньги, если не удалось найти работу.

Иконка программы Фронтенд-разработчик
Профессия
Разработка фронтенд-компонентов веб-приложений
30 июня 10 месяцев
Иконка программы Python-разработчик
Профессия
Разработка веб-приложений на Django
30 июня 10 месяцев
Иконка программы PHP-разработчик
Профессия
Разработка веб-приложений на Laravel
30 июня 10 месяцев
Иконка программы Node.js-разработчик
Профессия
Разработка бэкенд-компонентов веб-приложений
30 июня 10 месяцев
Иконка программы Fullstack-разработчик
Профессия
Новый
Разработка фронтенд и бэкенд компонентов веб-приложений
30 июня 16 месяцев
Иконка программы Верстальщик
Профессия
Вёрстка с использованием последних стандартов CSS
в любое время 5 месяцев
Иконка программы Java-разработчик
Профессия
Разработка приложений на языке Java
30 июня 10 месяцев
Иконка программы Разработчик на Ruby on Rails
Профессия
Создает веб-приложения со скоростью света
30 июня 5 месяцев