Главная | Все статьи | Код

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

Время чтения статьи ~3 минуты
Совершенный код: нормализация данных главное изображение

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

Представьте себе такую задачу: нужно извлечь из 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);

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

Подписывайтесь на канал Кирилла Мокевнина в Telegram — чтобы узнать больше о программировании и профессиональном пути разработчика

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

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
96
Рекомендуемые программы
профессия
от 6 300 ₽ в месяц
Разработка фронтенд-компонентов для веб-приложений
10 месяцев
с нуля
Старт 2 мая
профессия
от 6 300 ₽ в месяц
Разработка веб-приложений на Django
10 месяцев
с нуля
Старт 2 мая
профессия
от 6 183 ₽ в месяц
Ручное тестирование веб-приложений
4 месяца
с нуля
Старт 2 мая
профессия
от 6 300 ₽ в месяц
Разработка приложений на языке Java
10 месяцев
с нуля
Старт 2 мая
профессия
от 5 025 ₽ в месяц
новый
Сбор, анализ и интерпретация данных
9 месяцев
с нуля
Старт 2 мая
профессия
от 6 300 ₽ в месяц
Разработка веб-приложений на Laravel
10 месяцев
с нуля
Старт 2 мая
профессия
от 5 840 ₽ в месяц
Создание веб-приложений со скоростью света
5 месяцев
c опытом
Старт 2 мая
профессия
от 9 900 ₽ в месяц
Разработка фронтенд- и бэкенд-компонентов для веб-приложений
16 месяцев
с нуля
Старт 2 мая
профессия
от 6 300 ₽ в месяц
Разработка бэкенд-компонентов для веб-приложений
10 месяцев
с нуля
Старт 2 мая
профессия
новый
Автоматизированное тестирование веб-приложений на JavaScript
8 месяцев
c опытом
в разработке
Старт 2 мая
профессия
Верстка с использованием последних стандартов CSS
5 месяцев
с нуля
Старт в любое время