Делаю тут всякого разного и задумался над одной абстракцией, которую часто использую в библиотечном коде:
const options = mergeObjects(defaultOptions, userOptions);
Так выглядит ёмко выраженное намерение: есть опции по умолчанию, пользователь может некоторые из них изменить, но на выходе всегда нужен полный объект опций.
То же намерение можно выразить прямым проектным кодом:
const options = {
hyphenate: userOptions?.hyphenate ?? defaultOptions.hyphenate,
namespace: userOptions?.namespace ?? defaultOptions.namespace,
delimiters: {
element: userOptions?.delimiters?.element ?? defaultOptions.delimiters.element,
modifier: userOptions?.delimiters?.modifier ?? defaultOptions.delimiters.modifier,
modifierValue: userOptions?.delimiters?.modifierValue ?? defaultOptions.delimiters.modifierValue,
},
};Cори, это совершенно нечитаемо в тг. Cделаю себе большой блог когда-нибудь)
Воспринимается заметно тяжелее, да? И корректность хочется перепроверить: не затесалось ли что-то хитрое?
➿➿➿
Решил замерить разницу по скорости (как я рад, что в наше время это можно сделать за 5 минут, почти не участвуя в процессе) и получил такие результаты:
mergeObjects: 573 032 ops/sec
Прямой код: 54 282 687 ops/sec
Цена абстракции — примерно 100х замедления.
Срочно надо всё переделать.
А надо ли?
"В 100 раз быстрее" звучит очень круто, но фактически мы сравниваем
0.000001ms против 0.0001ms. На единичный вызов и то и другое описывается словом "мгновенно".
Убеждён, что в большинстве задач фронтенда ясность выражения намерения куда важнее оптимизации по цифрам, которые и без неё сильно меньше одной миллисекунды.
До абсурда ведь можно довести.
// (1)
for (const [key, value] of Object.entries(object)) {
// ...
}
// (2) Работает в 2-3 раза быстрее
for (const key of Object.keys(object)) {
const value = object[key];
}
// (3) Ещё на 20% быстрее
for (const key in object) {
if (!Object.hasOwn(object, key)) continue;
const value = object[key];
}
Но важнее декларация намерения и скорость её восприятия.
1) В первом случае сразу понимаем: перебираем объект, нужны и ключи, и значения.
2) Во втором перебираем объект, работаем только с ключами... А нет, и со значениями.
3) В третьем работаем с ключами... Всеми? Нет, только собственными... А, и ещё со значениями.
И тут стоит задуматься о стоимости сопровождения кода — на все многоточия выше разработчик тратит существенно больше времени, чем
0.0001ms. Что дороже стоит? :)➿➿➿
Пока писал, вспомнил пару тематических медиа.
Картинка просто забавная, а видео демонстрирует количество работы, которое скрывается за уже такой обыденной вещью, как простой вопрос в ChatGPT.
Если достаточно приблизить любую абстракцию, то за строкой вроде
createRoot(document.getElementById('app')) скрывается примерно столько же работы :)
