<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
  <channel>
    <title>CSSSR</title>
    <description>CSSSR — веб-студия по фронтенд-разработке. HTML, CSS, JavaScript.</description>
    <link>http://csssr.github.io/</link>
    <atom:link href="http://csssr.github.io/feed.xml" rel="self" type="application/rss+xml" />
    
      <item>
        <title>Кодекс тестировщика</title>
        <description>&lt;p&gt;Разработка — это хорошо, но без тестирования — никуда. Количество проектов в CSSSR постоянно увеличивается. Растет штат разработки, а значит, растет и потребность в квалифицированных QA-инженерах. Чтобы ускорить процесс отбора, мы, аналогично вакансиям для разработчиков, придумали тестовый квест для QA.&lt;/p&gt;

&lt;p&gt;Как и в случае с разработкой, только небольшая часть кандидатов справляется на достойном уровне, а значит, общему уровню тестирования точно есть куда расти. Мы дадим пару подсказок, в чём может быть дело, и как прокачать себя, а заодно получить шанс присоединиться к профессиональной команде CSSSR.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/images/qa/art_1.webp&quot; alt=&quot;art_1&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Нет, речь не о чит-кодах :) Мы разработали своеобразный «кодекс тестировщика», следуя которому, вы сможете решать тестовые квесты (а затем и рабочие задачи) намного эффективнее. Ниже вы увидите много слов «должен». Но это вы должны не нам, а профессии, когда выбрали свой путь в тестировании.&lt;/p&gt;

&lt;h3 id=&quot;тестировщик-должен-быть-внимательным&quot;&gt;Тестировщик должен быть внимательным&lt;/h3&gt;

&lt;p&gt;Это, в принципе, краеугольный камень профессии — замечать то, что не заметил никто другой. Для этого наш квест наводнен подводными камнями. Иногда камни настолько мелкие, что их непросто заметить. А иногда баги настолько бросаются в глаза, что воспринимаются как должное. Так что обо всем, что вызывает у вас подозрение, стоит подумать дважды и обсудить это поведение с &lt;a href=&quot;https://ru.wikipedia.org/wiki/%D0%9C%D0%B5%D1%82%D0%BE%D0%B4_%D1%83%D1%82%D1%91%D0%BD%D0%BA%D0%B0&quot;&gt;уточкой&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/images/qa/art_2.gif&quot; alt=&quot;art_2&quot; /&gt;&lt;/p&gt;

&lt;h3 id=&quot;тестировщик-должен-быть-азартным&quot;&gt;Тестировщик должен быть азартным&lt;/h3&gt;

&lt;p&gt;Не надо останавливаться на очевидных дефектах. Часто возникают ситуации, когда наиболее критичные ошибки находятся в результате выполнения нестандартных кейсов. Даже если дефект не критичен — в любом процессе важно зафиксировать его. Хороший QA не боится зайти далеко в своих проверках и зарепортить всё, что можно зарепортить.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/images/qa/art_3.gif&quot; alt=&quot;art_3&quot; /&gt;&lt;/p&gt;

&lt;h3 id=&quot;тестировщик-должен-думать-как-пользователь&quot;&gt;Тестировщик должен думать как пользователь&lt;/h3&gt;

&lt;p&gt;Нужно уметь думать и действовать как пользователь. А лучше — как разные, и не всегда логически мыслящие, пользователи. При тестировании QA должен учитывать не только соответствие требованиям и макету, но и удобство для пользователя, и сообщать, если с этим могут возникнуть проблемы.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/images/qa/art_4.gif&quot; alt=&quot;art_4&quot; /&gt;&lt;/p&gt;

&lt;h3 id=&quot;тестировщик-должен-быть-изобретательным&quot;&gt;Тестировщик должен быть изобретательным&lt;/h3&gt;

&lt;p&gt;Никакие препятствия не должны останавливать вас на пути ловли багов. Не можете найти android определенной версии или отсмотреть Safari? Внимание! Именно для таких случаев в природе существуют онлайн-эмуляторы, и не онлайн тоже есть, есть платные версии, есть абсолютно бесплатные. &lt;a href=&quot;https://quality-lab.ru/blog/cross-browser-compatibility-testing/&quot;&gt;Вот эта статья&lt;/a&gt; должна помочь.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/images/qa/art_5.gif&quot; alt=&quot;art_5&quot; /&gt;&lt;/p&gt;

&lt;h3 id=&quot;тестировщик-должен-быть-ловким&quot;&gt;Тестировщик должен быть ловким&lt;/h3&gt;

&lt;p&gt;Познавайте науку владения инструментами. Изучайте новый инструментарий, периодически проводите ревизию старого, придумывайте новые способы, но не забывайте и про стандартные решения. Подсказка в два слова: Dev Tools.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/images/qa/art_6.gif&quot; alt=&quot;art_6&quot; /&gt;&lt;/p&gt;

&lt;h3 id=&quot;тестировщик-должен-быть-командным-игроком&quot;&gt;Тестировщик должен быть командным игроком&lt;/h3&gt;

&lt;p&gt;Тестировщик не работает в гордом одиночестве. Он должен уметь конструктивно общаться с командой, не бояться сообщать о проблемах и думать не только о багах, но и о тех, кто их будет чинить.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/images/qa/art_7.gif&quot; alt=&quot;art_7&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Правильно оформленные репорты важны не столько проверяющим тестовый кейс, сколько самим разработчикам — ведь в итоге это делается для них. Часто нам присылают отчеты в виде тест-ранов. Задумайтесь, кому из команды, кроме лида тестирования, нужны раны на проекте? Разработчику совершенно некогда сидеть и вычитывать оттуда баги. Поэтому не лишним будет изучить или освежить в памяти принципы грамотного багтрекинга. &lt;a href=&quot;https://habr.com/ru/company/docsvision/blog/264163/&quot;&gt;Вот тут&lt;/a&gt; собрана полезная информация по оформлению баг репортов.&lt;/p&gt;

&lt;h3 id=&quot;тестировщик-должен-уметь-оптимизировать&quot;&gt;Тестировщик должен уметь оптимизировать&lt;/h3&gt;

&lt;p&gt;Даже если вы подаетесь на вакансию ручного тестировщика, навыки автоматизации рутинных задач крайне необходимы в условиях дефицита времени. Не стесняйтесь выделиться из толпы и прислать автотест. Пусть он будет максимально простым, но важно, что вы хотя бы попробовали.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/images/qa/art_8.gif&quot; alt=&quot;art_8&quot; /&gt;&lt;/p&gt;

&lt;h3 id=&quot;тестировщик-должен-быть-чист-умом-и-помыслами&quot;&gt;Тестировщик должен быть чист умом и помыслами&lt;/h3&gt;

&lt;p&gt;Наш человек умеет аккуратно оформлять свои мысли и доносить их. Он структурирует своё решение и раскладывает его по полочкам: вёрстка, кроссбраузерность, юзабилити. Каша в работе означает кашу в голове, поэтому таких кандидатов мы отправляем доучиваться мастерству.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/images/qa/art_9.gif&quot; alt=&quot;art_9&quot; /&gt;&lt;/p&gt;

&lt;h3 id=&quot;тестировщик-должен-быть-немного-больше-чем-тестировщиком&quot;&gt;Тестировщик должен быть немного больше, чем тестировщиком&lt;/h3&gt;

&lt;p&gt;&lt;img src=&quot;/images/qa/art_10.webp&quot; alt=&quot;art_10&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Тестировщику нужно разбираться в предмете деятельности основной команды. К примеру, мы разрабатываем фронтовую часть веб приложений. Для нас важно, когда пользователю красиво и понятно. Поэтому от своих тестировщиков мы ожидаем понимания UX и желания улучшить его &lt;a href=&quot;https://habr.com/ru/company/jugru/blog/436196/&quot;&gt;всеми возможными способами&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/images/qa/art_11.gif&quot; alt=&quot;art_11&quot; /&gt;&lt;/p&gt;

&lt;p&gt;В CSSSR тестировщик — это не просто собиратель чужих багов, он отличается высокой степенью самостоятельности и отвечает за качество разрабатываемого продукта. QA инженеру важно понимать, что тестирование — это важная часть разработки продукта, а не какая-то отдельная стадия после. Без тестировщика не обсуждаются фичи, без апрува тестировщика запрещено идти в прод с релизом. Тестировщик — это еще и кладезь знаний о проекте. По выверенной тестовой документации можно писать спеку, а при личном общении тестировщик может рассказать всю подноготную проекта.&lt;/p&gt;

&lt;p&gt;Если вы обладаете вышеперечисленными качествами и не боитесь принять на себя ответственность за качество продукта, то смело откликайтесь на вакансию. Мы очень вас ждем!&lt;/p&gt;

&lt;h3 id=&quot;список-полезных-ссылок&quot;&gt;Список полезных ссылок&lt;/h3&gt;

&lt;p&gt;&lt;a href=&quot;http://okiseleva.blogspot.com/2014/02/blog-post_6.html&quot;&gt;Список полезных книг для тестировщика&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;https://dou.ua/lenta/articles/scheme-for-qa/&quot;&gt;Универсальная схема для тестирования веб-приложения&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;https://quality-lab.ru/blog/key-principles-of-web-testing/&quot;&gt;Особенности тестирования веб-приложения&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;http://testingchallenges.thetestingmap.org/index.php&quot;&gt;Потренить свои скиллы&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Познавательные ресурсы:
&lt;a href=&quot;http://radio-qa.com/&quot;&gt;Radio QA&lt;/a&gt;
&lt;a href=&quot;https://qablog.practitest.com/&quot;&gt;PractiTest&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Про автоматизацию:
&lt;a href=&quot;https://webdriver.ru/&quot;&gt;Webdriver&lt;/a&gt;
&lt;a href=&quot;https://selenium.dev/documentation/en&quot;&gt;Selenium&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;https://trello.com/b/2hvbzg9y/nightwatchjs&quot;&gt;Если вы хотите быть модным автотестером :)&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;https://medium.com/javascript-testing/setup-javascript-based-qa-automation-testing-framework-with-nightwatch-js-selenium-web-driver-4a1b845c0a6d&quot;&gt;Почувствуй себя автоматизатором&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/images/qa/art_12.webp&quot; alt=&quot;art_12&quot; /&gt;&lt;/p&gt;
</description>
        <pubDate>Wed, 08 Apr 2020 00:00:00 +0000</pubDate>
        <link>http://csssr.github.io/2020/04/08/qa-codex/</link>
        <guid isPermaLink="true">http://csssr.github.io/2020/04/08/qa-codex/</guid>
      </item>
    
      <item>
        <title>Итоги 2019 от CSSSR</title>
        <description>&lt;h1 id=&quot;пролог&quot;&gt;Пролог&lt;/h1&gt;

&lt;p&gt;&lt;img src=&quot;/images/year-resume2019/zann.jpg&quot; alt=&quot;image&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Живу один в сталинке в ЦАО. Звукоизоляция от внешнего мира потрясающая, ибо стены из кирпича больше метра толщиной (где снаружи пилястры идут — больше полутора). От соседей звукоизоляция так себе, но это компенсируется их малой активностью, доходящей до незаметности. Неважно. Не суть.&lt;/p&gt;

&lt;p&gt;Часто я сижу в полнейшей тишине такого масштаба, что начинает казаться, что на десятки метров вокруг меня нет ничего живого в доме. Совершенная, абсолютная, полная тишина. Я выключаю свет, зажигаю свечи в канделябрах моего дореволюционного Мюльбаха и в густом бархатном охристом полумраке играю на гитаре, импровизируя в недобрых модальных ладах с недобрыми интервалами. Ощущения охуенные, чувствую себя мамкиным Эрихом Цанном. А если серьезно, тишина и общий антураж таковы, что реально ощущение, будто за окном Москва 1919-го, и как раз только что Осоргина посадили в корабль смерти, а кого-то ведут под Варсонофьевский гараж.&lt;/p&gt;

&lt;p&gt;И в этой циклопической, почти хтонической тишине, в ставшей уже аметистовой комнате, ты видишь его…&lt;/p&gt;

&lt;h1 id=&quot;10-лет-немого-крика&quot;&gt;10 лет немого крика…&lt;/h1&gt;

&lt;p&gt;…кажется, подходят к концу. Всё началось в мае 2009 года с первым релизом Ноды, потом через год релиз AngularJS, потом были knockout, meteor и backbone. Наконец релиз React в мае 2013го. Рывок JavaScript от jQuery до полноценных фреймворков оказался таким сильным, что в тот момент в сознании IT-индустрии появилось понятие «фронтенд разработка».&lt;/p&gt;

&lt;p&gt;Нет, конечно, такое понятие было и раньше, но тогда речь не шла о полноценной разработке ПО, с полноценным релизным циклом. Интерфейсы пилили те же бэкендеры, но с каждым годом сидеть на двух стульях становилось всё сложнее. Ибо, повторяюсь, качественный рывок JS был таким сильным и таким быстрым, что появилась потребность в новой профессии разработчиков софта.&lt;/p&gt;

&lt;h2 id=&quot;всё-javascript&quot;&gt;Всё JavaScript&lt;/h2&gt;

&lt;p&gt;10 лет насмешек над «снежинками» и «наследование не на классах? Ха-ха», «вот так просто взять и создать объект? Умора!».&lt;/p&gt;

&lt;p&gt;Но что мы имеем сейчас? Всё JavaScript. Не только веб-интерфейсы. Игровые тоже, и это не «индюшатина», а &lt;a href=&quot;https://www.youtube.com/watch?v=Pkf9H3XEMoE&quot;&gt;Battlefield&lt;/a&gt;. Electron и React Native — для устройств. Даже TensorFlow имеет порт на JavaScript.&lt;/p&gt;

&lt;p&gt;Посмотрите на ТОП-50 гитхаба. JavaScript стал символом опенсорс-разработки, раскатистым гимном того, что программирование доступно каждому пользователю Интернета.&lt;/p&gt;

&lt;p&gt;На этом, думаю, с ретроспективой покончено. Самое время перейти к «широко известным в узких кругах» событиям, не вошедшим в новогодний хит-парад подкаста «Новости 512».&lt;/p&gt;

&lt;h2 id=&quot;deno&quot;&gt;Deno&lt;/h2&gt;

&lt;p&gt;&lt;img src=&quot;/images/year-resume2019/deno.png&quot; alt=&quot;image&quot; /&gt;
Это новый (альтернативный?) виток эволюции Node, за авторством всё того же Райана Дала.&lt;/p&gt;

&lt;p&gt;Помните скандал c &lt;a href=&quot;https://habr.com/ru/post/431360/&quot;&gt;event-stream в ноябре прошлого года?&lt;/a&gt; Тогда малварь утекла на тысячи машин. Возможность достучаться к файловой системе — ахиллесова пята Node.&lt;/p&gt;

&lt;p&gt;В отличие от Node, Deno, по умолчанию, выполняет код в «песочнице». Это означает, что у среды выполнения нет возможности выполнить «посторонние» скрипты или работать с файловой системой. (На самом деле доступ есть и к файловой системе, и переменным окружения, но для этого нужно передать специальные ключи)&lt;/p&gt;

&lt;p&gt;Вторая киллер фича — TypeScript из коробки, никаких конфигов, никаких лоадеров. По сути получается, что Deno — это рантайм для TS.&lt;/p&gt;

&lt;h2 id=&quot;мультиязычность-graalvm&quot;&gt;Мультиязычность GraalVM&lt;/h2&gt;

&lt;p&gt;У GraalVM в этом году &lt;a href=&quot;https://github.com/oracle/graal/releases/tag/vm-19.0.0&quot;&gt;первый стаблильный релиз&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Всё в лучших библейских традициях. Вместо воды и вина интерпретаторы и компиляторы. GraalVM не даст возникнуть «вавилонскому столпотворению» в коде. Да, все по-прежнему будут «говорить» на разных языках, но при этом понимать друг друга.&lt;/p&gt;

&lt;p&gt;По сути это универсальная виртуальная машина для выполнения разных языков, в том числе и JS. Мы можем запускать приложения на разных языках в одной среде с возможностью шаринга данных между ними. Соответственно, можно юзать разные библиотеки (из разных ЯП) в одном проекте.&lt;/p&gt;

&lt;h2 id=&quot;commonjs---amd---umd----it-dont-matter-if-youre-black-or-white&quot;&gt;CommonJS -&amp;gt; AMD -&amp;gt; UMD -&amp;gt;  «It don’t matter if you’re black or white»&lt;/h2&gt;

&lt;p&gt;&lt;img src=&quot;/images/year-resume2019/mjs.png&quot; alt=&quot;image&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Да-да, это те самые michael-jackson-файлы (&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;.mjs&lt;/code&gt;). А если говорить общепринятым языком, &lt;a href=&quot;https://nodejs.org/api/esm.html#esm_ecmascript_modules&quot;&gt;ECMAScript Modules&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;В этом году был 12-й мажорный релиз Ноды, который ускорил доставку новой модульной системы в наши светлые репозитории. Фича пока экспериментальная, и всё не так радужно до сих пор, но работа активно ведется, и по сути это один из первых больших шагов на пути к стандартизации модульной системы в JS.&lt;/p&gt;

&lt;h2 id=&quot;bigint&quot;&gt;BigInt&lt;/h2&gt;

&lt;p&gt;Математика больших чисел в этом году &lt;a href=&quot;https://developer.mozilla.org/ru/docs/Web/JavaScript/Reference/Global_Objects/BigInt&quot;&gt;заехала&lt;/a&gt; во все популярные браузеры, за исключением Egde. Но Edge простительно, сами понимаете &lt;a href=&quot;https://www.theverge.com/2019/11/4/20942038/microsoft-edge-chromium-release-date-new-logo-features&quot;&gt;из-за чего&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;В финтехе часто приходится работать с большими числами. Для тех же арифметических операций над числами с плавающей точкой теперь можно эмулировать какой-нибудь BigDecimal, используя BigInt. До этого такие механики создавались с помощью сторонних библиотек.&lt;/p&gt;

&lt;p&gt;Очевидно, что нативная реализация должна быть существенно производительней текущих third-party решений.&lt;/p&gt;

&lt;h2 id=&quot;нет-виртуального-dom-нет-фреймворков-поверх-фреймворков-нет-фреймворка-в-рантайме-есть-svelte-и-тот-исчезающий&quot;&gt;Нет виртуального DOM. Нет фреймворков поверх фреймворков. Нет фреймворка в рантайме. Есть Svelte. И тот &lt;a href=&quot;https://www.youtube.com/watch?v=NvNe4nKmZT0&amp;amp;feature=emb_title&quot;&gt;«исчезающий»&lt;/a&gt;.&lt;/h2&gt;

&lt;p&gt;Строго говоря, само существование Svelte не ново. В этом году был релиз аж третьей версии. Но именно после третьей версии о &lt;a href=&quot;https://habr.com/ru/post/446026/&quot;&gt;Svelte&lt;/a&gt; &lt;a href=&quot;https://habr.com/ru/post/449450/&quot;&gt;заговорили&lt;/a&gt;. Да как заговорили! Сотни комментов только к статьям-переводам. И речь не про косяки Реакта или очередной «You don’t need Redux».&lt;/p&gt;

&lt;p&gt;А добавить-то и нечего. Основные понятия я уже вынес в подзаголовок. А для поленившихся тогда, но желающих «потыкать или хотя бы одним глазом глянуть» — вот образцовый интерактивный &lt;a href=&quot;https://svelte.dev/tutorial/basics&quot;&gt;учебник&lt;/a&gt;.&lt;/p&gt;

&lt;h2 id=&quot;logux&quot;&gt;Logux&lt;/h2&gt;

&lt;p&gt;Ещё одно детище отечественного опенсорса, собранного под эгидой Андрея Ситника и его алчущих «ваших мозгов» &lt;a href=&quot;https://cultofmartians.com/done.html&quot;&gt;марсиан&lt;/a&gt;. Тут ситуация сродни Svelte: о технологии знают достаточно давно. Среди киллер-фич были замечены:&lt;/p&gt;
&lt;ul&gt;
  &lt;li&gt;offline first,&lt;/li&gt;
  &lt;li&gt;синхронизация между вкладками,&lt;/li&gt;
  &lt;li&gt;упрощение (и часто &lt;em&gt;замещение&lt;/em&gt;) клиентского Redux.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Но только в этом году Logux сошёл с ярких страниц гитхаба и получил отдельный &lt;a href=&quot;https://logux.io/guide/architecture/core/&quot;&gt;ресурс с документацией&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;По словам Андрея:&lt;/p&gt;
&lt;blockquote&gt;
  &lt;p&gt;Само собой, сайт построен не на популярных реакт-решениях. В треде расскажу об экспериментах, которые удалось в нём реализовать.
17 килобайт веса, 100 очков на Lighthouse, никаких фреймворков. Фокус на DX и UX.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Помимо исходников в твите все могут изучить &lt;a href=&quot;https://evilmartians.com/chronicles/new-home-for-logux-pouring-love-into-an-oss-documentation-website&quot;&gt;развёрнутый пост&lt;/a&gt; Андрея о разработке доки, чтобы «заглянуть под капот новому лицу Logux».&lt;/p&gt;

&lt;h1 id=&quot;эпилог&quot;&gt;Эпилог&lt;/h1&gt;

&lt;p&gt;Мы заигрались за 10 лет становления JavaScript и фронтенда. Да так успешно, что все в награду получили аметистового протодракона. Сейчас покажу, как это вышло:&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/images/year-resume2019/wow1.png&quot; alt=&quot;image&quot; /&gt;
&lt;img src=&quot;/images/year-resume2019/wow2.png&quot; alt=&quot;image&quot; /&gt;
&lt;img src=&quot;/images/year-resume2019/wow3.png&quot; alt=&quot;image&quot; /&gt;
&lt;img src=&quot;/images/year-resume2019/wow4.png&quot; alt=&quot;image&quot; /&gt;
&lt;img src=&quot;/images/year-resume2019/wow5.png&quot; alt=&quot;image&quot; /&gt;
&lt;img src=&quot;/images/year-resume2019/wow6.png&quot; alt=&quot;image&quot; /&gt;
&lt;img src=&quot;/images/year-resume2019/wow7.png&quot; alt=&quot;image&quot; /&gt;
&lt;img src=&quot;/images/year-resume2019/wow8.png&quot; alt=&quot;image&quot; /&gt;
&lt;img src=&quot;/images/year-resume2019/wow9.png&quot; alt=&quot;image&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Ну было же? Было?&lt;/p&gt;

&lt;p&gt;С ежегодной речью выступил Максон «Черная Борода» Вислогуров. До новых встреч в новом десятилетии! Все по драконам!
&lt;img src=&quot;/images/recursion/outro.jpg&quot; alt=&quot;image&quot; /&gt;&lt;/p&gt;
</description>
        <pubDate>Thu, 26 Dec 2019 00:00:00 +0000</pubDate>
        <link>http://csssr.github.io/2019/12/26/year-resume-2019/</link>
        <guid isPermaLink="true">http://csssr.github.io/2019/12/26/year-resume-2019/</guid>
      </item>
    
      <item>
        <title>Оценка задач. Как перестать гадать и начать угадывать</title>
        <description>&lt;p&gt;&lt;img src=&quot;/images/sroki_illustr.png&quot; alt=&quot;estimation&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Работа с оценкой и сроками — это стресс и ответственность, и некоторые разработчики даже придумывают идеологические отмазы против оценки. Но хотят они того или нет, в IT-мире всё вертится не вокруг качества кода, а вокруг сроков и оценок. Разрабатывая быстрее, компания получает конкурентное преимущество перед себе подобными, а адекватная оценка позволяет точно рассчитывать расходы. Заказчика в первую очередь интересуют сроки и конкретная стоимость работы, и оба этих параметра завязаны на оценке разработчика, изучавшего проект на пресейле. Конечно, менеджер заложит дополнительные риски, но это не поможет, если разработчик обсчитался в 3 раза.&lt;/p&gt;

&lt;p&gt;Посмотрим правде в глаза — от оценки никуда не деться, и если вы не оцениваете задачи на проекте, то, скорее всего, за вас это делает кто-то другой. Между тем, разработчик, дающий адекватные оценки и в них попадающий — это бриллиант для работодателя. Такие специалисты ценны, и они растут гораздо быстрее, чем товарищи, у которых с оценками беда.&lt;/p&gt;

&lt;p&gt;Наша команда набила немало шишек на некачественных оценках. Из-за них мы не попадали в бюджет, портили отношения с заказчиками или, как минимум, выглядели глупо. Методом проб и ошибок мы вывели свод правил, которые помогли повысить точность наших оценок. Надеемся, вам они тоже пригодятся.&lt;/p&gt;

&lt;h2 id=&quot;создайте-условия&quot;&gt;Создайте условия&lt;/h2&gt;

&lt;p&gt;Начнём с того, что систематические плохие оценки и существенные просрочки могут быть не только вашей виной. Прежде всего, для хорошей оценки должен быть соблюдён ряд условий.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;На оценку выделяется достаточно времени&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Это ответственное и кропотливое дело, и если на оценку крупной фичи дают всего 15 минут — немудрено, что что-то важное может ускользнуть от внимания оценщика. Если у вас происходит именно так, ваш долг перед командой и её продуктивностью — донести до менеджмента, насколько высоки ставки, и что «лишний» час оценки сможет предотвратить 100 часов просрочки.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Оценка крепко вплетена в ваш воркфлоу&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Вы не сможете прокачать в себе навык оценки до приличного уровня, когда вокруг бардак: задачи оцениваются от случая к случаю, вас внезапно посреди работы над задачей заставляют её оценивать, и в целом неясно, когда задачу нужно оценивать, а когда нет. Первый шаг навстречу эффективной работе с оценкой — взрастить в своей команде культуру оценки. Высокий уровень командной дисциплины — один из гарантов эффективности. Если у вас есть точный регламент, гласящий, на каком этапе задачу нужно оценивать, а в конце проекта разработчик может сделать вывод о качестве своей оценки, то разброд и шатания в итоге будут минимальными, а плотность работы с оценкой — высокой. И тогда повышение качества станет делом времени.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Задачи ставятся качественно&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Каким бы огромным опытом вы ни обладали, вы не сможете заложить оценку на те части функционала, о существовании которых даже не догадываетесь. Чтобы учесть все-все детали задачи — и скрытые на начальном этапе, и те, которые появятся впоследствии — нужно обладать третьим глазом, и в реальном мире, увы, такого не бывает. Но можно минимизировать эти риски при помощи хорошего, или хотя бы сносного ТЗ.&lt;/p&gt;

&lt;p&gt;В тех случаях, когда ТЗ не оставляет никаких надежд на точную оценку, не бойтесь задавать вопросы, даже если это займёт время.&lt;/p&gt;

&lt;p&gt;В идеале оценка должна состоять из двух фаз:&lt;/p&gt;
&lt;ul&gt;
  &lt;li&gt;Вы внимательно читаете ТЗ, задаёте по нему вопросы аналитику или представителю заказчика.&lt;/li&gt;
  &lt;li&gt;Получаете ответы и оцениваете задачу.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Но на правду больше похожа другая история:&lt;/p&gt;
&lt;ul&gt;
  &lt;li&gt;Вы внимательно читаете ТЗ и задаёте возникшие вопросы носителю идеи.&lt;/li&gt;
  &lt;li&gt;Вы получаете ответы, на основе которых возникает ещё больше вопросов.&lt;/li&gt;
  &lt;li&gt;И снова.&lt;/li&gt;
  &lt;li&gt;И снова.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Процесс может затягиваться, но эти временные затраты обязательно окупятся. К слову, на этом этапе мы часто подключаем тестеров вместо разработчиков. Баги в постановке задачи — это дорогие баги, и чем больше людей будет участвовать в их отлове, тем стройнее и качественнее будет результат.&lt;/p&gt;

&lt;h2 id=&quot;работайте-над-собой&quot;&gt;Работайте над собой&lt;/h2&gt;

&lt;p&gt;Теперь перейдём к правилам оценки и поговорим о том, что можете сделать лично вы для улучшения перформанса команды.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Декомпозируйте задачу и делайте это на совесть&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Ешьте слона частями. Хорошая декомпозиция даёт мощный буст к укладываемости в оценку. Это стоит делать, даже если вы не планируете распараллеливать задачи между разными разработчиками. Во-первых, декомпозируя, вы смотрите на задачу чуть ближе, вертите так и сяк, планируете, как будете её выполнять, а значит — видите новые хитрости и заковыристости, на которые стоит заложить дополнительное время. Во-вторых, это дополнительная возможность самоконтроля: если вы пилите монолитную задачу на 120 часов, проще не уследить за временем и потратить 30 часов там, где стоило бы потратить 12. С декомпозицией такое не пройдёт.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Сравнивайте свои оценки и фактически затраченное время&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Чтобы прокачать навык оценки, необходимо получать обратную связь о том, насколько близки к реальности оказались ваши предыдущие эстимейты. Можно сделать себе фильтр в джире, или ведите список хоть в гугл-таблице.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Учитывайте риски&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Отдельно оговаривайте всё, что может существенно повлиять на оценку. К таким факторам относятся:&lt;/p&gt;
&lt;ul&gt;
  &lt;li&gt;незаконченная постановка задачи (неготовые макеты, незаконченное ТЗ, непонятки с API и всё-всё-всё, что «предоставят позже»);&lt;/li&gt;
  &lt;li&gt;технология, с которой вы раньше не работали;&lt;/li&gt;
  &lt;li&gt;«белые пятна» в описании и отсутствие ответов на ваши вопросы.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Сообщайте об этом при оценке задачи, кричите погромче о том, что изменение постановки задачи повлечёт за собой рост трудозатрат.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Будьте реалистами&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Ваш менеджер или тимлид, задавая вопрос «Сколько времени это займёт?», интересуется вовсе не тем, сколько вам понадобится времени конкретно на написание кода. Тем не менее, на этом первое время сыпятся все (ну или почти все). Здесь эта цифра бесполезна, она не соотносится с реальностью. Так что возьмите время, которое вы потратите на написание кода, прибавьте к нему время на покурить, выпить кофе, не выспаться и протупить полдня в стену, спросить совета у соседа, подождать ответа от аналитика, правок макета от дизайнера, заблокироваться бэкендом, разблокироваться, десять раз упасть и одиннадцать подняться. Сколько именно закладывать на риски? Мой совет — начните с 20% для больших задач и 50% для маленьких. Затем смотрите на результат и при необходимости корректируйте эту цифру.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Не прогибайтесь&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Не соглашайтесь занижать оценку, особенно если на 100% уверены, что это не сработает. Приучите своих коллег к тому, что это займёт столько времени, сколько займёт. Учитесь аргументировано защищать свои оценки, поскольку с вами всегда будут пытаться торговаться.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Не завышайте оценки (существенно)&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Если с заниженными оценками всё более-менее понятно, то что не так с оценками завышенными? Разве задача, сделанная в два раза быстрее, чем ожидалось, не станет приятным сюрпризом? Возможно, где-то, для кого-то. С некоторыми оговорками:&lt;/p&gt;

&lt;p&gt;Это снижает дисциплину.
Закон Паркинсона — задача занимает столько времени, сколько на неё заложили: может больше, но почти никогда не меньше. И по нашему опыту, лишь единицы могут нормально сдаваться раньше срока. Остальным же надо во что бы то ни стало израсходовать всё время, которое дано. Поэтому, перезакладываясь «на всякий случай» без реальных рисков, можете заранее попрощаться с этим временем, т.к., с большой долей вероятности, оно просто уйдёт на течение мыслью по древу.&lt;/p&gt;

&lt;p&gt;Это губительно для планирования и процессов в вашей команде.
Во-первых, загрузка разработчика спланирована наперед на определенный срок. Если каким-то образом карточки двухнедельного спринта уйдут в 3-4 дня, остальная команда останется в недоумении, а разработчик-стахановец — без задач. И выглядит это не геройски, а даже немного глупо, к тому же заставляет серьёзно сомневаться в навыках такого разработчика. 
Во-вторых, процесс разработки ПО не ограничивается одним написанием кода. Есть аналитика, планирование, тестирование, код-ревью, в которых участвуют другие специалисты. И вот ваш бэклог уже пуст, а всем этим ребятам надо прям вот щас всё бросить и побежать, оставляя свои, возможно, срочные дела, чтобы грумить вам новые задачи и тестировать старые.
Таким образом, эффективность планирования и взаимодействия команды плавно пикирует к нулю, плодя хаос и разрушение.&lt;/p&gt;

&lt;p&gt;И, пожалуй, последний совет.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Расслабьтесь :)&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Иногда вы будете факапить. Иногда и мы всё ещё факапим. Это не удивительно — столько всего может пойти не по плану! Но важно не опускать руки и анализировать свои успехи и неудачи, адаптировать чужие процессы и правила и изобретать свои собственные — такие, которые будут работать именно для вашей команды.&lt;/p&gt;

&lt;p&gt;Надеемся, перечисленные советы помогут избежать частых «детских» ошибок на этом долгом и увлекательном пути.&lt;/p&gt;
</description>
        <pubDate>Wed, 04 Sep 2019 00:00:00 +0000</pubDate>
        <link>http://csssr.github.io/2019/09/04/estimate-like-god/</link>
        <guid isPermaLink="true">http://csssr.github.io/2019/09/04/estimate-like-god/</guid>
      </item>
    
      <item>
        <title>Есть ли жизнь на удалёнке или как перестать верить в единорогов</title>
        <description>&lt;p&gt;&lt;em&gt;Однажды разработчик перешёл на удалёнку, уехал на Бали, больше никогда не стоял в пробках, забыл про дресс-код, курил на рабочем месте, жил-поживал и добра наживал. Конец?&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/images/opening.png&quot; alt=&quot;unicorn&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Привет, мы рекрутеры CSSSR, и мы должны вас предостеречь. Работать в распределённой команде — радостно и приятно. А ещё сложно и утомительно.  Многие кандидаты приходят к нам после офиса или фриланса и надеются на кардинально лучшую жизнь. И перспективы действительно радужные:&lt;/p&gt;
&lt;ul&gt;
  &lt;li&gt;Работа в штате = стабильность: есть пул задач, перспективы карьерного роста и равномерный финансовый поток.&lt;/li&gt;
  &lt;li&gt;Свободу перемещений при этом никто не отменял — если не брать самые строгие случаи, то home office может быть где угодно, так что зимовки на Бали вполне реальны.&lt;/li&gt;
  &lt;li&gt;Кажется, что можно успевать намного больше — не нужно тратить время на поиск задач (фриланс) или дорогу (офис), коллеги не отвлекают перекурами, а ходить на встречи можно сидя.&lt;/li&gt;
  &lt;li&gt;Отсутствие дресс-кода становится приятным дополнением для тех, кто до этого работал в классическом офисе. Даже если в компании приняты видеосозвоны, брюки можно не надевать.&lt;/li&gt;
  &lt;li&gt;В некоторых случаях это может быть единственным приемлемым вариантом — например, для тех, кто по каким-то причинам не может каждый день добираться до офиса, кому сложно находиться среди людей целый день или кто в офлайн-мире подвергается дискриминации.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Где же подвох?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;На самом деле, как очевидных препятствий, так и подводных граблей в удалённой работе немало. И чтобы эффективно и с удовольствием работать в распределённой команде, важно заранее чётко себе представлять, с чем имеешь дело. Чтобы не теоретизировать, мы попросили собственных родных и близких (далёких) коллег на условиях анонимности поделиться, с какими сложностями им пришлось столкнуться. В результате собрали эксклюзивную коллекцию болей и страданий среднестатистического удалёнщика.&lt;/p&gt;

&lt;p&gt;* * *&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/images/freelance_vs_udalenka.png&quot; alt=&quot;sad&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Начнём с основ: удалённая работа — это не фриланс. В случае CSSSR это означает работу по чёткому графику. За гарантию загрузки и стабильность приходится платить невозможностью каждый день спонтанно менять рабочее место или сорваться утром в понедельник и уехать на целый день фотографировать дельфинов.&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;«Я работала из Тасмании по московскому времени (с обеда и до ночи). Было обидно, когда пару раз я пропустила Южное сияние (Аврору) только потому, что не смогла сорваться сразу и поехать на гору его смотреть — были запланированы созвоны и другие задачи, которые можно решить только в команде и только в рабочее время»&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Сферический удалёнщик в вакууме посещает по одной стране в неделю. Среднестатистический удалёнщик в CSSSR перемещается «иногда», а часто вообще только в отпуске. Из опрошенных коллег только четверть признались, что регулярно меняют место жительства.&lt;/p&gt;

&lt;p&gt;Вот вам пруф:&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/images/stats.png&quot; alt=&quot;stata&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Безусловно, работать на берегу моря — очень романтично. И настолько же неудобно. Где розетка? Где туалет? Где тень? Зато точно знаешь, где песок — он повсюду, в том числе в клавиатуре. У бабушки в деревне — прекрасно, но проблемы с вайфаем. В кафе может оказаться и розетка, и вайфай, зато шумно и официант навязчиво предлагает заказать что-нибудь ещё. По нашему опыту, спонтанно путешествовать на постоянной основе и при этом эффективно работать — тонкий лёд.&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;«Каждый день менять себе рабочее место нельзя. В реальности мы путешествуем так — переезжаем на несколько месяцев в страну и задницу с места там не поднимаем»&lt;/p&gt;
&lt;/blockquote&gt;

&lt;blockquote&gt;
  &lt;p&gt;«Это называется Ньепи — четвёртый день местного НГ [День Тишины на Бали, в этот день запрещено выходить на улицу, включать свет и вообще проявлять признаки жизни]. Я попал на него в прошлом году, и у меня интернет не отключали. Свет тоже был, но включать его я не решился, т.к. сказали, что можно запросто получить за это кирпичом в окно. Если выйдешь на улицу, тебя поймает и отведёт в полицию специальный отряд печалангов (так они зовутся). В этом году инет отключали, но я свалил на соседний остров, чтобы не страдать»&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;* * *&lt;/p&gt;

&lt;p&gt;Но допустим, что путешествия не для вас. И вы затеяли всю эту историю с удалёнкой как раз для того, чтобы поменьше выходить из дома. Проблема решена? Ещё чего.&lt;/p&gt;

&lt;p&gt;При организации домашнего рабочего места всплывает много нюансов. В отличие от офиса, обеспечивать себя техникой, скорее всего, придется самостоятельно. А также столом, стулом, чашкой, пробудительными напитками, обедом и тишиной. Какой-то стол и стул найдётся, конечно, в любой квартире. Или диван с подушками. На худой конец пол, стена и колени. Для того, чтобы запилить быструю задачу, пойдёт, но на постоянной основе так работать не выйдет — спина, руки и другие части тела потребуют эргономики и заботы.&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;«Проводить целый рабочий день за обычным кухонным столом, сидя на табуретке, — больно»&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;img src=&quot;/images/taburetka1.png&quot; alt=&quot;taburetka&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Другая насущная проблема: при работе из дома теряется ритм «пришёл в офис — работаю, ушёл — отдыхаю». Может быть сложно погрузиться в работу утром или, наоборот, переключиться на другие дела вечером.&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;«Не ожидал столкнуться с тем, что рабочий день может случайно и не закончиться. Как с утра сел — так ночью и отвалился от компа :D»&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;К тому же интенсивность работы на удалёнке часто бывает выше, чем в офисе — коллеги, понятно, не видят, что вы отошли или разговариваете с кем-то другим, решая срочный вопрос. Спасают статусы в Slack, менеджмент задач и много терпения.&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;«Бывает ли у вас в офисе, что с вами одномоментно говорят 5 человек с разных проектов по 5 разным вопросам, и ты обязан им одновременно отвечать, иначе они возмущаются, что ты их не слушаешь и вообще куда-то пропал? Скорее всего нет. А на удаленке это самый обычный рабочий день менеджера»&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Физически не видят удалёнщика не только коллеги, но и начальство. Работодателю так или иначе нужно держать распределённый рабочий процесс под контролем, и к этому тоже нужно привыкнуть. В удалённых компаниях или командах могут быть задействованы разные способы управления по шкале от безоговорочного доверия до тяжёлой артиллерии в виде следящих программ. Как с этим жить — вопрос другой. Но стоит учитывать такие моменты и узнавать заранее все условия работы, это поможет сэкономить много нервов.&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;«Первое время у меня никак не получалось добиться желаемых 8 рабочих часов в день в трекере. После того, как я поделилась этой болью с менеджерами, они рассказали, какие ошибки я совершаю — много незатреканного времени уходило на обсуждения, переключения между задачами, а порой я и сама собственными руками сокращала затреканное время, т.к. мне казалось, что со стороны выглядит, что на задачу потрачено неоправданно много минут»&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;* * *&lt;/p&gt;

&lt;p&gt;Итак, вы проявили мудрость — сидите дома, подготовили рабочее место, настроили инструменты и предвкушаете продуктивный день. Что же мы имеем? Ожидание: меньше стресса, знакомая обстановка, тишина, «дома и стены помогают». Реальность: хорошо бы на этих стенах обои переклеить, а ещё вот собака просится на улицу, а раз уж ты идёшь с собакой, то сходи-ка в магазин и на почту… Cосредоточиться будет тяжело. Особенно это касается тех, кто живёт не один. Безобидные вопросы, заботливые приглашения к завтраку/обеду/чаю и даже простой бытовой шум будут сбивать с толку и мешать концентрироваться. В тяжёлых случаях работа из дома может вообще не восприниматься домашними всерьёз.&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;«У меня мама очень переживала, что я в шараге какой-то работу нашёл. Частично успокоилась она только после того, как компания оплатила мне билеты на митап в Москву и когда трудовой договор привёз. И совершенно успокоилась, когда я ушёл в оплачиваемый отпуск»&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;И если маму ещё можно убедить, что занят, и занят серьёзным делом, то с некоторыми другими членами семьи такое не пройдёт.&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;«Поначалу было сложно не отвлекаться на котиков»&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;img src=&quot;/images/kotik1.png&quot; alt=&quot;catgod&quot; /&gt;&lt;/p&gt;

&lt;p&gt;И даже если никто не мешает, поддержание мотивации и борьба с прокрастинацией всё равно полностью ложатся на собственные плечи. Когда никто не видит, может быть сложнее держать себя в руках, ведь они так и тянутся к соседним вкладкам с соцсетями и ютубом. Тем, кто изначально не может похвастаться высокой самоорганизованностью, поначалу придётся работать не только над задачами, но и над собой.&lt;/p&gt;

&lt;p&gt;* * *&lt;/p&gt;

&lt;p&gt;Предположим, вы справились со всеми помехами, благополучно работаете дома, выстроили график, заказали еду на неделю вперед и радуетесь по-интровертски.
Сюрприз! Не выходить из дома — тоже плохая идея.&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;«Раньше я думал, это [работать удалённо] наверное слишком интровертно для меня, и я оказался прав. Большую часть рабочего дня я сижу дома или в кофейне, или иногда выползаю в коворкинг, и * БЛИН * я просто ужасно страдаю от одиночества. Это стало моей самой лютой проблемой на удаленке»&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;После продолжительной работы на удалёнке многие из нас обнаружили, что живое человеческое общение творит чудеса. Первое время вы отдыхаете от болтливых коллег и неприятных попутчиков в общественном транспорте, но затем начинаете ощущать собственную изоляцию. Появляется апатия и вялость. С друзьями встречаться всё сложней, особенно если они работают в офисе и не прочь на выходных как раз таки остаться дома.&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;«Жить как интроверт круто только первые полгода. Потом ты постепенно теряешь человеческий вид»&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;img src=&quot;/images/introvert1.png&quot; alt=&quot;wild&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Кроме того, от нехватки движения и близости холодильника здоровье начнёт портиться, а формы — приобретать мягкость и округлость. Посмотрим правде в глаза — беговые дорожки и велотренажеры регулярно используют дома только самые организованные и оседлые люди с несколькими лишними квадратными метрами жилой площади. В сочетании с социальной изоляцией картина становится совсем печальна.&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;«Вынести мусор может быть приключением, если всю неделю работаешь, не выходя из дома»&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;* * *&lt;/p&gt;

&lt;p&gt;Так что же это, игра не стоит свеч? Безусловно, стоит. Просто нужно хорошо знать правила этой игры:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;
    &lt;p&gt;Отнеситесь к переходу на удалённую работу ответственно, взвесьте для себя все плюсы и минусы.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;Самоорганизованность спасёт мир. По крайней мере, ваш внутренний.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;Работа должна быть отделена от дома и личной жизни, даже если это в одном помещении и на одном компьютере.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;Важно организовать качественное рабочее место. Нет, не на диване.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;Не забывайте двигаться и выходить на свежий воздух.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;Удивительно, но живое общение — важно. Если не хотите брать количеством, берите качеством.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;Перемещаясь по миру, помните о трёх китах — интернет, розетка, тишина — и заранее продумывайте, где их найти.&lt;/p&gt;
  &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;img src=&quot;/images/final.png&quot; alt=&quot;i_am_unicorn&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Ну и напоследок простой, но дельный совет: если вы подумываете об удалёнке, попробуйте взять пару дней в неделю на текущей работе. Это очень многое расставит по своим местам.&lt;/p&gt;

&lt;p&gt;// На самом деле у нас есть ещё много советов, но об этом в другой раз.&lt;/p&gt;

&lt;p&gt;P.S.
Коллеги периодически пишут полезные статьи про быт удалёнщика, не проходите мимо:&lt;/p&gt;
&lt;ul&gt;
  &lt;li&gt;&lt;a href=&quot;https://blog.csssr.ru/2016/07/01/habits&quot;&gt;Полезные привычки для удалённой работы&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;Стимуляторы работы программиста: &lt;a href=&quot;https://blog.csssr.ru/2019/02/28/work-better&quot;&gt;Обстановка&lt;/a&gt;, &lt;a href=&quot;https://blog.csssr.ru/2019/03/18/work-harder&quot;&gt;Мотивация&lt;/a&gt;, &lt;a href=&quot;https://blog.csssr.ru/2019/05/07/work-stronger&quot;&gt;Здоровье&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://blog.csssr.ru/2016/02/25/how-remote-developers-talk&quot;&gt;Правила общения удалённых разработчиков&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
        <pubDate>Wed, 26 Jun 2019 00:00:00 +0000</pubDate>
        <link>http://csssr.github.io/2019/06/26/unicorn-busters/</link>
        <guid isPermaLink="true">http://csssr.github.io/2019/06/26/unicorn-busters/</guid>
      </item>
    
      <item>
        <title>Формальная и интуитивная семантика языка программирования на примерах JS и JSX</title>
        <description>&lt;blockquote&gt;
  &lt;p&gt;Эта статья — расширенная версия &lt;a href=&quot;https://youtu.be/rVFW009olAI&quot; target=&quot;_blank&quot;&gt;доклада&lt;/a&gt; на PiterJS tour#1.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Мотивацией к написанию этого материала послужила постоянная сложность, возникающая от чтения чужого кода, которая, должно быть, появляется у каждого. Какие-то конструкции кажутся избыточными или излишне сложными, какие-то вообще ошибочными. Иногда трудно понять, какую бизнес-задачу пытался решить автор и, в частности, какие особенности языка или стека ему в этом мешали. Даже собственный код спустя некоторое время становится малопонятным. Кажется, эта самая понятность исходит из контекстов: продукта, проекта, архитектуры и стека (фреймворки, библиотеки), команды и принятого кодстайла. С этим ничего не поделаешь, приходится вновь погружаться во все эти контексты и искать связи между ними — только тогда каждая конструкция в коде обрастает понятной мотивацией, страх перед неизвестностью проходит и желание всё переписать стихает.&lt;/p&gt;

&lt;p&gt;Но бывает, можно натолкнуться на чужой, совершенно неизвестный код, который выглядит лаконичным и понятным. Сразу ясно, какую задачу он решает и как. Причем такой код может быть даже написан на другом языке программирования или с использованием неизвестного стека, но почему-то он нормально читается, &lt;strong&gt;интуитивно&lt;/strong&gt; рассказывая свою историю.&lt;/p&gt;

&lt;p&gt;Вот я и задался вопросом, есть ли всё же какие-то универсальные правила построения и структурирования кода, которые бы не зависели от конкретного языка программирования или стека? Я решил попробовать найти ответ, копнув в самую глубь, изучив, что такое язык программирования в общем и как с помощью этого понимания вывести правила лучших практик. Получилось поверхностное исследование, которое лишь приоткрыло всю глубину, сложность и историю вопроса, но в то же время чётко определило направление пути.&lt;/p&gt;

&lt;h2 id=&quot;декларативность&quot;&gt;Декларативность&lt;/h2&gt;

&lt;p&gt;Многие называют «декларативное» программирование панацеей понятности и читаемости, но так ли это на самом деле? Почему кто-то с этим согласен на все 100%, а кто-то совершенно не разделяет энтузиазма? Нужно разобраться.&lt;/p&gt;

&lt;p&gt;Все, наверное, слышали, чем декларативное программирование отличается от императивного: декларативное описывает, &lt;strong&gt;что&lt;/strong&gt; нужно сделать, а императивное — &lt;strong&gt;как&lt;/strong&gt; это нужно сделать. Но говоря об этом, обязательно стоит помнить, что при декларациях того, что нужно сделать, идет оперирование какими-то &lt;strong&gt;существующими&lt;/strong&gt; элементами, о которых мы знаем, &lt;strong&gt;как&lt;/strong&gt; они работают (иначе наши декларации ничего бы не стоили). Декларативное программирование — это способ описания программы через набор &lt;strong&gt;верхнеуровневых&lt;/strong&gt; инструкций, детали реализации и исполнения которых скрыты за исполнителем этих инструкций. Под исполнителем могут подразумеваться: функции высшего порядка (ramda, react, redux-saga), макросы (JSX) в случае кодогенерации, JIT компилятор в случае исполнения (синтаксис ЯП — языка программирования), машинные коды — декларативное описание логики переключения транзисторов процессора. Т.е. средство описания деклараций всегда имеет какой-то контекст, и «декларативность» означает не какой-то конкретный паттерн, а текущий уровень восприятия глубины абстракции разработчиком.&lt;/p&gt;

&lt;p&gt;Например, классическим примером декларативного программирования является код в функциональном стиле:&lt;/p&gt;

&lt;div class=&quot;language-js highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nx&quot;&gt;array&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;filter&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;predicate&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;А что можно сказать про такой код?&lt;/p&gt;

&lt;div class=&quot;language-js highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nx&quot;&gt;instruction&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;type&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;filter&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;target&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;array&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;arguments&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;predicate&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Он более декларативен — в нём нет прямого вызова функций, а только описание того, что нужно сделать. Как такое может быть, есть градации декларативности? А лучше ли этот код в плане читаемости и понимаемости? Кажется, ответ не совсем однозначный.&lt;/p&gt;

&lt;p&gt;Так же можно рассмотреть классический «императивный» код:&lt;/p&gt;

&lt;div class=&quot;language-js highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kd&quot;&gt;let&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;i&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;i&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;array&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;length&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;++&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;predicate&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;array&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]))&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;result&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;push&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;array&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;])&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Он кажется более сложным, чем приведённые сниппеты выше, но если посмотреть на результирующий машинный код, то код с &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;for&lt;/code&gt; и &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;if&lt;/code&gt; покажется вполне простым и декларативным, т.к. он скрывает то, &lt;strong&gt;как&lt;/strong&gt; работать с памятью на системном уровне.&lt;/p&gt;

&lt;p&gt;Из всего этого можно сделать простой вывод: декларативность — это термин для определения уровня абстракции, который для каждого человека может быть разным в зависимости от контекста.&lt;/p&gt;

&lt;hr /&gt;

&lt;!-- https://gist.github.com/artalar/6de0d1778bb62634214b69dbcb7090cb --&gt;
&lt;!-- ![](/images/semantics-in-programming/fp-vs-imperative.png) --&gt;

&lt;p&gt;Как-то на ревью PR на работе я увидел чрезмерно «функциональный» подход в написании определённого набора действий и попробовал переписать этот код на «императивщину». Детали кода не важны, с первого взгляда видно, что «императивный» код (снизу) короче и в нём лучше выделены смысловые конструкции за счет их подсветки, а ещё он производительнее.&lt;/p&gt;

&lt;div class=&quot;language-js highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;export&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;validateFormFields&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;state&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;kd&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;displayedFields&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;selectFormFieldsNames&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;state&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;map&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;name&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;selectFormField&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;state&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;filter&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;isSystem&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;

  &lt;span class=&quot;kd&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;arrayFields&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;displayedFields&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;filter&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;isArray&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;

  &lt;span class=&quot;kd&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;emptyRequiredArraysErrors&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;arrayFields&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;filter&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;field&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;isArrayEmpty&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;field&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;field&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;required&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;map&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;field&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;selectFriendlyText&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;state&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;field&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;title&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;field&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;));&lt;/span&gt;

  &lt;span class=&quot;kd&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;arrayCellsErrors&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;arrayFields&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;filter&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;field&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;!&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;isArrayEmpty&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;field&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;isTable&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;field&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;reduce&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;((&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;acc&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;field&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[...&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;acc&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;...&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;validateArrayCells&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;state&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;field&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)],&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[]);&lt;/span&gt;

  &lt;span class=&quot;kd&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;notArrayFields&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;displayedFields&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;filter&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;field&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;!&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;isArray&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;field&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;));&lt;/span&gt;
  &lt;span class=&quot;kd&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;notArrayFieldsErrors&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;notArrayFields&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;filter&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;field&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;field&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;required&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;isValueExist&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;field&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;value&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;map&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;field&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;selectFriendlyText&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;state&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;field&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;title&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;field&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;));&lt;/span&gt;

  &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;...&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;notArrayFieldsErrors&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;...&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;emptyRequiredArraysErrors&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;...&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;arrayCellsErrors&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;];&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;VS&lt;/p&gt;

&lt;div class=&quot;language-js highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;kd&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;validateFormFields&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;state&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;kd&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;fieldsNames&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;selectFormFieldsNames&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;state&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
  &lt;span class=&quot;kd&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;result&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[];&lt;/span&gt;

  &lt;span class=&quot;k&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kd&quot;&gt;let&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;i&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;i&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;fieldsNames&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;length&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;++&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;kd&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;field&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;selectFormField&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;state&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;fieldsNames&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]);&lt;/span&gt;

    &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;isSystem&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;field&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;continue&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;

    &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;!&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;isArray&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;field&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;field&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;required&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;isValueExist&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;field&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;value&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt;
      &lt;span class=&quot;nx&quot;&gt;result&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;push&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;selectFriendlyText&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;state&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;field&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;title&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;field&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;));&lt;/span&gt;

    &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;!&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;isArray&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;field&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;continue&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;

    &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;isArrayEmpty&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;field&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;field&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;required&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
      &lt;span class=&quot;nx&quot;&gt;result&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;push&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;selectFriendlyText&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;state&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;field&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;title&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;field&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;));&lt;/span&gt;

    &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;!&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;isArrayEmpty&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;field&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;isTable&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;field&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt;
      &lt;span class=&quot;nx&quot;&gt;result&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;push&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(...&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;validateArrayCells&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;state&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;field&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;));&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

  &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;result&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;При этом многие коллеги высказывались, что функциональный код им нравится больше и стоит использовать его. Тогда я устроил голосование в чате. Как же было забавно наблюдать, как мнение делится поровну, и кому-то понятнее функциональный подход, а кому-то императивный:&lt;/p&gt;

&lt;!-- ![](http://s.csssr.ru/U8SMMLH99/2019.04.25-22:43:27.png) --&gt;
&lt;p&gt;&lt;img src=&quot;/images/semantics-in-programming/fp-vs-imperative-poll.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;

&lt;p&gt;За функциональный подход высказалось больше людей, и многие из них — разработчики с богатым опытом. Хотелось им доверять, но при этом результаты голосования показали, что не всё так однозначно. В действительности те, кто имел опыт и привык работать с библиотеками в функциональном стиле, просто привыкли к такому паттерну и образу мышления, но это не означает, что он является единственно верным.&lt;/p&gt;

&lt;p&gt;И функциональный, и императивный код решают одну и ту же задачу и дают один и тот же результат, но совершенно по-разному читаются, воспринимаются и даже исполняются в JIT. Проще говоря, эти два кода имеют разную &lt;strong&gt;семантику&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;P.S. Код был в итоге переписан в функциональном стиле, но с вынесением определенной логики в отдельные функции.&lt;/p&gt;

&lt;hr /&gt;

&lt;h2 id=&quot;семантика&quot;&gt;Семантика&lt;/h2&gt;

&lt;p&gt;В изучении проблематики вопроса у меня не сразу получилось сформулировать о чём, с формальной точки зрения, вообще идет речь, есть ли для этого термин? Конечно, я не первый задавался вопросами читаемости и явности кода, и на этот счёт есть немало трудов. Но большинство ответов из первых страниц поисковых запросов и популярных книг по программированию выдавали перечень прикладных советов, часть из которых могут быть реализованы только в некоторых языках (зависят от синтаксиса). Хотелось найти первопричину, а к ней простое и универсальное элегантное решение, в котором не было бы противоречий. Например, следуя классическим советам, проектируя переиспользуемые компоненты, очень сложно избежать &lt;a href=&quot;https://ru.wikipedia.org/wiki/Связность_(программирование)&quot; target=&quot;_blank&quot;&gt;«зацепленности»&lt;/a&gt;. И наоборот, при упрощении абстракций в коде снижается портированность и переиспользование его частей (повышается связанность), код повторяется. Особенно критично это может проявиться в долгосрочной перспективе, когда внесение изменений нужно синхронизировать между всеми одинаковыми участками кода.&lt;/p&gt;

&lt;!-- ![](http://s.csssr.ru/U8SMMLH99/2019.04.25-22:55:13.png) --&gt;
&lt;!-- ![](https://upload.wikimedia.org/wikipedia/ru/0/09/CouplingVsCohesion.svg) --&gt;
&lt;p&gt;&lt;img src=&quot;/images/semantics-in-programming/CouplingVsCohesion.svg&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Явность кода — это не про code style в плане визуального форматирования и именования переменных. Явность кода зависит от множества контекстов — это про микро и макро архитектуру всего приложения и принятых стандартов написания кода. Можно ли обобщить? И тут я подумал: что объединяет все языки программирования? То, что это &lt;strong&gt;языки&lt;/strong&gt; программирования.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Язык&lt;/strong&gt; в общем и язык программирования в частности — это &lt;strong&gt;синтаксис&lt;/strong&gt; и &lt;strong&gt;семантика&lt;/strong&gt;. Две ключевых составляющих, которые определяют, что такое язык, как им пользоваться и выражать на нём свои мысли. И если с синтаксисом всё более менее понятно, то что такое семантика можно долго и упорно (не) понимать, хотя я догадывался, что все ответы на вопросы явности кода — в ней.&lt;/p&gt;

&lt;p&gt;Вообще язык сам по себе — это сложная комплексная сущность, формализованные части которой также сложно понять. Википедия говорит:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Си́нтаксис&lt;/strong&gt; (др.-греч. σύν-ταξις — составление) — раздел лингвистики, изучающий строение и функциональное взаимодействие различных частей речи в предложениях, словосочетаниях и пр. языковых единицах.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Сема́нтика&lt;/strong&gt; (от др.-греч. σημαντικός «обозначающий») — раздел лингвистики, изучающий смысловое значение единиц языка.&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;&lt;strong&gt;Семантика&lt;/strong&gt; отвечает за смысловое значение — ясность выражения мысли.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Ну вот определения, ну вот они что-то описывают — но что это в действительности значит, и как это можно использовать? Всё понимается проще на аналогиях, и можно попытаться найти их для определения синтаксиса и семантики применительно к ЯП. Мне нравится такая: если синтаксис — это какой-то инструмент, то семантика — это правила пользования инструментом.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/images/semantics-in-programming/semantic.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Если попробовать детально разобраться в семантике как составляющей ЯП, то можно прийти к истории, общей теории языков программирования и, в частности, области компиляторов и формальному (математическому) доказательству корректности программ. На этот счёт есть хорошая &lt;a href=&quot;https://youtu.be/FtSWlpKuOKI&quot; target=&quot;_blank&quot;&gt;вводная лекция&lt;/a&gt; университетского курса «Языки программирования и компиляторы». Я кратко перескажу ее.&lt;/p&gt;

&lt;p&gt;Эволюция ЯП в улучшении абстракций: машинные коды, переменные (ассемблер), процедуры и условные переходы (Фортран), структуры (Алгол 68, Паскаль), ООП, функции высшего порядка и развитые системы типов. Сейчас мы, программисты, пользуемся этим, зачастую не задумываясь, как работают языки высокого уровня, какая история за ними стоит и почему они именно такие, какие есть. Но интересно, что сам принцип ЭВМ в процессе развития языков не менялся.&lt;/p&gt;

&lt;p&gt;Вычислительная машина — это большой конечный автомат, точнее, конечный преобразователь (трансдьюсер). Её инструкции — набор переходов. Человеку сложно оперировать такими понятиями, особенно в большой программе, он в принципе мыслит иначе и для быстрого понимания чего-то часто применяет &lt;strong&gt;интуицию&lt;/strong&gt; и абстракции, обобщая логику описания поведения (программы). Мостом же между инструкциями для вычислительной машины и человеком выступает интерфейс, который называется языком программирования. Вообще при написании кода и выражении задачи в виде набора операторов всё, что происходит — это перебор возможных вариантов работы с возможными данными, попытка описать строго формальным языком какую-то абстракцию — бизнес-задачу. И этот процесс (и код, в частности) очень похож на формальное математическое доказательство — бескомпромиссное, чёткое выведение верного решения. Эта похожесть называется &lt;a href=&quot;https://ru.wikipedia.org/wiki/Соответствие_Карри_—_Ховарда&quot; target=&quot;_blank&quot;&gt;«Соответствие Карри — Ховарда»&lt;/a&gt;. Но отличие математического доказательства от написания программы заключается в том, что логика построения программы в первую очередь строится не на формальных доказательствах, а на интуитивных умозаключениях программиста, которые он уже пытается наложить на формальные правила ЯП. Потому что каждую задачу можно описать по-разному. Это, в частности, зависит и от личного представления программиста о задаче, от его привычек и способа мышления, знаний и умения использовать то или иное API языка, библиотек, фреймворков. Но как соотнести абстрактное представление программиста о задаче с чётким и формальным алгоритмом, можно ли формализовать это соотношение? Есть ли какое-то правило, функция, которая описывает и представляет разницу между индивидуальным кодом программиста и формальным необходимым результатом? Вот это как раз и называется &lt;strong&gt;семантика&lt;/strong&gt;.&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;Синтаксис — для парсинга AST и построения структуры программы&lt;/p&gt;
&lt;/blockquote&gt;

&lt;blockquote&gt;
  &lt;p&gt;Семантика — для понимания программы компилятором и интерпретатором&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;В итоге: &lt;strong&gt;семантика позволяет конкретизировать до формального уровня интуитивное представление кода программы&lt;/strong&gt;. Иначе говоря, с первого взгляда код может иметь одну логику поведения, но, учитывая семантику, можно «увидеть» дополнительные аспекты/ветвления алгоритма и за счёт этого проверить программу на наличие ошибок. Я это понял именно так и для себя разделил семантику на две части: формальную и неформальную, или интуитивную. &lt;strong&gt;Формальная семантика&lt;/strong&gt; — это чёткое представление кода программы в инструкции, она описывается спецификацией языка и используется компилятором или линтером для логического анализа кода и ошибок в нём. &lt;strong&gt;Интуитивная семантика&lt;/strong&gt; — это примерное представление программиста о логике, которую воплощает код программы, она менее формализована, но проще понимается человеком.&lt;/p&gt;

&lt;h2 id=&quot;прикладные-примеры&quot;&gt;Прикладные примеры&lt;/h2&gt;

&lt;h3 id=&quot;null-vs-undefined&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;null&lt;/code&gt; VS &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;undefined&lt;/code&gt;&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;null&lt;/strong&gt; — это намеренно пустое значение, &lt;strong&gt;undefined&lt;/strong&gt; — это неопределённое значение или, актуально для JS, неожиданно пустое значение.&lt;/p&gt;

&lt;p&gt;С интуитивной точки зрения и null, и undefined означают пустое значение и имеют одно и тоже поведение, но с точки зрения формальной семантики это разные конструкции, что проявляется в мелочах. Например, если выражение &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;obj.prop === null&lt;/code&gt; верно, можно быть уверенным, что свойство &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;prop&lt;/code&gt; есть в объекте, но его значение пусто. Но если выражение &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;obj.prop === undefined&lt;/code&gt; верно, то нет никаких гарантий, что свойство &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;prop&lt;/code&gt; вообще есть в объекте, из этого ясно лишь то, что значение этого свойства отсутствует. И это наглядный пример, когда интуитивная и формальная семантика разные: первая рассказывает о проверке свойства и значения в объекте, вторая проверяет только значение. Для тех, кто работает с JS давно, это может быть очевидным, но в общем и целом, если я пишу код, в котором есть обращение к свойству, я ожидаю работу со значением этого свойства и не ожидаю, что этого свойства может не быть вовсе. Для проверки наличия свойства я буду использовать оператор &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;in&lt;/code&gt; или метод &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;hasOwnProperty&lt;/code&gt; — это более явно говорит о том, что делает код.&lt;/p&gt;

&lt;p&gt;Код, в котором интуитивная и формальная семантика могут отличаться, тяжелее читать и отлаживать, потому что для его понимания нужно прогонять в мозгу всю спецификацию ЯП, касающуюся используемых конструкций.&lt;/p&gt;

&lt;h3 id=&quot;cсылочная-прозрачность&quot;&gt;Cсылочная прозрачность&lt;/h3&gt;

&lt;div class=&quot;language-js highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;c1&quot;&gt;// [1]&lt;/span&gt;
&lt;span class=&quot;nx&quot;&gt;setTimeout&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;f&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;time&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;prop&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;// [2]&lt;/span&gt;
&lt;span class=&quot;nx&quot;&gt;setTimeout&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(()&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;f&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;prop&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;),&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;time&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Два небольших сниппета кода, приведённых выше, с точки зрения интуитивной семантики, постановки задачи, одинаковые — нужно через какое-то время выполнить колбэк &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;f&lt;/code&gt;. Однако фактически они различаются, и интересно, на что это может повлиять. Строго говоря, у второго варианта отсутствует ссылочная прозрачность: колбэк, который будет выполнен, зависит от переменной &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;prop&lt;/code&gt;, которая может быть изменена после инициализации таймаута, но до выполнения колбэка. В первом варианте это невозможно, т.к. аргумент передаётся по ссылке, а не через переменную замыкания. Это очень хороший пример того, как различия в интуитивной и формальной семантике могут ненамеренно привести к неожиданному поведению и ошибке.&lt;/p&gt;

&lt;h3 id=&quot;тонкости-спецификации&quot;&gt;Тонкости спецификации&lt;/h3&gt;

&lt;div class=&quot;language-js highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;c1&quot;&gt;// [1]&lt;/span&gt;
&lt;span class=&quot;nx&quot;&gt;console&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;log&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;({&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;kc&quot;&gt;null&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;...({&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;kc&quot;&gt;null&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;kc&quot;&gt;null&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;})&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;})&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;// [2]&lt;/span&gt;
&lt;span class=&quot;nx&quot;&gt;console&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;log&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;({&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;2.0&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;kc&quot;&gt;null&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;...({&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;1.0&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;kc&quot;&gt;null&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;2.0&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;kc&quot;&gt;null&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;})&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;})&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;С первого взгляда может показаться, что это очень похожий код, результаты которого тоже будет похожи. Но, согласно спецификации, сортировка свойств объекта имеет некоторые особенности, поэтому в первом случае результат будет &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;{1: null, 2: null}&lt;/code&gt;, а во втором &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;{2.0: null, 1.0: null}&lt;/code&gt; — первыми свойствами всегда идут валидные индексы. Как можно заметить, во втором варианте порядок свойств поменялся. Эта логика не интуитивна и описывается в дебрях спецификации ЯП — формальной семантикой.&lt;/p&gt;

&lt;h3 id=&quot;паттерн-заместитель&quot;&gt;Паттерн «заместитель»&lt;/h3&gt;

&lt;div class=&quot;language-js highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;c1&quot;&gt;// [1]&lt;/span&gt;
&lt;span class=&quot;kd&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;include&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;array&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;target&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kd&quot;&gt;let&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;i&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;i&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;array&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;length&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;++&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;array&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;===&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;target&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;kc&quot;&gt;true&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;kc&quot;&gt;false&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;// [2]&lt;/span&gt;
&lt;span class=&quot;kd&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;include&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;array&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;target&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kd&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;element&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;of&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;array&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;element&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;===&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;target&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;kc&quot;&gt;true&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;kc&quot;&gt;false&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Вот ещё похожий код. Интересный вопрос: какая у него может быть разница в производительности и почему? Продвинутые знания ЯП о работе итераторов могут подсказать, что &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;for of&lt;/code&gt; должен быть немного медленнее, но здесь скрывается ещё одна хитрая проблема.&lt;/p&gt;

&lt;p&gt;Proxy, get и set реализуют паттерн «заместитель», при котором возможно перехватить обращение к свойствам целевого объекта для выполнения какой-то дополнительной логики. Проблема этого паттерна в том, что он воздействует на поведение программы, но это воздействие никак не отражается &lt;em&gt;визуально&lt;/em&gt;. Т.е., говоря о формальной семантике: в этом паттерне она вообще никак не отображается, соответственно, не сходится с интуитивной семантикой.&lt;/p&gt;

&lt;p&gt;Если сравнить код &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;1&lt;/code&gt; и &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;2&lt;/code&gt;, то станет понятно, что с функциональной точки зрения разницы в нём нет, но если &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;array&lt;/code&gt; будет обёрнут в прокси, то каждый вызов &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;array[i]&lt;/code&gt; будет «утяжелён» перехватчиком, поэтому у этого, казалось бы, одинакового кода может быть заметная разница в производительности в пользу варианта с &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;for of&lt;/code&gt; (там перехватчик отработает лишь один раз на &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Symbol.iterator&lt;/code&gt;).&lt;/p&gt;

&lt;p&gt;Если в проекте используются прокси или геттеры и сеттеры, то в любой случайной точке кодовой базы никогда нельзя быть до конца уверенным, есть здесь они или нет. Это невидимый контекст, чтобы узнать о котором иногда, особенно в больших проектах, требуется исследовать большое количество связанного кода. Таким образом, приходится либо постоянно быть неуверенным в читаемом коде, либо производить его многочисленные инспекции. Решением проблемы может быть использование паттерна «декоратор» или любое &lt;em&gt;явное&lt;/em&gt; использование контекста и зависимостей.&lt;/p&gt;

&lt;h3 id=&quot;jsx-vs-js&quot;&gt;JSX vs JS&lt;/h3&gt;

&lt;blockquote&gt;
  &lt;p&gt;JSX должен быть в JS, а не JS в JSX. Top level синтаксис в файле — это JS, сам JSX пишется только между открывающим и закрывающим тегом, соответственно, там необходимо иметь минимум JS. Вот и весь простой принцип написания читабельного JSX.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;div class=&quot;language-jsx highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;p&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;nc&quot;&gt;Component&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;/&amp;gt;&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;// babel -&amp;gt;&lt;/span&gt;
&lt;span class=&quot;nx&quot;&gt;React&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;createElement&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;Component&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;kc&quot;&gt;null&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;JSX с точки зрения интуитивной семантики — вёрстка, он отвечает за то, &lt;strong&gt;&lt;em&gt;что&lt;/em&gt;&lt;/strong&gt; будет отображаться, а не &lt;strong&gt;&lt;em&gt;как&lt;/em&gt;&lt;/strong&gt;, потому что его задача именно в инкапсуляции логики &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;document.createElement&lt;/code&gt; (формальной семантики). И на этом примере можно понять, что хорошая декларативность / метапрограммирование — это когда фактической разницы в результате работы кода с точки зрения интуитивной и формальной семантики нет. Но возвращаясь к JSX: он, как и результат самого HTML, всегда должен быть статичен, независимо от данных. В подтверждение этому выступает API хуков жизненного цикла в классах или хуков в функциональных компонентах — они описываются в JS, до блока с JSX, это наглядно.&lt;/p&gt;

&lt;div class=&quot;language-jsx highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;Switch&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;Route&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;Redirect&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;react-router&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;

&lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;Switch&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;nc&quot;&gt;Route&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;exact&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;path&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;/&quot;&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;component&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;Home&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;/&amp;gt;&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;nc&quot;&gt;Route&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;path&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;/about&quot;&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;component&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;About&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;/&amp;gt;&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;nc&quot;&gt;Redirect&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;to&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;/&quot;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;/&amp;gt;&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;Switch&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Например, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;react-router&lt;/code&gt; является примером очень плохого API, т.к. через компонент &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;&amp;lt;Switch&amp;gt;&lt;/code&gt; он предлагает описывать логику зависимостей от данных прямо в JSX, более того, сам элемент превращается в управляющий блок. При этом классическая семантика полностью рушится, что ведет к ментальному усложнению чтения кода — в JSX может быть спрятана не только вёрстка, и его уже нужно читать вдумчивее, в голове нужно держать больше контекста. Правильнее в JS в начале блока функционального компонента или метода &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;render&lt;/code&gt; описывать все зависимости, высчитывать их и потом в конечный возвращаемый JSX вставлять всё необходимое. Это и есть декларативное описание.&lt;/p&gt;

&lt;div class=&quot;language-jsx highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nx&quot;&gt;title&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;predicate&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;?&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;first&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;second&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;span&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;title&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;span&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Желание описать роутинг или что угодно ещё (есть даже библиотека с компонентами &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;&amp;lt;If&amp;gt;&lt;/code&gt;, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;&amp;lt;For&amp;gt;&lt;/code&gt;) декларативно — понятно, т.к. это кажется нагляднее и проще (хотя не всё так просто, потому что &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;пониманиеАбстракции = время(документация)&lt;/code&gt;). Но нужно понимать, что декларативное описание не обязано иметь единственный синтаксис/шаблон. JSX — это декларативный синтаксис к описанию биндинга модели приложения на DOM, и это означает, что его &lt;strong&gt;не&lt;/strong&gt; нужно использовать для декларативного описания конструкций, которые не относятся к DOM напрямую. Для написания декларативного кода можно использовать, например, библиотеку &lt;a href=&quot;https://ramdajs.com&quot; target=&quot;_blank&quot;&gt;Ramda&lt;/a&gt;, писать &lt;a href=&quot;https://github.com/kentcdodds/babel-plugin-macros&quot; target=&quot;_blank&quot;&gt;макросы&lt;/a&gt; и много другое.&lt;/p&gt;

&lt;p&gt;Также &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;react-router&lt;/code&gt; нарушает принцип SSoT, если в приложении имеется глобальный стейт-менеджер. Из-за этого компоненты, использующие и роутер, и стор, часто имеют какие-то костыли или выступают мостом между двумя стейтами. Хорошим решением было бы использовать роутинг через глобальный стор.&lt;/p&gt;

&lt;hr /&gt;

&lt;div class=&quot;language-jsx highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;nx&quot;&gt;render&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(){&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;
      &lt;span class=&quot;p&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;div&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;gt;&lt;/span&gt;
        &lt;span class=&quot;si&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;renderHeader&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;}&lt;/span&gt;
        &lt;span class=&quot;si&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;renderError&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;}&lt;/span&gt;
        &lt;span class=&quot;si&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;renderList&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;}&lt;/span&gt;
      &lt;span class=&quot;p&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;div&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;gt;&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Есть подход «рендерМетодов», который подразумевает вынесение каких-то логических частей JSX в отдельные методы. Но проблема заключается в том, что связанность такого кода сильно увеличена из-за разброса props и отсутствия этих методов в react-devtools (отображается просто портянка JSX, непонятно откуда взявшаяся).&lt;/p&gt;

&lt;div class=&quot;language-jsx highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;nx&quot;&gt;render&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(){&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;
      &lt;span class=&quot;p&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;div&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;gt;&lt;/span&gt;
        &lt;span class=&quot;p&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;nc&quot;&gt;Header&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;/&amp;gt;&lt;/span&gt;
        &lt;span class=&quot;p&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;nc&quot;&gt;Error&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;/&amp;gt;&lt;/span&gt;
        &lt;span class=&quot;p&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;nc&quot;&gt;List&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;/&amp;gt;&lt;/span&gt;
      &lt;span class=&quot;p&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;div&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;gt;&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Чтобы избежать проблем с «рендерМетодами», достаточно вынести их тело в отдельные компоненты. При этом их проще будет отследить в react-devtools, а некоторые зависимости класса, которые получаются из контекста, скорее всего, получится перенести в новые дочерние компоненты и разгрузить таким образом связанность в родительском компоненте.&lt;/p&gt;

&lt;p&gt;Это наглядный пример того, как, игнорируя заветы семантики, можно получить практические проблемы, которые решаются исправлением кода к семантической верности.&lt;/p&gt;

&lt;hr /&gt;

&lt;p&gt;Render Props через &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;children&lt;/code&gt; тоже подходит как явный пример антипаттерна семантики. Да, сам подход хорошо решает технические проблемы, но сильно ухудшает читаемость кода, нарушая принципы ответственности JSX. Решением может быть использование &lt;a href=&quot;https://github.com/pedronauck/react-adopt&quot; target=&quot;_blank&quot;&gt;сведе’ния&lt;/a&gt; render-props.&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;https://css-tricks.com/an-overview-of-render-props-in-react/&quot; target=&quot;_blank&quot;&gt;Плохие советы&lt;/a&gt; по render-props дают даже на популярном ресурсе &lt;strong&gt;&lt;em&gt;css-tricks&lt;/em&gt;&lt;/strong&gt;:&lt;/p&gt;

&lt;div class=&quot;language-jsx highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;kd&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;App&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;nc&quot;&gt;Wrapper&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;link&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;https://jsonplaceholder.typicode.com/users&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;gt;&lt;/span&gt;
      &lt;span class=&quot;si&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;({&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;list&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;isLoading&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;error&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;})&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;
        &lt;span class=&quot;p&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;div&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;gt;&lt;/span&gt;
          &lt;span class=&quot;p&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;h2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;gt;&lt;/span&gt;Random Users&lt;span class=&quot;p&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;h2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;gt;&lt;/span&gt;
          &lt;span class=&quot;si&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;error&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;?&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;p&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;error&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;message&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;p&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;kc&quot;&gt;null&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;}&lt;/span&gt;
          &lt;span class=&quot;si&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;isLoading&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;?&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;
            &lt;span class=&quot;p&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;h2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;gt;&lt;/span&gt;Loading...&lt;span class=&quot;p&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;h2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;gt;&lt;/span&gt;
          &lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;
            &lt;span class=&quot;p&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;ul&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;list&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;map&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;user&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;li&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;key&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;user&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;id&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;user&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;li&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;gt;)&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;ul&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;gt;&lt;/span&gt;
          &lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;}&lt;/span&gt;
        &lt;span class=&quot;p&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;div&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;gt;&lt;/span&gt;
      &lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;}&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;nc&quot;&gt;Wrapper&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;/&amp;gt;&lt;/span&gt;
  );
}
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Приведённый код выглядит как каша: JSX и JS сильно смешаны, очень сложно разобрать саму вёрстку.&lt;/p&gt;

&lt;p&gt;Можно попробовать не использовать JSX для контейнеров. Интересно, что тогда код больше похож на использование хуков:&lt;/p&gt;

&lt;div class=&quot;language-jsx highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;kd&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;App&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;React&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;createElement&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;
    &lt;span class=&quot;nx&quot;&gt;Wrapper&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;link&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;https://jsonplaceholder.typicode.com/users&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;},&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;({&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;list&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;isLoading&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;error&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;})&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
      &lt;span class=&quot;kd&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;errorView&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;error&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;p&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;error&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;message&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;p&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;gt;&lt;/span&gt;
      &lt;span class=&quot;kd&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;listView&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;list&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;map&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;user&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;li&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;key&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;user&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;id&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;user&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;li&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;gt;)&lt;/span&gt;
      &lt;span class=&quot;kd&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;bodyView&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;isLoading&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;?&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;h2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;gt;&lt;/span&gt;Loading...&lt;span class=&quot;p&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;h2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;ul&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;listView&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;ul&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;gt;&lt;/span&gt;

      &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;
        &lt;span class=&quot;p&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;div&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;gt;&lt;/span&gt;
          &lt;span class=&quot;p&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;h2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;gt;&lt;/span&gt;Random Users&lt;span class=&quot;p&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;h2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;gt;&lt;/span&gt;
          &lt;span class=&quot;si&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;errorView&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;}&lt;/span&gt;
          &lt;span class=&quot;si&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;bodyView&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;}&lt;/span&gt;
        &lt;span class=&quot;p&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;div&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;gt;&lt;/span&gt;
      &lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Во втором примере &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;errorView&lt;/code&gt; и &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;bodyView&lt;/code&gt; проще вынести в отдельные компоненты и уменьшить связанность.&lt;/p&gt;

&lt;hr /&gt;

&lt;p&gt;Показательным примером важности семантики расстановки блоков кода являются новые хуки в React.js:
&lt;!-- https://twitter.com/threepointone/status/1056594421079261185
https://twitter.com/prchdk/status/1056960391543062528
--&gt;
&lt;!-- ![](lost-chapters-of-frontend-book/2019-03-21-14-18-27.png) --&gt;
&lt;img src=&quot;/images/semantics-in-programming/class-vs-hooks.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;

&lt;p&gt;В этом примере код на классах был переписан на хуки, и, помимо сокращения количества строк, можно увидеть, что смысловые блоки сгруппировались. Благодаря этому понимать какие-то конкретные процессы, описанные кодом, стало проще. Т.е. интуитивную семантику можно повышать не только за счёт другого синтаксиса, но и за счёт правильной расстановки блоков кода. Идеальный баланс: сохранение одинаковой функциональности интуитивной и формальной семантики при минимальном количестве кода.&lt;/p&gt;

&lt;h2 id=&quot;вывод&quot;&gt;Вывод&lt;/h2&gt;

&lt;p&gt;Говоря обобщённо: за кодочитаемость отвечает семантика. В частности, под этим может подразумеваться множество аспектов языка: правильное использование типов данных и их особенностей, синтаксических конструкций, реализованных паттернов программирования (прокси), макросов и метапрограммирования и многое другое. Конечно, невозможно охватить такое многообразие перечнем небольших и конкретных правил, которые помогут писать исключительно идеальный код. Но общий вывод я мог бы сделать такой: явный код не содержит скрытых контекстов или скрытого поведения.&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;&lt;strong&gt;В читаемом и понятном коде нет разницы между интуитивной и формальной семантикой&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;На этом всё, но я буду продолжать исследовать семантику в ЯП и связанные с ней вещи в поисках универсальных правил явности и кодочитаемости. Если у вас будут какие-то предложения — оставляйте комментарии или пишите мне в Телеграм (&lt;a href=&quot;https://t.me/artalar&quot; target=&quot;_blank&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;@artalar&lt;/code&gt;&lt;/a&gt;)&lt;/p&gt;

&lt;h2 id=&quot;полезные-материалы&quot;&gt;Полезные материалы&lt;/h2&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;a href=&quot;https://docs.google.com/presentation/d/1vIg3ZT9C8jmhktWe7yF_CUfHtzfBXRZ0qPls_5o9TIo/edit?usp=sharing&quot; target=&quot;_blank&quot;&gt;Презентация&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;Университетская лекция &lt;a href=&quot;https://youtu.be/FtSWlpKuOKI&quot; target=&quot;_blank&quot;&gt;«Языки программирования, синтаксис, семантика, прагматика»&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;Что такое &lt;a href=&quot;https://ru.wikipedia.org/wiki/Связность_(программирование)&quot; target=&quot;_blank&quot;&gt;зацепленность&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;Что такое &lt;a href=&quot;https://ru.wikipedia.org/wiki/Соответствие_Карри_—_Ховарда&quot; target=&quot;_blank&quot;&gt;соответствие Карри — Ховарда&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://habr.com/ru/company/oleg-bunin/blog/433326/&quot; target=&quot;_blank&quot;&gt;Практические советы по качеству кода&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://twitter.com/prchdk/status/1056960391543062528&quot; target=&quot;_blank&quot;&gt;Разница классов и хуков в React.js&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;Доклад &lt;a href=&quot;https://youtu.be/dCXvQkvSyQg?t=862&quot; target=&quot;_blank&quot;&gt;«Краткий пересказ утерянных глав руководства по фронтенду»&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://youtu.be/rVFW009olAI&quot; target=&quot;_blank&quot;&gt;Доклад&lt;/a&gt; по этой статье&lt;/li&gt;
&lt;/ul&gt;

&lt;blockquote&gt;
  &lt;p&gt;Мнение редактора, сотрудников компании и ваше может не совпадать с авторским, но в этом ведь и смысл дискуссионных статей ¯ \_(ツ)_/¯&lt;/p&gt;
&lt;/blockquote&gt;
</description>
        <pubDate>Sun, 26 May 2019 00:00:00 +0000</pubDate>
        <link>http://csssr.github.io/2019/05/26/semantics-in-programming/</link>
        <guid isPermaLink="true">http://csssr.github.io/2019/05/26/semantics-in-programming/</guid>
      </item>
    
      <item>
        <title>Стимуляторы работы программиста. Здоровье</title>
        <description>&lt;p&gt;&lt;em&gt;Ведущий JS-разработчик CSSSR Евгений Вецель — о том, как повысить производительность, развить суперспособности и получать от работы больше удовольствия.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;О какой &lt;a target=&quot;_blank&quot; href=&quot;http://blog.csssr.ru/2019/03/18/work-harder&quot;&gt;мотивации&lt;/a&gt; может идти речь, если вы чувствуете постоянную усталость, не высыпаетесь и страдаете от головной боли? Организм сообщает, что что-то в вашей жизни нужно поменять. Конечно, есть небольшой шанс, что он намекает, мол, неплохо бы добавить &lt;a target=&quot;_blank&quot; href=&quot;http://blog.csssr.ru/2019/02/28/work-better&quot;&gt;ещё один UltraWide монитор&lt;/a&gt;. Но скорее всего, вам банально не хватает витаминов, у вас аллергия, низкий иммунитет, вы мало отдыхаете или гуляете. Поговорим о здоровье.&lt;/p&gt;

&lt;h2 id=&quot;глава-3-здоровье&quot;&gt;Глава 3. Здоровье&lt;/h2&gt;

&lt;p&gt;Все знают, что на здоровье экономить нельзя, но при нехватке времени на нём экономят в первую очередь. 
В долгосрочной перспективе это очень плохое решение, поэтому предлагаю вам позаботиться о себе, тем более, хорошее самочувствие —  одно из главных условий высокой производительности.&lt;/p&gt;

&lt;p&gt;* * *&lt;/p&gt;

&lt;p&gt;Здоровье — это, прежде всего, физическая нагрузка. Работаешь умом — не забывай и про тело. Смотрите сами, какие физические нагрузки вам нравятся. Бассейн, ходьба, теннис, бег, любая секция, фитнес-клуб, турник дома, отжимание от пола — в наше время выбор большой. Может, в этом и проблема: когда слишком много вариантов, ты пытаешься выбрать вид спорта, а сам в это время едешь в лифте на третий этаж. А бывает, едешь на машине тридцать минут в фитнес-зал, а там ходишь на беговой дорожке час. Но не вините себя: ещё раз скажу, самобичевание и комплекс вины — первая причина прокрастинации и откладывания.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/images/health_1.png&quot; alt=&quot;tired&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Посмотрите на жителей тех стран, где лечение стоит баснословно дорого. Где все жители по утрам? Правильно, на пробежке. Лично я не призываю бегать, я люблю ходить. Я хожу очень много и на большие расстояния. Хоть я и работаю дома, но хожу в дальние магазины, провожаю жену на работу, выдумываю дела в другом конце района. Как мотивировать себя много ходить? Расскажу, как приучал меня к этому папа. Когда я был маленьким и не умел читать, папа рассказывал нам с сестрой разные истории из книг. Длинные истории, содержательные, увлекательные. Но у него был один простой принцип: идём по улице — рассказывает, пришли в помещение — замолкает. Мы с сестрой искали любой повод пойти с папой куда угодно.&lt;/p&gt;

&lt;p&gt;Сейчас, чтобы не скучно было ходить, всегда беру с собой наушники. На YouTube у меня есть плейлист «Поход», куда я складываю все ролики, которые собираюсь послушать во время пеших походов. Поверьте, этот плейлист приходится постоянно пополнять, ведь я хожу минимум час в день. А другие потребляют и больше аудио-видео контента, но при этом сидят на стульях или лежат на диванах, сажая зрение, портя спину, тратя мыслетопливо впустую. Лучше прогуляйтесь, не пожалеете.&lt;/p&gt;

&lt;p&gt;Для плохой погоды у меня есть беговая дорожка. Бегать на ней я, конечно же, не люблю. Ходить могу. Но тоже не очень люблю. Распространённая ошибка — думать, что дорожка сама вас замотивирует, как только вы её купите. Но на ней можно смотреть фильмы или ролики подлиннее и таким образом растягивать «удовольствие».&lt;/p&gt;

&lt;p&gt;* * *&lt;/p&gt;

&lt;p&gt;Поработали, побегали, энергию потратили — теперь поговорим о том, как эту энергию восстановить. Здесь пока нет ничего лучше классики — еда и сон. 
Наверняка вы замечали, что после плотного обеда работоспособность резко падает, и единственное, чего хочется, это поспать. Если нет возможности, то вы идёте курить, развлекать коллег разговорами, появляются важные дела за дверями офиса. Возникает внезапное желание проверить, что нового в рекомендациях YouTube, или глянуть пару новых твитов в ленте. Судя по всему, это связано это с тем, что во время обеда кровь приливает к желудку. Вегетативная система организма заставляет вас снизить уровень активности, и лучшее, что вы можете сделать после обеда — это немного вздремнуть.&lt;/p&gt;

&lt;p&gt;Лично мне хватает 15-20 минут дневного сна, чтобы потом до самого позднего вечера чувствовать себя продуктивным. Даже если вы работаете в офисе, можно найти возможность поспать — я, например, бегал спать в машину. Бросайте отговорки, спите. Только знайте, что 30-40 минут дневного сна работают уже против вас — это связано с чередованием фаз сна. Бодрости такой перерыв не прибавит, мыслетоплива тоже.&lt;/p&gt;

&lt;p&gt;Если вы не можете позволить себе сиесту днём (зря, конечно), делайте между завтраком и обедом 1-2 перекуса, чтобы за счёт этого сократить объём потребляемой в обед пищи. Ещё один из универсальных приёмов уменьшения размера обеда — плотный завтрак, основанный на «долгих» углеводах. Обратите внимание и на другие факторы, которые влияют на прожорливость в вашем случае. Может быть, вы погружаетесь в соцсети, не замечая, сколько съедаете, а может быть, не сразу чувствуете насыщение? Всё это, конечно, индивидуально, поэтому поэкспериментируйте над собой и на практике подберите оптимальный режим.&lt;/p&gt;

&lt;p&gt;Ну и немаловажно: кушайте полезную еду. Узнавайте, какая еда полезная. Редко едите яблоки? Утром разрежьте яблоко и положите в прозрачном контейнере возле рабочего места. Ну и помните, что лёгкие стадии рахита, цинги, авитаминоза, хрупкости костей, ожирения, болезни печени — всё это сопровождает не только мореплавателей, но и производителей ПО для мореплавателей, если они не питаются разнообразно и полезно.&lt;/p&gt;

&lt;p&gt;Старайтесь есть в одно и то же время, не используйте как напоминание, что пора перекусить, ваших коллег и, тем более, функцию Math.random(). Если вы питаетесь нерегулярно, то организм успевает проголодаться, почувствовать нехватку глюкозы и других питательных веществ, и срабатывает система защиты — она будет заставлять вас съесть больше, чтобы накопить запасы. Регулярные обеды позволят вам войти в режим и ввести в режим коллег, которые подсознательно привыкнут, что все вопросы вам нужно задавать до определённого времени. 
Кроме того, сделав перерыв на обед, вы отвлечётесь, а все ваши задачи при этом продвинутся, так как мозг в фоновом режиме будет продолжать решать все зависшие вопросы и укладывать информацию в голове. Вспомните, как после обеда вы стирали или переписывали весь код, который писали всё утро. Запой вреден, в том числе в работе.&lt;/p&gt;

&lt;p&gt;Да, о запоях. Очень многие программисты пьют во время работы. Чай, кофе, газировку, воду и другие напитки. Поговорим об этом. Лично я работаю по системе Pomodoro, и на каждую «помидорку», которая в моём нестандартном случае длится 52 минуты (20 минут перерыв), мне нужна большая кружка жидкости. Эту кружку я выпиваю, не замечая. Привычка, выработанная годами.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/images/health_2.png&quot; alt=&quot;evolution&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Оптимизация питья шла у меня от регулярного кофе, потом пришла к сладкому чаю, потом я перестал класть сахар, а потом перестал класть и чай, и открыл для себя вкусную 16-литровую бутыль обычной воды. Теперь у меня рядом стоит кулер, и я пью столько, сколько нужно моему организму.&lt;/p&gt;

&lt;p&gt;* * *&lt;/p&gt;

&lt;p&gt;Поговорим о главной зависимости творческих людей. Кофе. Однажды этот ароматный напиток позволил мне легко продать квартиру. Квартира казалась уютнее, чем было на самом деле, так как перед просмотром я сварил 6 кружек кофе. Кстати, вы знали, что запах кофе, выпечки, карамелизованного сахара, запах шашлыка, жареного лучка и картошки — это всё одна и та же химическая реакция карамелизации сахаров в разных продуктах? Реакция Майяра — химическая реакция между аминокислотой и сахарами.&lt;/p&gt;

&lt;p&gt;Так вот, вернёмся к кофе. Горячая тема в среде любых много работающих людей. Кофе в долгосрочной перспективе, как и большинство стимуляторов, не даёт энергетического преимущества в производительности. Тут как с кредитом — вы получаете производительность здесь и сейчас, но потом вам хочется спать, и, чтобы продолжать жить в этом состоянии, вам нужно снова выпить кофе, при этом ваш долг будет расти. В придачу, абсолютно бесплатно, ваш организм получает зависимость и необходимость повышать дозу. Зависимость даже обсуждать не буду, почитайте в других местах, но кофе, выпитый после 15:00, может влиять на сон. А сон —  это наше всё.&lt;/p&gt;

&lt;p&gt;Почитайте про реакцию организма на кофе. Помните, что в хороших ресторанах к эспрессо дают стакан воды? Это связано с тем, что кофе, ко всему прочему, — мочегонное. Выплатите кредит и спите спокойно, то есть выпивайте не больше одной чашки натурального кофе утром и запивайте его водой. Удовольствие осталось, зависимость притупилась, производительность в порядке.&lt;/p&gt;

&lt;p&gt;Удивляюсь, как мало людей знает о самом древнем стимуляторе производительности. Китайский чай. Запомните слово Пуэр. Найдите чайный магазин, купите маленький кусочек от чайного «блина». Попросите закинуть вам побольше задач в бэклог, заварите этот чёрный напиток — уверяю, вас ждёт сюрприз. Одна чашечка Пуэра даёт мне эффект чашки кофе, но растянутый до самого вечера и, о чудо, не влияет на сон. Больше о китайском чае я ничего не скажу, чтобы не спугнуть ваше промелькнувшее желание попробовать.&lt;/p&gt;

&lt;p&gt;А теперь коротко о химических стимуляторах работы программиста. Есть различные лекарства, которые стимулируют работу. Лично я их пробовал, да, эффект есть, причём значительный. Но большинство из них имеет и побочные действия: желание всё вокруг переделать, зацикленность на конкретной задаче и невозможность остановиться, желание плясать во время работы, внезапные вспышки памяти, которые заставляют побежать делать то, что вы мечтали сделать год назад. И потом очень жёсткий отходняк в виде внезапных приступов агрессии, ощущения, что стал глупым без лекарств. Всё это приблизительно описано в фильме «Области тьмы». Это не тот путь, который я рекомендую.&lt;/p&gt;

&lt;p&gt;* * *&lt;/p&gt;

&lt;p&gt;Отличный способ поддерживать бодрость и здоровье — закаливание и контрастный душ. Лично я всегда предпочту чашке кофе тазик холодной воды. 
Как понять, что закаляетесь правильно? Если у вас перехватывало дыхание во время процедуры и вы закончили процедуру на холодной воде, то всё правильно. Организм должен испытать короткий неопасный стресс. Тогда он активизирует все защитные силы, и в моём случае их хватает на целый день. Если вы сонливы, ничего не хочется делать, но никогда не закалялись, начните с обливания ног холодной водой — это не больно и не напрягает. Попробуйте, рекомендую.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/images/health_4_.png&quot; alt=&quot;water&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Многие программисты работают без свежего воздуха. Если у вас часто болит голова, вам душно, есть сонливость, ничего не хочется — это может быть признаком кислородного голодания. И если вы думаете, что открыв окно, вы это голодание прекратите, то ошибаетесь. Воздух в комнате должен обновляться дважды в час, это минимум. Должна быть приточная и вытяжная вентиляция. Если вы дышите, но не двигаетесь, то организм не насыщается кислородом. Вспоминаем систему Pomodoro и во время 5-15 минутных перерывов открываем окна, не забывая открыть дверь в комнату.&lt;/p&gt;

&lt;p&gt;Замерьте комфортную вам температуру. В моем случае — чем прохладнее, тем лучше я работаю. Многие учёные тоже считают, что спать и работать лучше при прохладе. Ну и не забывайте измерять влажность помещения. Если чувствуете, что сохнут глаза и часть хочется пить, может быть, стоит подумать об увлажнителе.&lt;/p&gt;

&lt;p&gt;* * *&lt;/p&gt;

&lt;p&gt;Статью о здоровье, конечно, нельзя оставлять без советов проходить ежегодную диспансеризацию. Большинство болезней лечатся специалистами на ранних стадиях, а запустить болезнь можно и за пару лет отсутствия наблюдений.&lt;/p&gt;

&lt;p&gt;Уже знаете, что такое туннельный синдром (надеюсь, не на своём опыте)? Это когда любое движение рукой — провести по пальцами по тачпаду, нажать кнопку на клавиатуре, подвинуть мышку — отдаётся болью, и боль с каждым днём всё сильнее и сильнее. В принципе, это одна из немногих профессиональных болезней программистов, о которой задумываются, когда уже поздно. О какой производительности может идти речь, когда вы в состоянии набирать текст на клавиатуре только одним пальцем? Да, у меня тоже был туннельный синдром. Как я его победил? Вот список мер: 
Стал пользоваться трекпадом с подставкой для запястья, чтобы рука не висела в воздухе.
Клавиатуры использую или slim, где запястье лежит на столе, или с подставкой.
Научился пользоваться левой рукой для трекпада, теперь одинаково хорошо управляюсь, ломка была лишь одну неделю.
Люблю повисеть на турнике.
Предпочитаю помогать коллегам не при помощи чата, а при помощи созвона с расшаренным экраном, времени уходит меньше, а клавиатура вообще не требуется — многие недооценивают, сколько текста они набирают в чатах. К сожалению, ресурс наших суставов не бесконечный.
Делаю регулярные перерывы.
Чтобы не сдавливать локтевой сустав, подкладываю подушечки под локти или пользуюсь мягкими подлокотниками стола.
Слежу, чтобы во время сна не лежать на руке.
Выучил горячие клавиши, изучил vim раскладку и активно ей пользуюсь.
Ну и всё-таки ходите к врачам: не превращайте себя в кота Шрёдингера, добавьте наблюдателя.&lt;/p&gt;

&lt;p&gt;Резюмирую: чередуйте работу и отдых, разумно питайтесь, занимайтесь физическим трудом, много ходите, проветривайте комнату, не пренебрегайте диспансеризацией — и у вас впереди будет много счастливых человеко-часов за компьютером, и большинство из них будут оплачены деньгами, опытом, удовольствием, а не здоровьем.&lt;/p&gt;
</description>
        <pubDate>Tue, 07 May 2019 00:00:00 +0000</pubDate>
        <link>http://csssr.github.io/2019/05/07/work-stronger/</link>
        <guid isPermaLink="true">http://csssr.github.io/2019/05/07/work-stronger/</guid>
      </item>
    
      <item>
        <title>Стимуляторы работы программиста. Мотивация</title>
        <description>&lt;p&gt;&lt;em&gt;Ведущий JS-разработчик CSSSR Евгений Вецель — о том, как повысить производительность, развить суперспособности и получать от работы больше удовольствия.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Итак, вы обставили свой домашний офис, выбрали клавиатуру, настроили высоту кресла, поставили фотку любимого кота на рабочий стол (ещё нет? Тогда вам сюда: &lt;a target=&quot;_blank&quot; href=&quot;http://blog.csssr.ru/2019/02/28/work-better&quot;&gt;Глава 1. Обстановка&lt;/a&gt;). Пора приступать к работе. Но… не хочется!&lt;/p&gt;

&lt;h2 id=&quot;глава-2-мотивация&quot;&gt;Глава 2. Мотивация&lt;/h2&gt;

&lt;p&gt;Представим, что будущее уже наступило и каждый человек — немного киборг. Удобно: чтобы выполнять свою задачу более эффективно, достаточно что-то подкрутить, что-то перепрошить, а в особых случаях нажать кнопку «Boost». В настоящем, к сожалению, всё сложнее. Чтобы начать что-то делать и довести это до конца, нам всегда нужно, пусть и минимальное, волевое усилие. Вот об этих тонких материях мы и поговорим в этой главе.&lt;/p&gt;

&lt;p&gt;* * *&lt;/p&gt;

&lt;p&gt;Мозг человека так устроен, что в нём, на самом деле, тоже есть кнопка, которая умеет включать на сто процентов память, внимание и высокую производительность. За таким состоянием закрепилось название «потока», и оно относится не только к программированию, но к любой деятельности. Другое дело, что нажимать эту кнопку умеют далеко не все. В деле мотивации нужно найти то, что вас «зажигает». Это может быть похвала и оценка окружающих: человек — существо социальное, и в этом нет ничего страшного. В таком случае постарайтесь не предупреждать, что вы задумали грандиозный проект. То, что вы будете делать его втайне и ожидать похвалу, нужно именно вам.&lt;/p&gt;

&lt;p&gt;Если мы говорим о более общих закономерностях, то, думаю, ни для кого не секрет, что память и работа мозга улучшаются, если информация интересна. Прокрастинация и производительность тоже напрямую зависят от интересности задачи.&lt;/p&gt;

&lt;p&gt;Но суровая реальность такова, что, несмотря на корону, никто не обязан давать вам только интересные задачи. Скучные проекты не означают, что руководство вас особенно не любит. Просто то, что интересно другим, не всегда интересно вам, и наоборот. Все люди разные.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/images/motivation1_new.png&quot; alt=&quot;motivation1&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Если хотите быть полезным универсалом, учитесь делать любую задачу интересной для себя. Очень многие люди ждут музу и вдохновение, ждут понедельника или начала года, а некоторые — переезда или появления отдельного кабинета, тем самым оправдывая своё безделье и прокрастинацию.&lt;/p&gt;

&lt;p&gt;Как унылую задачу сделать интересной? Для запоминания скучной информации, вроде списка покупок, часто используют мнемонические приёмы (например, придумывают смешные образы, ассоциирующиеся с тем, что нужно запомнить). Но что делать с полноценной задачей? Ответ: рассмотреть её повнимательнее, оценить опыт, который можно получить, выбрать другой способ выполнения, чтобы превратить её из скучной в увлекательную. Вам дали задачу оцифровать целую тонну xls файлов и превратить в таблицы БД с вложенностью, а сделать это больше некому? Напишите автоимпорт с ручным принятием решения там, где программа затрудняется с ответом. И, чтобы снизить градус нудности задачи, всю редактуру текста делайте в vim, попутно изучая его горячие клавиши. Научитесь хитрить.&lt;/p&gt;

&lt;p&gt;Даже если вы не можете заставить себя взяться за задачу и постоянно откладываете её выполнение, просто сядьте за компьютер, откройте текстовый редактор и начните делать подготовительную работу. Постепенно втянетесь. Наверняка вы помните моменты, когда начинали скучную задачу и вам тут же хотелось пойти сделать мелкие дела, устроить небольшой перерыв, покушать, налить чай, постирать носки. Возьмите в такой момент большой фонарь и осветите преступника, осознайте, что вы намеренно пытаетесь улизнуть.&lt;/p&gt;

&lt;p&gt;Если вы будете читать статьи про прокрастинацию (вместо работы, конечно же), то в них обычно всего два вывода. Первый — прокрастинация усиливается, когда вы предъявляете к себе и к ожидаемому результату завышенные требования, боитесь ошибок и провала. Перфекционизм — самая часто встречающаяся причина прокрастинации.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/images/motivation3.png&quot; alt=&quot;sculptor&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Второй вывод — проблема усиливается, когда вы испытываете чувство вины и стыда за то, что не можете себя заставить работать. Именно ощущение вины, вечное чувство долга и боязнь добавить в копилку ещё один долг могут заставить вас откладывать дело. Вывод: вам стоит научиться говорить «стоп» самому себе. Идеал недостижим, а чувство вины никуда не приведёт, поэтому давайте переходить к действиям.&lt;/p&gt;

&lt;p&gt;* * *&lt;/p&gt;

&lt;p&gt;Итак, поговорим о состоянии потока. Об этом легко ускользающем состоянии, когда всё получается и делается легко, когда ты проваливаешься в задачу и выполняешь её с упоением. Для начала напомню, что работать можно и без состояния потока. Не думайте о потоке, просто работайте работу. Если вам тяжело сконцентрироваться, вы чувствуете, что сегодня не тот день, вы устали, не выспались, объелись, глаза слипаются — займитесь простыми делами, не требующими гениальных решений.&lt;/p&gt;

&lt;p&gt;Если вы не в настроении — можете сделать полезное дело для себя же. Поступайте как опытные столяры: достаньте все необходимые материалы, инструменты, метизы и крепежи, почистите все свои фуганки, рейсмусы, подключите стружкоотсос. Когда все подготовительные работы проведены, приступите к задаче. Если всё под рукой, вы легко сделаете ту самую универсальную модалку, даже не заметив, как прошёл всего час, а вы выполнили задачу, которую планировали делать весь прошлый год.&lt;/p&gt;

&lt;p&gt;Как ещё помочь себе войти в состояние потока? Вспомните фильм «Начало». Используйте триггер. Я люблю один простой приём: включать определённую музыку только во время работы. У меня есть плейлист, который я прослушал уже более тысячи раз. Если начал отвлекаться — открыл новостной сайт, социальные сети или приступил к чтению книги — выключаю плейлист. Должен вырабатываться рефлекс: конкретная музыка = работа. Можно придумать и другой ритуал, который поможет вам включиться в процесс.&lt;/p&gt;

&lt;p&gt;Есть ещё один момент: мозг может отказываться садиться за работу, если знает, что сейчас будет непредсказуемый по времени сеанс. Ему нужно выспаться, приготовить все необходимые химические вещества, морально подготовиться. Если вы регулярно работаете запоями и истощаете все ресурсы, не предупреждая мозг о том, сколько продлится работа, то в следующий раз он обязательно подберёт приёмы, которые позволят отложить эти выматывающие сеансы самоистязания. Именно поэтому нужны регулярные перерывы.&lt;/p&gt;

&lt;p&gt;* * *&lt;/p&gt;

&lt;p&gt;Для организации рабочих интервалов есть различные техники, например «Pomodoro». Это когда вы заводите будильник на 25 или 52 минуты (или другой индивидуально подобранный промежуток). А после того, как он прозвонил, сбегаете с рабочего места отдохнуть. Отдых длится, соответственно, 5 или 17 минут. Во время перерыва у вас тоже тикает таймер, чтобы не появилось соблазна удлинить отдых. Лично у меня в это время идет процесс обдумывания прошлой «помидорки», и после перерыва я зачастую или переписываю, или вообще удаляю код, который написал, не подумав.&lt;/p&gt;

&lt;p&gt;Человеку свойственно зацикливаться, поэтому важно уметь выходить из этого состояния, отвлекаться и смотреть на свою работу со стороны. Так вы легко обнаружите, что занялись «копипастом», уже четыре «помидорки» подряд изобретаете велосипед, забыли учесть ещё одно состояние алгоритма или не обработали ошибки.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/images/motivation2_2.png&quot; alt=&quot;pomodoro&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Техника Pomodoro помогает не отвлекаться. Вы отключаете все уведомления, кроме самых важных, и предупреждаете коллег, что работаете по этой системе. Тогда все сообщения будут накапливаться и вы сможете перед окончанием «помидорки» просмотреть уведомления и начать на них отвечать. Как проверить, нужно ли вам отключать уведомления? Если по выходным, рано утром или поздно вечером, когда все ушли с работы и не отвлекают, вам работается лучше и вы успеваете за эти пару часов сделать больше, чем за весь день — бинго. 25 минут без вас спокойно обойдутся, поэтому заводите таймер.&lt;/p&gt;

&lt;p&gt;Человек многозадачен лишь в теории, он как JavaScript в браузере. Кажется, что можно выполнять задачу и смотреть фильм в фоне. На самом же деле, мозг будет постоянно переключаться между фильмом и программированием, а потом ты удивляешься, как так вымотался, делая простейшую задачу. Делайте одно дело за раз, а остальные забывайте, а лучше записывайте.&lt;/p&gt;

&lt;p&gt;Сейчас вообще процветает &lt;a target=&quot;_blank&quot; href=&quot;https://ru.wikipedia.org/wiki/Клиповая_культура&quot;&gt;«клиповое мышление»&lt;/a&gt; — всё должно мелькать, мы потребляем информацию быстро, не жуя, на огромной скорости. Мы перестаём читать длинные книги, большие статьи, вести собственную базу знаний. Через нас проходит сотня уведомлений, новостей, проектов, задач, дел, и мы впадаем в панику, если пару часов телефон лежит в стороне и молчит. Мы ощущаем себя оторванными от мира, боимся, что за день без интернета отстанем от жизни и уже никогда не догоним. Это не так.&lt;/p&gt;

&lt;p&gt;Опять же, возьмите большой фонарик и осветите преступника «уведомление». Он вас отвлекает. Он вам мешает. Он поглощает всё ваше внимание. Вы превращаетесь в short messages поколение. Всё это незаметно, по грамму, по десять тратит ваше внимание.&lt;/p&gt;

&lt;p&gt;Я люблю представлять, что вся моя мотивация, желание работать, действовать, думать, читать — это «мыслетопливо» (ёмкий термин, который ввёл Максим Дорофеев в книге &lt;a target=&quot;_blank&quot; href=&quot;https://www.mann-ivanov-ferber.ru/books/dzhedajskie-texniki/&quot;&gt;Джедайские техники»&lt;/a&gt;). Работая, ты его тратишь. Отдыхая — накапливаешь. Многие думают, что, когда они прокрастинируют, мыслетопливо накапливается. На самом деле, оно только тратится на все те мелкие дела, которые выдумывает прокрастинирующий. Сесть на диван, закрыть глаза и ничего не делать — вот это верный путь накопления. Вся идея мыслетоплива в том, что нужно уметь анализировать себя и понимать, что конкретно в вашем случае его потребляет, а что производит. И постарайтесь расходовать его продуктивно. Доставайте большой фонарь и освещайте все свои попытки потратить энергию на всякую ерунду.&lt;/p&gt;

&lt;p&gt;Да, и напоследок: не забывайте похвалить себя в конце работы. Если вас критикуют — подумайте, прислушайтесь, поправьте корону на голове, ухмыльнитесь и продолжите быть крутым.&lt;/p&gt;
</description>
        <pubDate>Mon, 18 Mar 2019 00:00:00 +0000</pubDate>
        <link>http://csssr.github.io/2019/03/18/work-harder/</link>
        <guid isPermaLink="true">http://csssr.github.io/2019/03/18/work-harder/</guid>
      </item>
    
      <item>
        <title>Стимуляторы работы программиста. Обстановка</title>
        <description>&lt;p&gt;&lt;em&gt;Ведущий JS-разработчик CSSSR Евгений Вецель — о том, как повысить производительность, развить суперспособности и получать от работы больше удовольствия.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Все хотят написать гениальный код на одном дыхании и после рабочего дня удовлетворенно смотреть на уменьшившийся список задач. Но у одних это получается регулярно, у других только пока Луна в Козероге, а у кого-то практически никогда. Как же себе помочь?&lt;/p&gt;

&lt;p&gt;В интернете на каждом шагу встречаются книги, курсы и вебинары по личной эффективности и повышению производительности. Как показывает практика, волшебного рецепта нет. Зато есть много, казалось бы, мелочей, из которых можно сделать неплохой бодрящий коктейль. В этом цикле статей я не буду давать готовых решений, а поделюсь своим практическим опытом и выводами, полученными в результате многолетних экспериментов над собой. Буду рад, если что-то из этого окажется полезным и сделает вашу жизнь качественно лучше.&lt;/p&gt;

&lt;h2 id=&quot;глава-1-обстановка&quot;&gt;Глава 1. Обстановка&lt;/h2&gt;

&lt;p&gt;Как ни «революционно» это звучит, но условия труда влияют на производительность не только на фабриках. Для тех, кто работает в офисе, этот вопрос частично уже решен. Удалённые сотрудники сталкиваются, с одной стороны, с необходимостью самостоятельно обеспечивать себе все условия, с другой — с полной свободой действий.&lt;/p&gt;

&lt;p&gt;Как я себе представляю программирование большой сложной системы: ты в голове выстраиваешь из хрустальных игральных карт дворец, учитываешь все коммуникации, удобство интерфейсов, просчитываешь вес конструкции, делаешь запас прочности, стараешься не забыть про все требования, пытаешься интегрироваться с чужим полцарством… Так, стоп, кувалдой в центральную башню — Бах! —  Пусть осколки тут полежат, потом соберёшь, что случилось? А это всего лишь короткий вопрос от семейства: «Кушать будешь?», а для тех, кто работает в офисе, сообщение: «Молоко, яйца, хлеб и вкусненькое». Про то, как бороться с отвлечением, мы ещё поговорим в дальнейших статьях, а сейчас — о самой обстановке.&lt;/p&gt;

&lt;p&gt;* * *&lt;/p&gt;

&lt;p&gt;Многие успешные стартапы начинались в &lt;a href=&quot;https://www.blog.google/products/maps/inside-googles-original-garage-1998-style/&quot;&gt;гараже&lt;/a&gt;. В гараже много хлама, помещение не похоже на офис, а чтобы начать работу, приходится выгонять автомобиль. Вместо стола — доски, зимой холодно, летом жарко. Обстановка вроде бы не способствует созданию шедевров… Ан нет, я всё же думаю, что именно гараж, в немалой степени, идеальный образ офиса для многих. В нём нет близких, которые отвлекают, зовут покушать, заходят задать якобы не сильно отвлекающий вопрос: «Ты просто скажи — да или нет». При отключенных мессенджерах даже летящий к гаражу метеорит не сможет вас отвлечь от процесса создания универсальной модалки.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/images//place_1.png&quot; alt=&quot;сave1&quot; /&gt;&lt;/p&gt;

&lt;p&gt;«Подожди, парень, — скажете вы, — то были другие времена. Вот давай мы тебя сейчас посадим за самый дешёвый ноутбук Acer с TFT экраном с разрешением 1024 пикселей и заставим собирать при помощи webpack тяжёлый проект — как ты запоёшь? Какая будет производительность? Давай мы ещё тебя посадим на табурет, вместо стола будет пара картонных коробок, а позади тебя рабочие будут усердно грузить чеснок». 
«Сложно будет», — отвечу я. Но нормальный программист должен воспринимать такие условия как хороший повод потренировать свою помехозащищённость. Профи могут выйти с такого ноутбука в облако, настроить там среду разработки и комфортно работать, попутно обучившись новому навыку настройки серверов.&lt;/p&gt;

&lt;p&gt;Ок, палку не перегибаем, в крайности не впадаем. На картоне не работаем, Windows 95 не используем, неудобные стулья, мышки, клавиатуры обходим стороной. Пока вы ещё джуниор и не имеете большого стажа сидения за компьютером, ваш организм не подаёт сигналов. Чуть позже от коллег, из статей, а, не дай Бог, и от своих кистей или поясницы вы услышите: «Друг, купил бы ты хороших инструментов, а то мы скоро тебе покажем прелести остеохондроза, туннельного синдрома и прочих радостей, которые при определённой настойчивости могут сделать тебя инвалидом!»&lt;/p&gt;

&lt;p&gt;* * *&lt;/p&gt;

&lt;p&gt;Я много лет экспериментировал со своим рабочим местом, оно менялось многократно и самым разным и диким образом, и в итоге сделал для себя вывод, что лучше всего — классическое рабочее место с эргономичным креслом и удобным столом, хорошей вентиляцией и изоляцией от внешнего шума.&lt;/p&gt;

&lt;p&gt;Всё это я организовал у себя на балконе с тройным зеркальным остеклением, кондиционером и теплым полом. Главный плюс балкона — полная изоляция от квартиры. Я могу слушать музыку без наушников, никому не мешая, и мне, в свою очередь, тоже никто не мешает. Можно сказать, это такой современный аналог гаража в российской действительности. Главный минус — внутренний резко континентальный климат: солнце может превратить балкон в 40-градусную теплицу (даже ноутбук чуть вздулся от жары). Поэтому задумывать балкон как постоянный кабинет означает запланировать приобретение кондиционера.&lt;/p&gt;

&lt;p&gt;Один из самых актуальных вопросов — мониторы. Сколько их должно быть? Какого размера? Может, хватит экрана ноутбука? Как это влияет на производительность? Путём долгих экспериментов я выяснил, что если у вас достаточно большой монитор, то производительность при добавлении ещё одного монитора может и упасть. Ведь есть вероятность, что вы расположите там чат или будете тратить время на дирижирование окнами. Кстати, отвлекитесь, поставьте менеджер окон, который умеет двигать окна горячими клавишами. Вы никогда не ставили запись своего экрана и не смотрели таймлапсом за своей работой? Попробуйте, вы удивитесь и сделаете полезные выводы. Так сколько мониторов нужно для высокой производительности? Ответ: не меньше одного. Дальше уже вопрос практики и личных предпочтений.
Лично я обожаю повернутый на 90 градусов экран — почти все статьи, сайты, код, чаты, да практически всё, кроме видео, удобнее смотреть на таком экране. Скроллинг почти не нужен, и глаза находят информацию мгновенно.&lt;/p&gt;

&lt;p&gt;Что ещё помогает мне каждый день?
Механическая &lt;a href=&quot;https://geekboards.ru/product/leopold-fc660c-gray&quot;&gt;клавиатура Leopold&lt;/a&gt; на topre клавишах. &lt;a href=&quot;https://www.youtube.com/watch?v=e9QxYYGPhjA&quot;&gt;Беспроводной трекбол&lt;/a&gt; — спасение от профболезней программистов. &lt;a href=&quot;https://www.apple.com/shop/product/MMEF2AM/A/airpods&quot;&gt;Apple-наушники&lt;/a&gt; с микрофоном.&lt;/p&gt;

&lt;p&gt;В понятие обстановки я бы также включил звуки при работе. Это может быть музыка, звуки природы, звук кафе, шум дороги, ролики с обучением на фоне, работающий телевизор. Как они влияют на производительность? Сильно. Но всё это индивидуально. Когда далее будем говорить о прокрастинации и психологии производительности, я выскажу своё мнение на тему влияния этих звуков. Если коротко, фоновый звук можно превратить в триггер включения в работу, главное правильно им распорядиться.&lt;/p&gt;

&lt;p&gt;* * *&lt;/p&gt;

&lt;p&gt;Ну вот, неплохое рабочее место мы устроили, но, может быть, что-то забыли и его можно сделать ещё лучше? Тут, главное, не впадать в крайности. Организовывая своё рабочее место, очень многие попадают в западню, которую я называю &lt;em&gt;инструментальная прокрастинация&lt;/em&gt;. Если вместо того, чтобы доделать модалку для Джарвиса, вам захотелось подвигать стул, отрегулировать стол, закрыть окно, протереть клавиатуру, поменять разрешение монитора или добавить новый — поздравляю! Вы сейчас инструментально прокрастинируете.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/images/cave.png&quot; alt=&quot;cave2&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Стол, стул, большое количество мониторов, лучшая в мире клавиатура, мышка с трекпадом, рядом беговая дорожка, массажное кресло, доставка еды по расписанию, кресло-мешок, переговорка и спортзал, где можно вздремнуть, отдельный кабинет, коллеги, с которыми можно посоветоваться… Многие думают, что именно этого не хватает, чтобы быть производительным: «Вот сейчас у меня этого всего нет, поэтому я отложу сложную задачу с развитием своего домашнего проекта, так как не хватает ни времени, ни обстановки. Да и спал я не очень, так что завтра…» 
Но западня как раз в том, что чем больше у вас будет денег, тем больше вы будете инструментально прокрастинировать. Вы будете сливать все ваши доходы на эксперименты, вы будете улучшать ваше рабочее место. Вы будете доводить его до идеала, а производительность будет вырастать только на недельку-две, а потом снова падать.&lt;/p&gt;

&lt;p&gt;Вот теперь я открою секрет, который от вас скрывали всю вашу жизнь. Будь у вас деньги, кабинет, всё оборудование и знания железного человека, вы бы не сделали эту универсальную модалку быстро, без боли и не устав. Вы точно так же будете отвлекаться, вам тяжело будет сконцентрироваться, вы будете нервничать на тему нечёткого ТЗ и нелюбимого фреймворка. Так и будете летать и спасать мир с неправильно работающей модалкой в вашем железном шлеме.&lt;/p&gt;

&lt;p&gt;Для меня однажды было откровением, что задача программиста не всегда будет интересной. Язык, на котором нужно написать код, не должен быть хорошим. Фреймворк, который выбрал заказчик, не обязан быть модным. Хороший программист при наличии альтернатив, конечно, выбирает оптимальные инструменты, но он должен уметь выполнить свою задачу и при «военном положении». Нужно уметь захотеть выполнить задачу. Как захотеть? Ответ в следующей главе «Мотивация».&lt;/p&gt;
</description>
        <pubDate>Thu, 28 Feb 2019 00:00:00 +0000</pubDate>
        <link>http://csssr.github.io/2019/02/28/work-better/</link>
        <guid isPermaLink="true">http://csssr.github.io/2019/02/28/work-better/</guid>
      </item>
    
      <item>
        <title>Итоги 2018 от CSSSR</title>
        <description>&lt;p&gt;Здравствуйте! В 2016 я уже подводил &lt;a href=&quot;https://blog.csssr.ru/2016/12/26/year-resume&quot;&gt;итоги&lt;/a&gt;, но тогда у нас в CSSSR не было своего радио и широко охватить события минувшего года не представлялось возможным. В этом году у нас вышли «Новости 512», и вы наверняка уже слушали предновогодний спецвыпуск (если нет, то &lt;a href=&quot;https://soundcloud.com/csssr/512_newyear&quot;&gt;вот он&lt;/a&gt;), в котором Ислам рассказал о самых знаковых событиях года. Сегодня я расскажу о том, что не вошло в итоговый хит-парад «Новостей» в силу самых разных обстоятельств, но о чём всё же стоит упомянуть.&lt;/p&gt;

&lt;p&gt;В целом статья будет выдержана в несколько постироничном, декадентском характере. Многие события года были не совсем позитивными. Скорее противоречивыми. Но, как говорит Никита Прокопов: «Иногда на пасмурном небосводе просвечивают лучики надежды».
Да, кстати, со статьи Никиты я и начну.&lt;/p&gt;

&lt;p&gt;Осторожно! Присутствует ненормативная лексика. 18+&lt;/p&gt;

&lt;h3 id=&quot;нынешняя-ситуация--полное-дерьмо&quot;&gt;«Нынешняя ситуация — полное дерьмо»&lt;/h3&gt;

&lt;p&gt;В очередной раз GitKraken чуть не спалил мне ноут. В очередной раз прогон jest чуть не спалил мне ноут. Мой ноут легонько потрескивает на Ведьмаке 3, но намертво зависает, если открыть WebStorm, Atom или большую репу в кракене. Это вообще законно?&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;cd csssr.blog
mkdir article
cd article
touch why-is-modern-software-such-a-shit.md
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Почему современный софт такое дерьмо? Это не только фронтенда касается, а софта вообще. Интерфейс PS4 — это череда загрузочных экранов и тупящих анимаций.
На сайте PS Store форма оплаты работает через раз. Форма оплаты, Карл! Тачбар на макбуке зависает, пока меняешь ползунок громкости.
В общем, я хотел излить своё негодование на головы читателей, но Никита меня &lt;a href=&quot;https://habr.com/post/423889/&quot;&gt;опередил&lt;/a&gt;. Оригинал &lt;a href=&quot;http://tonsky.me/blog/disenchantment/&quot;&gt;тут&lt;/a&gt;. Тысячи комментов и ретвитов — значит, не только у меня «пригорело», значит, сообществу не всё равно.&lt;/p&gt;

&lt;h3 id=&quot;бета-luna-lang&quot;&gt;Бета luna-lang&lt;/h3&gt;
&lt;p&gt;&lt;img src=&quot;/images/year-resume2018/tony.jpg&quot; alt=&quot;image&quot; /&gt;&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;
	— А если бы кто-нибудь умер? Если бы взорвался макбук прямо в Старбаксе?
&lt;/p&gt;
&lt;p&gt;
	— Я просто хотел быть как вы.
&lt;/p&gt;
&lt;p&gt;
	— Ты должен быть лучше. Верни мне костюм.
&lt;/p&gt;
&lt;p&gt;
	— Но я никто без костюма!
&lt;/p&gt;
&lt;p&gt;
	— Если без него ты никто — ты его не достоин!
&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Luna — это функциональный язык програмирования, главной «фишкой» которого является возможность рисовать или чертить программы. Этакая школьная доска «на стероидах». Без шуток, вы можете моделировать компоненты и буквально рисовать связи и способы передачи данных между ними. Почти как Тони Старк в своей лаборатории. Компоненты в Luna представляют собой вложенные графы потоков данных. Благодаря этому можно перемещаться между различными уровнями абстракций: от визуальной части к побитовым операциям внутри компонента.&lt;/p&gt;

&lt;p&gt;Выглядит это всё, конечно, сногсшибательно, но есть одна проблема. Это «костюм» Luna, его визуальная часть, невероятно разогревающая компьютерное железо. Отдельного упоминания заслуживает лендинг Lunа, отправляющий макбуки в глубокий термотроттлинг. Печально, но без «костюма» перспективы у языка весьма и весьма призрачные.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;UPD:&lt;/em&gt; На момент написания статьи (середина декабря) лендинг всё же отрефакторили, уже без термотроттлинга.&lt;/p&gt;

&lt;h3 id=&quot;перспективный-стейт-менеджмент&quot;&gt;Перспективный стейт-менеджмент&lt;/h3&gt;

&lt;blockquote&gt;
&lt;p&gt;
XXX:
я вот чо узнал в этом году

и мне прям понравилось

https://github.com/zerobias/effector
&lt;/p&gt;
&lt;p&gt;
YYY:
И чому оно замена редаксу?
&lt;/p&gt;
&lt;p&gt;
XXX:
это не замена редаксу, это лучше
&lt;/p&gt;
&lt;p&gt;
YYY:
Документация конечно огонь тут, всё понятно [САРКАЗМ]

Надо понять, чому оно лучше
&lt;/p&gt;
&lt;p&gt;
XXX:
потому что это продвинутый инструментарий для работы с шиной событий

типа вот редакс зачастую прост не нужен, т.к. query там реализован на одном сторе, который отслеживается целиком

а тут query это просто чтение из конкретного места
change-detection и не нужен

command тут вообще огонь, это просто функция которая файрит событие

по сути как в редаксе

но есть эффекты и домены

прям простор для фантазии то какой
&lt;/p&gt;
&lt;p&gt;
YYY:
Ну вроде годится, я как раз такие непопулярные экземпляры собираю
&lt;/p&gt;
&lt;p&gt;
XXX:
ну и так как там ваще говоря по большому счёту шина событий, то прикрутить продвинутые сторы ваще как делать нечего

типа mobx
&lt;/p&gt;
&lt;p&gt;
YYY:
А раньше подобной либы не было?

Это революционная идея что ли?

Чому в редаксе так не сделают?
&lt;/p&gt;
&lt;p&gt;
XXX:
так было во флаксе по сути

mobx можно так организовать
&lt;/p&gt;
&lt;p&gt;
YYY:
Так это изобретение флакса?
&lt;/p&gt;
&lt;p&gt;
XXX:
не, ну домены, эффекты и тд чувак сам придумал

но общая концепция могла увидеть свет и во флаксе

просто сделано заебись, хочется пользоваться
&lt;/p&gt;
&lt;p&gt;
YYY:
Да бля, как ты понял?((( ни доки, ничего нет
&lt;/p&gt;
&lt;p&gt;
XXX:
ну посмотрел)))
&lt;/p&gt;
вообще штука сырая и не прод реди
&lt;/blockquote&gt;

&lt;p&gt;Примерно такой диалог состоялся у меня в этом году (авторская орфография и пунктуация сохранены).
TLDR: вот &lt;a href=&quot;https://github.com/zerobias/effector&quot;&gt;ссылка&lt;/a&gt; на либу, которая, предположительно, воплощает в себе концепцию реактивного флакса и продвинутого стейт-менеджмента. Уйдут ли эти идеи в массовый прод — подскажет статистика: 123 звезды на гитхибе и 0 PR’ов.&lt;/p&gt;

&lt;h3 id=&quot;ssr-не-нужен&quot;&gt;SSR не нужен!&lt;/h3&gt;

&lt;p&gt;И CRITICAL_CSS тоже. И rel=”preload”. И чанки. И бандлы. В список можно докинуть ещё техник, «прокачивающих» загрузку первого экрана.
В твите факты, указывающие на такие перемены.&lt;/p&gt;

&lt;blockquote class=&quot;twitter-tweet&quot; data-lang=&quot;ru&quot;&gt;&lt;p lang=&quot;en&quot; dir=&quot;ltr&quot;&gt;Every website in 2018 &lt;a href=&quot;https://t.co/Gm7jhfuuUO&quot;&gt;pic.twitter.com/Gm7jhfuuUO&lt;/a&gt;&lt;/p&gt;&amp;mdash; Daryl Ginn (@darylginn) &lt;a href=&quot;https://twitter.com/darylginn/status/1053646859686809600?ref_src=twsrc%5Etfw&quot;&gt;20 октября 2018 г.&lt;/a&gt;&lt;/blockquote&gt;
&lt;script async=&quot;&quot; src=&quot;https://platform.twitter.com/widgets.js&quot; charset=&quot;utf-8&quot;&gt;&lt;/script&gt;

&lt;p&gt;Больше не нужно беспокоиться о first-time user experience. Пользователь всё равно этого не заметит, ведь первые 20-30 секунд он будет прокликивать и пиксельхантить все попапы, алерты, GPS-метрики и push уведомления. Пусть ваш сайт, SPA или даже PWA отрендерится сразу на клиенте без каких-либо оптимизаций вообще. Времени хватит на всё.
В попытке не упустить пользователя, старгетировать его интересы, а с мая этого года и соблюсти GDPR визуальным мусором стал наглухо забиваться UX.&lt;/p&gt;

&lt;p&gt;Да, кстати, что там с GDPR? Так ли он нужен? Ведь неспроста…&lt;/p&gt;

&lt;h3 id=&quot;p2p-наносит-ответный-удар&quot;&gt;…p2p наносит ответный удар!&lt;/h3&gt;

&lt;p&gt;Почему это произошло?&lt;/p&gt;

&lt;p&gt;Вообще, тут, конечно, нужно вспомнить, в контексте каких событий прошел год. Шпионские скандалы вокруг Google, сливы инфы от Facebook, блокировки телеги, архивы с личными данными от ВК. На этом фоне набиравшие доселе популярность решения с end-to-end шифрованием и единым центром оказались скомпроментированы.&lt;/p&gt;

&lt;p&gt;Проекты вроде &lt;a href=&quot;https://beakerbrowser.com/&quot;&gt;Beaker Browser&lt;/a&gt; или &lt;a href=&quot;https://getaether.net/&quot;&gt;getaether&lt;/a&gt; очень быстро завоевали внимание пользователей, нуждающихся в настоящей приватности в сети.&lt;/p&gt;

&lt;p&gt;Одним этим дело не ограничивается, прозвенели ещё «звоночки», говорящие о децентрализации веба, об интернете на блокчейнах:&lt;/p&gt;
&lt;ul&gt;
  &lt;li&gt;Андре «Cycle.js» Штальц разрабатывает p2p социальную сеть &lt;a href=&quot;https://www.manyver.se/&quot;&gt;manyverse&lt;/a&gt;. Open Source, без рекламы, аналитики и слежки.&lt;/li&gt;
  &lt;li&gt;PoW релиз либы &lt;a href=&quot;https://github.com/orbitdb/orbit-db&quot;&gt;OrbitDB&lt;/a&gt; — библиотеки, реализующей базу данных на основе p2p сети.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;В условиях, когда до приватной инфы, что называется, «рукой подать», принцип «мой комп - моя крепость» придётся как нельзя кстати.&lt;/p&gt;

&lt;h3 id=&quot;странный-эксперимент-с-нодой&quot;&gt;Странный эксперимент с нодой&lt;/h3&gt;

&lt;p&gt;Всё произошло с релизом 10.5, добавляющим поддержку &lt;a href=&quot;https://nodejs.org/dist/latest-v10.x/docs/api/worker_threads.html&quot;&gt;working_threads&lt;/a&gt;. Что странного?&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;
    &lt;p&gt;Первое — потоки (не путать со стримами) эти не могут нормально между собой данными обмениваться, для передачи объекта из треда в тред объект копируется. &lt;a href=&quot;https://github.com/nodejs/node/pull/20876&quot;&gt;Workers can share and transfer memory, but not JS objects&lt;/a&gt;
Соответственно, конкурентные коллекции на этом не построишь.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;Второе — сама суть изменений. Асинхронность, однопоточность всегда была визитной карточкой Ноды. Фактически, Нода создавалась как альтернатива многопоточным бэкендам (Джаве, например)…&lt;/p&gt;
  &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;img src=&quot;/images/year-resume2018/obivan.jpg&quot; alt=&quot;obivan&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Ну ладно, насчёт «становления» Джавой, я, пожалуй, слукавил. Воркер-треды, скорее, должны дополнить асинхронность Ноды, стать фичей, типа child process. При этом явно об этом в официальной доке ни слова. Так сказать, «имеющий глаза да увидит». Согласитесь, выглядит странно, учитывая невозможность конкурентных коллекций. Радует, что функционал ещё экспериментальный, наверняка ещё будут поясняющие PR’ы.&lt;/p&gt;

&lt;h3 id=&quot;посыл-года&quot;&gt;Посыл года&lt;/h3&gt;

&lt;p&gt;«Сегодня многие разработчики используют Redux, но при этом не знают, на каких идеях он стоит». Я сказал это два года назад, касаясь темы &lt;a href=&quot;https://www.youtube.com/watch?v=Tkjg179M-Nc&quot;&gt;обмена сообщениями&lt;/a&gt;. Это всё навеяно волной «нахватывания верхов» и последующим «выгоранием» годовалых, вновь обращенных во фронтендеры.&lt;/p&gt;

&lt;p&gt;В ноябре этого года к тому посылу добавился вот этот, от анонимного Дона:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;
Функциональные маньки, поймите, что расцвет ФП связан не с его охуенностью, и не с хуевостью ООП, а с тем, что процессорные мощности уперлись в потолок и теперь в процессорах втупую наращивают количество ядер. Функциональщина же из коробки лучше работает с многопоточностью, т.к. там иммутабельность - это основа парадигмы и сразу отпадают многие заебы. Это единственная причина, и если вы писали хуевый код в ООП, то вы точно так же будете писать хуевый код в ФП, смена парадигмы вам не поможет, это я гарантирую.

Твои проблемы решаются тем, что ты думаешь над структурой/иерархией своих наследований и используешь композицию и наследование в тех местах, где они удобны и имеют смысл, а не где попало. Понимаю, сложно думать, лучше сказать «все беды не от моего долбоебизма и нежелания ознакомиться с базовыми паттернами и идеями ООП, а от наследования, нужно его выкинуть».
&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Камрады, зрите в корень, проникайтесь основами и концепциями разработки. Тогда и ваша экспертиза станет более эффективной, и у занятия программированием появится смысл. А если ещё и хотите работать у нас, то вот &lt;a href=&quot;https://blog.csssr.ru/2018/08/16/candidates-mistakes&quot;&gt;палочка-выручалочка&lt;/a&gt;.&lt;/p&gt;

&lt;h3 id=&quot;ps&quot;&gt;P.S&lt;/h3&gt;

&lt;p&gt;Ладно, что-то я нагнал на всех тут. Я сам-то только недавно перешел из реакт-верстальщиков в реакт-программисты.&lt;/p&gt;

&lt;p&gt;Скажу так: хороший фронтенд — это праздник. Поэтому в новом году пришло время исправляться. Надо дерзать, а то мы так рискуем потерять этот праздник. А если в жизни нет праздника, то, по Летову, она вообще не нужна.&lt;/p&gt;

&lt;p&gt;С вами был по-прежнему чернобородый фронтенд-пират, бороздящий на подлодке украинские степи Максон Вислогуров. Оставайтесь на связи.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/images/recursion/outro.jpg&quot; alt=&quot;image&quot; /&gt;&lt;/p&gt;
</description>
        <pubDate>Sun, 16 Dec 2018 00:00:00 +0000</pubDate>
        <link>http://csssr.github.io/2018/12/16/year-resume-2018/</link>
        <guid isPermaLink="true">http://csssr.github.io/2018/12/16/year-resume-2018/</guid>
      </item>
    
      <item>
        <title>Безболезненный линтинг CSS с помощью stylelint</title>
        <description>&lt;p class=&quot;italic&quot;&gt;Некоторые приемы, описанные в&amp;nbsp;статье, ориентированы на&amp;nbsp;использование PostCSS (в&amp;nbsp;связке с&amp;nbsp;&lt;nobr&gt;css-modules&lt;/nobr&gt; и&amp;nbsp;webpack), однако они с&amp;nbsp;легкостью адаптируются под LESS / SASS / ванильный CSS.&lt;/p&gt;

&lt;h2 id=&quot;часть-i-кодстайл-vs-личные-предпочтения-делаем-одинаково&quot;&gt;Часть I. Кодстайл vs личные предпочтения. Делаем одинаково&lt;/h2&gt;
&lt;p&gt;Рано или поздно перед любой командой разработчиков встаёт вопрос о внедрении стандартов написания кода и подключении линтеров на проект. Стандартизация кода позволяет:&lt;/p&gt;
&lt;ul&gt;
  &lt;li&gt;&lt;span class=&quot;bold&quot;&gt;быстрее проводить code review&lt;/span&gt;, так как полностью убирается необходимость следить за общим форматированием и распространёнными ошибками (благодаря &lt;span class=&quot;no-wrap&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;--fix&lt;/code&gt;&lt;/span&gt; флагу);&lt;/li&gt;
  &lt;li&gt;&lt;span class=&quot;bold&quot;&gt;упростить работу с компонентами других членов команды&lt;/span&gt; — за счёт одинакового порядка свойств/селекторов вы всегда знаете, в каком именно месте искать проблемное свойство/селектор при рефакторинге/поддержке;&lt;/li&gt;
  &lt;li&gt;&lt;span class=&quot;bold&quot;&gt;быстрее вводить в проект новых разработчиков&lt;/span&gt;, так как полностью пропадет необходимость объяснять все договоренности о кодстайле. Здесь стоит отметить, что в идеале все ваши стандарты написания кода должны проверяться линтером, если линтер не может проверить &lt;nobr&gt;какой-либо&lt;/nobr&gt; кейс — не вводите такое требование к коду.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;С другой стороны, у каждого разработчика есть свой собственный стиль, к которому он привык. Вспомните, как вы обычно пишете стили — скорее всего, правила добавляются в рандомном порядке. И если стандарты на проекте отличаются от личных предпочтений, а линтер настроен так, что даже локальная сборка не будет запускаться/пересобираться при наличии ошибок линтера — эффективность разработки падает в разы, огромное количество времени уходит на то, чтобы привести код в соответствие стандартам, и это больно. &lt;span class=&quot;bold&quot;&gt;Очень больно&lt;/span&gt;.&lt;/p&gt;

&lt;h2 id=&quot;часть-ii-общее-форматирование-делаемкрасиво&quot;&gt;Часть II. Общее форматирование. Делаем красиво&lt;/h2&gt;
&lt;p&gt;Под общим форматированием я имею в виду все правила stylelint, отвечающие непосредственно за внешний вид кода и никак не влияющие на его работу. Разделять ли селекторы пустой строкой, переносить каждое правило на новую строку или писать все правила в одну линию? Отделять ли открывающую фигурную скобку селектора пробелом, писать &lt;nobr&gt;hex-цвета&lt;/nobr&gt; в сокращённом или длинном виде, оставлять или опускать ведущие нули у чисел? Всё это (и еще многое другое) относится только к форматированию и на работу ваших стилей никак не влияет.&lt;/p&gt;

&lt;h3 id=&quot;все-пишут-по-разному&quot;&gt;Все пишут по-разному&lt;/h3&gt;
&lt;p&gt;Взгляните на примеры ниже — на каждом из них реальный, работающий код, хотя манеры его написания очень различаются:&lt;/p&gt;

&lt;div class=&quot;language-scss highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nc&quot;&gt;.main-info&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;nl&quot;&gt;padding&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;nl&quot;&gt;padding-top&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;21px&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;nl&quot;&gt;margin&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;nl&quot;&gt;border&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;none&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;nl&quot;&gt;margin-bottom&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;50px&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;__field&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;nl&quot;&gt;display&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;flex&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
        &lt;span class=&quot;nl&quot;&gt;align-items&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;flex-end&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
        &lt;span class=&quot;nl&quot;&gt;margin-bottom&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;19px&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;__field-name&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;nl&quot;&gt;color&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;$grey&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
        &lt;span class=&quot;nl&quot;&gt;font-size&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;22px&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
        &lt;span class=&quot;nl&quot;&gt;font-weight&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;700&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
        &lt;span class=&quot;nl&quot;&gt;margin-right&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;18px&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;div class=&quot;language-css highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nc&quot;&gt;.root&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;nl&quot;&gt;padding-top&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;60px&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;nc&quot;&gt;.title&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;nl&quot;&gt;margin&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;0&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;auto&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;40px&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;nl&quot;&gt;width&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;170px&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;nl&quot;&gt;height&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;70px&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;nl&quot;&gt;color&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;transparent&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;nl&quot;&gt;background-image&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;sx&quot;&gt;url('./images/title.svg')&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;nl&quot;&gt;background-size&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;contain&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;py&quot;&gt;user-select&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;none&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;

  &lt;span class=&quot;err&quot;&gt;@media&lt;/span&gt; &lt;span class=&quot;err&quot;&gt;(--tablet-large)&lt;/span&gt; &lt;span class=&quot;err&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;nl&quot;&gt;margin&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;0&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;auto&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;60px&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;nl&quot;&gt;width&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;328px&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;nl&quot;&gt;height&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;136px&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;err&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;div class=&quot;language-css highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nt&quot;&gt;body&lt;/span&gt;
	&lt;span class=&quot;nt&quot;&gt;font-family&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;PTSansBold&lt;/span&gt;
&lt;span class=&quot;nc&quot;&gt;.wrap&lt;/span&gt;
	&lt;span class=&quot;nt&quot;&gt;width&lt;/span&gt; &lt;span class=&quot;err&quot;&gt;1000&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;px&lt;/span&gt;
	&lt;span class=&quot;nt&quot;&gt;margin&lt;/span&gt; &lt;span class=&quot;err&quot;&gt;0&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;auto&lt;/span&gt;
	&lt;span class=&quot;nt&quot;&gt;background-image&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;url&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(../&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;images&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;background&lt;/span&gt;&lt;span class=&quot;nc&quot;&gt;.png&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;nc&quot;&gt;.wrap__header&lt;/span&gt;
	&lt;span class=&quot;nt&quot;&gt;display&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;flex&lt;/span&gt;
	&lt;span class=&quot;nt&quot;&gt;justify-content&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;space-between&lt;/span&gt;
&lt;span class=&quot;nc&quot;&gt;.wrap__logo&lt;/span&gt;
	&lt;span class=&quot;nt&quot;&gt;padding&lt;/span&gt; &lt;span class=&quot;err&quot;&gt;62&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;px&lt;/span&gt; &lt;span class=&quot;err&quot;&gt;0&lt;/span&gt; &lt;span class=&quot;err&quot;&gt;0&lt;/span&gt; &lt;span class=&quot;err&quot;&gt;112&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;px&lt;/span&gt;
&lt;span class=&quot;nc&quot;&gt;.wrap__secret&lt;/span&gt;
	&lt;span class=&quot;nt&quot;&gt;padding&lt;/span&gt; &lt;span class=&quot;err&quot;&gt;48&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;px&lt;/span&gt; &lt;span class=&quot;err&quot;&gt;54&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;px&lt;/span&gt; &lt;span class=&quot;err&quot;&gt;0&lt;/span&gt; &lt;span class=&quot;err&quot;&gt;0&lt;/span&gt;
&lt;span class=&quot;nc&quot;&gt;.wrap__content&lt;/span&gt;
	&lt;span class=&quot;nt&quot;&gt;padding&lt;/span&gt; &lt;span class=&quot;err&quot;&gt;0&lt;/span&gt; &lt;span class=&quot;err&quot;&gt;112&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;px&lt;/span&gt; &lt;span class=&quot;err&quot;&gt;73&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;px&lt;/span&gt; &lt;span class=&quot;err&quot;&gt;112&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;px&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p class=&quot;image-caption&quot;&gt;Абсолютно разные подходы к&amp;nbsp;форматированию стилевых файлов&lt;/p&gt;

&lt;p&gt;Конечно же, использование определённых пре- или постпроцессоров накладывает свои ограничения, но некоторые из нюансов форматирования остаются всегда. Но представьте себе, что творилось бы на проекте без линтера, если бы на него одновременно пришли авторы трёх кодов выше. &lt;span class=&quot;bold&quot;&gt;Боль&lt;/span&gt;.&lt;/p&gt;

&lt;h3 id=&quot;линтим-форматирование&quot;&gt;Линтим форматирование&lt;/h3&gt;
&lt;p&gt;По сути, подходов к решению проблемы стандартизации форматирования всего два.&lt;/p&gt;

&lt;p&gt;Вы разрабатываете свой собственный кодстайл и прописываете правила линтера в соответствии с этими требованиями. В этом случае ваш &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;.stylelintrc&lt;/code&gt; может выглядеть примерно так:&lt;/p&gt;
&lt;div class=&quot;language-json highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
    &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;rules&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
        &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;indentation&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
        &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;string-quotes&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;single&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
        &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;declaration-colon-space-before&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;never&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
        &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;declaration-colon-space-after&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;never&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
        &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;rule-empty-line-before&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;never&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
        &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;media-feature-range-operator-space-before&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;never&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
        &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;media-feature-range-operator-space-after&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;never&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
        &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;media-feature-colon-space-before&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;never&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
        &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;media-feature-colon-space-after&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;never&quot;&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
    &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Либо вы можете взять уже готовый кодстайл, написанный &lt;nobr&gt;какой-либо&lt;/nobr&gt; известной компанией,&lt;/p&gt;
&lt;div class=&quot;language-zsh highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;npm &lt;span class=&quot;nb&quot;&gt;install &lt;/span&gt;stylelint-config-airbnb &lt;span class=&quot;nt&quot;&gt;--save-dev&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;и использовать его в виде расширения конфигурации линтера. &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;.stylelintrc&lt;/code&gt; в таком случае приобретёт следующий вид:&lt;/p&gt;
&lt;div class=&quot;language-json highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;extends&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;stylelint-config-airbnb&quot;&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;Конечно, ничто не мешает вам расширить или изменить готовый набор правил на свой вкус, переопределив некоторые правила конфига вручную.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/images/lint-your-css/formatting.gif&quot; alt=&quot;image&quot; /&gt;&lt;/p&gt;
&lt;p class=&quot;image-caption&quot;&gt;Результат работы линтера&lt;/p&gt;

&lt;h3 id=&quot;prettier&quot;&gt;&lt;a href=&quot;https://prettier.io/&quot; target=&quot;_blank&quot;&gt;Prettier&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;В моей команде выбор был сделан в пользу кодстайла Prettier. На самом деле &lt;a href=&quot;https://github.com/prettier/stylelint-config-prettier#stylelint-config-prettier&quot; target=&quot;_blank&quot;&gt;его конфиг для stylelint&lt;/a&gt; не добавляет никаких правил, а наоборот, &lt;span class=&quot;bold&quot;&gt;отключает&lt;/span&gt; бОльшую их часть. Сделано это для того, чтобы отключить все пересекающиеся правила из предыдущих конфигов (конфиг Prettier должен подключаться последним), дабы они не конфликтовали с логикой форматирования, заложенной в Prettier.&lt;/p&gt;

&lt;p&gt;Как следствие отключения правил линтера — в текстовом редакторе пропадают предупреждения об ошибках форматирования, так как stylelint вообще перестаёт наблюдать за этими правилами. Это требует от разработчиков не забывать запускать Prettier либо &lt;a href=&quot;https://prettier.io/docs/en/cli.html&quot; target=&quot;_blank&quot;&gt;через CLI&lt;/a&gt;, либо через плагин для текстового редактора (&lt;a href=&quot;https://marketplace.visualstudio.com/items?itemName=esbenp.prettier-vscode&quot; target=&quot;_blank&quot;&gt;вот такой, к примеру, для VS Code&lt;/a&gt;).&lt;/p&gt;

&lt;h2 id=&quot;часть-iii-порядок-свойств-внутри-селектора-делаем-структурированно&quot;&gt;Часть III. Порядок свойств внутри селектора. Делаем структурированно&lt;/h2&gt;
&lt;p&gt;Порядок, в котором вы пишете свойства внутри селектора, очень важен. Это может быть менее очевидно для разработчиков, которые работают в одиночку, но становится очень значимым фактором при командной разработке.&lt;/p&gt;

&lt;p&gt;Если все ваши свойства сгруппированы по логическому смыслу и отсортированы внутри этих групп, код становится более структурированным. Преимущества такой сортировки:&lt;/p&gt;
&lt;ul&gt;
  &lt;li&gt;&lt;span class=&quot;bold&quot;&gt;более быстрое нахождение определённых свойств&lt;/span&gt; (например, вы всегда уверены, что &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;position&lt;/code&gt; идёт самым первым свойством, а &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;margin&lt;/code&gt; всегда идут до &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;padding&lt;/code&gt;);&lt;/li&gt;
  &lt;li&gt;&lt;span class=&quot;bold&quot;&gt;внедрение новых фич не снижает качество кода&lt;/span&gt; (как бы вы ни были организованы в плане написания кода на первоначальном этапе разработки, чаще всего, к моменту выхода проекта на стадию поддержки эта организованность значительно снижается);&lt;/li&gt;
  &lt;li&gt;&lt;span class=&quot;bold&quot;&gt;упрощается работа с кодом, который писали не вы&lt;/span&gt;, а другой разработчик команды.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3 id=&quot;реализация-сортировки&quot;&gt;Реализация сортировки&lt;/h3&gt;
&lt;p&gt;Для достижения поставленной цели в виде сгруппированных и отсортированных свойств следует воспользоваться &lt;a href=&quot;https://github.com/hudochenkov/stylelint-order#stylelint-order---&quot; target=&quot;_blank&quot;&gt;плагином для stylelint&lt;/a&gt;.&lt;/p&gt;
&lt;div class=&quot;language-zsh highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;npm &lt;span class=&quot;nb&quot;&gt;install &lt;/span&gt;stylelint-order &lt;span class=&quot;nt&quot;&gt;--save-dev&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;После установки плагина достаточно добавить его в список плагинов, а также указать нужный порядок свойств в &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;.stylelintrc&lt;/code&gt;&lt;/p&gt;
&lt;div class=&quot;language-json highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;plugins&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
    &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;stylelint-order&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;],&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;rules&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
    &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;order/properties-order&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
      &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;position&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
      &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;z-index&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
      &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;top&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
      &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;right&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
      &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;bottom&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
      &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;left&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
    &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;],&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;},&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;Порядком расположения не перечисленных в конфиге свойств относительно перечисленных можно управлять с помощью необязательного параметра &lt;a href=&quot;https://github.com/hudochenkov/stylelint-order/blob/master/rules/properties-order/README.md#unspecified-topbottombottomalphabeticalignore&quot; target=&quot;_blank&quot;&gt;unspecified&lt;/a&gt;.&lt;/p&gt;
&lt;div class=&quot;language-json highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nl&quot;&gt;&quot;order/properties-order&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
    &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;position&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
    &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;z-index&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;],&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
    &lt;/span&gt;&lt;span class=&quot;err&quot;&gt;unspecified:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;bottom&quot;&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;&lt;img src=&quot;/images/lint-your-css/sorting.gif&quot; alt=&quot;image&quot; /&gt;&lt;/p&gt;
&lt;p class=&quot;image-caption&quot;&gt;Результат работы линтера&lt;/p&gt;

&lt;h2 id=&quot;часть-iv-очерёдность-в-нестинге-снижаем-риски-иповышаем-читаемость&quot;&gt;Часть IV. Очерёдность в «нестинге». Снижаем риски и повышаем читаемость&lt;/h2&gt;
&lt;p&gt;«Нестинг», или вложенность — крайне удобный и мощный инструмент, в который умеют все пре- и постпроцессоры. Однако неумелое его использование открывает возможность выстрелить себе в ногу (чаще всего, &lt;nobr&gt;из-за&lt;/nobr&gt; незнания того, как работает специфичность селекторов).&lt;/p&gt;

&lt;p&gt;Если же говорить про кодстайл, то при командной разработке вы наверняка хотели бы иметь возможность управлять очерёдностью в нестинге. Ведь код, в котором очерёдность ‘БЭМ модификатор — media — псевдоклассы — псевдоэлементы’, будет ОЧЕНЬ сильно отличаться от кода с обратной очерёдностью.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/images/lint-your-css/nestingOrder.png&quot; alt=&quot;image&quot; /&gt;&lt;/p&gt;
&lt;p class=&quot;image-caption&quot;&gt;Различные варианты сортировки в&amp;nbsp;нестинге&lt;/p&gt;

&lt;p&gt;Так же как и одинаковый порядок свойств в селекторе, одинаковая очерёдность в нестинге позволяет облегчить работу с кодом, который писал другой разработчик команды, так как вы всегда уверены, в каком именно месте искать определенные вложенные правила. Плюс это страхует от ошибок при поддержке кода, когда, к примеру, к уже существующим media добавляется ещё одно, но в неправильной очерёдности. Добавьте к этому правило о максимальной глубине вложенности и запрет на любые селекторы внутри media (&lt;nobr&gt;т.е.&lt;/nobr&gt; чтобы изменить эффект при наведении на планшетах, вы обязываете своих разработчиков вкладывать media в hover, а не наоборот) — и на выходе получите очень мощный инструмент стандартизации кода.&lt;/p&gt;

&lt;h3 id=&quot;реализация-сортировки-1&quot;&gt;Реализация сортировки&lt;/h3&gt;
&lt;p&gt;Данная сортировка достигается за счёт использования упомянутого выше плагина &lt;nobr&gt;stylelint-order&lt;/nobr&gt;, возможный конфиг &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;.stylelintrc&lt;/code&gt; может выглядеть так:&lt;/p&gt;
&lt;div class=&quot;language-json highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;plugins&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
    &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;stylelint-order&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;],&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;rules&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
    &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;order/order&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
      &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;declarations&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
      &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
        &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;type&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;at-rule&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
        &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;name&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;media&quot;&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
      &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;},&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
      &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
        &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;type&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;rule&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
        &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;selector&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;^&amp;amp;::(before|after)&quot;&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
      &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;},&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
      &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
        &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;type&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;rule&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
        &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;selector&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;^&amp;amp;:&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\\&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;w&quot;&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
      &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;},&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
      &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
        &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;type&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;rule&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
        &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;selector&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;^&amp;amp;_&quot;&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
      &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;},&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
      &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
        &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;type&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;rule&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
        &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;selector&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;^.&quot;&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
      &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
    &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;],&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;},&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;Обратите особое внимание, что для определения вложенного правила &lt;a href=&quot;https://github.com/hudochenkov/stylelint-order/blob/master/rules/order/README.md#extended-rule-objects&quot; target=&quot;_blank&quot;&gt;используются регулярные выражения&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/images/lint-your-css/nesting.gif&quot; alt=&quot;image&quot; /&gt;&lt;/p&gt;
&lt;p class=&quot;image-caption&quot;&gt;Результат работы линтера&lt;/p&gt;

&lt;h2 id=&quot;часть-v-не-форматированием-единым-заботимся-окачестве&quot;&gt;Часть V. Не форматированием единым. Заботимся о качестве&lt;/h2&gt;
&lt;p&gt;Как вы могли заметить, всё, о чём шла речь выше, касалось лишь форматирования кода, работал он при этом абсолютно одинаково. Но помимо соглашений о форматировании любой кодстайл включает себя также и соглашения о качестве кода.&lt;/p&gt;

&lt;p&gt;Хотите запретить использование тегов или id в селекторах? Застраховаться от дублирования правил внутри селектора или дублирования самих селекторов? Запретить &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;!important&lt;/code&gt;, ограничить максимальную глубину нестинга, запретить использование &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;em&lt;/code&gt; или &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;px&lt;/code&gt;? А может, запретить целые правила, вроде сокращённой записи &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;margin/padding/flex&lt;/code&gt;? stylelint предоставляет огромное количество правил, отвечающих именно за такие ситуации. За счет их использования внутри команды достигается некое единообразие в самой логике написания стилевых файлов.&lt;/p&gt;

&lt;p&gt;Помимо стандартных правил stylelint также стоит обратить внимание на &lt;a href=&quot;https://stylelint.io/user-guide/plugins/&quot; target=&quot;_blank&quot;&gt;плагины&lt;/a&gt;, расширяющие возможности проверки кода — например, можно &lt;a href=&quot;https://github.com/csstools/stylelint-media-use-custom-media#media-use-custom-media-&quot; target=&quot;_blank&quot;&gt;запретить использование media без custom-media&lt;/a&gt; или &lt;a href=&quot;https://github.com/adityavm/stylelint-at-rule-no-children#tldr&quot; target=&quot;_blank&quot;&gt;запретить вкладывать селекторы внутрь media&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Использование таких правил очень сильно зависит от договоренностей внутри команды. Главный посыл здесь должен быть «не навреди» — обсуждайте внедрение правил с командой, ставьте их под сомнение, разбирайте все плюсы и минусы их использования. Хорошим маркером для подключения нового правила (или расширения уже подключенного) является момент, когда при прохождении code review ошибка встречается более двух раз, &lt;nobr&gt;т.е.&lt;/nobr&gt; в первый раз разработчик поправил ошибку после замечания, но через некоторое время снова отправил на проверку код с такой же ошибкой.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/images/lint-your-css/quality.png&quot; alt=&quot;image&quot; /&gt;&lt;/p&gt;
&lt;p class=&quot;image-caption&quot;&gt;&amp;laquo;Качественные&amp;raquo; ошибки линтера&lt;/p&gt;

&lt;h2 id=&quot;часть-vi-автоматизация-процесса-убираемболь&quot;&gt;Часть VI. Автоматизация процесса. Убираем боль&lt;/h2&gt;
&lt;p&gt;Итак, вы потратили достаточно времени на составление добротного конфига stylelint, который покрывает все требуемые вашим кодстайлом моменты — общее форматирование, различные сортировки правил, а также «качественные» нюансы. Следующий вопрос, который вам предстоит решить — «в какой момент запускать проверку линтера, и что должно происходить при наличии ошибок в этой проверке?». Этот вопрос имеет огромное значение.&lt;/p&gt;

&lt;p&gt;Представьте себе такую ситуацию — ваша система сборки (gulp/webpack/etc.) настроена таким образом, что проверка линтера запускается на каждое сохранение файла и при наличии ошибок не даёт обновить локальный сервер, &lt;nobr&gt;т.е.&lt;/nobr&gt; вы не сможете увидеть результат внесённых изменений. Неважно, на какой стадии находится проект — на начальном этапе разработки самых мелких реиспользуемых компонент или же на этапе поддержки, когда код вносится в уже функционирующую систему с огромным количеством файлов и строк кода. Вы не увидите ни одного изменения до тех пор, пока не расставите все написанные правила в правильном порядке и не соблюдёте все &lt;nobr&gt;бест-практики&lt;/nobr&gt;, предписанные кодстайлом. &lt;span class=&quot;bold&quot;&gt;Боль&lt;/span&gt;.&lt;/p&gt;

&lt;p&gt;Настроив систему сборки и/или сам линтер так, чтобы ошибки общего форматирования и сортировки не препятствовали обновлению локального сервера (к примеру, за счёт смены отображения ошибок в правилах на предупреждения), вы снизите боль, но не уберёте её полностью. Ведь большинство разработчиков, которые имеют хоть &lt;nobr&gt;какой-то&lt;/nobr&gt; опыт работы на проектах с линтерами, пользуются плагинами для своих текстовых редакторов/IDE, чтобы ошибки и предупреждения линтеров подсвечивались в коде. Все эти подчёркивания и всплывающие попапы знатно мозолят глаза и прилично отвлекают от основной задачи — написания кода. Слёз перфекционистов вообще не счесть.&lt;/p&gt;

&lt;p&gt;К великому облегчению, есть как минимум три способа, позволяющие полностью автоматизировать процесс линтинга и исправления всего, что связано с общим форматированием и сортировками правил. Но перед описанием этих способов стоит сказать об одном очень простом и одновременно крайне мощном подходе.&lt;/p&gt;

&lt;h3 id=&quot;разделяй-ивластвуй&quot;&gt;Разделяй и властвуй&lt;/h3&gt;
&lt;p&gt;Скорее всего, вы заметили, что на приведённых выше в статье скриншотах, где был показан результат работы линтера, его запуск осуществлялся с флагом &lt;span class=&quot;no-wrap&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;--fix&lt;/code&gt;&lt;/span&gt;. В результате этого все ошибки исправлялись автоматически. И напротив, ошибки правил, о которых шла речь в V части статьи, невозможно исправить автоматически, для их решения необходимо непосредственное вмешательство разработчика.&lt;/p&gt;

&lt;p&gt;Помимо &lt;span class=&quot;no-wrap&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;--fix&lt;/code&gt;&lt;/span&gt; флага существует ещё и такой флаг как &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;--config&lt;/code&gt;, который позволяет указать путь к определённому конфигу, а не использовать для проверки дефолтный конфиг. Такая возможность позволяет &lt;span class=&quot;bold&quot;&gt;разделить правила для нашего кодстайла на два конфига&lt;/span&gt;:&lt;/p&gt;
&lt;ul&gt;
  &lt;li&gt;Первый (он же дефолтный, к примеру &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;.stylelintrc&lt;/code&gt;) будет содержать только те правила, для исправления ошибок которых необходимо вмешательство разработчика (не работает автоисправление). Именно этот конфиг будет подгружаться в плагины текстовых редакторов / IDE для проверки кода в режиме реального времени. Это обеспечит следование «качественным» критериям кодстайла, не отвлекая разработчиков на вопросы общего форматирования/сортировок.&lt;/li&gt;
  &lt;li&gt;Второй конфиг (к примеру, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;.stylelintrc-extended&lt;/code&gt;) будет содержать &lt;span class=&quot;bold&quot;&gt;все правила из первого&lt;/span&gt;, а также будет дополнен правилами для форматирования/сортировок. Вызов такого конфига будет всегда сопровождаться флагом &lt;span class=&quot;no-wrap&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;--fix&lt;/code&gt;&lt;/span&gt;, что обеспечит следующую логику: линтер самостоятельно исправит все ошибки, которые сможет, а затем проверит код на соответствие качественным критериям кодстайла. Прохождение такой проверки без ошибок будет сигналом о том, что код полностью соответствует кодстайлу и его можно отправлять в репозиторий проекта.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Также стоит отметить, что на этапе локальной работы с кодом запускать проверки линтера не имеет особого смысла. Другими словами — &lt;em&gt;&lt;span class=&quot;bold&quot;&gt;дайте разработчикам возможность писать код как можно быстрее&lt;/span&gt;&lt;/em&gt;, не создавайте для них лишних препятствий, ведь до тех пор, пока код примет окончательный вид, пригодный для отправки в репозиторий, он будет изменён великое множество раз.&lt;/p&gt;

&lt;h3 id=&quot;автоматизация-запускалинтера&quot;&gt;Автоматизация запуска линтера&lt;/h3&gt;
&lt;p&gt;Как уже упоминалось выше, есть как минимум три способа запуска линтера, обеспечивающие автоматизацию процесса проверки.&lt;/p&gt;

&lt;p&gt;Первый — запуск линтера в момент сохранения файлов. Этого можно достичь за счёт настройки вашей системы сборки (&lt;a href=&quot;https://github.com/webpack-contrib/stylelint-webpack-plugin#stylelint-webpack-plugin&quot; target=&quot;_blank&quot;&gt;так — для webpack&lt;/a&gt; и &lt;a href=&quot;https://github.com/olegskl/gulp-stylelint#gulp-stylelint&quot; target=&quot;_blank&quot;&gt;вот так — для gulp&lt;/a&gt;). Лично мне не нравится этот подход по ряду причин:&lt;/p&gt;
&lt;ul&gt;
  &lt;li&gt;из-за сортировок код перемешивается прямо у вас на глазах, что вызывает дискомфорт, &lt;nobr&gt;т.к.&lt;/nobr&gt; теряется положение курсора на последнем месте изменения в редакторе, а также нарушается порядок действий для &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;cmd/ctrl + z&lt;/code&gt; команды;&lt;/li&gt;
  &lt;li&gt;повышается задержка между сохранением файла и реальным отображением правок в браузере (hot reload), а ведь сохранений в течение рабочего дня может быть ОЧЕНЬ много;&lt;/li&gt;
  &lt;li&gt;нет гарантий того, что код с ошибками не попадёт в репозиторий.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Второй — запуск линтера перед созданием коммита (&lt;nobr&gt;т.к.&lt;/nobr&gt; в репозитории хранится вся история коммитов, мы не можем полагаться именно на &lt;em&gt;момент отправки&lt;/em&gt; кода в него).
Преимущества подхода:&lt;/p&gt;
&lt;ul&gt;
  &lt;li&gt;линтер не вмешивается в процесс активной разработки, автоисправления будут применены, только когда работа с кодом завершена;&lt;/li&gt;
  &lt;li&gt;количество запускаемых проверок снижается в разы, что повышает общую производительность процесса разработки;&lt;/li&gt;
  &lt;li&gt;&lt;span class=&quot;bold&quot;&gt;код с ошибками линтера не может попасть в репозиторий&lt;/span&gt;, так как наличие ошибок при проверке просто не даст создать новый коммит (конечно же, флаг &lt;span class=&quot;no-wrap&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;--no-verify&lt;/code&gt;&lt;/span&gt; никто не отменял, но за его использование следует бить по рукам).&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Именно реализацию такого подхода мы и рассмотрим далее. Заключается она в использовании прекоммит хука, запускающего проверку линтера (с расширенным конфигом и флагом &lt;span class=&quot;no-wrap&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;--fix&lt;/code&gt;&lt;/span&gt;) с помощью husky и &lt;nobr&gt;lint-staged&lt;/nobr&gt;.&lt;/p&gt;

&lt;p&gt;Третий способ заключается в использовании &lt;a href=&quot;https://en.wikipedia.org/wiki/Continuous_integration&quot; target=&quot;_blank&quot;&gt;CI (Continuous integration)&lt;/a&gt;, проверка линтером в таком случае может быть проведена автоматически для каждого отдельного Pull/Merge Request. Такой подход обеспечивает чистоту и порядок в стабильной ветке проекта без необходимости запуска проверки для каждого отдельного коммита в &lt;nobr&gt;feature-ветках&lt;/nobr&gt;.&lt;/p&gt;

&lt;h3 id=&quot;husky--lint-staged--prettier-️️️&quot;&gt;husky + lint-staged + prettier = ❤️❤️❤️&lt;/h3&gt;
&lt;p&gt;&lt;a href=&quot;https://github.com/typicode/husky#husky&quot; target=&quot;_blank&quot;&gt;husky&lt;/a&gt; — инструмент, позволяющий использовать различные гит хуки, в том числе и прекоммит хук.&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;https://github.com/okonet/lint-staged#-lint-staged----&quot; target=&quot;_blank&quot;&gt;lint-staged&lt;/a&gt; — позволяет запускать линтер только для тех файлов, которые находятся в &lt;a href=&quot;https://githowto.com/staging_changes&quot; target=&quot;_blank&quot;&gt;«staged»&lt;/a&gt; состоянии, а не прогонять проверку всего проекта целиком.&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;https://github.com/prettier/prettier#opinionated-code-formatter&quot; target=&quot;_blank&quot;&gt;prettier&lt;/a&gt; — форматтер кода, который будет отвечать за следование правилам общего форматирования (о них шла речь во второй части статьи) нашего кодстайла.&lt;/p&gt;

&lt;p&gt;Перейдём к настройке этих инструментов для работы в связке. Первым делом установим зависимости:&lt;/p&gt;
&lt;div class=&quot;language-zsh highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;npm &lt;span class=&quot;nb&quot;&gt;install &lt;/span&gt;prettier husky lint-staged stylelint-order stylelint-config-prettier stylelint-config-recommended &lt;span class=&quot;nt&quot;&gt;--save-dev&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Далее нужно настроить ваш &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;.package.json&lt;/code&gt; следующим образом:&lt;/p&gt;
&lt;div class=&quot;language-json highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;devDependencies&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
    &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;husky&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;^1.2.0&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
    &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;lint-staged&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;^8.1.0&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
    &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;prettier&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;^1.15.2&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
    &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;stylelint&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;^9.8.0&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
    &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;stylelint-config-prettier&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;^4.0.0&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
    &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;stylelint-config-recommended&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;^2.1.0&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
    &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;stylelint-order&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;^2.0.0&quot;&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;},&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;husky&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
    &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;hooks&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
      &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;pre-commit&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;lint-staged&quot;&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
    &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;},&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;lint-staged&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
    &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;linters&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
      &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;*.css&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
        &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;prettier --write&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
        &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;stylelint --fix --config ./.stylelintrc-format&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
        &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;git add&quot;&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
      &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
    &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Для того, чтобы переопределить &lt;a href=&quot;https://prettier.io/docs/en/options.html&quot; target=&quot;_blank&quot;&gt;дефолтные настройки prettier&lt;/a&gt;, можно создать &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;.prettierrc&lt;/code&gt; файл в корне вашего проекта. Выглядеть он может, к примеру, так:&lt;/p&gt;
&lt;div class=&quot;language-json highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;singleQuote&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;kc&quot;&gt;true&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;tabWidth&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;4&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Также убедитесь в том, что вы передаете нужный конфиг в строке с вызовом линтера (скорее всего, это будет не дефолтный &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;.stylelintrc&lt;/code&gt;).&lt;/p&gt;

&lt;h3 id=&quot;итоговый-результат&quot;&gt;Итоговый результат&lt;/h3&gt;
&lt;p&gt;Настроив связку инструментов по приведённым выше примерам, на выходе мы получим следующую логику работы линтера на проекте:&lt;/p&gt;
&lt;ul&gt;
  &lt;li&gt;базовый конфиг &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;.stylelintrc&lt;/code&gt; включает в себя только «качественные» правила, плагины для текстовых редакторов / IDE используют именно его;&lt;/li&gt;
  &lt;li&gt;на этапе локальной работы с кодом проверки линтера не запускаются и не препятствуют разработке;&lt;/li&gt;
  &lt;li&gt;в момент создания коммита для файлов, &lt;span class=&quot;bold&quot;&gt;которые находятся в «staged» состоянии&lt;/span&gt;, сначала отработает prettier, пофиксив общее форматирование. Затем запустится stylelint с расширенным конфигом и &lt;span class=&quot;no-wrap&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;--fix&lt;/code&gt;&lt;/span&gt; флагом, пофиксив сортировки правил и нестинга. Далее проводится проверка «качественных» правил, и в случае наличия ошибок коммит не будет создан. Если же ошибок нет, то все изменения, внесённые в результате автоисправлений, &lt;span class=&quot;bold&quot;&gt;будут автоматически добавлены в «staged» состояние&lt;/span&gt; и коммит будет создан.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Допустим, что ваш итоговый конфиг имеет следующий вид:&lt;/p&gt;
&lt;div class=&quot;language-json highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;err&quot;&gt;//&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;err&quot;&gt;.stylelintrc&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;rules&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
    &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;declaration-block-no-imortant&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;kc&quot;&gt;true&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
    &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;property-blacklist&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;flex&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;],&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
    &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;unit-blacklist&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;em&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;rem&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;],&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;},&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;div class=&quot;language-json highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;err&quot;&gt;//&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;err&quot;&gt;.stylelint-format&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;extends&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
    &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;stylelint-config-recommended&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
    &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;stylelint-config-prettier&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;],&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;plugins&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
    &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;stylelint-order&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;],&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;rules&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
    &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;declaration-block-no-imortant&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;kc&quot;&gt;true&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
    &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;indentation&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
    &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;rule-empty-line-before&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;always&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
    &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;at-rule-empty-line-before&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;always&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
    &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;property-blacklist&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;flex&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;],&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
    &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;unit-blacklist&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;em&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;rem&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;],&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
    &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;order/order&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
      &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;declarations&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
      &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
        &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;type&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;at-rule&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
        &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;name&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;media&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
      &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;},&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
      &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
        &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;type&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;rule&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
        &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;selector&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;^&amp;amp;:&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\\&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;w&quot;&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
      &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;},&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
      &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
        &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;type&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;rule&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
        &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;selector&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;^&amp;amp;_&quot;&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
      &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;},&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
    &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;],&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
    &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;order/properties-order&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
      &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
        &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;position&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
        &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;top&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
        &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;right&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
        &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;bottom&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
        &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;left&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
      &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;],&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
      &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
        &lt;/span&gt;&lt;span class=&quot;err&quot;&gt;unspecified:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;bottom&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
      &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
    &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;],&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;},&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;div class=&quot;language-json highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;err&quot;&gt;//&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;err&quot;&gt;.package.json&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;devDependencies&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
    &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;husky&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;^1.1.3&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
    &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;lint-staged&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;^8.0.4&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
    &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;prettier&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;^1.15.2&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
    &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;stylelint&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;^9.8.0&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
    &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;stylelint-config-prettier&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;^4.0.0&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
    &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;stylelint-config-recommended&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;^2.1.0&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
    &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;stylelint-order&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;^1.0.0&quot;&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;},&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;husky&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
    &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;hooks&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
      &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;pre-commit&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;lint-staged&quot;&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
    &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;},&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;lint-staged&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
    &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;linters&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
      &lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;&quot;*.css&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
        &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;prettier --write&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
        &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;stylelint --fix --config ./.stylelintrc-format&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
        &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;git add&quot;&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
      &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
    &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
  &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;Тогда работа линтера будет выглядеть так (обратите внимание, что в staged состоянии находится только один стилевой файл):&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/images/lint-your-css/fail.gif&quot; alt=&quot;image&quot; /&gt;&lt;/p&gt;
&lt;p class=&quot;image-caption&quot;&gt;Попытка коммита вызывает прекоммит хук и&amp;nbsp;автоисправление форматирования. Линтер падает с&amp;nbsp;ошибками на&amp;nbsp;&amp;laquo;качественных&amp;raquo; правилах, внесённые prettier изменения форматирования при этом сохраняются&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/images/lint-your-css/success.gif&quot; alt=&quot;image&quot; /&gt;&lt;/p&gt;
&lt;p class=&quot;image-caption&quot;&gt;Пример успешного коммита без ошибок в&amp;nbsp;&amp;laquo;качественных&amp;raquo; правилах&lt;/p&gt;

&lt;h2 id=&quot;заключение&quot;&gt;Заключение&lt;/h2&gt;
&lt;p&gt;С каждым днем stylelint становится всё мощнее, дополняясь новыми правилами и возможностями для автоматических исправлений. Так что если вы ещё не используете данный инструмент, я очень надеюсь, что после прочтения этой статьи вы хотя бы попробуете внедрить его на свои проекты. Также некоторые подходы, описанные в статье, применимы к линтингу не только стилевых файлов, но и, к примеру, JSX файлов, но это уже совсем другая история…&lt;/p&gt;

&lt;p&gt;Для тех же из вас, кто захочет поучаствовать в разработке новых или улучшении уже существующих фич, разработчики stylelint подготовили &lt;a href=&quot;https://github.com/stylelint/stylelint/blob/master/docs/developer-guide/rules.md#working-on-rules&quot; target=&quot;_blank&quot;&gt;хороший гайд&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Конфиги линтера, которые используются в моей команде, вы можете &lt;a href=&quot;https://github.com/v1z/linters-example&quot; target=&quot;_blank&quot;&gt;найти тут&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Спасибо за внимание!&lt;/p&gt;

</description>
        <pubDate>Wed, 05 Dec 2018 00:00:00 +0000</pubDate>
        <link>http://csssr.github.io/2018/12/05/lint-your-css/</link>
        <guid isPermaLink="true">http://csssr.github.io/2018/12/05/lint-your-css/</guid>
      </item>
    
  </channel>
</rss>
