<?xml version="1.0" encoding="utf-8" ?><feed xmlns="http://www.w3.org/2005/Atom" xmlns:tt="http://teletype.in/" xmlns:opensearch="http://a9.com/-/spec/opensearch/1.1/"><title>Aleksandr Kitov</title><author><name>Aleksandr Kitov</name></author><id>https://teletype.in/atom/heymdall</id><link rel="self" type="application/atom+xml" href="https://teletype.in/atom/heymdall?offset=0"></link><link rel="alternate" type="text/html" href="https://blog.akitov.info/?utm_source=teletype&amp;utm_medium=feed_atom&amp;utm_campaign=heymdall"></link><link rel="next" type="application/rss+xml" href="https://teletype.in/atom/heymdall?offset=10"></link><link rel="search" type="application/opensearchdescription+xml" title="Teletype" href="https://teletype.in/opensearch.xml"></link><updated>2026-04-11T07:44:56.352Z</updated><entry><id>heymdall:vulnerability-is-broken</id><link rel="alternate" type="text/html" href="https://blog.akitov.info/vulnerability-is-broken?utm_source=teletype&amp;utm_medium=feed_atom&amp;utm_campaign=heymdall"></link><title>&quot;Польза&quot; от уязвимостей</title><published>2025-11-26T12:49:06.878Z</published><updated>2025-11-26T12:49:06.878Z</updated><summary type="html">Я вообще не очень люблю ныть, когда у меня нет какого-то конкретного предложения, как починить причину нытья, но тут что-то уже клинит.</summary><content type="html">
  &lt;p id=&quot;seDW&quot;&gt;Я вообще не очень люблю ныть, когда у меня нет какого-то конкретного предложения, как починить причину нытья, но тут что-то уже клинит.&lt;/p&gt;
  &lt;p id=&quot;yRry&quot;&gt;Безопасность - это важно. Важно, чтобы все писали свой код так, чтобы его нельзя было просто взломать. Важно, чтобы мы не писали в своем коде &lt;code&gt;NODE_TLS_REJECT_UNAUTHORIZED&lt;/code&gt;. Важно, чтобы библиотеки, которые обрабатывают http-запросы, не давали возможности сделать запрос типа &lt;code&gt;GET ../../../etc/passwd&lt;/code&gt;.&lt;/p&gt;
  &lt;p id=&quot;pqTs&quot;&gt;Но мне кажется, что за последнее время поиск уязвимостей в библиотеках превратился в какой-то абсурд. И мне кажется, что это может превратиться в историю про мальчика, который кричал &amp;quot;волки&amp;quot;.&lt;/p&gt;
  &lt;p id=&quot;TH4l&quot;&gt;Рандомные примеры критических уязвимостей за последнее время:&lt;/p&gt;
  &lt;h3 id=&quot;b7Gs&quot;&gt;Уязвимость в fast-redact&lt;/h3&gt;
  &lt;p id=&quot;u7Il&quot;&gt;&lt;a href=&quot;https://nvd.nist.gov/vuln/detail/CVE-2025-57319&quot; target=&quot;_blank&quot;&gt;CVE-2025-57319&lt;/a&gt; - жуткая (high severity!) уязвимость в библиотеке, которая предназначена для маскирования данных в объектах. Часто используется в системах логирования. В чем же там суть? Какой-то секьюрити-ресёрчер обнаружил prototype pollution уязвимость в одном из методов библиотеки.&lt;/p&gt;
  &lt;p id=&quot;JBjo&quot;&gt;Если передать в него специальным образом сконструированный объект - он может испортить глобальные прототипы всех объектов. В первую секунду ты думаешь &amp;quot;да, действительно неприятно, надо чтобы это исправили&amp;quot;. Но потом начинаешь смотреть на пример того, а как же это работает.&lt;/p&gt;
  &lt;p id=&quot;Oldf&quot;&gt;Вот пример из самой уязвимости:&lt;/p&gt;
  &lt;pre id=&quot;GKyh&quot; data-lang=&quot;javascript&quot;&gt;// Create a custom object
const customObject = {};

// Craft the instructions to inject a property into Object.prototype
const instructions = [
  {
    target: customObject,
    path: [&amp;quot;polluted&amp;quot;, &amp;quot;prototype&amp;quot;, &amp;quot;constructor&amp;quot;],
    value: true
  }
];

// Call the vulnerable function with the crafted instructions
require(&amp;quot;fast-redact/lib/modifiers&amp;quot;).nestedRestore(instructions);

// Verify the exploit
console.log({}.polluted !== undefined ? &amp;#x27;[POLLUTION_TRIGGERED]&amp;#x27;:&amp;#x27;&amp;#x27;);
&lt;/pre&gt;
  &lt;p id=&quot;hpWS&quot;&gt;Кажется, что чтобы это сработало в реальности - нужно либо допустить то, что ваши разработчики - злые буратины, которые пытаются заменить поля типа &lt;code&gt;constructor&lt;/code&gt; и &lt;code&gt;prototype&lt;/code&gt; в объекте, либо, что еще хуже, они дают возможность внешним пользователям определять &amp;quot;а что же надо удалить из логов&amp;quot;. И в том, и в другом случае - вам уже мало что поможет.&lt;/p&gt;
  &lt;p id=&quot;YYZ3&quot;&gt;Но если посмотреть на уязвимость еще внимательнее - выяснится, что это вообще не реальный API библиотеки - это одна из внутренних функций библиотеки. Она не задокументирована и использоваться вообще не должна. А при использовании нормального внешнего API - даже злые или не очень сообразительные разработчики будут в безопасности:&lt;/p&gt;
  &lt;pre id=&quot;7hTT&quot; data-lang=&quot;javascript&quot;&gt;const fastRedact = require(&amp;quot;fast-redact&amp;quot;);

const customObject = {};

const redact = fastRedact({
  paths: [&amp;#x27;polluted.prototype.constructor&amp;#x27;],
});

console.log({}.polluted !== undefined ? &amp;#x27;[POLLUTION_TRIGGERED]&amp;#x27;:&amp;#x27;&amp;#x27;); // выведет &amp;#x27;&amp;#x27;
&lt;/pre&gt;
  &lt;p id=&quot;MOIK&quot;&gt;Да, сейчас уязвимость перевели в статус disputed. Но какой ценой? Люди уже успели наделать бесчисленное количество issue, форков, кто-то (даже поняв, что проблемы реально нет!) сделал &lt;a href=&quot;https://adventures.nodeland.dev/archive/from-fast-redact-to-slow-redact/&quot; target=&quot;_blank&quot;&gt;полностью свою реализацию библиотеки&lt;/a&gt;.&lt;/p&gt;
  &lt;p id=&quot;dzJS&quot;&gt;Принесло ли это пользу человечеству? Что-то я сомневаюсь.&lt;/p&gt;
  &lt;h3 id=&quot;hi4l&quot;&gt;Уязвимость в докер-образах&lt;/h3&gt;
  &lt;p id=&quot;WJLR&quot;&gt;Наши стандартные докер-образы основаны на node:alpine. В них почти нет лишних пакетов, и они почти совсем пустые - только код приложения и рантайм, чтобы его запустить. Да, иногда даже в совсем базовых пакетах (типа zlib или tzdata) обнаруживаются уязвимости, но это происходит не так уж и часто. Но вот недавно в кучу чатов начали стучаться. &amp;quot;Аларм!&amp;quot;, &amp;quot;Все сломалось!&amp;quot;, &amp;quot;Мы в опасности!&amp;quot;. Сканер нашел в базовых образах критические уязвимости с высоким приоритетом, а именно &lt;a href=&quot;https://nvd.nist.gov/vuln/detail/CVE-2025-64756&quot; target=&quot;_blank&quot;&gt;CVE-2025-64756&lt;/a&gt;. Откуда? Из пакета &lt;code&gt;glob&lt;/code&gt;. Откуда у нас пакет &lt;code&gt;glob&lt;/code&gt;? Из &lt;code&gt;npm&lt;/code&gt;. Он является базовой частью node:alpine.&lt;/p&gt;
  &lt;p id=&quot;TM7G&quot;&gt;А в чем там вообще уязвимость?&lt;/p&gt;
  &lt;p id=&quot;crFh&quot;&gt;Оказывается, что уязвимость срабатывает только если использовать cli-интерфейс &lt;code&gt;glob&lt;/code&gt;, запускать его с флагом &lt;code&gt;--cmd&lt;/code&gt;. В таком случае, если злоумышленник создаст файл с именем вида &lt;code&gt;$(touch pwned)&lt;/code&gt; и он попадет под glob - то код из имени файла успешно выполнится.&lt;/p&gt;
  &lt;p id=&quot;EuWX&quot;&gt;Что ж, действительно уязвимость... Но только если вы используете этот самый пакет glob как cli-утилиту. Ну и если кто-то уже понаписал в вашу файловую систему файлов с командами в их именах (а как он их туда напихал? Он уже вас взломал?) &lt;/p&gt;
  &lt;p id=&quot;dYR9&quot;&gt;Но у нас эта библиотека - зависимость зависимости. Никто никогда его не запускал и запускать не будет. Понятное дело, что правильным решением с точки зрения мейнтейнеров glob было бы выделить это все в отдельный пакет (что они и сделали, теперь есть отдельный &lt;a href=&quot;https://www.npmjs.com/package/glob-bin&quot; target=&quot;_blank&quot;&gt;glob-bin&lt;/a&gt;, в котором и уязвимость заодно починили). Да и вообще - виной всему любовь js-разработчиков к пакетам, в которых лежат еще пакеты, а в них - еще пакеты...&lt;/p&gt;
  &lt;p id=&quot;Inaf&quot;&gt;Но вот реально, являлась ли эта уязвимость критичной в нашем конкретном случае? На мой взгляд - нет.&lt;/p&gt;
  &lt;h2 id=&quot;B2R4&quot;&gt;Вместо вывода&lt;/h2&gt;
  &lt;p id=&quot;Jxmp&quot;&gt;Проблема не в этих двух конкретных уязвимостях. Это просто то, что я легко вспомнил. Почти все уязвимости, с которыми я сталкивался за последнее время, являются именно такими мутными вещами. Всегда для их эксплуатации надо сделать какие то кривые вещи со стороны самих разработчиков. Всегда для исправления ставятся максимально сжатые сроки - починить их надо уже всера.&lt;/p&gt;
  &lt;p id=&quot;8ciJ&quot;&gt;Как я в самом начале и сказал - у меня нет какого-то решения. Уязвимости надо искать. Их надо исправлять. Но ощущение, что что-то в этом процессе фундаментально неправильно - не покидает меня.&lt;/p&gt;

</content></entry><entry><id>heymdall:boolean-is-bad-for-you</id><link rel="alternate" type="text/html" href="https://blog.akitov.info/boolean-is-bad-for-you?utm_source=teletype&amp;utm_medium=feed_atom&amp;utm_campaign=heymdall"></link><title>Boolean - легкий способ сделать плохой API</title><published>2024-09-07T07:01:47.610Z</published><updated>2024-09-08T10:46:00.805Z</updated><summary type="html">Что? Почему? Это же прекрасный тип данных - всего два значения, которые так легко использовать...</summary><content type="html">
  &lt;p id=&quot;MHmR&quot;&gt;Что? Почему? Это же прекрасный тип данных - всего два значения, которые так легко использовать...&lt;/p&gt;
  &lt;p id=&quot;H5ij&quot;&gt;Проще всего показать проблему на примере. Представьте, что мы делаем обертку над webpack, которая прячет в себя весь ужас вебпака и дает такой простой програмный API для использования:&lt;/p&gt;
  &lt;pre id=&quot;0xXJ&quot; data-lang=&quot;typescript&quot;&gt;function buildApp(entryPoint: string): Promise&amp;lt;void&amp;gt;;&lt;/pre&gt;
  &lt;p id=&quot;0WOu&quot;&gt;Вроде бы всё просто и понятно. Чуть позже вы понимаете, что части ваших пользователей хочется немного настраивать вашу сборку - они хотят использовать &lt;code&gt;ts-loader&lt;/code&gt; вместо &lt;code&gt;babel-loader&lt;/code&gt; для обработки ts файлов.&lt;/p&gt;
  &lt;p id=&quot;XaQ3&quot;&gt;Что-ж, доработаем наш API!&lt;/p&gt;
  &lt;pre id=&quot;P0qg&quot; data-lang=&quot;typescript&quot;&gt;function buildApp(
  entryPoint: string,
  useTsLoader: boolean = false,
): Promise&amp;lt;void&amp;gt;;&lt;/pre&gt;
  &lt;p id=&quot;wgBf&quot;&gt;При вызове это выглядит как то так:&lt;/p&gt;
  &lt;pre id=&quot;O5So&quot; data-lang=&quot;typescript&quot;&gt;await buildApp(&amp;#x27;./my-entry.tsx&amp;#x27;, true);&lt;/pre&gt;
  &lt;p id=&quot;ahkl&quot;&gt;Конечно же любой опытный разработчик сразу поймет, что лучше бы переписать это API чтобы он принимал объект, а не отдельные аргументы. Если читать вызов в текущем варианте - вообще не понятно что же за &lt;code&gt;true&lt;/code&gt; передается тут во втором аргументе&lt;/p&gt;
  &lt;pre id=&quot;sBHm&quot; data-lang=&quot;typescript&quot;&gt;type BuildAppParams = {
  entryPoint: string;
  useTsLoader?: boolean;
}
function buildApp({
  entryPoint,
  useTsLoader = false,
}: BuildAppParams): Promise&amp;lt;void&amp;gt;;

// вызов
buildApp({
  entryPoint: &amp;#x27;./my-entry.tsx&amp;#x27;,
  useTsLoader: true,
});&lt;/pre&gt;
  &lt;p id=&quot;bV0s&quot;&gt;Красота? Вроде бы все понятно?&lt;/p&gt;
  &lt;p id=&quot;cCMk&quot;&gt;Нет. А что если мы напишем &lt;code&gt;useTsLoader: false&lt;/code&gt;? Что это вообще будет означать? Что будет использоваться вместо него? Конечно можно прочитать документацию и понять какое будет поведение..&lt;/p&gt;
  &lt;p id=&quot;fmXY&quot;&gt;А что если через какое то время мы захотим добавить еще немного гибкости, и давать возможность использовать например &lt;code&gt;swc&lt;/code&gt; или &lt;code&gt;esbuild&lt;/code&gt;?&lt;/p&gt;
  &lt;pre id=&quot;eZrL&quot; data-lang=&quot;typescript&quot;&gt;type BuildAppParams = {
  entryPoint: string;
  useTsLoader?: boolean;
  useSwcLoader?: boolean;
};
function buildApp(options: BuildAppParams): Promise&amp;lt;void&amp;gt;;
&lt;/pre&gt;
  &lt;p id=&quot;cdz7&quot;&gt;Теперь вопрос - что будет происходить когда и &lt;code&gt;useTsLoader&lt;/code&gt;, и &lt;code&gt;useSwcLoader&lt;/code&gt; выставлены в &lt;code&gt;true&lt;/code&gt;? Наверное можно указать в документации что использование параметров одновременно - некорректно, или даже попробовать починить это на уровне типов:&lt;/p&gt;
  &lt;pre id=&quot;Obwt&quot; data-lang=&quot;typescript&quot;&gt;type BuildAppPrams = {
  entryPoint: string;
} &amp;amp; ({
  useTsLoader: true;
  useSwcLoader?: false;
} | {
  useTsLoader?: false;
  useSwcLoader: true;
} | {
  useTsLoader?: false;
  useSwcLoader?: false;
})

// валидно:
buildApp({
  entryPoint: &amp;#x27;./my-entry.tsx&amp;#x27;,
});
buildApp({
  entryPoint: &amp;#x27;./my-entry.tsx&amp;#x27;, useTsLoader: true,
});
buildApp({
  entryPoint: &amp;#x27;./my-entry.tsx&amp;#x27;, useSwcLoader: true,
});
// ошибка от ts:
buildApp({
  entryPoint: &amp;#x27;./my-entry.tsx&amp;#x27;,
  useSwcLoader: true,
  useTsLoader: true,
});&lt;/pre&gt;
  &lt;p id=&quot;rQyN&quot;&gt;Но согласитесь, смотреть на такие типы становится больно, и очень редко кто-то действительно строит такие типы.&lt;/p&gt;
  &lt;h2 id=&quot;Oa65&quot;&gt;Что же делать?&lt;/h2&gt;
  &lt;p id=&quot;U7ps&quot;&gt;Очевидно, использовать перечисляемые типы! enum в ts недолюбливают, но есть понятная альтернатива - union + literal types.&lt;/p&gt;
  &lt;pre id=&quot;f8Sr&quot; data-lang=&quot;typescript&quot;&gt;type BuildAppParams = {
  entryPoint: string;
  loader?: &amp;#x27;ts&amp;#x27; | &amp;#x27;babel&amp;#x27; | &amp;#x27;swc&amp;#x27;;
};

buildApp({ entryPoint: &amp;#x27;./my-entry.tsx&amp;#x27;, loader: &amp;#x27;ts&amp;#x27; });&lt;/pre&gt;
  &lt;p id=&quot;lNmB&quot;&gt;Этот вариант стоит использовать даже если на текущий момент у вас предполагается всего два варианта - кто знает как захочется расширить API в будущем?&lt;/p&gt;
  &lt;p id=&quot;sYWG&quot;&gt;Другой вариант, &lt;a href=&quot;https://martinfowler.com/bliki/FlagArgument.html&quot; target=&quot;_blank&quot;&gt;предлагаемый Мартином Фаулером&lt;/a&gt; - делать полность отдельные методы вместо использования флагов:&lt;/p&gt;
  &lt;pre id=&quot;YFZe&quot; data-lang=&quot;typescript&quot;&gt;function buildAppWithBabel(entryPoint: string): Promise&amp;lt;void&amp;gt;;
function buildAppWithTs(entryPoint: string): Promise&amp;lt;void&amp;gt;;
function buildAppWithSwc(entryPoint: string): Promise&amp;lt;void&amp;gt;;&lt;/pre&gt;
  &lt;p id=&quot;Tgca&quot;&gt;Мне персонально такой вариант в мире react кажется менее удобным, но полноценных аргументов кроме вкусовщины на это у меня нет.&lt;/p&gt;
  &lt;p id=&quot;ZpaI&quot;&gt;Конечно, бывают варианты, когда &lt;code&gt;boolean&lt;/code&gt; является очевидным и правильным решением. Условный &lt;code&gt;setModalOpen(boolean)&lt;/code&gt; будет понятен, и вариантов с наполовину открытой модалкой у вас скорее всего не появится. Но даже в подобных случаях лучше задумываться - например проп для селекта &lt;code&gt;defaultOpen&lt;/code&gt; возможно стоит заменить на &lt;code&gt;defaultState: &amp;#x27;open&amp;#x27; | &amp;#x27;closed&amp;#x27;&lt;/code&gt; - вдруг вы захотите менять его поведение в зависимости от количества опций?&lt;/p&gt;
  &lt;p id=&quot;BbW7&quot;&gt;Вообщем проектируйте апи правильно, думайте не только о том как удобно написать вам сейчас, но и как оно будет работать потом, и как это будут использовать.&lt;/p&gt;

</content></entry><entry><id>heymdall:code-review-levels</id><link rel="alternate" type="text/html" href="https://blog.akitov.info/code-review-levels?utm_source=teletype&amp;utm_medium=feed_atom&amp;utm_campaign=heymdall"></link><title>Про код ревью - как перестать докапываться до мелочей и начать получать удовольствие</title><published>2024-09-07T06:58:40.588Z</published><updated>2024-09-07T06:58:40.588Z</updated><summary type="html">Сделать так, чтобы все писали код одинаково - невозможно. Как бы нам не хотелось чтобы все делали все абсолютно так же как и мы - это не реально. У нас у всех разный опыт, разный бекграунд и разные подходы к написанию одного и того же.</summary><content type="html">
  &lt;p id=&quot;s8qm&quot;&gt;Сделать так, чтобы все писали код одинаково - невозможно. Как бы нам не хотелось чтобы все делали все абсолютно так же как и мы - это не реально. У нас у всех разный опыт, разный бекграунд и разные подходы к написанию одного и того же.&lt;/p&gt;
  &lt;p id=&quot;AP23&quot;&gt;Тем не менее зачастую разработчики пытаются сделать на ревью именно это. Советы по тому, что в коде стоит отделять дополнительным &lt;code&gt;\\n&lt;/code&gt;, рекомендации использовать один метод вместо другого (ведь так будет на 1 строчку короче!), настоятельные просьбы вынести что-то в отдельную функцию…&lt;/p&gt;
  &lt;p id=&quot;NQ0n&quot;&gt;А точно ли все эти комментарии нужны?&lt;/p&gt;
  &lt;h2 id=&quot;JpjN&quot;&gt;Уровни комментариев&lt;/h2&gt;
  &lt;p id=&quot;TQZy&quot;&gt;Содержимое любого ПР-а можно условно разделить на 5 уровней:&lt;/p&gt;
  &lt;ol id=&quot;74HG&quot;&gt;
    &lt;li id=&quot;XNU0&quot;&gt;Архитектурный. Это то, &lt;strong&gt;что делает фича&lt;/strong&gt;, какие системы вызываются, как именно устроено взаимодействие с ними.&lt;/li&gt;
    &lt;li id=&quot;WxfF&quot;&gt;Фичёвый. А &lt;strong&gt;как фича реализована&lt;/strong&gt;? Покрыты ли все нужные в бизнес-логике кейсы? Будет ли код работать корректно в специфичных кейсах?&lt;/li&gt;
    &lt;li id=&quot;ZcR2&quot;&gt;Структурный. Это то, &lt;strong&gt;как код структурирован&lt;/strong&gt;. На какие модули он разбит, как эти модули внутри взаимодействуют&lt;/li&gt;
    &lt;li id=&quot;ETdO&quot;&gt;Уровень кода. Это то, &lt;strong&gt;как внутри устроены модули&lt;/strong&gt;. Как называются переменные, какие фичи языка используются, как реализованы какие то алгоритмы.&lt;/li&gt;
    &lt;li id=&quot;UNpo&quot;&gt;Уровень форматирования. Это то, &lt;strong&gt;как код выглядит&lt;/strong&gt;. Пробелы, комментарии в коде, какие кавычки использованы - относится сюда.&lt;/li&gt;
  &lt;/ol&gt;
  &lt;p id=&quot;2Uzx&quot;&gt;Комментарии к пул-реквесту чаще всего относятся к одному из этих уровней. И на мой взгляд первому и последнему уровню не место на этапе пул-реквеста. Остальные же можно и нужно пытаться минимизировать.&lt;/p&gt;
  &lt;h3 id=&quot;m9fb&quot;&gt;Архитектурные&lt;/h3&gt;
  &lt;p id=&quot;qJ5Q&quot;&gt;Предположим какой то разработчик уже проделал большую работу, сделал новую фичу, а потом приходит кто-то и говорит что надо было вообще использовать другой микросервис/писать в другую базу/реализовывать всё это в другом модуле. Это &lt;strong&gt;архитектурные&lt;/strong&gt; замечания.&lt;/p&gt;
  &lt;p id=&quot;O1yq&quot;&gt;Если у вас возникают архитектурные вопросы на этапе пул-реквеста - кажется у вас что-то не так с процессом разработки/аналитики. Либо реализацию не обсудили с заинтересованными сторонами, либо не потратили достаточно времени на дискавери. В большинстве случаев на этом этапе логичнее всего сложить это замечание в беклог, а текущую реализацию помержить как есть. Как убедиться что задача из беклога будет сделана - отдельная большая тема, но сейчас оставим её за скобками.&lt;/p&gt;
  &lt;h3 id=&quot;V1Je&quot;&gt;Фичевые&lt;/h3&gt;
  &lt;p id=&quot;qxLL&quot;&gt;&lt;strong&gt;Фичевые&lt;/strong&gt; комментарии - самые полезные при погружении в проект. Это те вещи, которые могут знать аналитики или те, кто давно работает над проектом. “А если придет пользователь с 500 записями?”, “А не забыли ли мы про мобильную версию”. Сюда же можно отнести и комментарии по нефункциональным требованиям - “Этот сервис должен маскировать данные, которые он отправляет в логи”, “Надо написать тесты” и так далее.&lt;/p&gt;
  &lt;p id=&quot;rHdF&quot;&gt;Это полезные комментарии, и если у вы хотите такой написать - не стоит колебаться. Конечно, можно сказать что такие вещи должны отлавливаться на этапе сбора требований, но в реальности при какой-либо agile разработке учесть всё - очень тяжело.&lt;/p&gt;
  &lt;h3 id=&quot;13R8&quot;&gt;Структурные&lt;/h3&gt;
  &lt;p id=&quot;xxyF&quot;&gt;&lt;strong&gt;Структурные&lt;/strong&gt; комментарии объясняют как стоит склеивать код из мелких кусочков. Что нужно выносить в отдельные функции? Может быть есть слой, в котором должно происходить любое взаимодействие с базами данных? Или вообще такой код у вас обычно размещается в библиотеке?&lt;/p&gt;
  &lt;p id=&quot;6JpG&quot;&gt;Такие коменты могут возникать независимо от уровня разработчика, написавшего код. Если вы хотите снижать их количество - фиксируйте договоренности о структуре и пишите их в ридми вашего проекта.&lt;/p&gt;
  &lt;h3 id=&quot;mSFg&quot;&gt;Про код&lt;/h3&gt;
  &lt;p id=&quot;IJdk&quot;&gt;Комментарии, относящиеся к &lt;strong&gt;уровню кода&lt;/strong&gt; могут быть полезны начинающим/людям которые только присоединились к проекту. Но тут нужно быть осторожными, и не пытаться заставлять всех писать в точности так, как пишите вы. Запись &lt;code&gt;if (items.length == 0)&lt;/code&gt; и запись &lt;code&gt;if (!items.length)&lt;/code&gt; эквиваленты для ts. Как писать правильно? По моему субъективному мнению первая запись понятнее, но это именно субъективное мнение. Стоит ли писать про это при ревью? Если у вас нигде не зафиксированы договоренности об этом и у вас нет цели научить разработчика - вполне возможно что правильным решением будет промолчать. В то же время если в новом коде все переменные названы одной рандомной буквой - молчать нельзя.&lt;/p&gt;
  &lt;p id=&quot;rghb&quot;&gt;Многие комментарии с этого уровня могут решаться автоматическими проверками. Линтеры, code-quality инструменты - все они нужны чтобы снять нагрузку на отлавливание мелочей с разработчиков и переложить их на уровень машин. Если вы замечаете что часто пишите комментарии на этом уровне - подумайте об автоматизации.&lt;/p&gt;
  &lt;h3 id=&quot;FI2N&quot;&gt;Форматирование&lt;/h3&gt;
  &lt;p id=&quot;KCgF&quot;&gt;Комментарии про отсутствующий пробел или не ту форму кавычек - это просто трата времени. Это уровень &lt;strong&gt;форматирования&lt;/strong&gt;, и он должен решаться инструментами. Для большинства языков есть автоматические форматеры. prettier в js, gofmt в go, autopep8 для python и так далее. Если тот код, который получается на выходе из таких инструментов вас не устраивает (он не такой красивый!) - у вас есть два варианта - смириться или сделать свой инструмент, который будет выдавать такой код, который будет вам казаться эстетичным. Только сделайте так, чтобы этот инструмент работал не только на вашем компьютере, но и у других разработчиков.&lt;/p&gt;
  &lt;h2 id=&quot;vSgx&quot;&gt;Критичность комментариев&lt;/h2&gt;
  &lt;p id=&quot;62br&quot;&gt;Кроме разделения на “уровень” комментариев, их можно (и нужно!) разделять и по их критичности. Некоторые вещи могут быть простым замечанием - если его проигнорировать - об этом забудется очень скоро. Какие то могут быть важными моментами, на которые автору стоит обратить внимание и постараться это исправить. Ну и некоторые комментарии могут быть блокерами. Код с такими комментариями не должен попасть в мастер ни при каких условиях.&lt;/p&gt;
  &lt;p id=&quot;OXpg&quot;&gt;У всех известных инструментов для работы с гит есть возможность поставить блокирующий комментарий - NEED_WORKS в битбакете, request changes в гитхабе/гитлабе. Не стоит разбрасываться таким статусом по каждой мелочи. Блокирующие комментарии по &lt;strong&gt;уровню кода&lt;/strong&gt; - странный выбор. Простановка такого статуса - это повод задуматься о том, что нужно поменять чтобы таких ситуаций не возникало.&lt;/p&gt;
  &lt;p id=&quot;96E8&quot;&gt;Для разделения между двумя другими уровнями критичности никаких инструментов нет. В команде лучше всего выработать договоренности о том, как именно их разделять. Одним из популярных вариантов является префикс &lt;code&gt;nit:&lt;/code&gt; для комментариев низкой критичности. Оставляя такой комментарий вы должны быть готовы что его проигнорируют. Получая - вы можете его проигнорировать (но всё же стоит о нём хотя бы задуматься - может быть там действительно ценное замечание?)&lt;/p&gt;
  &lt;h2 id=&quot;Gw7X&quot;&gt;Выводы?&lt;/h2&gt;
  &lt;p id=&quot;DVHK&quot;&gt;Ну а тут должен идти какой то разумный вывод, который логически вытекает из всего этого потока мыслей. Что вот мол, если обращать внимание на то, какой “уровень” вы комментируете, и постоянно задумываться над вопросом “а что надо сделать чтобы больше таких коментов не писать” - можно получить быстрые и приятные код-ревью, которые будут приятны и ревьюверам, и авторам кода. Но пока этого вывода тут нет.&lt;/p&gt;

</content></entry><entry><id>heymdall:js-tools-is-painfull</id><link rel="alternate" type="text/html" href="https://blog.akitov.info/js-tools-is-painfull?utm_source=teletype&amp;utm_medium=feed_atom&amp;utm_campaign=heymdall"></link><title>Нытье про js тулинг</title><published>2024-09-07T06:57:18.677Z</published><updated>2024-09-07T06:57:18.677Z</updated><summary type="html">Иногда я напитываюсь огромных количеством ненависти к тому, как устроена вся “экосистема” фронтенда. Это просто дикий набор костылей, который работает просто на удаче.</summary><content type="html">
  &lt;p id=&quot;9sxR&quot;&gt;Иногда я напитываюсь огромных количеством ненависти к тому, как устроена вся “экосистема” фронтенда. Это просто дикий набор костылей, который работает просто на удаче.&lt;/p&gt;
  &lt;p id=&quot;g5h8&quot;&gt;Исследую возможность добавить vite в свою обертку вокруг дев тулзов для дев режима. В целом понятно что это будет приносить проблемы, абсолютно ожидаемо я читаю огромное кол-во issue, разбираюсь какие отличия есть в разных методах настройки и сборки и так далее. Но по сути - за день я получил вполне рабочий прототип.&lt;/p&gt;
  &lt;p id=&quot;TRGR&quot;&gt;В процессе обнаруживается что vite, будучи нацеленным в первую очередь на esm ругается на одну из зависимостей наших пакетов. Пакет &lt;code&gt;A&lt;/code&gt; (библиотека компонентов) импортирует в себя пакет &lt;code&gt;B&lt;/code&gt;(набор тулзов), а у него внутри некорректное поле main в package.json. Чтож, можно же поправить!&lt;/p&gt;
  &lt;p id=&quot;OoTh&quot;&gt;Идем в пакет &lt;code&gt;B&lt;/code&gt;, видим что там уже всё поправлено - добавлено поле &lt;code&gt;exports&lt;/code&gt;, которое имеет более высокий приоритет, и все сборщики (что вебпак, что vite) прекрасно с ним работают. Нужно просто обновить версию - и все будет отлично.&lt;/p&gt;
  &lt;p id=&quot;SrZy&quot;&gt;Идем, обновляем. Сборка проходит. Запускаем тесты - видим что теперь jest не понимает как с этим работать. Читаем внимательнее, понимаем что в библиотеке компонентов jest версии 26, а с полями exports jest научился работать только в 28.&lt;/p&gt;
  &lt;p id=&quot;LM9W&quot;&gt;Обновляем до 28 версии - видим 100+ ошибок о том, что теперь jest вроде как встречает неизвестный токен &lt;code&gt;export&lt;/code&gt; в зависимости зависимости! Хотя казалось бы, мы же вроде поддержку esm должны были получить после обновления…&lt;/p&gt;
  &lt;p id=&quot;l0EM&quot;&gt;Смотрим в пакет на который ругается, видим что в его package.json написано такое:&lt;/p&gt;
  &lt;pre id=&quot;9XTu&quot; data-lang=&quot;javascript&quot;&gt;  &amp;quot;main&amp;quot;: &amp;quot;./dist/index.js&amp;quot;,
  &amp;quot;exports&amp;quot;: {
    &amp;quot;.&amp;quot;: {
      &amp;quot;node&amp;quot;: {
        &amp;quot;module&amp;quot;: &amp;quot;./dist/esm-node/index.js&amp;quot;,
        &amp;quot;require&amp;quot;: &amp;quot;./dist/index.js&amp;quot;,
        &amp;quot;import&amp;quot;: &amp;quot;./wrapper.mjs&amp;quot;
      },
      &amp;quot;default&amp;quot;: &amp;quot;./dist/esm-browser/index.js&amp;quot;
    },
    &amp;quot;./package.json&amp;quot;: &amp;quot;./package.json&amp;quot;
  },
&lt;/pre&gt;
  &lt;p id=&quot;A0m1&quot;&gt;Ругается наш jest именно на &lt;code&gt;esm-browser/index.js&lt;/code&gt;. Проверяем - руками в node_modules меняем default на &lt;code&gt;./dist/index.js&lt;/code&gt; - тесты идут.&lt;/p&gt;
  &lt;p id=&quot;xQk0&quot;&gt;Таак. И че делать? Наобум пробуем обновить jest еще дальше, на 29 версию, получаем полное расхождение всех снапшотов + проблемы с jsdom. Ок, не катит.&lt;/p&gt;
  &lt;p id=&quot;m4TO&quot;&gt;Вроде vitest есть! Он же совместим почти полностью по апи, и построен сразу с идеей нормальной работы с esm-модулями!&lt;/p&gt;
  &lt;p id=&quot;onc4&quot;&gt;Пробуем перейти на него. Мигрируем код &lt;a href=&quot;https://github.com/trivikr/vitest-codemod&quot; target=&quot;_blank&quot;&gt;код-модом&lt;/a&gt;, это же не долго! Запускаем. Получаем кучу изменений, но вроде бы вполне вменяемых. &lt;code&gt;yarn vitest&lt;/code&gt;… не, ну конечно оно не запустилось. Выясняется что &lt;code&gt;window.computedStyle&lt;/code&gt; нет в jsdom! Это патчится в jest какими то костылями, но vitest логично решили что это не их дело - пусть пользователи &lt;a href=&quot;https://github.com/vitest-dev/vitest/issues/2061&quot; target=&quot;_blank&quot;&gt;сами разбираются&lt;/a&gt;.&lt;/p&gt;
  &lt;p id=&quot;p29K&quot;&gt;Напоминаю, я просто хотел апнуть версию одной зависимости. Кажется переход на другой тестовый фреймворк для этого - слишком жирно.&lt;/p&gt;
  &lt;p id=&quot;QGD8&quot;&gt;Читаем внимательно то, как можно конфигурировать jest. Вроде в вебпаке можно было указывать поле в package, из которого должен браться resolution…&lt;/p&gt;
  &lt;p id=&quot;YCg7&quot;&gt;Такого апи нет, но можно написать свой резолвер! Пробираемся через дебри не очень подробной документации, смотрим как написаны другие резолверы, делаем свой. Отлавливаем баги, вроде все запускается.&lt;/p&gt;
  &lt;p id=&quot;T34D&quot;&gt;На данном этапе на это ушло уже несколько часов, а изначальная задачка еще совсем не решена. Но мы же уже близко?&lt;/p&gt;
  &lt;p id=&quot;lAGV&quot;&gt;Локально тесты проходят. Создаем пр, пушим нашу ветку. Тесты падают в ci. Понимаем что наш резолвер работает не совсем корректно. Потом вспоминаем что часть разработчиков вообще сидит на windows, и наш резолвер вообще не умеет работать с отличными от &lt;code&gt;/&lt;/code&gt; разделителями. Может пойти и просто поправить зависимости в core-components?&lt;/p&gt;
  &lt;p id=&quot;68Hl&quot;&gt;Теперь все это напоминает чудесный отрывок из шоу “Malcolm in the middle “&lt;/p&gt;
  &lt;p id=&quot;SFy1&quot;&gt;&lt;a href=&quot;https://youtu.be/_UZFI-8D5uA?si=yzBwabQNHgtBYm9_&quot; target=&quot;_blank&quot;&gt;https://youtu.be/&lt;em&gt;UZFI-8D5uA?si=yzBwabQNHgtBYm9&lt;/em&gt;&lt;/a&gt;&lt;/p&gt;
  &lt;p id=&quot;FYS2&quot;&gt;Короче говоря - в такие моменты хочется просто забить на весь этот тулинг, esm/cjs, тесты и вообще всё что связано с инструментами.&lt;/p&gt;
  &lt;p id=&quot;nbMY&quot;&gt;Хочется писать в блокноте код на jquery, рисовать скруглённые уголки таблицами и заливать всё это на сервер через ftp. А не вот это вот все.&lt;/p&gt;

</content></entry></feed>