<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom">

  <title>Ношу шлем, тяжело дышу</title>
  <link href="http://shuvalov.info/atom.xml" rel="self"/>
  <link href="http://shuvalov.info"/>
  <updated>2020-07-13T04:01:20+00:00</updated>
  <id>http://shuvalov.info</id>
  <author>
    <name></name>
    <email>anton@shuvalov.info</email>
  </author>

  
  <entry>
    <title>Музыка для работы #5</title>
    <updated>2015-03-07T00:00:00+00:00</updated>
    
      <id>http://shuvalov.info/2015/03/07/sc-workset-5</id>
      <link href="http://shuvalov.info/2015/03/07/sc-workset-5"/>
    
      <content type="html" xml:base="http://shuvalov.info/">&lt;p&gt;Ю-ху, &lt;a href=&quot;https://soundcloud.com/asheee/sets/workset-5&quot;&gt;пятый плейлист&lt;/a&gt;!&lt;/p&gt;

&lt;div id=&quot;player&quot;&gt;&lt;/div&gt;
&lt;script&gt;
  (function() {
      var script = document.createElement(&quot;script&quot;);

      script.type = &quot;text/javascript&quot;;
      script.async = true;
      script.src = &quot;//sd.toneden.io/production/toneden.loader.js&quot;

      var entry = document.getElementsByTagName(&quot;script&quot;)[0];
      entry.parentNode.insertBefore(script, entry);
  }());

  ToneDenReady = window.ToneDenReady || [];
  ToneDenReady.push(function() {
      // Modify the dom and urls parameters to position
      // your player and select tracks/sets/artists to play.
      ToneDen.player.create({
          dom: '#player',
          urls: [
            'https://soundcloud.com/asheee/sets/workset-5'
          ],
          eq: 'waves'
      });
  });
&lt;/script&gt;

</content>
  </entry>
  
  <entry>
    <title>Белый шум</title>
    <updated>2015-01-25T00:00:00+00:00</updated>
    
      <id>http://shuvalov.info/2015/01/25/white-noise</id>
      <link href="http://shuvalov.info/2015/01/25/white-noise"/>
    
      <content type="html" xml:base="http://shuvalov.info/">&lt;style&gt;
  .no-covered img {
    background: none;
    box-shadow: none;
  }
&lt;/style&gt;

&lt;p class=&quot;no-covered&quot;&gt;&lt;img src=&quot;http://shuvalov.info/assets/articles-assets/lena/darth.png&quot; alt=&quot;Никакого баттхёрта&quot; /&gt;&lt;/p&gt;

&lt;p class=&quot;photo-author&quot;&gt;&lt;em&gt;рисунок: &lt;a href=&quot;http://vk.com/lenabg&quot;&gt;Лена Шувалова&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Решил пожаловаться на жизнь :D&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;Конечно, я драматизирую. И, конечно, это всё относится не только к хабру. Фидли я практически
перестал читать по той же причине.&lt;/p&gt;

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

&lt;p&gt;Немного о том, что я прочитал:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;a href=&quot;http://www.amazon.com/Async-JavaScript-Responsive-Pragmatic-Express/dp/1937785270&quot;&gt;Async JavaScript&lt;/a&gt; — очень и очень крутая книга, которая здорово объясняет все нюансы асинхронности
в JS. Уж точно не ровня статейкам с хабра о &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;setTimeout(function, 0)&lt;/code&gt;.&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://www.gnu.org/software/bash/manual/bashref.html&quot;&gt;Bash Reference Manual&lt;/a&gt; — внезапно очень простая и понятная книга о программировании на Bash.
Я узнал о таких возможностях Bash, о которых я даже не догадывался. Правда я прочитал только половину.&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;http://shuvalov.info/2014/09/17/a-byte-of-vim/&quot;&gt;Просто о Vim&lt;/a&gt; — потрясающе короткая, простая и действенная книга о Vim. Вот да!&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;http://shuvalov.info/2014/08/30/emotional-design/&quot;&gt;Эмоциональный веб-дизайн&lt;/a&gt; — отличная книга о том, почему важно быть человечным. Этот лейтмотив
я встречаю очень часто. Наверное, это такой, даже не голос, а скорее уже крик эпохи. Возвышенный язык,
дизайн, и даже люди. Разве так ведут себя с друзьями?&lt;/li&gt;
  &lt;li&gt;«Король Лир» — одна из моих любимых книг у Шекспира и вообще. «Ромео и Джульетта» – розовые сопли на голубом заборе
по сравнению с трагедией целого государства, такой глобальной и в то же время такой личной. Конечно же
все умерли.&lt;/li&gt;
&lt;/ul&gt;

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

&lt;p&gt;PS. Я ни в коем случае не предлагаю отказаться от интернета, фидли, хабра или чего-то еще.
Просто так сложилось у меня. Ну, как говорится: «ОЙ ВСЁ!».&lt;/p&gt;

</content>
  </entry>
  
  <entry>
    <title>CommonJS для браузера</title>
    <updated>2014-12-14T00:00:00+00:00</updated>
    
      <id>http://shuvalov.info/2014/12/14/moscowjs-browserify</id>
      <link href="http://shuvalov.info/2014/12/14/moscowjs-browserify"/>
    
      <content type="html" xml:base="http://shuvalov.info/">&lt;iframe width=&quot;688&quot; height=&quot;388&quot; src=&quot;//www.youtube.com/embed/89bZfKSvNGo&quot; frameborder=&quot;0&quot; allowfullscreen=&quot;&quot;&gt;&lt;/iframe&gt;

&lt;p&gt;&lt;a href=&quot;http://www.slideshare.net/moscowjs/commonjs&quot;&gt;слайды&lt;/a&gt;&lt;/p&gt;
</content>
  </entry>
  
  <entry>
    <title>Музыка для работы #4</title>
    <updated>2014-12-10T00:00:00+00:00</updated>
    
      <id>http://shuvalov.info/2014/12/10/sc-workset-4</id>
      <link href="http://shuvalov.info/2014/12/10/sc-workset-4"/>
    
      <content type="html" xml:base="http://shuvalov.info/">&lt;p&gt;&lt;img src=&quot;/assets/articles-assets/music/5.jpg&quot; alt=&quot;Музыка для работы&quot; /&gt;&lt;/p&gt;

&lt;p class=&quot;photo-author&quot;&gt;&lt;em&gt;фото: &lt;a href=&quot;https://www.flickr.com/photos/didmyself/&quot;&gt;Daniel Kulinski&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Четвертый плейлист ждал своего часа с сентября. Октябрь и ноябрь выдались просто
безумными — упарывался я в основном под лондонский пост-хардкор от &lt;a href=&quot;https://www.youtube.com/watch?v=afX5kz9hfHI&quot;&gt;Marmozets&lt;/a&gt;
(&lt;a href=&quot;https://www.youtube.com/watch?v=y9xUGVxI63c&quot;&gt;спасибо, Эрик Рикка&lt;/a&gt;), a последние недели под пару треков Lady Sovereign
по кругу (&lt;a href=&quot;https://www.youtube.com/watch?v=TAO9EFY0Fm4&quot;&gt;1&lt;/a&gt;, &lt;a href=&quot;https://www.youtube.com/watch?v=MpEkI5MGDjY&quot;&gt;2&lt;/a&gt;). В SC заглядывал как-то совсем эпизодически.&lt;/p&gt;

&lt;p&gt;Но я делаю успехи, и за последний месяц мне уже не так стыдно — стыд
всех предыдущих месяцев в купе с огромной скидкой на &lt;a href=&quot;http://culturedcode.com&quot;&gt;Things App&lt;/a&gt; убедил моего
Внутреннего &lt;s&gt;Нарк&lt;/s&gt;^w &lt;s&gt;Прокр&lt;/s&gt;^w Деятеля восстановить былое величие GTD,
и вот уже 3 недели я наверстываю упущенное. Честно сказать, даже не знаю, выйдет
из этого что-то или нет, но пока что-то да выходит.&lt;/p&gt;

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

&lt;div id=&quot;player&quot;&gt;&lt;/div&gt;

&lt;script&gt;
  (function() {
      var script = document.createElement(&quot;script&quot;);

      script.type = &quot;text/javascript&quot;;
      script.async = true;
      script.src = &quot;//sd.toneden.io/production/toneden.loader.js&quot;

      var entry = document.getElementsByTagName(&quot;script&quot;)[0];
      entry.parentNode.insertBefore(script, entry);
  }());

  ToneDenReady = window.ToneDenReady || [];
  ToneDenReady.push(function() {
      // Modify the dom and urls parameters to position
      // your player and select tracks/sets/artists to play.
      ToneDen.player.create({
          dom: '#player',
          urls: [
              'https://soundcloud.com/asheee/sets/workset-4'
          ],
          skin: 'aurora'
      });
  });
&lt;/script&gt;

&lt;p&gt;&lt;a href=&quot;https://soundcloud.com/asheee/sets/workset-4&quot;&gt;Ссылка на SoundCloud&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Буду рад, если вы поделитесь в комментариях треками, под которые вам нравится
работать :D&lt;/p&gt;

</content>
  </entry>
  
  <entry>
    <title>Instapaper и Pocket</title>
    <updated>2014-11-28T00:00:00+00:00</updated>
    
      <id>http://shuvalov.info/2014/11/28/pocket-n-instapaper</id>
      <link href="http://shuvalov.info/2014/11/28/pocket-n-instapaper"/>
    
      <content type="html" xml:base="http://shuvalov.info/">&lt;p style=&quot;text-align:right;&quot;&gt;&lt;em&gt;Though this be madness, yet there is method in’t.&lt;/em&gt;&lt;/p&gt;

&lt;p class=&quot;photo-author&quot;&gt;William Shakespeare&lt;/p&gt;

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

&lt;p&gt;Из 150 ссылок осталось 4:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;a href=&quot;https://dev.opera.com/articles/perfect-javascript-framework/&quot;&gt;In search of the perfect JavaScript framework&lt;/a&gt;  — статья от ребят из Opera.&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;http://zenhabits.net/fat-loss/&quot;&gt;What to Eat for Fat Loss&lt;/a&gt; — я не умею в здоровое питание, но всё время собираюсь начать.&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;http://www.dsnews.ua/society/mitio-kaku-ucheba-uzhe-ne-budet-bazirovatsya-na-zapominanii-28082014231600&quot;&gt;Митио Каку: Учеба уже не будет базироваться на запоминании&lt;/a&gt; — не смог удалить: интересно же!&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;http://freetonik.com/blog/all/english-at-ulcamp14/&quot;&gt;Как учить английский всю жизнь&lt;/a&gt; — видео доклада Рахима. Давно собирался посмотреть.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Я понял, что я &lt;em&gt;всё делал неправильно&lt;/em&gt;. Pocket или Instapaper —
не место для закладок. Не нужно класть туда всё, что попадается под
руку — это трата времени. Трата внимания.&lt;/p&gt;

&lt;p&gt;Отложенных статей всё больше. Желания их читать всё меньше.
Это раздражает.&lt;/p&gt;

&lt;p&gt;К чёртовой матери.&lt;/p&gt;

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

&lt;p&gt;Я путал отложенные статьи и закладки. Первые полезны &lt;em&gt;прямо сейчас&lt;/em&gt;.
Вторые же &lt;em&gt;могут стать полезными&lt;/em&gt;. Я сохраняю их на всякий случай
в &lt;a href=&quot;http://pinboard.in&quot;&gt;pinboard.in&lt;/a&gt;. &lt;strong&gt;Не читая&lt;/strong&gt;.&lt;/p&gt;

</content>
  </entry>
  
  <entry>
    <title>Byobu</title>
    <updated>2014-11-18T00:00:00+00:00</updated>
    
      <id>http://shuvalov.info/2014/11/18/byobu</id>
      <link href="http://shuvalov.info/2014/11/18/byobu"/>
    
      <content type="html" xml:base="http://shuvalov.info/">&lt;p&gt;Разглядывая экраны разработчиков в &lt;a href=&quot;https://github.com/shuvalov-anton/code-screenshots&quot;&gt;code-screenshots&lt;/a&gt;, заметил,
что многие используют &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;tmux&lt;/code&gt;. С одной стороны это такой простой тайловый
менеджер, а с другой ещё и удобная работа с сессиями, которая экономит
кучу времени на открытие нужных вкладок и окон в терминале.&lt;/p&gt;

&lt;p&gt;До этого я использовал сплиты iTerm2, чтобы держать на одном экране
несколько панелей с консолью. В принципе, этого может вполне хватить —
если не закрывать терминал или использовать его лишь изредка. Я же 90% времени
провожу в консоли, так что iTerm меня уже давно перестал устраивать.
Ну и еще одна печальная печаль — в полноэкранном режиме iTerm не показывает
открытые табы. Только если удерживать &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;cmd&lt;/code&gt; пару секунд.&lt;/p&gt;

&lt;p&gt;Сначала я попробовал &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;tmux&lt;/code&gt;. Если приноровиться к его «удобным» хоткеям (хотя,
я пользуюсь Vim, кого я обманываю…), то, как говорится, «мне норм».
Но из коробки в &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;tmux&lt;/code&gt; &lt;s&gt;скушные обои&lt;/s&gt; достаточно скромный статусбар.
Я хотел что-то более прекрасное, но мне было лень настраивать. Обычно
на такое дело уходит добрая пара дней, а я даже не знал, буду ли я
вообще использовать &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;tmux&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;И тут добрые люди показали мне &lt;a href=&quot;http://byobu.co/&quot;&gt;byobu&lt;/a&gt;. Byobu — это что-то вроде набора
полезных утилит и биндингов для &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;tmux&lt;/code&gt;/&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;screen&lt;/code&gt;. Вот &lt;a href=&quot;http://www.youtube.com/watch?v=NawuGmcvKus&quot;&gt;здесь&lt;/a&gt; есть клёвое
видео о том, как удобно им пользоваться.&lt;/p&gt;

&lt;p&gt;Увы, удобные хоткеи в iTerm не заработали. Но я нашел &lt;a href=&quot;https://github.com/shuvalov-anton/.dotfiles#byobu&quot;&gt;решение&lt;/a&gt;,
и просто перебиндил в iTerm эскейп-коды для нужных сочетаний клавиш.
Говорят, что в обычном Terminal.app все должно работать отлично,
но у меня там много чего другого работает из рук вон плохо, поэтому
даже ради интереса я проверять не стал.&lt;/p&gt;

&lt;p&gt;Выглядит у меня byobu примерно так:&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;https://cloud.githubusercontent.com/assets/1410106/5081469/f4ed60f0-6ee0-11e4-98f0-77cc2353a64f.png&quot;&gt;&lt;img src=&quot;https://cloud.githubusercontent.com/assets/1410106/5081469/f4ed60f0-6ee0-11e4-98f0-77cc2353a64f.png&quot; alt=&quot;byobu&quot; /&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p class=&quot;photo-author&quot;&gt;Byobu. Сплиты и статусбар внизу.&lt;/p&gt;

&lt;p&gt;Установка, не считая той &lt;a href=&quot;https://github.com/shuvalov-anton/.dotfiles#byobu&quot;&gt;проблемы с хоткеями&lt;/a&gt; вполне простая:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;brew &lt;span class=&quot;nb&quot;&gt;install &lt;/span&gt;byobu
byobu-config&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;Вроде бы, всё. Можно пользоваться.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Подписывайтесь на &lt;a href=&quot;http://feeds.feedburner.com/anton-shuvalov/FJHar&quot;&gt;РСС&lt;/a&gt;.
Всем добра и штурмовиков&lt;/em&gt;.&lt;/p&gt;
</content>
  </entry>
  
  <entry>
    <title>Чейнинг</title>
    <updated>2014-10-24T00:00:00+00:00</updated>
    
      <id>http://shuvalov.info/2014/10/24/chaining</id>
      <link href="http://shuvalov.info/2014/10/24/chaining"/>
    
      <content type="html" xml:base="http://shuvalov.info/">&lt;p&gt;&lt;img src=&quot;http://shuvalov.info/assets/articles-assets/chaining.jpg&quot; alt=&quot;или Как сделать код проще, добавив одну строчку&quot; /&gt;&lt;/p&gt;

&lt;p class=&quot;photo-author&quot;&gt;&lt;em&gt;фото: &lt;a href=&quot;https://www.flickr.com/photos/ep_jhu/&quot;&gt;ep_jhu&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

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

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-javascript&quot; data-lang=&quot;javascript&quot;&gt;&lt;span class=&quot;c1&quot;&gt;// …&lt;/span&gt;
&lt;span class=&quot;nx&quot;&gt;initialize&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;function&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;options&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;k&quot;&gt;this&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;parseOpts&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;options&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;setElement&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&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;.js-labels&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;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;tagsCollectionCreate&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;tagsCollectionSavable&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;renderSearch&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;renderTags&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;c1&quot;&gt;// …&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;Многие библиотеки поддерживают чейнинг «из коробки»: jQuery, Backbone, Underscore.&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-javascript&quot; data-lang=&quot;javascript&quot;&gt;&lt;span class=&quot;c1&quot;&gt;// jQuery&lt;/span&gt;
&lt;span class=&quot;nx&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;.circle&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;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;animate&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;({&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;left&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;+500px&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;top&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;+250px&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;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;duration&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;800&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;animate&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;({&lt;/span&gt;
    &lt;span class=&quot;na&quot;&gt;width&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;200px&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;height&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;200px&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;borderRadius&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;100px&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;na&quot;&gt;duration&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1500&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;animate&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;({&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;textIndent&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;100&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;step&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;function&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;now&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;fx&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;$&lt;/span&gt;&lt;span class=&quot;p&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;css&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;-webkit-transform&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;rotate(&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;now&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;deg)&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;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;na&quot;&gt;duration&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1000&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;na&quot;&gt;easing&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;linear&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;p&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-javascript&quot; data-lang=&quot;javascript&quot;&gt;&lt;span class=&quot;c1&quot;&gt;// Backbone&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;tags&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;setElement&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&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;.js-labels&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;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;on&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;remove&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;this&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;save&lt;/span&gt;&lt;span class=&quot;p&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;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;on&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;reset&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;this&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;save&lt;/span&gt;&lt;span class=&quot;p&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;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;on&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;add&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;this&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;save&lt;/span&gt;&lt;span class=&quot;p&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;p&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;h3 id=&quot;как-работает-чейнинг&quot;&gt;Как работает чейнинг&lt;/h3&gt;

&lt;p&gt;Чейнить космически просто: нужно лишь возвращать &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;this&lt;/code&gt; в каждом методе цепочки:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-javascript&quot; data-lang=&quot;javascript&quot;&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;c1&quot;&gt;// ...&lt;/span&gt;
  &lt;span class=&quot;nl&quot;&gt;parseOptions&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;function&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;options&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;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;===&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;typeof&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;options&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;this&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;options&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;this&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;options&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;tags&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;options&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;else&lt;/span&gt; &lt;span class=&quot;p&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;options&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;options&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;k&quot;&gt;this&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;// ...&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;Или вот пример с плагином для jQuery:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-javascript&quot; data-lang=&quot;javascript&quot;&gt;&lt;span class=&quot;nx&quot;&gt;$&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;fn&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;sticky&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;function&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;this&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;each&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kd&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;el&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;// make element sticky&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;k&quot;&gt;this&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;$&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;.js-header&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;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;sticky&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;fadeIn&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;/figure&gt;

&lt;p&gt;Вот такой нехитрый способ одной строчкой сделать код проще.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Подписывайтесь на &lt;a href=&quot;http://feeds.feedburner.com/anton-shuvalov/FJHar&quot;&gt;РСС&lt;/a&gt;.
Всем добра и штурмовиков&lt;/em&gt;.&lt;/p&gt;

</content>
  </entry>
  
  <entry>
    <title>«An introduction to programming in Go», Caleb Doxsey</title>
    <updated>2014-10-14T00:00:00+00:00</updated>
    
      <id>http://shuvalov.info/2014/10/14/an-itroduction-to-programming-in-go</id>
      <link href="http://shuvalov.info/2014/10/14/an-itroduction-to-programming-in-go"/>
    
      <content type="html" xml:base="http://shuvalov.info/">&lt;p class=&quot;book-cover&quot;&gt;&lt;img src=&quot;http://shuvalov.info/assets/articles-assets/go-book.png&quot; alt=&quot;«An introduction to programming in Go», Caleb Doxsey&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Недавно я отправился в славное путешествие в Пермь. Как раз перед самой поездкой
я наткнулся на бесплатную книгу о Go &lt;a href=&quot;http://www.golang-book.com/&quot;&gt;«An introduction to programming in Go»&lt;/a&gt;
от Caleb Doxsey.&lt;/p&gt;

&lt;p&gt;Книга небольшая — я прочитал ее в дороге часа за 4-5. Большая часть совсем для начинающих:
системы счисления, редакторы, базовые типы. С другой стороны, в там есть
много интересного о типах, которых нет в моем любимом JS: &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;pointers&lt;/code&gt;, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;maps&lt;/code&gt;, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;slices&lt;/code&gt;,
о структурах, интерфейсах, тестах, синтаксисе, пакетах, которые идут с языком.&lt;/p&gt;

&lt;p&gt;Когда я открывал книгу, я хотел научиться писать на Go утилиты,
и инструменты, которые я сейчас пишу на NodeJS. В этом книга полностью
себя оправдала. Я закрыл последнюю страницу, и решил написать на Go CLI для поиска документации
в браузере прямо из терминала с возможностью хранить в &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;~/.search&lt;/code&gt; список сайтов
для поиска. Я писал эту штуку последние пару дней &lt;a href=&quot;https://github.com/shuvalov-anton/node-search-me&quot;&gt;на NodeJS&lt;/a&gt;, и вот что
получилось &lt;a href=&quot;https://github.com/shuvalov-anton/go-search-me&quot;&gt;на Golang&lt;/a&gt;. Правда, и там, и там код требует рефакторинга,
так что не судите слишком строго! :D&lt;/p&gt;

&lt;h2 id=&quot;the-pretty-wagon-to-go&quot;&gt;The Pretty Wagon to Go&lt;/h2&gt;

&lt;p&gt;После NodeJS, Go выглядит чертовски круто ( ⚆ _ ⚆ ) Теперь я понял и могу согласиться
с тем, о чем писал TJ Holowaychuk в своем посте «&lt;a href=&quot;https://medium.com/code-adventures/farewell-node-js-4ba9e7f3e52b&quot;&gt;Farewell Node.JS&lt;/a&gt;».&lt;/p&gt;

&lt;p&gt;Строгая типизация, проверка типов, синтаксиса и забытых переменных во время
написания кода — это потрясающе! В JS я чувствую себя уверенно только с линтером,
&lt;a href=&quot;/2014/10/02/javascript-coverage/&quot;&gt;написав достаточно unit-тестов&lt;/a&gt;. В Go я начинаю думать, что успешный билд —
это уже тест. Строгая типизация тоже выглядит потрясающе. Правда я еще не чувствую
себя уверенно с некоторыми типами, вроде &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;pointers&lt;/code&gt;, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;slices&lt;/code&gt; или &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;maps&lt;/code&gt;. Возможно,
структуры лучше подходят для тех вещий, где я пытаюсь использовать эти типы.&lt;/p&gt;

&lt;h2 id=&quot;документация-в-golang&quot;&gt;Документация в Golang&lt;/h2&gt;

&lt;p&gt;Мне очень понравилась идея документации — просто пишешь комментарии над методами.
&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;godoc&lt;/code&gt; сделает остальное сам:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-golang&quot; data-lang=&quot;golang&quot;&gt;&lt;span class=&quot;c&quot;&gt;// Finds the average of a series of numbers&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;func&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Average&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;xs&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[]&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;float64&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;float64&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-golang&quot; data-lang=&quot;golang&quot;&gt;&lt;span class=&quot;n&quot;&gt;godoc&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;golang&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;book&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;chapter11&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;math&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Average&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;h2 id=&quot;gorutines&quot;&gt;Gorutines&lt;/h2&gt;

&lt;p&gt;Многопоточность в Go очень приятна. Есть &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;gorutine&lt;/code&gt;s в которых запускаются
подпрограммы, есть &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;channel&lt;/code&gt;s, которые обеспечивают транспорт между &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;gorutine&lt;/code&gt;s.
По-моему, это выглядит гораздо проще, чем &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;EventEmmiter&lt;/code&gt;‘ы в NodeJS и&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt; WebWorker&lt;/code&gt;‘ы.&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-go&quot; data-lang=&quot;go&quot;&gt;&lt;span class=&quot;k&quot;&gt;func&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;pinger&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;c&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;chan&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;lt;-&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;func&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;printer&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;c&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;-&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;chan&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;h2 id=&quot;еще-раз-о-книге&quot;&gt;Еще раз о книге&lt;/h2&gt;

&lt;p&gt;Книга клёвая — и определенно стоит 4 часов чтения. У меня вот получилось что-то
написать на Go практически сразу, после того, как я закончил ее читать, так что
это отличный способ начать. Вообще в книге, очень много совсем элементарных вещей
в программировании, так что, наверное, ее могут читать даже те самые «юноши бледные
со взором горячим». Но если вы уже работаете с Go,
то, как мне кажется, ничего нового вы там не найдете. Книгу можно &lt;a href=&quot;http://www.golang-book.com/&quot;&gt;скачать в PDF&lt;/a&gt;
бесплатно, или &lt;a href=&quot;http://www.golang-book.com/&quot;&gt;читать прямо на сайте&lt;/a&gt;, так что… А почему бы и нет? :D&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;http://shuvalov.info/assets/articles-assets/go.jpg&quot; alt=&quot;Прочитал. Попробовал. Понравилось.&quot; /&gt;&lt;/p&gt;

&lt;p class=&quot;photo-author&quot;&gt;&lt;em&gt;фото: &lt;a href=&quot;https://www.flickr.com/photos/marfis75/&quot;&gt;Martin Fisch&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Подписывайтесь на &lt;a href=&quot;http://feeds.feedburner.com/anton-shuvalov/FJHar&quot;&gt;РСС&lt;/a&gt;&lt;/em&gt;.&lt;/p&gt;

</content>
  </entry>
  
  <entry>
    <title>Анализ покрытия JavaScript-кода тестами</title>
    <updated>2014-10-02T00:00:00+00:00</updated>
    
      <id>http://shuvalov.info/2014/10/02/javascript-coverage</id>
      <link href="http://shuvalov.info/2014/10/02/javascript-coverage"/>
    
      <content type="html" xml:base="http://shuvalov.info/">&lt;p&gt;&lt;a href=&quot;https://travis-ci.org/shuvalov-anton/microlog&quot;&gt;&lt;img src=&quot;https://travis-ci.org/shuvalov-anton/microlog.svg&quot; alt=&quot;Build Status&quot; /&gt;&lt;/a&gt;
&lt;a href=&quot;https://codeclimate.com/github/shuvalov-anton/microlog&quot;&gt;&lt;img src=&quot;https://codeclimate.com/github/shuvalov-anton/microlog/badges/gpa.svg&quot; alt=&quot;Code Climate&quot; /&gt;&lt;/a&gt;
&lt;a href=&quot;https://coveralls.io/r/shuvalov-anton/microlog?branch=master&quot;&gt;&lt;img src=&quot;https://coveralls.io/repos/shuvalov-anton/microlog/badge.png?branch=master&quot; alt=&quot;Coverage Status&quot; /&gt;&lt;/a&gt;&lt;/p&gt;

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

&lt;p&gt;И сразу дисклеймер — утилит для инструментирования и тестирования, ровно как и облачных сервисов
очень много. Я использую &lt;a href=&quot;https://www.npmjs.org/package/mocha&quot;&gt;mocha&lt;/a&gt; для тестов, &lt;a href=&quot;https://www.npmjs.org/package/jscoverage&quot;&gt;jscoverage&lt;/a&gt; для инструментирования и &lt;a href=&quot;https://coveralls.io/&quot;&gt;Coveralls&lt;/a&gt;
прикрученный к &lt;a href=&quot;https://travis-ci.org&quot;&gt;Travis&lt;/a&gt; как CI-сервис для анализа покрытия. Просто потому что я так привык.&lt;/p&gt;

&lt;h2 id=&quot;зачем-знать-процент-покрытия-тестами&quot;&gt;Зачем знать процент покрытия тестами?&lt;/h2&gt;

&lt;p&gt;Нельзя улучшить то, что не нельзя измерить. Это утверждение подходит и для тестов.
Хотя, писать тесты уже само по себе хорошо, но это только первый шаг. Следующая ступень — измерять
процент покрытия кода.&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;a href=&quot;http://shuvalov.info/assets/articles-assets/coverage/coverage.html&quot;&gt;&lt;img src=&quot;http://shuvalov.info/assets/articles-assets/coverage/coverage.png&quot; alt=&quot;javascript coverage&quot; /&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3 id=&quot;если-файл--один&quot;&gt;Если файл  один…&lt;/h3&gt;

&lt;p&gt;Инструментируем модуль:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;&lt;span class=&quot;nb&quot;&gt;cd &lt;/span&gt;my-project
jscoverage index.js index-cov.js&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;Затем при тестировании покрытия нужно подключить специально подготовленную &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;cov&lt;/code&gt;-версию эту версию вместо настоящей библиотеки.
Для этого логичнее всего использовать переменную окружения. Советуют называть эту переменную &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;MYPROJECT_COV&lt;/code&gt;.
Некоторые библиотеки используют просто &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;COV&lt;/code&gt;, но у меня возникли конфликты где-то в &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;jscoverage&lt;/code&gt;, так что
лучше добавлять префиксом название проекта.&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-js&quot; data-lang=&quot;js&quot;&gt;&lt;span class=&quot;cm&quot;&gt;/* test/index.js */&lt;/span&gt;
&lt;span class=&quot;kd&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;myProject&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;process&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;env&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;MYPROJECT_COV&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;?&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;require&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;../index-cov&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;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;require&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;../index&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;Теперь остается  запустить тесты и сгенерировать отчет о покрытии. Делается это так:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-js&quot; data-lang=&quot;js&quot;&gt;&lt;span class=&quot;nx&quot;&gt;MYPROJECT_COV&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&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;node_modules&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;nx&quot;&gt;bin&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;mocha&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;R&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;html&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;cov&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;coverage&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;html&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;Файлы &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;coverage.html&lt;/code&gt; и &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;index-cov.js&lt;/code&gt; стоит добавить в &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;.gitignore&lt;/code&gt;, чтобы не закоммитить  случайно.&lt;/p&gt;

&lt;h3 id=&quot;если-файлов-много&quot;&gt;Если файлов много…&lt;/h3&gt;

&lt;p&gt;Если в проекте много JS-файлов, которые скрываются за index.js, то обычно все эти штуки убираются в &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;lib/&lt;/code&gt;,
который инструментируется в &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;lib-cov/&lt;/code&gt;:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;&lt;span class=&quot;nb&quot;&gt;cd &lt;/span&gt;my-project
jscoverage lib lib-cov&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;В &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;index.js&lt;/code&gt; остается только код, который, в зависимости от переменной окружения подключает &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;lib/&lt;/code&gt; или &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;lib-cov/&lt;/code&gt;:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-js&quot; data-lang=&quot;js&quot;&gt;&lt;span class=&quot;cm&quot;&gt;/* index.js */&lt;/span&gt;
&lt;span class=&quot;nx&quot;&gt;module&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;exports&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;process&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;env&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;MYPROJECT_COV&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;?&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;require&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;../lib-cov&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;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;require&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;../lib&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;Ну и в &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;tests/&lt;/code&gt; проверять переменную окружения уже не нужно — так что там не остается ничего необычного.
Не забудте добавить &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;lib-cov/&lt;/code&gt; в &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;.gitignore&lt;/code&gt;.&lt;/p&gt;

&lt;h2 id=&quot;coveralls&quot;&gt;Coveralls&lt;/h2&gt;

&lt;p&gt;Окей, Google. Теперь мы знаем насколько наш модуль покрыт тестами — можно смотреть в &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;coverage.html&lt;/code&gt;, улучшать
покрытие тестами, и всячески делать этот мир лучше.&lt;/p&gt;

&lt;p&gt;Но вот беда — &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;coverage.html&lt;/code&gt; есть только локально, да и при каждой генерации
отчета о покрытии он перезаписывается, не оставляя никакой истории, и, соответственно,
возможности наблюдать прогресс. Если вы разрабатываете небольшой модуль — наверное, в этом нет ничего страшного.
Но если вы пишете что-то посложнее, то, скорее всего, вам хотелось бы знать, какое покрытие кода
в разных бранчах, пулл-реквестах, иметь возможность заглянуть в историю. А как насчет
клёвого бейджа —
&lt;a href=&quot;https://coveralls.io/r/shuvalov-anton/microlog?branch=master&quot;&gt;&lt;img src=&quot;https://coveralls.io/repos/shuvalov-anton/microlog/badge.png?branch=master&quot; alt=&quot;Coverage Status&quot; /&gt;&lt;/a&gt;
в &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;readme.md&lt;/code&gt;?&lt;/p&gt;

&lt;p&gt;Насколько я знаю, таких сервисов не мало. К примеру, &lt;a href=&quot;https://codeclimate.com/&quot;&gt;code climate&lt;/a&gt; может следить за покрытием кода. Я же пока остановился
(хотя, конечно, я только начал :D) на &lt;a href=&quot;https://coveralls.io/&quot;&gt;Coveralls&lt;/a&gt;. Coveralls интегрируется с &lt;a href=&quot;https://travis-ci.org&quot;&gt;Travis CI&lt;/a&gt;. В &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;.travis&lt;/code&gt; нужно будет добавить несколько
скриптов, которые после завершения обычного тестирования будут запустят тесты на покрытие и отправят результаты на сервер
Coveralls.&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-yml&quot; data-lang=&quot;yml&quot;&gt;&lt;span class=&quot;na&quot;&gt;after_success&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
  &lt;span class=&quot;pi&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;./node_modules/.bin/jscoverage lib lib-cov&lt;/span&gt;
  &lt;span class=&quot;pi&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;MYPROJECT_COV=1 ./node_modules/.bin/mocha test -R mocha-lcov-reporter | ./node_modules/coveralls/bin/coveralls.js&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;h2 id=&quot;packagejson&quot;&gt;package.json&lt;/h2&gt;

&lt;p&gt;Для работы Coveralls понадобится парочка модулей:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;a href=&quot;https://www.npmjs.org/package/mocha-lcov-reporter&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;mocha-lcov-reporter&lt;/code&gt;&lt;/a&gt;, который адаптирует данные о покрытии кода в &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;lcov&lt;/code&gt;-формат, с которым работает Coveralls,&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://www.npmjs.org/package/coveralls&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;coveralls&lt;/code&gt;&lt;/a&gt; — CLI-реализация API coveralls.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Кстати, ничего не мешает вынести вынести генерацию &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;coverage.html&lt;/code&gt; в &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;package.json&lt;/code&gt; — не писать же руками каждый раз:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-js&quot; data-lang=&quot;js&quot;&gt;&lt;span class=&quot;c1&quot;&gt;// package.json&lt;/span&gt;
&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;scripts&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;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;test&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;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;mocha&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;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;test-cov&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;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;jscoverage lib lib-cov; MS_COV=1 ./node_modules/.bin/mocha -R html-cov &amp;gt; coverage.html&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;c1&quot;&gt;// ...&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;Теперь можно просто писать &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;npm run test-cov&lt;/code&gt; и не вспоминать нужные команды каждый раз. Осталось
только бейдж из coverals в &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;readme.md&lt;/code&gt; добавить.&lt;/p&gt;

&lt;h2 id=&quot;примеры&quot;&gt;Примеры&lt;/h2&gt;

&lt;p&gt;В примерах можно посмотреть &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;.travis.yml&lt;/code&gt;, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;package.json&lt;/code&gt; и покликать на бейджи:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;a href=&quot;https://github.com/shuvalov-anton/to-ms&quot;&gt;ms-to&lt;/a&gt; — небольшая утилита для работы с миллисекундами в JS.&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://github.com/visionmedia/page.js&quot;&gt;page.js&lt;/a&gt; — роутер в духе ExpressJS только для браузера.&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://github.com/shuvalov-anton/microlog&quot;&gt;microlog&lt;/a&gt; — небольшой и удобный логгер для NodeJS приложений.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;img src=&quot;http://shuvalov.info/assets/articles-assets/footer/trooper-11.jpg&quot; alt=&quot;Вместе с нашими друзьями: Mocha, JSCoverage, Coveralls и Travis&quot; /&gt;&lt;/p&gt;

&lt;p class=&quot;photo-author&quot;&gt;&lt;em&gt;фото: &lt;a href=&quot;https://www.flickr.com/photos/bossone/&quot;&gt;Cyril Bosselut&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Подписывайтесь на &lt;a href=&quot;http://feeds.feedburner.com/anton-shuvalov/FJHar&quot;&gt;РСС&lt;/a&gt;.
Всем добра и штурмовиков&lt;/em&gt;.&lt;/p&gt;

</content>
  </entry>
  
  <entry>
    <title>Ссылколог #9</title>
    <updated>2014-09-23T00:00:00+00:00</updated>
    
      <id>http://shuvalov.info/2014/09/23/linkolog-9</id>
      <link href="http://shuvalov.info/2014/09/23/linkolog-9"/>
    
      <content type="html" xml:base="http://shuvalov.info/">&lt;ul&gt;
  &lt;li&gt;Есть одно &lt;a href=&quot;https://github.com/h5bp/lazyweb-requests&quot;&gt;очень крутое сообщество&lt;/a&gt;, в котором разные ребята делятся
классными идеями о том, как сделать этот веб лучше. Cреди этих самых ребят
&lt;a href=&quot;https://github.com/mathiasbynens&quot;&gt;@mathiasbynens&lt;/a&gt;, &lt;a href=&quot;https://github.com/paulirish&quot;&gt;@paulirish&lt;/a&gt;, &lt;a href=&quot;https://github.com/sindresorhus&quot;&gt;@sindresorhus&lt;/a&gt;, &lt;a href=&quot;https://github.com/isaacs&quot;&gt;@isaacs&lt;/a&gt;,
&lt;a href=&quot;https://github.com/addyosmani&quot;&gt;@addyosmani&lt;/a&gt;, контрибуторы Bootstrap, HTML5 Boilerplate и куча других крутых чуваков.
Пишут туда не так уж часто, чтобы следить за сообществом было в тягость,
так что советую подписываться!&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;http://blog.npmjs.org/post/98131109725/npm-2-0-0&quot;&gt;NPM обновился&lt;/a&gt; до версии &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;2.0.0&lt;/code&gt;. Как пишут разработчики, мажорная
версия сменилась потому что &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;run scripts&lt;/code&gt; теперь научили принимать аргументы,
но сломали обратную совместимость. Вообще, изменений много: к примеру,
npm теперь использует &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;semver@4.0.0&lt;/code&gt;, а еще в &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;package.json&lt;/code&gt; появилась возможность
указывать бранчи для зависимостей, которые ставятся с github как-то так:
&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;component/entejs#branch&lt;/code&gt;.&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;http://blog.stackoverflow.com/2014/09/introducing-runnable-javascript-css-and-html-code-snippets/&quot;&gt;Stack Overflow запускает js-песочницы&lt;/a&gt; прямо в ответах.&lt;/li&gt;
  &lt;li&gt;Интересная &lt;a href=&quot;http://kamranahmed.info/javascript-magic-of-browsers-console/&quot;&gt;статья&lt;/a&gt; о том, как использовать &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;console.log&lt;/code&gt; на 100%. Я вот
вообще ничего не знал о фильтрах и CSS для стилизации вывода консоли.&lt;/li&gt;
  &lt;li&gt;Интересная &lt;a href=&quot;http://writeapp.net/mac/&quot;&gt;минималистичная замена Evernote&lt;/a&gt;. Похоже на нечто среднее между
Writer Pro и Evernote. Мне как фанату Markdown очень интересно попробовать.
Пока еще не поставил, так что если кто-то уже попробовал — поделитесь мнением :D&lt;/li&gt;
  &lt;li&gt;Забавная &lt;a href=&quot;http://bezier.method.ac/#&quot;&gt;игра&lt;/a&gt;, в которой нужно строить кривые Безье.&lt;/li&gt;
  &lt;li&gt;Automations в OS X &lt;a href=&quot;https://developer.apple.com/library/prerelease/mac/releasenotes/InterapplicationCommunication/RN-JavaScriptForAutomation/index.html&quot;&gt;теперь можно писать на JS&lt;/a&gt;,&lt;/li&gt;
  &lt;li&gt;и в iOS 8 Apple &lt;a href=&quot;http://www.sencha.com/blog/apple-shows-love-for-html5-with-ios-8&quot;&gt;добавили&lt;/a&gt; в Safari и WebView просто огромное количество HTML5 и JS фич. Ну не милахи ли?&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;img src=&quot;http://shuvalov.info/assets/articles-assets/footer/trooper-10.jpg&quot; alt=&quot;Тайная гильдия, NPM@2.0, песочницы на SO и немного о console.log и Apple&quot; /&gt;&lt;/p&gt;

&lt;p class=&quot;photo-author&quot;&gt;&lt;em&gt;фото: &lt;a href=&quot;https://www.flickr.com/photos/kalexanderson/&quot;&gt;Kristina Alexanderson&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Подписывайтесь на &lt;a href=&quot;http://feeds.feedburner.com/anton-shuvalov/FJHar&quot;&gt;РСС&lt;/a&gt;.
Всем добра и штурмовиков&lt;/em&gt;.&lt;/p&gt;

</content>
  </entry>
  
  <entry>
    <title>Из Pocket в Instapaper</title>
    <updated>2014-09-20T00:00:00+00:00</updated>
    
      <id>http://shuvalov.info/2014/09/20/pocket-to-instapaper</id>
      <link href="http://shuvalov.info/2014/09/20/pocket-to-instapaper"/>
    
      <content type="html" xml:base="http://shuvalov.info/">&lt;p&gt;Недавно в твиттере &lt;a href=&quot;https://gist.github.com/shuvalov-anton/862276679479cfcd0421&quot;&gt;@juev&lt;/a&gt; написал:&lt;/p&gt;

&lt;blockquote class=&quot;twitter-tweet&quot; lang=&quot;ru&quot;&gt;&lt;p&gt;Обалденно! Открыл в Instapaper for iOS статью на русском языке и включил проговаривание. Так четко читает, слушать приятно.&lt;/p&gt;&amp;mdash; Denis Evsyukov (@Juev) &lt;a href=&quot;https://twitter.com/Juev/status/512643235420717056&quot;&gt;18 сентября 2014&lt;/a&gt;&lt;/blockquote&gt;
&lt;script async=&quot;&quot; src=&quot;//platform.twitter.com/widgets.js&quot; charset=&quot;utf-8&quot;&gt;&lt;/script&gt;

&lt;p&gt;И я, конечно же, решил заставить робота ласкать своим милым голоском и мои уши. 
Качество очень сильно зависит от статьи. В вычурных материалах ударения
и эмфазисы в гротескно-напыщенных выражениях стоят отнюдь не там где им полагается,
а код даже люди читают вслух очень забавно. Но в большинстве статей качества
произношения вполне хватает для того, чтобы слушать статьи как подкасты. В платной
версии Instacast можно даже делать плейлисты из статей. Потрясающе, не правда ли?
Теперь можно &lt;s&gt;читать&lt;/s&gt; слушать отложенные статьи за работой, быстрее опустошая
огромный завал из Pocket’а :D&lt;/p&gt;

&lt;iframe class=&quot;youtube&quot; src=&quot;//www.youtube.com/embed/bNUJCl6lppk&quot; frameborder=&quot;0&quot; allowfullscreen=&quot;&quot;&gt;&lt;/iframe&gt;

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

&lt;p&gt;&lt;img src=&quot;http://shuvalov.info/assets/articles-assets/instacast.jpg&quot; alt=&quot;Из Pocket в Instapaper&quot; /&gt;&lt;/p&gt;

&lt;h2 id=&quot;перенос-статей-из-pocket-в-instapaper&quot;&gt;Перенос статей из Pocket в Instapaper&lt;/h2&gt;

&lt;p&gt;Внезапно, я не нашел абсолютно никаких быстрых способов перенести статьи из Pocket
в Instapaper: ни импорта, ни утилит. Всё что было, датировалось годом 2012, было
покрыто пылью и работало с предсказуемым результатом &lt;span class=&quot;hidden&quot;&gt;никак&lt;/span&gt;.&lt;/p&gt;

&lt;p&gt;Я посмотрел на эти пыльные труды и решил сделать все в консоли.&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;В Pocket нужно доскроллить страницу до конца, чтобы появились все статьи&lt;/li&gt;
  &lt;li&gt;Затем нужно собрать ссылки на все статьи и скопировать результат без первой
и последней кавычки:&lt;/li&gt;
&lt;/ul&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-js&quot; data-lang=&quot;js&quot;&gt;&lt;span class=&quot;nx&quot;&gt;JSON&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;stringify&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;
  &lt;span class=&quot;nx&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;.original_url&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;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;kd&quot;&gt;function&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;k&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;href&lt;/span&gt;
      &lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;replace&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;http://getpocket.com/redirect?url=&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;p&quot;&gt;)&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;}).&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;toArray&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;/figure&gt;

&lt;ul&gt;
  &lt;li&gt;После этого идем на сайт Instapaper, и создаем переменную, куда запишем ссылки из Pocket:&lt;/li&gt;
&lt;/ul&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-js&quot; data-lang=&quot;js&quot;&gt;  &lt;span class=&quot;kd&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;urls&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;cm&quot;&gt;/* скопированные ссылки */&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;ul&gt;
  &lt;li&gt;И осталось только добавить каждую ссылку через API Instapaper к себе в аккаунт:&lt;/li&gt;
&lt;/ul&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-js&quot; data-lang=&quot;js&quot;&gt;&lt;span class=&quot;nx&quot;&gt;urls&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;kd&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;url&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;url&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;decodeURIComponent&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;url&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&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;nx&quot;&gt;url&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
  &lt;span class=&quot;nx&quot;&gt;$&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;ajax&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;({&lt;/span&gt;
      &lt;span class=&quot;na&quot;&gt;url&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;https://www.instapaper.com/api/add&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;data&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;url&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;url&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
        &lt;span class=&quot;na&quot;&gt;username&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;cm&quot;&gt;/* email */&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
        &lt;span class=&quot;na&quot;&gt;password&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;cm&quot;&gt;/* password */&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;nx&quot;&gt;done&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kd&quot;&gt;function&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;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;nx&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;p&quot;&gt;})&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;Ну и, о чудо, теперь о Pocket можно забыть.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Подписывайтесь на &lt;a href=&quot;http://feeds.feedburner.com/anton-shuvalov/FJHar&quot;&gt;РСС&lt;/a&gt;.
Всем добра и штурмовиков&lt;/em&gt;.&lt;/p&gt;

</content>
  </entry>
  
  <entry>
    <title>«Просто о vim», Суэруп Си Эйч</title>
    <updated>2014-09-17T00:00:00+00:00</updated>
    
      <id>http://shuvalov.info/2014/09/17/a-byte-of-vim</id>
      <link href="http://shuvalov.info/2014/09/17/a-byte-of-vim"/>
    
      <content type="html" xml:base="http://shuvalov.info/">&lt;p class=&quot;book-cover&quot;&gt;&lt;img src=&quot;http://shuvalov.info/assets/articles-assets/a-byte-of-vim.jpg&quot; alt=&quot;«Просто о vim», Суэруп Си Эйч&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Полтора месяца прошло с тех пор, как я &lt;a href=&quot;http://shuvalov.info/2014/08/30/month-of-vim/&quot;&gt;променял на Vim&lt;/a&gt; Atom и Sublime Text. Оказалось, что
двух недель вполне хватает чтобы освоиться, но без этой книги я вряд ли я смог бы так быстро справиться.&lt;/p&gt;

&lt;p&gt;С первых страниц книга завораживает магией вроде &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;:50,100s/old/new/g&lt;/code&gt;.
Список «случайных» примеров работы в Vim мгновенно подкупил меня, и только
спустя два с лишним часа я понял, что я закутавшись в одеяле все еще, в три
ночи как опытный мьсе ковыряюсь с этими примерами в Vim — не спроста же автор практически
сразу рассказывает как пользоваться документацией для поиска невлезших
в семьдесят две страницы объяснений, подробностей да и вообще ответов
на любые интересные вопросы.&lt;/p&gt;

&lt;p&gt;Три часа. ಠ╭╮ಠ&lt;/p&gt;

&lt;p&gt;Ещё из книги я узнал о самом нужном в работе с vim: режимах, работе с курсором,
окнами и вкладками. На сладенькое автор приберёг создание собственных плагинов
и что-то вроде GTD с помощью Vim &lt;em&gt;(берегись Omnifocus)&lt;/em&gt;.&lt;/p&gt;

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

&lt;p&gt;Пока читал книгу — писал &lt;a href=&quot;https://gist.github.com/shuvalov-anton/862276679479cfcd0421&quot;&gt;шпаргалку&lt;/a&gt;, чтобы быстро находить и легче запоминать нужные
команды. Думаю, она пригодиться не только мне: даже если вы опытный вимер —
вы можете найти там что-то интересное. Ну и вот еще &lt;a href=&quot;https://github.com/shuvalov-anton/.dotfiles/blob/master/.vimrc&quot;&gt;.vimrc&lt;/a&gt; за одно.&lt;/p&gt;

&lt;p&gt;А самое приятное в том, что книга эта совершенно бесплатна, скачать оригинал
можно &lt;a href=&quot;http://files.swaroopch.com/vim/byte_of_vim_v051.pdf&quot;&gt;здесь&lt;/a&gt;, а русскую версию &lt;a href=&quot;http://rus-linux.net/MyLDP/BOOKS/Vim/prosto-o-vim.pdf&quot;&gt;здесь&lt;/a&gt;. Английская, вроде как новее и
больше.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;http://shuvalov.info/assets/articles-assets/footer/time.png&quot; alt=&quot;Отзыв о небольшой, но очень полезной книге&quot; /&gt;&lt;/p&gt;

&lt;p class=&quot;photo-author&quot;&gt;&lt;em&gt;фото: &lt;a href=&quot;https://www.flickr.com/photos/smemon/&quot;&gt;Sean MacEntee&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Подписывайтесь на &lt;a href=&quot;http://feeds.feedburner.com/anton-shuvalov/FJHar&quot;&gt;РСС&lt;/a&gt;.
Всем добра и времени&lt;/em&gt;.&lt;/p&gt;

</content>
  </entry>
  
  <entry>
    <title>Ссылколог #8</title>
    <updated>2014-09-15T00:00:00+00:00</updated>
    
      <id>http://shuvalov.info/2014/09/15/linkolog-8</id>
      <link href="http://shuvalov.info/2014/09/15/linkolog-8"/>
    
      <content type="html" xml:base="http://shuvalov.info/">&lt;ol&gt;
  &lt;li&gt;&lt;a href=&quot;http://psdcleaner.madebysource.com/&quot;&gt;Плагин для Photoshop&lt;/a&gt;, позволяющий отслеживать типичные проблемы, за которые верстальщики недолюбливают дизайнеров: невоспроизводимые эффекты, имена слоев в стиле «Layer 1 copy», режимы наложения, использование point-текста вместо блоков, и еще целую кучу всего. Интересно, достаточно ли вежливо будет купить такую штуку паре дизайнеров, чьи макеты я верстал? :D&lt;/li&gt;
  &lt;li&gt;Потрясающая бесплатнная &lt;a href=&quot;http://mozilla.github.io/Fira/&quot;&gt;гарнитура «Fira» от Mozilla&lt;/a&gt;. Я уже месяца 4 использую шрифт «Fira Mono» в тех редакторах, где я пишу код. Что действительно здорово — гарнитура включает шрифты «Light» и «UltraLight» и хорошие жирные начертания с поддержкой кириллицы. Так что это можно назвать достаточно хорошей бесплатной заменой «Helvetica Neue».&lt;/li&gt;
  &lt;li&gt;Простой и достаточно отзывчивый &lt;a href=&quot;http://superlooper.universlabs.co.uk/&quot;&gt;онлайн секвенсор&lt;/a&gt;. Похоже, что скоро музыку можно будет писать прямо в браузере.&lt;/li&gt;
  &lt;li&gt;Smashing Magazine &lt;a href=&quot;http://www.smashingmagazine.com/2014/09/03/testing-mobile-emulators-simulators-remote-debugging/&quot;&gt;делится списком инструментов тестирования поведения сайтов на мобильных устройствах&lt;/a&gt;.&lt;/li&gt;
  &lt;li&gt;Разбирая избранное твиттера наткнулся &lt;a href=&quot;https://gist.github.com/subzey/8115612&quot;&gt;на статью @subzey&lt;/a&gt; о хороших и плохих названиях переменной, в которую сохраняется &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;this&lt;/code&gt; в замыканиях.&lt;/li&gt;
  &lt;li&gt;Шикарно оформленный &lt;a href=&quot;http://www.colors.commutercreative.com/grid/&quot;&gt;список названий цветов в css&lt;/a&gt;.&lt;/li&gt;
  &lt;li&gt;(づ｡◕‿‿◕｡)づ &lt;a href=&quot;http://asciiface.zeke.xxx/&quot;&gt;Сайт со смешными ascii-лицами&lt;/a&gt;, которые еще и как &lt;a href=&quot;https://github.com/maxogden/cool-ascii-faces&quot;&gt;npm-модуль с cli&lt;/a&gt; можно поставить.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;em&gt;Подписывайтесь на &lt;a href=&quot;http://feeds.feedburner.com/anton-shuvalov/FJHar&quot;&gt;РСС&lt;/a&gt;.
Всем добра и штурмовиков&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;http://shuvalov.info/assets/articles-assets/footer/trooper-9.jpg&quot; alt=&quot;Полезный плагин для photoshop, шрифт от Mozila, инструменты для мобильного тестирования, this в javascript, и не только это&quot; /&gt;&lt;/p&gt;

&lt;p class=&quot;photo-author&quot;&gt;&lt;em&gt;фото: &lt;a href=&quot;https://www.flickr.com/photos/nukamari/&quot;&gt;Nukamari&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;
</content>
  </entry>
  
  <entry>
    <title>Интересные эксперименты на CSS, HTML и JS</title>
    <updated>2014-09-12T00:00:00+00:00</updated>
    
      <id>http://shuvalov.info/2014/09/12/codepens-1</id>
      <link href="http://shuvalov.info/2014/09/12/codepens-1"/>
    
      <content type="html" xml:base="http://shuvalov.info/">&lt;h2 id=&quot;иконка-encription-на-svg-и-css&quot;&gt;Иконка «Encription» на SVG и CSS&lt;/h2&gt;

&lt;p data-height=&quot;480&quot; data-theme-id=&quot;8468&quot; data-slug-hash=&quot;zCkvJ&quot; data-default-tab=&quot;result&quot; data-user=&quot;kenchen&quot; class=&quot;codepen&quot;&gt;See the Pen &lt;a href=&quot;http://codepen.io/kenchen/pen/zCkvJ/&quot;&gt;Encryption&lt;/a&gt; by Ken Chen (&lt;a href=&quot;http://codepen.io/kenchen&quot;&gt;@kenchen&lt;/a&gt;) on &lt;a href=&quot;http://codepen.io&quot;&gt;CodePen&lt;/a&gt;.&lt;/p&gt;

&lt;h2 id=&quot;скролл-в-перспективе&quot;&gt;Скролл в перспективе&lt;/h2&gt;

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

&lt;p data-height=&quot;480&quot; data-theme-id=&quot;8468&quot; data-slug-hash=&quot;tlqug&quot; data-default-tab=&quot;result&quot; data-user=&quot;typista&quot; class=&quot;codepen&quot;&gt;See the Pen &lt;a href=&quot;http://codepen.io/typista/pen/tlqug/&quot;&gt;Scroll iPhone in iPhone&lt;/a&gt; by makoto (&lt;a href=&quot;http://codepen.io/typista&quot;&gt;@typista&lt;/a&gt;) on &lt;a href=&quot;http://codepen.io&quot;&gt;CodePen&lt;/a&gt;.&lt;/p&gt;

&lt;h2 id=&quot;ironman-рисуемый-скроллом&quot;&gt;IronMan рисуемый скроллом&lt;/h2&gt;

&lt;p data-height=&quot;480&quot; data-theme-id=&quot;8468&quot; data-slug-hash=&quot;JDbcF&quot; data-default-tab=&quot;result&quot; data-user=&quot;paintbycode&quot; class=&quot;codepen&quot;&gt;See the Pen &lt;a href=&quot;http://codepen.io/paintbycode/pen/JDbcF/&quot;&gt;Scroll controlled SVG animation&lt;/a&gt; by Ben Laley (&lt;a href=&quot;http://codepen.io/paintbycode&quot;&gt;@paintbycode&lt;/a&gt;) on &lt;a href=&quot;http://codepen.io&quot;&gt;CodePen&lt;/a&gt;.&lt;/p&gt;

&lt;h2 id=&quot;эффект-глитча-на-тексте&quot;&gt;Эффект глитча на тексте&lt;/h2&gt;

&lt;p data-height=&quot;180&quot; data-theme-id=&quot;8468&quot; data-slug-hash=&quot;ypgql&quot; data-default-tab=&quot;result&quot; data-user=&quot;lbebber&quot; class=&quot;codepen&quot;&gt;See the Pen &lt;a href=&quot;http://codepen.io/lbebber/pen/ypgql/&quot;&gt;CSS Glitched Text&lt;/a&gt; by Lucas Bebber (&lt;a href=&quot;http://codepen.io/lbebber&quot;&gt;@lbebber&lt;/a&gt;) on &lt;a href=&quot;http://codepen.io&quot;&gt;CodePen&lt;/a&gt;.&lt;/p&gt;

&lt;h2 id=&quot;интересная-реализация-меню&quot;&gt;Интересная реализация меню&lt;/h2&gt;

&lt;p data-height=&quot;480&quot; data-theme-id=&quot;8468&quot; data-slug-hash=&quot;ebqmk&quot; data-default-tab=&quot;result&quot; data-user=&quot;WhiteWolfWizard&quot; class=&quot;codepen&quot;&gt;See the Pen &lt;a href=&quot;http://codepen.io/WhiteWolfWizard/pen/ebqmk/&quot;&gt;ebqmk&lt;/a&gt; by White Wolf Wizard (&lt;a href=&quot;http://codepen.io/WhiteWolfWizard&quot;&gt;@WhiteWolfWizard&lt;/a&gt;) on &lt;a href=&quot;http://codepen.io&quot;&gt;CodePen&lt;/a&gt;.&lt;/p&gt;

&lt;h2 id=&quot;диаграммы-в-iwatch&quot;&gt;Диаграммы в iWatch&lt;/h2&gt;

&lt;p data-height=&quot;1080&quot; data-theme-id=&quot;8468&quot; data-slug-hash=&quot;Dmqso&quot; data-default-tab=&quot;result&quot; data-user=&quot;xna2&quot; class=&quot;codepen&quot;&gt;See the Pen &lt;a href=&quot;http://codepen.io/xna2/pen/Dmqso/&quot;&gt;Apple Watch Radial Chart&lt;/a&gt; by Mark (&lt;a href=&quot;http://codepen.io/xna2&quot;&gt;@xna2&lt;/a&gt;) on &lt;a href=&quot;http://codepen.io&quot;&gt;CodePen&lt;/a&gt;.&lt;/p&gt;

&lt;h2 id=&quot;магия-css-фильтров&quot;&gt;Магия CSS-фильтров&lt;/h2&gt;

&lt;p data-height=&quot;480&quot; data-theme-id=&quot;8468&quot; data-slug-hash=&quot;rpIKz&quot; data-default-tab=&quot;result&quot; data-user=&quot;samthejarvis&quot; class=&quot;codepen&quot;&gt;See the Pen &lt;a href=&quot;http://codepen.io/samthejarvis/pen/rpIKz/&quot;&gt;Playing with CSS Filters.&lt;/a&gt; by Sam Jarvis (&lt;a href=&quot;http://codepen.io/samthejarvis&quot;&gt;@samthejarvis&lt;/a&gt;) on &lt;a href=&quot;http://codepen.io&quot;&gt;CodePen&lt;/a&gt;.&lt;/p&gt;

&lt;h2 id=&quot;видео-бекграунд&quot;&gt;Видео-бекграунд&lt;/h2&gt;

&lt;p data-height=&quot;480&quot; data-theme-id=&quot;8468&quot; data-slug-hash=&quot;knqyK&quot; data-default-tab=&quot;result&quot; data-user=&quot;dudleystorey&quot; class=&quot;codepen&quot;&gt;See the Pen &lt;a href=&quot;http://codepen.io/dudleystorey/pen/knqyK/&quot;&gt;Fullscreen HTML5 Page Background Video&lt;/a&gt; by Dudley Storey (&lt;a href=&quot;http://codepen.io/dudleystorey&quot;&gt;@dudleystorey&lt;/a&gt;) on &lt;a href=&quot;http://codepen.io&quot;&gt;CodePen&lt;/a&gt;.&lt;/p&gt;

&lt;h2 id=&quot;разбегающиеся-от-курсора-круги-на-canvas&quot;&gt;Разбегающиеся от курсора круги на Canvas&lt;/h2&gt;

&lt;p data-height=&quot;480&quot; data-theme-id=&quot;8468&quot; data-slug-hash=&quot;lvwhs&quot; data-default-tab=&quot;result&quot; data-user=&quot;pimskie&quot; class=&quot;codepen&quot;&gt;See the Pen &lt;a href=&quot;http://codepen.io/pimskie/pen/lvwhs/&quot;&gt;lvwhs&lt;/a&gt; by pimskie (&lt;a href=&quot;http://codepen.io/pimskie&quot;&gt;@pimskie&lt;/a&gt;) on &lt;a href=&quot;http://codepen.io&quot;&gt;CodePen&lt;/a&gt;.&lt;/p&gt;

&lt;h2 id=&quot;летающая-геометрия-на-canvas&quot;&gt;Летающая геометрия на Canvas&lt;/h2&gt;

&lt;p data-height=&quot;480&quot; data-theme-id=&quot;8468&quot; data-slug-hash=&quot;JBmhC&quot; data-default-tab=&quot;result&quot; data-user=&quot;abergin&quot; class=&quot;codepen&quot;&gt;See the Pen &lt;a href=&quot;http://codepen.io/abergin/pen/JBmhC/&quot;&gt;background animation&lt;/a&gt; by Alex Bergin (&lt;a href=&quot;http://codepen.io/abergin&quot;&gt;@abergin&lt;/a&gt;) on &lt;a href=&quot;http://codepen.io&quot;&gt;CodePen&lt;/a&gt;.&lt;/p&gt;

&lt;script async=&quot;&quot; src=&quot;//codepen.io/assets/embed/ei.js&quot;&gt;&lt;/script&gt;

</content>
  </entry>
  
  <entry>
    <title>Паттерн «объект-представление»</title>
    <updated>2014-09-09T00:00:00+00:00</updated>
    
      <id>http://shuvalov.info/2014/09/09/7-patterns-to-refactor-javascript-applications-view</id>
      <link href="http://shuvalov.info/2014/09/09/7-patterns-to-refactor-javascript-applications-view"/>
    
      <content type="html" xml:base="http://shuvalov.info/">&lt;p&gt;&lt;img src=&quot;/assets/articles-assets/footer/l/l-9.jpg&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;

&lt;p class=&quot;photo-author&quot;&gt;&lt;em&gt;фото: &lt;a href=&quot;https://www.flickr.com/photos/shuttermanic/&quot;&gt;shuttermanic&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;17 октября 2012 года Bryan Helmkamp, основатель &lt;a href=&quot;https://codeclimate.com/&quot;&gt;Code Climate&lt;/a&gt; написал
&lt;a href=&quot;http://blog.codeclimate.com/blog/2012/10/17/7-ways-to-decompose-fat-activerecord-models/&quot;&gt;пост&lt;/a&gt; описывающий 7 паттернов для рефакторинга толстых &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ActiveRecord&lt;/code&gt;-моделей
в Ruby on Rails. Здесь, в Crush &amp;amp; Lovely, у всех Rails-разработчиков этот пост
является основным ориентиром для написания модульного, лаконичного, выразительного
и тестируемого кода.&lt;/p&gt;

&lt;p&gt;В этой серии статей мы расскажем о подобных концепциях в JavaScript. Как и работа
Bryan Helmkamp, эта серия так же применима к моделям данных, и не менее полезна.
В этом посте обсудим паттерн «объект-форму.&lt;/p&gt;

&lt;h2 id=&quot;паттерны-рефакторинга-javascript-приложений&quot;&gt;Паттерны рефакторинга JavaScript-приложений&lt;/h2&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;a href=&quot;/2014/08/03/7-patterns-to-refactor-javascript-applications-value/&quot;&gt;Объект-значение&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;/2014/08/04/7-patterns-to-refactor-javascript-applications-service-object/&quot;&gt;Объект-сервис&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;/2014/08/05/7-patterns-to-refactor-javascript-applications-form/&quot;&gt;Объект-форма&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;/2014/08/20/7-patterns-to-refactor-javascript-applications-query&quot;&gt;Объект-запрос&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;/2014/09/09/7-patterns-to-refactor-javascript-applications-view/&quot;&gt;Объект-представление&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;Объект-политика&lt;/li&gt;
  &lt;li&gt;Декораторы&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;объект-представление&quot;&gt;Объект-представление&lt;/h2&gt;

&lt;p&gt;Лучше всего храненить логику и атрибуты необходимые только для формирования
представления (HTML в обычных сайтах или JSON в API) вне моделей.
Хранение специфичной информации непосредственно в модели создает путаницу
в том, что является «настоящими» данными модели (и хранится в базе),
а что требуется только для представления. Объект-представление работает как
адаптер между «настоящими» данными модели и представлением этих данных.&lt;/p&gt;

&lt;p&gt;Представим, например, модель товара с атрибутом &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;price&lt;/code&gt;,
который хранится в базе со значением &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;599&lt;/code&gt; центов,  но в представлении
продукта значение изменяется на &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;$5.99&lt;/code&gt;. С одной стороны, хранить это значение
как второй атрибут &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;price&lt;/code&gt; в модели совсем не правильно. С другой, также неправильно
включать логику форматирования в шаблон.&lt;/p&gt;

&lt;p&gt;Объект-представление «одевает» данные модели, трансформируя, добавляя или удаляя
значения, и возвращая новый объект для использования в слое представления.
Этот подход создает хорошее место для логики и атрибутов, связанных с
представлением и не смешивает их со свойствами модели.&lt;/p&gt;

&lt;p&gt;Я хочу отметить, что существуют различные мнения о том, что именно подразумевается
под этим паттерном. Helmkamp упоминает об этом в оригинальной статье, да и
у нас в Crush &amp;amp; Lovely это частая тема для споров — наши инженеры предпочитают
не употреблять название «объект-представление», в основном, потому что обычно
под представлением имеют в виду HTML, а этот паттерн может использоваться и для
формирования ответа API, и для передачи данных внешним сервисам и любыми другим
способами. Мы предпочитаем название «Presenter», в первую очередь потому что это
имя хорошо отражает суть паттерна — формирование представления данных, вне зависимости
от их конечной формы.&lt;/p&gt;

&lt;h3 id=&quot;пример&quot;&gt;Пример&lt;/h3&gt;

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

&lt;p&gt;Скрипт для генерации отчетов находит каждого студента и оценки которые он получал
в течение года, создавая «настоящее» представление объекта:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-js&quot; data-lang=&quot;js&quot;&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;id&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;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;123456&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;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;firstName&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;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;Susan&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;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;lastName&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;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;Smith&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;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;gender&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;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;f&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;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;phone&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;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;5551234567&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;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;assignments&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;p&quot;&gt;{&lt;/span&gt;
      &lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;grade&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;mf&quot;&gt;0.65&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;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;grade&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;mf&quot;&gt;0.83&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;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;grade&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;mf&quot;&gt;0.90&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;/figure&gt;

&lt;p&gt;PDF-верстка отчета «глупа» и ничего не знает о форматировании данных:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-js&quot; data-lang=&quot;js&quot;&gt;&lt;span class=&quot;p&quot;&gt;...&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;p&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;class&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;average-grade&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;Average&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;grade&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;across&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;all&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;assignments&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;sr&quot;&gt;/p&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;&amp;gt;
&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;p&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;class&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;passing-status&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;Passing&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;sr&quot;&gt;/p&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;&amp;gt;
&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;...&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;p&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt;
  &lt;span class=&quot;nx&quot;&gt;For&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;any&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;questions&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;please&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;call&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;the&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;teacher&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;at&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;sr&quot;&gt;/p&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;&amp;gt;
&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;...&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;Формирование данных студента для представления станет проще если мы воспользуемся
объектом-представлением, который, после создания, передадим прямо в шаблон. Вот
пример того, как должен выглядеть объект-представление «одевающий» модели наших
студентов для использования в шаблоне:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-js&quot; data-lang=&quot;js&quot;&gt;&lt;span class=&quot;kd&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;_&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;require&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;underscore&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;kd&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;DetermineStudentPassingStatus&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;require&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;./determineStudentPassingStatus&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;kd&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;GetAverageGradeFromAssignments&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;require&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;./getAverageGradeFromAssignments&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;kd&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;StudentGradeReportPresenter&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;function&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;students&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;// ensure students variable is array&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;students&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;nx&quot;&gt;students&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;instanceof&lt;/span&gt; &lt;span class=&quot;nb&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;nx&quot;&gt;students&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;students&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;StudentGradeReportPresenter&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;whitelistKeys&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;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;firstName&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;lastName&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;isPassing&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;averageGrade&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;phone&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;nx&quot;&gt;StudentGradeReportPresenter&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;prototype&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;_&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;extend&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;StudentGradeReportPresenter&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;prototype&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;present&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;function&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;var&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;process&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;_&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;compose&lt;/span&gt;&lt;span class=&quot;p&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;sanitizeAttributes&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;bind&lt;/span&gt;&lt;span class=&quot;p&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;k&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;getAverageGrade&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;bind&lt;/span&gt;&lt;span class=&quot;p&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;k&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;getPassingStatus&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;bind&lt;/span&gt;&lt;span class=&quot;p&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;k&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;formatPhoneNumber&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;bind&lt;/span&gt;&lt;span class=&quot;p&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;p&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;result&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;_&lt;/span&gt;&lt;span class=&quot;p&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;students&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;process&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;

    &lt;span class=&quot;c1&quot;&gt;// return same type of primitive that was passed in&lt;/span&gt;
    &lt;span class=&quot;c1&quot;&gt;// either Array or single object&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;k&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;students&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;o&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&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;this&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;k&quot;&gt;this&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;mi&quot;&gt;0&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;sanitizeAttributes&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;function&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;student&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;student&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;_&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;pick&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;apply&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;nx&quot;&gt;student&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;].&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;concat&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;StudentGradeReportPresenter&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;whitelistKeys&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;student&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;getAverageGrade&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;function&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;student&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;student&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;isPassing&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;DetermineStudentPassingStatus&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;student&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;p&quot;&gt;).&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;fromAssignments&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;student&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;assignments&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;student&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;getPassingStatus&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;function&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;student&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;student&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;averageGrade&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;GetAverageGradeFromAssignments&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;student&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;assignments&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;).&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;run&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;student&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;formatPhoneNumber&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;function&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;student&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;student&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;phone&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;student&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;phone&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;replace&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;sr&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;(\d{3})(\d{3})(\d{4})&lt;/span&gt;&lt;span class=&quot;sr&quot;&gt;/&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;$1-$2-$3&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;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;student&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;nx&quot;&gt;module&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;exports&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;StudentGradeReportPresenter&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;Так что, все, что нужно сделать — взять данные студентов и передать их
в представление для рендеринга:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-js&quot; data-lang=&quot;js&quot;&gt;&lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;CurrentStudentsWithAssignmentsQuery&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;().&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;run&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;then&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kd&quot;&gt;function&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;students&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;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;StudentGradeReportPresenter&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;students&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;).&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;present&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;nx&quot;&gt;then&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kd&quot;&gt;function&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;students&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;res&lt;/span&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;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;reportCard&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;nx&quot;&gt;students&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;/figure&gt;

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

&lt;h3 id=&quot;тестирование&quot;&gt;Тестирование&lt;/h3&gt;

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

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-js&quot; data-lang=&quot;js&quot;&gt;&lt;span class=&quot;kd&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;expect&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;require&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;chai&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;nx&quot;&gt;expect&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;kd&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;StudentGradeReportPresenter&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;require&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;./studentGradeReportPresenter&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;kd&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;Grade&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;require&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;./grade&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;nx&quot;&gt;describe&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;StudentGradeReportPresenter&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;kd&quot;&gt;function&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(){&lt;/span&gt;
  &lt;span class=&quot;kd&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;student&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;kd&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;presentedStudent&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;

  &lt;span class=&quot;nx&quot;&gt;before&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kd&quot;&gt;function&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(){&lt;/span&gt;
    &lt;span class=&quot;nx&quot;&gt;student&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;id&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;123456&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;firstName&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;Susan&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;lastName&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;Smith&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;gender&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;f&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;phone&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;5551234567&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;na&quot;&gt;assignments&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;na&quot;&gt;grade&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;Grade&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mf&quot;&gt;0.65&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;na&quot;&gt;grade&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;Grade&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mf&quot;&gt;0.83&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;na&quot;&gt;grade&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;Grade&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mf&quot;&gt;0.90&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;span class=&quot;nx&quot;&gt;presentedStudent&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;StudentGradeReportPresenter&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;student&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;).&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;present&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;it&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;returns only the specified properties&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;kd&quot;&gt;function&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(){&lt;/span&gt;
    &lt;span class=&quot;nx&quot;&gt;expect&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;presentedStudent&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;).&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;to&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;have&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;keys&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;firstName&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;lastName&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;phone&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;averageGrade&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;isPassing&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;p&quot;&gt;});&lt;/span&gt;

  &lt;span class=&quot;nx&quot;&gt;describe&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;.phone&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;kd&quot;&gt;function&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(){&lt;/span&gt;

    &lt;span class=&quot;nx&quot;&gt;it&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;returns the correct value&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;kd&quot;&gt;function&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;expect&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;presentedStudent&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;phone&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;).&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;to&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;equal&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;555-123-4567&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;p&quot;&gt;});&lt;/span&gt;

  &lt;span class=&quot;p&quot;&gt;});&lt;/span&gt;

  &lt;span class=&quot;nx&quot;&gt;describe&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;.isPassing&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;kd&quot;&gt;function&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(){&lt;/span&gt;

    &lt;span class=&quot;nx&quot;&gt;it&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;returns the correct value&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;kd&quot;&gt;function&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;expect&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;presentedStudent&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;isPassing&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;).&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;to&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;equal&lt;/span&gt;&lt;span class=&quot;p&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;p&quot;&gt;});&lt;/span&gt;

  &lt;span class=&quot;p&quot;&gt;});&lt;/span&gt;

  &lt;span class=&quot;nx&quot;&gt;describe&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;.averageGrade&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;kd&quot;&gt;function&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(){&lt;/span&gt;

    &lt;span class=&quot;nx&quot;&gt;it&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;returns the correct value&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;kd&quot;&gt;function&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(){&lt;/span&gt;
      &lt;span class=&quot;nx&quot;&gt;expect&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;presentedStudent&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;averageGrade&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;).&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;to&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;equal&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mf&quot;&gt;0.79&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;/figure&gt;

&lt;hr /&gt;

&lt;p&gt;В следующем посте мы рассмотрим объекты-политики, которые представляют отличные
инструменты для инкапсуляции бизнес-логики.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/articles-assets/footer/l/l-10.jpg&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;

&lt;p class=&quot;photo-author&quot;&gt;&lt;em&gt;фото: &lt;a href=&quot;https://www.flickr.com/photos/shuttermanic/&quot;&gt;shuttermanic&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Подписывайтесь на &lt;a href=&quot;http://feeds.feedburner.com/anton-shuvalov/FJHar&quot;&gt;РСС&lt;/a&gt;.
Всем добра!&lt;/em&gt;&lt;/p&gt;

</content>
  </entry>
  
  <entry>
    <title>«Как рушатся комплексные системы», Ричард И. Кук</title>
    <updated>2014-09-05T00:00:00+00:00</updated>
    
      <id>http://shuvalov.info/2014/09/05/how-complex-systems-fail</id>
      <link href="http://shuvalov.info/2014/09/05/how-complex-systems-fail"/>
    
      <content type="html" xml:base="http://shuvalov.info/">&lt;h2 id=&quot;о-статье&quot;&gt;О статье&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;/assets/articles-assets/cook.jpg&quot; alt=&quot;«Как рушатся комплексные системы», Ричард И. Кук&quot; /&gt;&lt;/p&gt;

&lt;h2 id=&quot;как-рушатся-комплексные-системы&quot;&gt;Как рушатся комплексные системы&lt;/h2&gt;

&lt;h3 id=&quot;1-коплексные-системы-опасны-по-своей-природе&quot;&gt;1. Коплексные системы опасны по своей природе&lt;/h3&gt;

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

&lt;h3 id=&quot;2-комплексные-системы-надежно-защищены-от-ошибок&quot;&gt;2. Комплексные системы надежно защищены от ошибок&lt;/h3&gt;

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

&lt;h3 id=&quot;3-к-катастрофе-приводят-несколько-ошибок--одной-не-достаточно&quot;&gt;3. К катастрофе приводят несколько ошибок — одной не достаточно&lt;/h3&gt;

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

&lt;h3 id=&quot;4-комплексные-системы-работают-с-ошибками-которые-остаются-незамеченными&quot;&gt;4. Комплексные системы работают с ошибками, которые остаются незамеченными&lt;/h3&gt;

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

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

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

&lt;h3 id=&quot;6-катастрофа-происходит-на-пересечении&quot;&gt;6. Катастрофа происходит на пересечении&lt;/h3&gt;

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

&lt;h3 id=&quot;7-сама-идея-понять-главную-причину-не-правильна&quot;&gt;7. Сама идея понять «главную причину» не правильна&lt;/h3&gt;

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

&lt;h3 id=&quot;8-пост-анализ-работы-людей-после-происшествий&quot;&gt;8. Пост-анализ работы людей после происшествий&lt;/h3&gt;

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

&lt;h3 id=&quot;9-человеческая-роль-двойственна-он-и-разработчик-и-защитник-от-ошибок&quot;&gt;9. Человеческая роль двойственна: он и разработчик и защитник от ошибок&lt;/h3&gt;

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

&lt;h3 id=&quot;10-все-действия-врачей--азартные-игры&quot;&gt;10. Все действия врачей — азартные игры&lt;/h3&gt;

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

&lt;h3 id=&quot;11-действия--нож-раскрывающий-неопределенность&quot;&gt;11. Действия — нож, раскрывающий неопределенность&lt;/h3&gt;

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

&lt;h3 id=&quot;12-люди--адаптивный-элемент-комплексных-систем&quot;&gt;12. Люди — адаптивный элемент комплексных систем&lt;/h3&gt;

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

  &lt;ol&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;/ol&gt;
&lt;/blockquote&gt;

&lt;h3 id=&quot;13-экспертиза-людей-в-сложной-системе-постоянно-меняется&quot;&gt;13. Экспертиза людей в сложной системе постоянно меняется&lt;/h3&gt;

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

&lt;h3 id=&quot;14-изменения-приводят-к-новой-форме-ошибок&quot;&gt;14. Изменения приводят к новой форме ошибок&lt;/h3&gt;

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

&lt;h3 id=&quot;15-оценка-причин-ограничивает-эффективность-борьбы-с-ошибками-в-будущем&quot;&gt;15. Оценка «причин» ограничивает эффективность борьбы с ошибками в будущем&lt;/h3&gt;

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

&lt;h3 id=&quot;16-безопасность--это-характеристика-системы-а-не-отдельных-ее-компонентов&quot;&gt;16. Безопасность — это характеристика системы, а не отдельных ее компонентов&lt;/h3&gt;

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

&lt;h3 id=&quot;17-люди-постоянно-создают-безопасность&quot;&gt;17. Люди постоянно создают безопасность&lt;/h3&gt;

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

&lt;h3 id=&quot;18-безошибочная-деятельность-требует-экспертизы-в-ошибках&quot;&gt;18. Безошибочная деятельность требует экспертизы в ошибках&lt;/h3&gt;

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

&lt;p&gt;Подписывайтесь на &lt;a href=&quot;http://feeds.feedburner.com/anton-shuvalov/FJHar&quot;&gt;РСС&lt;/a&gt;.&lt;/p&gt;

</content>
  </entry>
  
  <entry>
    <title>Ссылколог-7</title>
    <updated>2014-09-01T00:00:00+00:00</updated>
    
      <id>http://shuvalov.info/2014/09/01/linkolog-7</id>
      <link href="http://shuvalov.info/2014/09/01/linkolog-7"/>
    
      <content type="html" xml:base="http://shuvalov.info/">&lt;ol&gt;
  &lt;li&gt;&lt;a href=&quot;http://markdotto.com/2014/07/23/githubs-css/&quot;&gt;Основательная статья&lt;/a&gt; о CSS-архитектуре GitHub, еще и от автора Bootstrap. Об Autoprefixer, BEM, линтинге и рефакторинге.&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://speakerdeck.com/addyosmani/javascript-memory-management-masterclass&quot;&gt;Презентация&lt;/a&gt; Эдди Османи об управлении памятью в JavaScript. Много любопытных вещей, к примеру, я никак не думал, что удалив у объекта поле через &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;delete&lt;/code&gt;, расходы памяти ни только не уменьшишь, а наоборот, из-за сброса внутренних оптимизаций v8, значительно увеличишь.&lt;/li&gt;
  &lt;li&gt;Как-то я искал курс по функциональному программированию в JavaScript, и тут как раз наткнулся на что-то похожее на то, что искал — &lt;a href=&quot;https://frontendmasters.com/courses/functional-javascript/&quot;&gt;Hardcore Functional Programming in JavaScript&lt;/a&gt;. Надо будет купить.&lt;/li&gt;
  &lt;li&gt;Крутая статья о дизайне и программировании от Романа Шамина &lt;a href=&quot;https://medium.com/design-news-russia-ru/2c3eb83c7f11&quot;&gt;«Как успокоиться насчет кодинга и начать жить»&lt;/a&gt;.&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;http://vimcasts.org/categories/&quot;&gt;Скринкасты о Vim&lt;/a&gt; — наверное, все о них уже знают, но, на всякий случай напишу — огромный список скринкастов для тех, кто только начал разбираться с vim.&lt;/li&gt;
  &lt;li&gt;Забавная статья &lt;a href=&quot;http://bjorn.tipling.com/if-programming-languages-were-weapons&quot;&gt;«Если бы языки программирования были оружием»&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;http://www.paulolyslager.com/free-ebooks-about-user-experience-interface-design/&quot;&gt;15 бесплатных книг по UX&lt;/a&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;em&gt;Подписывайтесь на &lt;a href=&quot;http://feeds.feedburner.com/anton-shuvalov/FJHar&quot;&gt;РСС&lt;/a&gt;.
Всем добра и штурмовиков&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/articles-assets/footer/trooper-8.jpg&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;

&lt;p class=&quot;photo-author&quot;&gt;&lt;em&gt;фото: &lt;a href=&quot;https://www.flickr.com/photos/nukamari/&quot;&gt;Nukamari&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

</content>
  </entry>
  
  <entry>
    <title>T Doug</title>
    <updated>2014-08-31T00:00:00+00:00</updated>
    
      <id>http://shuvalov.info/2014/08/31/t-doug</id>
      <link href="http://shuvalov.info/2014/08/31/t-doug"/>
    
      <content type="html" xml:base="http://shuvalov.info/">
</content>
  </entry>
  
  <entry>
    <title>Strongloop And Express</title>
    <updated>2014-08-31T00:00:00+00:00</updated>
    
      <id>http://shuvalov.info/2014/08/31/strongLoop-and-express</id>
      <link href="http://shuvalov.info/2014/08/31/strongLoop-and-express"/>
    
      <content type="html" xml:base="http://shuvalov.info/">
</content>
  </entry>
  
  <entry>
    <title>Open Source Dickishness</title>
    <updated>2014-08-31T00:00:00+00:00</updated>
    
      <id>http://shuvalov.info/2014/08/31/open-source-dickishness</id>
      <link href="http://shuvalov.info/2014/08/31/open-source-dickishness"/>
    
      <content type="html" xml:base="http://shuvalov.info/">
</content>
  </entry>
  
  <entry>
    <title>Скринкаст: месяц в редакторе Vim</title>
    <updated>2014-08-30T00:00:00+00:00</updated>
    
      <id>http://shuvalov.info/2014/08/30/month-of-vim</id>
      <link href="http://shuvalov.info/2014/08/30/month-of-vim"/>
    
      <content type="html" xml:base="http://shuvalov.info/">&lt;p&gt;&lt;img src=&quot;/assets/articles-assets/features/vim.jpg&quot; alt=&quot;page.title&quot; /&gt;&lt;/p&gt;

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

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

&lt;ol&gt;
  &lt;li&gt;Как открыть, закрыть и сохранить файл в Vim&lt;/li&gt;
  &lt;li&gt;Режимы: normal, insert, visual.&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://github.com/gmarik/Vundle.vim&quot;&gt;Vundle&lt;/a&gt;: установка и удаление плагинов&lt;/li&gt;
  &lt;li&gt;Работа с деревом проекта в &lt;a href=&quot;https://github.com/scrooloose/nerdtree&quot;&gt;NERD tree&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;Поиск по открытым файлам&lt;/li&gt;
  &lt;li&gt;Быстрый и удобный поиск по проекту с помощью &lt;a href=&quot;https://github.com/mileszs/ack.vim&quot;&gt;Ack&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;Открытие файлов проекта по названию с помощью &lt;a href=&quot;https://github.com/kien/ctrlp.vim&quot;&gt;ctrl-p&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;Работа с окнами&lt;/li&gt;
  &lt;li&gt;Работа с табами&lt;/li&gt;
  &lt;li&gt;Работа с буферами&lt;/li&gt;
&lt;/ol&gt;

&lt;h2 id=&quot;месяц-в-vim&quot;&gt;Месяц в Vim&lt;/h2&gt;

&lt;iframe class=&quot;youtube&quot; src=&quot;//www.youtube.com/embed/AOZ3Mi1213U&quot; frameborder=&quot;0&quot; allowfullscreen=&quot;&quot;&gt;&lt;/iframe&gt;

&lt;p&gt;Для тех кто решил использовать vim — &lt;a href=&quot;https://github.com/shuvalov-anton/.dotfiles/blob/master/.vimrc&quot;&gt;вот мой &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;.vimrc&lt;/code&gt;-файл&lt;/a&gt;. Надеюсь, вы
разберетесь в почти отсутствующих комментариях к моим настройками для vim :D&lt;/p&gt;

&lt;p&gt;Увы, многие темы в формате небольшого скринкаста раскрыть не получилось, а
повторять ошибку и затягивать скринкаст как &lt;a href=&quot;http://kompyutery-soft-igry-tehnika.rpod.ru/327190.html&quot;&gt;наш с @matmuhrapna первый подкаст&lt;/a&gt;
не очень хотелось. Поэтому я постарался рассказать о самом главном, без чего
работать в vim практически не возможно, и начал подумывать о том, чтобы
записать второй скринкаст, если это окажется интересным.&lt;/p&gt;

&lt;p&gt;Так что, я буду очень рад вашим комментариям, советам, замечаниям и идеям :D&lt;/p&gt;

</content>
  </entry>
  
  <entry>
    <title>«Эмоциональный веб-дизайн», Аарон Уолтер</title>
    <updated>2014-08-30T00:00:00+00:00</updated>
    
      <id>http://shuvalov.info/2014/08/30/emotional-design</id>
      <link href="http://shuvalov.info/2014/08/30/emotional-design"/>
    
      <content type="html" xml:base="http://shuvalov.info/">&lt;p&gt;Эту книгу я прочитал больше полугода назад, но все никак не мог собраться и записать ту мысль, которая красной нитью проходит через все повествование.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/articles-assets/emotsionalnyi-web-design.jpg&quot; alt=&quot;Эмоциональный веб-дизайн&quot; /&gt;&lt;/p&gt;

&lt;p class=&quot;photo-author&quot;&gt;&lt;em&gt;&lt;a href=&quot;http://www.mann-ivanov-ferber.ru/books/book-apart/emotional_web_design&quot;&gt;купить&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

&lt;h3 id=&quot;готика-и-гротеск&quot;&gt;Готика и гротеск&lt;/h3&gt;

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

&lt;h3 id=&quot;эмоции-и-люди&quot;&gt;Эмоции и люди&lt;/h3&gt;

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

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

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

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

&lt;h3 id=&quot;примеры&quot;&gt;Примеры&lt;/h3&gt;

&lt;p&gt;Для примера, можно взглянуть на &lt;a href=&quot;https://rocketbank.ru&quot;&gt;Рокет Банк&lt;/a&gt;  с его дружеской поддержкой пользователей (если зарегистрируетесь &lt;a href=&quot;https://rocketbank.ru/loves/anton.shuvalov&quot;&gt;по моему инвайту&lt;/a&gt; мы оба получим по 500 рокет-рублей :D), &lt;a href=&quot;http://authenticweather.com/&quot;&gt;Authentic Weather&lt;/a&gt; с забавными прогнозами погоды, &lt;a href=&quot;http://mailchimp.com/&quot;&gt;MailChimp&lt;/a&gt; с его обезьяной-маскотом, &lt;a href=&quot;https://www.etsy.com/&quot;&gt;Etsy&lt;/a&gt; с уютной атмосферой и потрясающими снимками товаров, сервис личных водителей &lt;a href=&quot;https://wheely.com/&quot;&gt;Wheely&lt;/a&gt; — все эти продукты очень разные, но все они по-своему человечные и оставляющие приятные воспоминания. Еще приятнее понимать, что теплые воспоминания — это не случайно возникшие эмоции, а кропотливая и вымеренная до мелочей работа дизайнера.&lt;/p&gt;

&lt;p&gt;Думаю вы тоже вспомните не мало подобных проектов, не так ли?&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/articles-assets/footer/at-1.jpg&quot; alt=&quot;Эмоциональный веб-дизайн&quot; /&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Подписывайтесь на &lt;a href=&quot;http://feeds.feedburner.com/anton-shuvalov/FJHar&quot;&gt;РСС&lt;/a&gt;.
Всем добра!&lt;/em&gt;&lt;/p&gt;

&lt;p class=&quot;photo-author&quot;&gt;&lt;em&gt;фото: &lt;a href=&quot;https://www.flickr.com/photos/jdhancock/&quot;&gt;jdhancock&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

</content>
  </entry>
  
  <entry>
    <title>Музыка для работы #3</title>
    <updated>2014-08-25T00:00:00+00:00</updated>
    
      <id>http://shuvalov.info/2014/08/25/sc-workset-3</id>
      <link href="http://shuvalov.info/2014/08/25/sc-workset-3"/>
    
      <content type="html" xml:base="http://shuvalov.info/">&lt;p&gt;&lt;img src=&quot;/assets/articles-assets/music/3.jpg&quot; alt=&quot;Музыка для работы&quot; /&gt;&lt;/p&gt;

&lt;p&gt;На этот раз плейлист получился достаточно эклектичным: мягкий саунд Nori в начале
плавно перетекает в забавный indie-rock от «Now, Now» и «Sadnes» через немного драматичные треки
Andian и Greyhat. Затем все немного оживляется более динамичной электроникой
The Glitch Mob, а потом после мягкой ямы все переходит в кульминацию из
breakcore/IDM от Kashiwa Daisuke и более жесткого и драматичного развития от Igorrr
с многоточием трека «Memory Stream» от Peter Clark.&lt;/p&gt;

&lt;p&gt;Несмотря на разрозненность жанров, как мне кажется, саунд получился достаточно
цельным.&lt;/p&gt;

&lt;div id=&quot;player&quot;&gt;&lt;/div&gt;

&lt;script&gt;
  (function() {
      var script = document.createElement(&quot;script&quot;);
      
      script.type = &quot;text/javascript&quot;;
      script.async = true;
      script.src = &quot;//sd.toneden.io/production/toneden.loader.js&quot;
      
      var entry = document.getElementsByTagName(&quot;script&quot;)[0];
      entry.parentNode.insertBefore(script, entry);
  }());
  
  ToneDenReady = window.ToneDenReady || [];
  ToneDenReady.push(function() {
      // Modify the dom and urls parameters to position
      // your player and select tracks/sets/artists to play.
      ToneDen.player.create({
          dom: '#player',
          urls: [
              'https://soundcloud.com/asheee/sets/workset-3'
          ],
          skin: 'aurora'
      });
  });
&lt;/script&gt;

&lt;p&gt;&lt;a href=&quot;https://soundcloud.com/asheee/sets/workset-3&quot;&gt;Ссылка на SoundCloud&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Буду рад, если вы поделитесь в комментариях треками, под которые вам нравится
работать :D&lt;/p&gt;

</content>
  </entry>
  
  <entry>
    <title>7 паттернов для рефакторинга JavaScript-приложений</title>
    <updated>2014-08-24T00:00:00+00:00</updated>
    
      <id>http://shuvalov.info/2014/08/24/7-patterns-to-refactor-javascript</id>
      <link href="http://shuvalov.info/2014/08/24/7-patterns-to-refactor-javascript"/>
    
      <content type="html" xml:base="http://shuvalov.info/">&lt;p&gt;&lt;img src=&quot;/assets/articles-assets/features/feature-1.jpg&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;

&lt;p class=&quot;photo-author&quot;&gt;&lt;em&gt;фото: &lt;a href=&quot;https://www.flickr.com/photos/dmitry-baranovskiy/&quot;&gt;Dmitry Baranovskiy&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;17 октября 2012 года Bryan Helmkamp, основатель &lt;a href=&quot;https://codeclimate.com/&quot;&gt;Code Climate&lt;/a&gt; написал
&lt;a href=&quot;http://blog.codeclimate.com/blog/2012/10/17/7-ways-to-decompose-fat-activerecord-models/&quot;&gt;пост&lt;/a&gt; описывающий 7 паттернов для рефакторинга толстых &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ActiveRecord&lt;/code&gt;-моделей
в Ruby on Rails. Здесь, в Crush &amp;amp; Lovely, у всех Rails-разработчиков этот пост
является основным ориентиром для написания модульного, лаконичного, выразительного
и тестируемого кода.&lt;/p&gt;

&lt;p&gt;В этой серии статей мы расскажем о подобных концепциях в JavaScript. Как и работа
Bryan Helmkamp, эта серия так же применима к моделям данных, и не менее полезна.&lt;/p&gt;

&lt;h2 id=&quot;паттерны-рефакторинга-javascript-приложений&quot;&gt;Паттерны рефакторинга JavaScript-приложений&lt;/h2&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;a href=&quot;/2014/08/03/7-patterns-to-refactor-javascript-applications-value/&quot;&gt;Объект-значение&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;/2014/08/04/7-patterns-to-refactor-javascript-applications-service-object/&quot;&gt;Объект-сервис&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;/2014/08/05/7-patterns-to-refactor-javascript-applications-form/&quot;&gt;Объект-форма&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;/2014/08/20/7-patterns-to-refactor-javascript-applications-query&quot;&gt;Объект-запрос&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;/2014/09/09/7-patterns-to-refactor-javascript-applications-view/&quot;&gt;Объект-представление&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;Объект-политика&lt;/li&gt;
  &lt;li&gt;Декораторы&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;em&gt;Подписывайтесь на &lt;a href=&quot;http://feeds.feedburner.com/anton-shuvalov/FJHar&quot;&gt;РСС&lt;/a&gt;,
чтобы не пропустить новые публикации!&lt;/em&gt;&lt;/p&gt;

</content>
  </entry>
  
  <entry>
    <title>Паттерн «объект-запрос»</title>
    <updated>2014-08-20T00:00:00+00:00</updated>
    
      <id>http://shuvalov.info/2014/08/20/7-patterns-to-refactor-javascript-applications-query</id>
      <link href="http://shuvalov.info/2014/08/20/7-patterns-to-refactor-javascript-applications-query"/>
    
      <content type="html" xml:base="http://shuvalov.info/">&lt;p&gt;&lt;img src=&quot;/assets/articles-assets/footer/l/l-7.jpg&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;

&lt;p class=&quot;photo-author&quot;&gt;&lt;em&gt;фото: &lt;a href=&quot;https://www.flickr.com/photos/shuttermanic/&quot;&gt;shuttermanic&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;17 октября 2012 года Bryan Helmkamp, основатель &lt;a href=&quot;https://codeclimate.com/&quot;&gt;Code Climate&lt;/a&gt; написал
&lt;a href=&quot;http://blog.codeclimate.com/blog/2012/10/17/7-ways-to-decompose-fat-activerecord-models/&quot;&gt;пост&lt;/a&gt; описывающий 7 паттернов для рефакторинга толстых &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ActiveRecord&lt;/code&gt;-моделей
в Ruby on Rails. Здесь, в Crush &amp;amp; Lovely, у всех Rails-разработчиков этот пост
является основным ориентиром для написания модульного, лаконичного, выразительного
и тестируемого кода.&lt;/p&gt;

&lt;p&gt;В этой серии статей мы расскажем о подобных концепциях в JavaScript. Как и работа
Bryan Helmkamp, эта серия так же применима к моделям данных, и не менее полезна.
В этом посте обсудим паттерн «объект-форму.&lt;/p&gt;

&lt;h2 id=&quot;паттерны-рефакторинга-javascript-приложений&quot;&gt;Паттерны рефакторинга JavaScript-приложений&lt;/h2&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;a href=&quot;/2014/08/03/7-patterns-to-refactor-javascript-applications-value/&quot;&gt;Объект-значение&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;/2014/08/04/7-patterns-to-refactor-javascript-applications-service-object/&quot;&gt;Объект-сервис&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;/2014/08/05/7-patterns-to-refactor-javascript-applications-form/&quot;&gt;Объект-форма&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;/2014/08/20/7-patterns-to-refactor-javascript-applications-query&quot;&gt;Объект-запрос&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;/2014/09/09/7-patterns-to-refactor-javascript-applications-view/&quot;&gt;Объект-представление&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;Объект-политика&lt;/li&gt;
  &lt;li&gt;Декораторы&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;объект-запрос&quot;&gt;Объект-запрос&lt;/h2&gt;

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

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

&lt;h3 id=&quot;пример&quot;&gt;Пример&lt;/h3&gt;

&lt;p&gt;Давайте представим какой-нибудь метод API, который возвращает список
всех студентов, перешедших на следующий курс, в JSON-формате.&lt;/p&gt;

&lt;p&gt;Без использования объекта запросов у нас могла бы быть функция в API-контроллере или объект-сервис, как в примере ниже. Стоит отметить,  что
&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;DetermineStudentPassingStatus&lt;/code&gt; я взял из статьи об &lt;a href=&quot;/2014/08/04/7-patterns-to-refactor-javascript-applications-service-object/&quot;&gt;объекте-сервисе&lt;/a&gt;.&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-js&quot; data-lang=&quot;js&quot;&gt;&lt;span class=&quot;c1&quot;&gt;// expecting all collection variables to be defined&lt;/span&gt;

&lt;span class=&quot;kd&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;_&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;require&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;underscore&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;kd&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;Q&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;require&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;q&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;kd&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;DetermineStudentPassingStatus&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;require&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;./determineStudentPassingStatus&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;kd&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;getCurrentlyPassingStudents&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;function&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;var&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;token&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;Q&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;defer&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;();&lt;/span&gt;  

  &lt;span class=&quot;c1&quot;&gt;// find all current students&lt;/span&gt;
  &lt;span class=&quot;nx&quot;&gt;studentCollection&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;findAll&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;({&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;isCurrent&lt;/span&gt;&lt;span class=&quot;p&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;kd&quot;&gt;function&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;students&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;var&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;studentIds&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;_&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;students&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;).&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;pluck&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;_id&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;c1&quot;&gt;// find all assignments for those current students&lt;/span&gt;
    &lt;span class=&quot;nx&quot;&gt;assignmentsCollection&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;findAll&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;({&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;studentId&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;$in&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;studentIds&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;}},&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;function&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;assignments&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;var&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;passingStudentIds&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;c1&quot;&gt;// group the assignments by studentId and then assess passing status&lt;/span&gt;
      &lt;span class=&quot;c1&quot;&gt;// adding the studentId to the array of passing students if passing&lt;/span&gt;
      &lt;span class=&quot;nx&quot;&gt;_&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;assignments&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;).&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;chain&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;groupBy&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;studentId&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;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;each&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;function&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;assignments&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;studentId&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;var&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;passingStatus&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;DetermineStudentPassingStatus&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;studentId&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;).&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;run&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;assignments&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;passingStatus&lt;/span&gt; &lt;span class=&quot;o&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;nx&quot;&gt;passingStudentIds&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;studentId&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;nx&quot;&gt;value&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;();&lt;/span&gt;

      &lt;span class=&quot;c1&quot;&gt;// filter all current students down to those that are passing&lt;/span&gt;
      &lt;span class=&quot;c1&quot;&gt;// and resolve the deferred&lt;/span&gt;
      &lt;span class=&quot;kd&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;passingStudents&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;_&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;students&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;kd&quot;&gt;function&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;student&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;passingStudentIds&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;indexOf&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;student&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;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;!==&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&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;token&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;resolve&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;passingStudents&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;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;token&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;promise&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;/figure&gt;

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

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-js&quot; data-lang=&quot;js&quot;&gt;&lt;span class=&quot;kd&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;_&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;require&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;underscore&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;kd&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;async&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;require&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;async&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;kd&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;Q&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;require&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;q&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;kd&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;CurrentlyPassingStudentsQuery&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;function&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;CurrentlyPassingStudentsQuery&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;prototype&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;_&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;extend&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;CurrentlyPassingStudentsQuery&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;prototype&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;run&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;function&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;this&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;deferred&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;Q&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;defer&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;();&lt;/span&gt;

    &lt;span class=&quot;nx&quot;&gt;_&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;bindAll&lt;/span&gt;&lt;span class=&quot;p&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;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;fetchCurrentStudents&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;fetchAssignmentsForCurrentStudents&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;compilePassingStudentIds&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;filterAllPassingStudents&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;result&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;async&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;waterfall&lt;/span&gt;&lt;span class=&quot;p&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;fetchCurrentStudents&lt;/span&gt;&lt;span class=&quot;p&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;fetchAssignmentsForCurrentStudents&lt;/span&gt;&lt;span class=&quot;p&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;filterAllPassingStudents&lt;/span&gt;
    &lt;span class=&quot;p&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;result&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;k&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;deferred&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;promise&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;fetchCurrentStudents&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;function&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;next&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;studentCollection&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;findAll&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;({&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;isCurrent&lt;/span&gt;&lt;span class=&quot;p&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;kd&quot;&gt;function&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;currentStudents&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;next&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;nx&quot;&gt;currentStudents&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;na&quot;&gt;fetchAssignmentsForCurrentStudents&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;function&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;currentStudents&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;next&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;var&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;currentStudentIds&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;_&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;currentStudents&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;).&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;pluck&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;_id&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;nx&quot;&gt;assignmentsCollection&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;findAll&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;({&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;studentId&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;$in&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;studentIds&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;}},&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;function&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;assignments&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;next&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;nx&quot;&gt;currentStudents&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;assignments&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;na&quot;&gt;compilePassingStudentIds&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;function&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;currentStudents&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;assignments&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;next&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;var&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;passingStudentIds&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;nx&quot;&gt;_&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;assignments&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;).&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;chain&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;groupBy&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;studentId&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;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;each&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;function&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;assignments&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;studentId&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;var&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;passingStatus&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;DetermineStudentPassingStatus&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;studentId&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;).&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;run&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;assignments&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;passingStatus&lt;/span&gt; &lt;span class=&quot;o&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;nx&quot;&gt;passingStudentIds&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;studentId&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;nx&quot;&gt;value&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;();&lt;/span&gt;

    &lt;span class=&quot;nx&quot;&gt;next&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;nx&quot;&gt;passingStudentIds&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;filterAllPassingStudents&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;function&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;passingStudentIds&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;next&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;var&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;currentlyPassingStudents&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;_&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;students&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;kd&quot;&gt;function&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;student&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;passingStudentIds&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;indexOf&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;student&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;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;!==&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&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;next&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;nx&quot;&gt;currentlyPassingStudents&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;result&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;function&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;err&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;currentlyPassingStudents&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;err&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;this&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;deferred&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;reject&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;err&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;else&lt;/span&gt; &lt;span class=&quot;p&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;deferred&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;resolve&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;currentlyPassingStudents&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;/figure&gt;

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

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-js&quot; data-lang=&quot;js&quot;&gt;&lt;span class=&quot;kd&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;CurrentlyPassingStudentsQuery&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;require&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;./currentlyPassingStudentsQuery&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;c1&quot;&gt;// for route GET /api/students/passing&lt;/span&gt;
&lt;span class=&quot;kd&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;currentlyPassingStudents&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;function&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;req&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;res&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;new&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;CurrentlyPassingStudentsQuery&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;().&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;run&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;then&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kd&quot;&gt;function&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;currentlyPassingStudents&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;res&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;send&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;200&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;currentlyPassingStudents&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;nx&quot;&gt;fail&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kd&quot;&gt;function&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;err&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;res&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;send&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;422&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;err&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;/figure&gt;

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

&lt;p&gt;Есть еще одна вещь, которую хочется отметить. Паттерн «объект-запрос»
открывает очень интересные возможности композиции. К примеру, в коде
приложения может быть много мест, где вам понадобится получить все оценки
определенной группы студентов, и в этом случае мы можем вынести эту
операцию в отдельный объект-запрос, and use it in the 
&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;#fetchAssignmentsForCurrentStudents&lt;/code&gt; method.&lt;/p&gt;

&lt;h3 id=&quot;тестирование&quot;&gt;Тестирование&lt;/h3&gt;

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

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-js&quot; data-lang=&quot;js&quot;&gt;&lt;span class=&quot;kd&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;expect&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;require&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;chai&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;nx&quot;&gt;expect&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;kd&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;CurrentlyPassingStudentsQuery&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;require&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;./currentlyPassingStudentsQuery&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;nx&quot;&gt;describe&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;CurrentlyPassingStudentsQuery&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;kd&quot;&gt;function&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(){&lt;/span&gt;
  &lt;span class=&quot;kd&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;currentlyPassingStudents&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
  &lt;span class=&quot;kd&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;err&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;

  &lt;span class=&quot;nx&quot;&gt;before&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kd&quot;&gt;function&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;done&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;){&lt;/span&gt;
    &lt;span class=&quot;c1&quot;&gt;// first build all records in the necessary&lt;/span&gt;
    &lt;span class=&quot;c1&quot;&gt;// tables for testing (steps not shown)&lt;/span&gt;
    &lt;span class=&quot;c1&quot;&gt;// then run the Query Object&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;CurrentlyPassingStudentsQuery&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;().&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;run&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;then&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;function&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;_currentlyPassingStudents&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;currentlyPassingStudents&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;_currentlyPassingStudents&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
        &lt;span class=&quot;nx&quot;&gt;done&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;nx&quot;&gt;fail&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;function&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;_err&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;err&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;_err&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
        &lt;span class=&quot;nx&quot;&gt;done&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;nx&quot;&gt;it&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;returns the correct set of records&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;kd&quot;&gt;function&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(){&lt;/span&gt;
    &lt;span class=&quot;nx&quot;&gt;expect&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;currentlyPassingStudents&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;).&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;to&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;have&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;expectedLength&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;);&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;// however many you are expecting&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;/figure&gt;

&lt;hr /&gt;

&lt;p&gt;В следующем посте мы обсудим объект-представление — отличный инструмент для
изоляции преобразований данных модели в их представление.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/articles-assets/footer/l/l-8.jpg&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Подписывайтесь на &lt;a href=&quot;http://feeds.feedburner.com/anton-shuvalov/FJHar&quot;&gt;РСС&lt;/a&gt;.
Всем добра!&lt;/em&gt;&lt;/p&gt;

&lt;p class=&quot;photo-author&quot;&gt;&lt;em&gt;фото: &lt;a href=&quot;https://www.flickr.com/photos/shuttermanic/&quot;&gt;shuttermanic&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;
</content>
  </entry>
  
  <entry>
    <title>ASI и мистические знаки перед IIFE в JavaScript</title>
    <updated>2014-08-18T00:00:00+00:00</updated>
    
      <id>http://shuvalov.info/2014/08/18/function-asi</id>
      <link href="http://shuvalov.info/2014/08/18/function-asi"/>
    
      <content type="html" xml:base="http://shuvalov.info/">&lt;p&gt;В JavaScript часто можно встретить такую констркуцию и различные вариации:&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;;(function($, undefined){
  // my awesome code here
})(jqery);
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;В числе странных мистических знаков перед IIFE могут встречаться, наверное,
любые унарные операторы (&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;~&lt;/code&gt;, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;!&lt;/code&gt; или &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;void&lt;/code&gt;) и точка с запятой. Впервые увидев в коде
что-то в духе &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;~(function(){}())&lt;/code&gt; можно и испугаться, но на самом деле
причина прозаична.&lt;/p&gt;

&lt;h2 id=&quot;asi&quot;&gt;ASI&lt;/h2&gt;

&lt;p&gt;В JavaScript есть механизм автоподстановки точек с запятой (ASI), позволяющий
программистам не заботиться о том, чтобы в конце выражения всегда стояла &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;;&lt;/code&gt; —
ASI самостоятельно разберется с тем, чтобы в конце каждой строки стоял необходимый символ.
Но ASI срабатывает лишь в определенных случаях. Подробнее об этом можно 
прочитать в &lt;a href=&quot;http://javascript.ru/ecma/part7#a-7.9&quot;&gt;спецификации&lt;/a&gt;, я же процитирую только самое интересное:&lt;/p&gt;

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

  &lt;ol&gt;
    &lt;li&gt;Токен-нарушитель отделён от предыдущего токена как минимум одним КонцомСтроки.&lt;/li&gt;
    &lt;li&gt;Токеном-нарушителем является закрывающая фигурная скобка }.&lt;/li&gt;
  &lt;/ol&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;img src=&quot;/assets/articles-assets/footer/at-3.jpg&quot; alt=&quot;ASI и мистические знаки перед IIFE в JavaScript&quot; /&gt;&lt;/p&gt;

&lt;p class=&quot;photo-author&quot;&gt;&lt;em&gt;фото: &lt;a href=&quot;https://www.flickr.com/photos/63909360@N03/&quot;&gt;RyanRWarner&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Проще всего это объяснить на примере. И так, в первом случае ASI сработает, потому что
функции &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;foo&lt;/code&gt; не существует на уровне грамматики языка:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-js&quot; data-lang=&quot;js&quot;&gt;&lt;span class=&quot;kd&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;a&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;b&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;c&lt;/span&gt;
&lt;span class=&quot;nx&quot;&gt;foo&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;a&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

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

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-js&quot; data-lang=&quot;js&quot;&gt;&lt;span class=&quot;c1&quot;&gt;// 1&lt;/span&gt;
&lt;span class=&quot;kd&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;a&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;b&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;c&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;a&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;?&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;foo&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;bar&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;var&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;a&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;b&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;c&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;a&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;foo&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;bar&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;

&lt;span class=&quot;c1&quot;&gt;// 3&lt;/span&gt;
&lt;span class=&quot;kd&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;a&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;b&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;c&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;a&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;b&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;c&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;alert&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;В этих случая ASI не сработает, и JavaScript проинтерпретирует эти строки несколько
иначе, чем мы было ожидали:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-js&quot; data-lang=&quot;js&quot;&gt;&lt;span class=&quot;c1&quot;&gt;// 1&lt;/span&gt;
&lt;span class=&quot;kd&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;a&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;b&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;c&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;a&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;?&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;foo&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;bar&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;var&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;a&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;b&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;c&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;a&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;foo&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;bar&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;

&lt;span class=&quot;c1&quot;&gt;// 3&lt;/span&gt;
&lt;span class=&quot;kd&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;a&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;b&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;c&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;a&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;b&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;c&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;alert&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;Возвращаясь к точке с запятой перед вызовом функции, выходит, что строка, которая начинается
на &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;(&lt;/code&gt;, дефакто, находится в группе риска. Но, &lt;a href=&quot;http://www.farnamstreetblog.com/2014/04/how-complex-systems-fail/&quot;&gt;сложные системы не падают от одной ошибки&lt;/a&gt;.
Они падают от нескольких. И эти несколько ошибок порой сильно запутывают исследователей.&lt;/p&gt;

&lt;h2 id=&quot;сборка-javascript&quot;&gt;Сборка JavaScript&lt;/h2&gt;

&lt;p&gt;На большинстве сайтов JavaScript собирается в один файл с помощью какой-то вариации на тему &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;cat *.js &amp;gt; app.js&lt;/code&gt;,
затем еще минифицируется, и, скорее всего, регулярными выражениями, потому что строить AST-дерево
достаточно долго, и только затем уже записывается в известный каждому фронтент-разработчику файл &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;app.min.js&lt;/code&gt;.
Но вообще, все может не ограничиваться этим: разработчики могут, к примеру, решить, что нужно
вырезать &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;console.log&lt;/code&gt; на production-сборке, и, конечно, регулярными выражениями (&lt;em&gt;Esprima, тебя не существует!&lt;/em&gt;).&lt;/p&gt;

&lt;p&gt;Так вот, благодаря всему этому процессу, может легко получиться ситуация, в которой перед &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;(function(){})()&lt;/code&gt;
появится что-то, что помешает ASI сделать свою работу, и наградит вас потрясающим &lt;a href=&quot;https://ru.wikipedia.org/wiki/%D0%93%D0%B5%D0%B9%D0%B7%D0%B5%D0%BD%D0%B1%D0%B0%D0%B3&quot;&gt;гейзенбагом&lt;/a&gt;,
который будет пропадать, как только вы отключите процессинг JS. Конечно эта ошибка не такая
уж и сложная, но не имея представления о ASI, IIFE и минификации, можно серьезно запутаться
в происходящем.&lt;/p&gt;

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

&lt;p&gt;&lt;img src=&quot;/assets/articles-assets/footer/at-2.jpg&quot; alt=&quot;ASI и мистические знаки перед IIFE в JavaScript&quot; /&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Подписывайтесь на &lt;a href=&quot;http://feeds.feedburner.com/anton-shuvalov/FJHar&quot;&gt;РСС&lt;/a&gt;.
Всем добра и приключений!&lt;/em&gt;&lt;/p&gt;

&lt;p class=&quot;photo-author&quot;&gt;&lt;em&gt;фото: &lt;a href=&quot;https://www.flickr.com/photos/hperticarati/&quot;&gt;hperticarati&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

</content>
  </entry>
  
  <entry>
    <title>Паттерн «объект-форма»</title>
    <updated>2014-08-05T00:00:00+00:00</updated>
    
      <id>http://shuvalov.info/2014/08/05/7-patterns-to-refactor-javascript-applications-form</id>
      <link href="http://shuvalov.info/2014/08/05/7-patterns-to-refactor-javascript-applications-form"/>
    
      <content type="html" xml:base="http://shuvalov.info/">&lt;p&gt;&lt;img src=&quot;/assets/articles-assets/footer/l/l-5.jpg&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;

&lt;p class=&quot;photo-author&quot;&gt;&lt;em&gt;фото: &lt;a href=&quot;https://www.flickr.com/photos/shuttermanic/&quot;&gt;shuttermanic&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;17 октября 2012 года Bryan Helmkamp, основатель &lt;a href=&quot;https://codeclimate.com/&quot;&gt;Code Climate&lt;/a&gt; написал
&lt;a href=&quot;http://blog.codeclimate.com/blog/2012/10/17/7-ways-to-decompose-fat-activerecord-models/&quot;&gt;пост&lt;/a&gt; описывающий 7 паттернов для рефакторинга толстых &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ActiveRecord&lt;/code&gt;-моделей
в Ruby on Rails. Здесь, в Crush &amp;amp; Lovely, у всех Rails-разработчиков этот пост
является основным ориентиром для написания модульного, лаконичного, выразительного
и тестируемого кода.&lt;/p&gt;

&lt;p&gt;В этой серии статей мы расскажем о подобных концепциях в JavaScript. Как и работа
Bryan Helmkamp, эта серия так же применима к моделям данных, и не менее полезна.
В этом посте обсудим паттерн «объект-форму.&lt;/p&gt;

&lt;h2 id=&quot;паттерны-рефакторинга-javascript-приложений&quot;&gt;Паттерны рефакторинга JavaScript-приложений&lt;/h2&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;a href=&quot;/2014/08/03/7-patterns-to-refactor-javascript-applications-value/&quot;&gt;Объект-значение&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;/2014/08/04/7-patterns-to-refactor-javascript-applications-service-object/&quot;&gt;Объект-сервис&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;/2014/08/05/7-patterns-to-refactor-javascript-applications-form/&quot;&gt;Объект-форма&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;/2014/08/20/7-patterns-to-refactor-javascript-applications-query&quot;&gt;Объект-запрос&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;/2014/09/09/7-patterns-to-refactor-javascript-applications-view/&quot;&gt;Объект-представление&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;Объект-политика&lt;/li&gt;
  &lt;li&gt;Декораторы&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;объект-форма&quot;&gt;Объект-форма&lt;/h2&gt;

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

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

&lt;ol&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;/ol&gt;

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

&lt;p&gt;Фактически, если подумать более глобально — с помощью объектов-форм мы разгружаем понятие «Модель», и превращая модели в Data Access Objects (DAO). В таком формате, модель будет полагаться на объект-форму, который гарантирует, что все данные, которые получает модель — корректны. Это хороший паттерн проектирования с позиции архитектуры приложения.&lt;/p&gt;

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

&lt;h3 id=&quot;пример&quot;&gt;Пример&lt;/h3&gt;

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

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-javascript&quot; data-lang=&quot;javascript&quot;&gt;&lt;span class=&quot;kd&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;_&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;require&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;underscore&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;kd&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;async&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;require&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;async&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;kd&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;Q&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;require&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;q&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;err&quot;&gt; &lt;/span&gt;
&lt;span class=&quot;kd&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;NewStudentForm&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;function&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;formData&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;this&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;formData&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;formData&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;span class=&quot;nx&quot;&gt;NewStudentForm&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;prototype&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;_&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;extend&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;NewStudentForm&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;prototype&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;process&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;function&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;this&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;token&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;Q&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;defer&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;();&lt;/span&gt;
&lt;span class=&quot;err&quot;&gt; &lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;async&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;series&lt;/span&gt;&lt;span class=&quot;p&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;validate&lt;/span&gt;&lt;span class=&quot;p&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;persist&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;this&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;k&quot;&gt;return&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;token&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;promise&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;span class=&quot;na&quot;&gt;validate&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;function&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;next&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;// validate object properties,&lt;/span&gt;
    &lt;span class=&quot;c1&quot;&gt;// e.g. required fields, pattern matching, etc&lt;/span&gt;
    &lt;span class=&quot;nx&quot;&gt;next&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;span class=&quot;na&quot;&gt;persist&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;function&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;next&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;// persistence, such as write to DB or send to server&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;CreateNewStudent&lt;/span&gt;&lt;span class=&quot;p&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;formData&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;).&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;run&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;then&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kd&quot;&gt;function&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;next&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;nx&quot;&gt;fail&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;next&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;span class=&quot;na&quot;&gt;result&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;function&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;err&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;// resolve or reject the deferred&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;err&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;this&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;nx&quot;&gt;err&lt;/span&gt; &lt;span class=&quot;p&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;token&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;reject&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;err&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;else&lt;/span&gt; &lt;span class=&quot;p&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;token&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;resolve&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;err&quot;&gt; &lt;/span&gt;
  &lt;span class=&quot;na&quot;&gt;error&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;function&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;err&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;// send errors back to the user&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;err&quot;&gt; &lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;});&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

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

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-javascript&quot; data-lang=&quot;javascript&quot;&gt;&lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;NewStudentForm&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;formData&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;).&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;process&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;then&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kd&quot;&gt;function&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;// success callback&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;fail&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kd&quot;&gt;function&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;// error callback&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;});&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

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

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

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-javascript&quot; data-lang=&quot;javascript&quot;&gt;&lt;span class=&quot;kd&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;_&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;require&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;underscore&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;kd&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;async&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;require&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;async&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;kd&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;Q&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;require&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;q&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;err&quot;&gt; &lt;/span&gt;
&lt;span class=&quot;kd&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;NewStudentFormValidator&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;function&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;formData&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;this&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;formData&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;formData&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;span class=&quot;nx&quot;&gt;NewStudentFormValidator&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;prototype&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;_&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;extend&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;NewStudentFormValidator&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;prototype&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;validate&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;function&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;this&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;token&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;Q&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;defer&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;();&lt;/span&gt;
&lt;span class=&quot;err&quot;&gt; &lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;async&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;series&lt;/span&gt;&lt;span class=&quot;p&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;validateEmail&lt;/span&gt;&lt;span class=&quot;p&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;validatePhoneNumber&lt;/span&gt;
      &lt;span class=&quot;c1&quot;&gt;// any other validations&lt;/span&gt;
    &lt;span class=&quot;p&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;result&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;k&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;token&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;promise&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;span class=&quot;na&quot;&gt;validateEmail&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;function&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;next&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;// run email validation&lt;/span&gt;
    &lt;span class=&quot;nx&quot;&gt;next&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;span class=&quot;na&quot;&gt;validatePhoneNumber&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;function&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;next&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;// run phone number validation&lt;/span&gt;
    &lt;span class=&quot;nx&quot;&gt;next&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;span class=&quot;na&quot;&gt;result&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;function&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;err&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;// resolve or reject the deferred&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;err&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;this&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;token&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;reject&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;err&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;else&lt;/span&gt; &lt;span class=&quot;p&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;token&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;resolve&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;err&quot;&gt; &lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;});&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

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

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-javascript&quot; data-lang=&quot;javascript&quot;&gt;&lt;span class=&quot;c1&quot;&gt;// Client-side&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;NewStudentFormValidator&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;formData&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;).&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;validate&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;then&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kd&quot;&gt;function&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;// submit form to server via standard HTTP form&lt;/span&gt;
    &lt;span class=&quot;c1&quot;&gt;// or via AJAX&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;fail&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kd&quot;&gt;function&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;err&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;// message errors to user&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;});&lt;/span&gt;
&lt;span class=&quot;err&quot;&gt; &lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;// Server-side (application route)&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;NewStudentFormValidator&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;formData&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;).&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;validate&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;then&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kd&quot;&gt;function&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;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;CreateNewStudent&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;formData&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;).&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;run&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;nx&quot;&gt;then&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kd&quot;&gt;function&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;// send user to the success page&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;fail&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kd&quot;&gt;function&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;err&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;// set flash, send user back to form&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;});&lt;/span&gt;
&lt;span class=&quot;err&quot;&gt; &lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;// Server-side (API route)&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;NewStudentFormValidator&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;formData&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;).&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;validate&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;then&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kd&quot;&gt;function&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;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;CreateNewStudent&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;formData&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;).&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;run&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;nx&quot;&gt;then&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kd&quot;&gt;function&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;// send 200 OK&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;fail&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kd&quot;&gt;function&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;err&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;// send 422 with errors&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;});&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

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

&lt;h3 id=&quot;тестирование&quot;&gt;Тестирование&lt;/h3&gt;

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

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-javascript&quot; data-lang=&quot;javascript&quot;&gt;&lt;span class=&quot;kd&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;_&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;require&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;underscore&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;kd&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;expect&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;require&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;chai&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;nx&quot;&gt;expect&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;kd&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;chaiAsPromised&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;require&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;chai-as-promised&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;nx&quot;&gt;chai&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;use&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;chaiAsPromised&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
&lt;span class=&quot;err&quot;&gt; &lt;/span&gt;
&lt;span class=&quot;err&quot;&gt; &lt;/span&gt;
&lt;span class=&quot;kd&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;NewStudentForm&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;require&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;./NewStudentForm&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;err&quot;&gt; &lt;/span&gt;
&lt;span class=&quot;nx&quot;&gt;describe&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;NewStudentForm&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;kd&quot;&gt;function&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(){&lt;/span&gt;
&lt;span class=&quot;err&quot;&gt; &lt;/span&gt;
  &lt;span class=&quot;nx&quot;&gt;describe&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;Passing Data&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;kd&quot;&gt;function&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(){&lt;/span&gt;  
    &lt;span class=&quot;kd&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;formData&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;firstName&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;John&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;lastName&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;Smith&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;gender&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;m&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;err&quot;&gt; &lt;/span&gt;
    &lt;span class=&quot;nx&quot;&gt;before&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kd&quot;&gt;function&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(){&lt;/span&gt;
      &lt;span class=&quot;kd&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;newStudentForm&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;NewStudentForm&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;formData&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;).&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;process&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;span class=&quot;nx&quot;&gt;it&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;persists the data&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;kd&quot;&gt;function&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(){&lt;/span&gt;
      &lt;span class=&quot;c1&quot;&gt;// check database for persisted documents&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;});&lt;/span&gt;
&lt;span class=&quot;err&quot;&gt; &lt;/span&gt;
    &lt;span class=&quot;nx&quot;&gt;it&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;resolves the promise&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;kd&quot;&gt;function&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(){&lt;/span&gt;
      &lt;span class=&quot;nx&quot;&gt;expect&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;newStudentForm&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;).&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;to&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;eventually&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;be&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;fulfilled&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;err&quot;&gt; &lt;/span&gt;
  &lt;span class=&quot;nx&quot;&gt;describe&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;Failing Data&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;kd&quot;&gt;function&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(){&lt;/span&gt;  
    &lt;span class=&quot;kd&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;formData&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;firstName&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;na&quot;&gt;lastName&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;Smith&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;gender&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;m&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;err&quot;&gt; &lt;/span&gt;
    &lt;span class=&quot;nx&quot;&gt;before&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kd&quot;&gt;function&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(){&lt;/span&gt;
      &lt;span class=&quot;kd&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;newStudentForm&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;NewStudentForm&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;formData&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;).&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;process&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;span class=&quot;nx&quot;&gt;it&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;does not persist the data&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;kd&quot;&gt;function&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(){&lt;/span&gt;
      &lt;span class=&quot;c1&quot;&gt;// check database for absence of persisted data&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;});&lt;/span&gt;
&lt;span class=&quot;err&quot;&gt; &lt;/span&gt;
    &lt;span class=&quot;nx&quot;&gt;it&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;rejects the promise&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;kd&quot;&gt;function&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(){&lt;/span&gt;
      &lt;span class=&quot;nx&quot;&gt;expect&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;newStudentForm&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;).&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;to&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;eventually&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;be&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;rejected&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;/figure&gt;

&lt;hr /&gt;

&lt;p&gt;В следующем посте мы обсудим объекты-запросы, позволяющие очень выразительно и понятно получать данные из базы или создавать отфильтрованную выборку из коллекции.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/articles-assets/footer/l/l-6.jpg&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Подписывайтесь на &lt;a href=&quot;http://feeds.feedburner.com/anton-shuvalov/FJHar&quot;&gt;РСС&lt;/a&gt;.
Всем добра!&lt;/em&gt;&lt;/p&gt;

&lt;p class=&quot;photo-author&quot;&gt;&lt;em&gt;фото: &lt;a href=&quot;https://www.flickr.com/photos/shuttermanic/&quot;&gt;shuttermanic&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;
</content>
  </entry>
  
  <entry>
    <title>Паттерн «объект-сервис»</title>
    <updated>2014-08-04T00:00:00+00:00</updated>
    
      <id>http://shuvalov.info/2014/08/04/7-patterns-to-refactor-javascript-applications-service-object</id>
      <link href="http://shuvalov.info/2014/08/04/7-patterns-to-refactor-javascript-applications-service-object"/>
    
      <content type="html" xml:base="http://shuvalov.info/">&lt;p&gt;&lt;img src=&quot;/assets/articles-assets/footer/l/l-3.jpg&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;

&lt;p class=&quot;photo-author&quot;&gt;&lt;em&gt;фото: &lt;a href=&quot;https://www.flickr.com/photos/shuttermanic/&quot;&gt;shuttermanic&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;17 октября 2012 года Bryan Helmkamp, основатель &lt;a href=&quot;https://codeclimate.com/&quot;&gt;Code Climate&lt;/a&gt; написал
&lt;a href=&quot;http://blog.codeclimate.com/blog/2012/10/17/7-ways-to-decompose-fat-activerecord-models/&quot;&gt;пост&lt;/a&gt; описывающий 7 паттернов для рефакторинга толстых &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ActiveRecord&lt;/code&gt;-моделей
в Ruby on Rails. Здесь, в Crush &amp;amp; Lovely, у всех Rails-разработчиков этот пост
является основным ориентиром для написания модульного, лаконичного, выразительного
и тестируемого кода.&lt;/p&gt;

&lt;p&gt;В этой серии статей мы расскажем о подобных концепциях в JavaScript. Как и работа
Bryan Helmkamp, эта серия так же применима к моделям данных, и не менее полезна.
В этом посте обсудим паттерн «объект-сервис».&lt;/p&gt;

&lt;h2 id=&quot;паттерны-рефакторинга-javascript-приложений&quot;&gt;Паттерны рефакторинга JavaScript-приложений&lt;/h2&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;a href=&quot;/2014/08/03/7-patterns-to-refactor-javascript-applications-value/&quot;&gt;Объект-значение&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;/2014/08/04/7-patterns-to-refactor-javascript-applications-service-object/&quot;&gt;Объект-сервис&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;/2014/08/05/7-patterns-to-refactor-javascript-applications-form/&quot;&gt;Объект-форма&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;/2014/08/20/7-patterns-to-refactor-javascript-applications-query&quot;&gt;Объект-запрос&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;/2014/09/09/7-patterns-to-refactor-javascript-applications-view/&quot;&gt;Объект-представление&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;Объект-политика&lt;/li&gt;
  &lt;li&gt;Декораторы&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;объект-сервис&quot;&gt;Объект-сервис&lt;/h2&gt;

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

&lt;p&gt;Цель объекта-сервиса — изолировать операции, в соответствии со следующими принципами:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;strong&gt;Строгость на входе и выходе&lt;/strong&gt;. Объект-сервис  создается, для работы  с очень
специфичными процессами, так что можно пожертвовать &lt;a href=&quot;http://en.wikipedia.org/wiki/Robustness_principle&quot;&gt;принципом надежности&lt;/a&gt;
  в пользу создания очень узкоспециализированного инструмента.&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Тщательная документация&lt;/strong&gt;. Этот модуль будет использоваться в совершенно
неожиданных местах, поэтому очень важно хорошо задокументировать его использование.&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Завершение после выполнения операции&lt;/strong&gt;. Паттерн не должен смешиваться
с рабочим процессом, который выполняется с регулярной периодичностью, постоянно
слушает сообщения веб-сокетов, или выполняет любые другие операции, которые
не могут быть завершены сразу. При вызове объекта-сервиса, он должен выполнить
все операции (синхронные и асинхронные), затем завершиться.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3 id=&quot;пример&quot;&gt;Пример&lt;/h3&gt;

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

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-javascript&quot; data-lang=&quot;javascript&quot;&gt;&lt;span class=&quot;kd&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;_&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;require&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;underscore&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;err&quot;&gt; &lt;/span&gt;
&lt;span class=&quot;kd&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;DetermineStudentPassingStatus&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;function&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;student&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;this&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;student&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;student&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;span class=&quot;nx&quot;&gt;DetermineStudentPassingStatus&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;prototype&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;_&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;extend&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;DetermineStudentPassingStatus&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;prototype&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;span class=&quot;na&quot;&gt;minimumPassingPercentage&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;mf&quot;&gt;0.6&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
&lt;span class=&quot;err&quot;&gt; &lt;/span&gt;
  &lt;span class=&quot;na&quot;&gt;fromAssignments&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;function&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;assignments&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;_&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;compose&lt;/span&gt;&lt;span class=&quot;p&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;determinePassingStatus&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;bind&lt;/span&gt;&lt;span class=&quot;p&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;k&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;averageAssignmentGrade&lt;/span&gt;&lt;span class=&quot;p&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;extractAssignmentGrades&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;)(&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;assignments&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;span class=&quot;na&quot;&gt;extractAssignmentGrades&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;function&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;assignments&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;_&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;pluck&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;assignments&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;grade&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;p&quot;&gt;},&lt;/span&gt;
&lt;span class=&quot;err&quot;&gt; &lt;/span&gt;
  &lt;span class=&quot;na&quot;&gt;averageAssignmentGrade&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;function&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;grades&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;grades&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;kd&quot;&gt;function&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;memo&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;grade&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;memo&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;grade&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;percentage&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;mi&quot;&gt;0&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;grades&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;p&quot;&gt;},&lt;/span&gt;
&lt;span class=&quot;err&quot;&gt; &lt;/span&gt;
  &lt;span class=&quot;na&quot;&gt;determinePassingStatus&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;function&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;averageGrade&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;averageGrade&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;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;minimumPassingPercentage&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;span class=&quot;p&quot;&gt;});&lt;/span&gt;
&lt;span class=&quot;err&quot;&gt; &lt;/span&gt;
&lt;span class=&quot;nx&quot;&gt;module&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;exports&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;DetermineStudentPassingStatus&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

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

&lt;h3 id=&quot;тестирование&quot;&gt;Тестирование&lt;/h3&gt;

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

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-javascript&quot; data-lang=&quot;javascript&quot;&gt;&lt;span class=&quot;kd&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;expect&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;require&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;chai&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;nx&quot;&gt;expect&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;kd&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;DetermineStudentPassingStatus&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;require&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;./determineStudentPassingStatus&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;kd&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;Grade&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;require&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;./grade&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;err&quot;&gt; &lt;/span&gt;
&lt;span class=&quot;nx&quot;&gt;describe&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;DetermineStudentPassingStatus&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;kd&quot;&gt;function&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(){&lt;/span&gt;
  &lt;span class=&quot;kd&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;student&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;kd&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;assignments&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;na&quot;&gt;grade&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;Grade&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mf&quot;&gt;0.5&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;grade&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;Grade&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mf&quot;&gt;0.8&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;grade&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;Grade&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mf&quot;&gt;0.9&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;grade&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;Grade&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mf&quot;&gt;0.6&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;var&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;determineStudentPassingStatus&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;DetermineStudentPassingStatus&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;student&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
&lt;span class=&quot;err&quot;&gt; &lt;/span&gt;
  &lt;span class=&quot;nx&quot;&gt;describe&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;#extractAssignmentGrades&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;kd&quot;&gt;function&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(){&lt;/span&gt;

    &lt;span class=&quot;nx&quot;&gt;it&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;returns an array of grade value objects&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;kd&quot;&gt;function&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(){&lt;/span&gt;
      &lt;span class=&quot;kd&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;grades&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;determineStudentPassingStatus&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;extractAssignmentGrades&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;assignments&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
      &lt;span class=&quot;nx&quot;&gt;expect&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;grades&lt;/span&gt;&lt;span class=&quot;p&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;p&quot;&gt;).&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;to&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;be&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;an&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;instanceof&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;Grade&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;span class=&quot;p&quot;&gt;});&lt;/span&gt;
&lt;span class=&quot;err&quot;&gt; &lt;/span&gt;
  &lt;span class=&quot;nx&quot;&gt;describe&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;#averageAssignmentGrade&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;kd&quot;&gt;function&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(){&lt;/span&gt;

    &lt;span class=&quot;nx&quot;&gt;it&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;returns the average of all of the grades&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;kd&quot;&gt;function&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(){&lt;/span&gt;
      &lt;span class=&quot;kd&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;grades&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;determineStudentPassingStatus&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;extractAssignmentGrades&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;assignments&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
      &lt;span class=&quot;kd&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;averageGrade&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;determineStudentPassingStatus&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;averageAssignmentGrade&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;grades&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
      &lt;span class=&quot;nx&quot;&gt;expect&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;averageGrade&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;).&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;to&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;equal&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;mf&quot;&gt;0.5&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;mf&quot;&gt;0.8&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;mf&quot;&gt;0.9&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;mf&quot;&gt;0.6&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;mi&quot;&gt;4&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;err&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;span class=&quot;nx&quot;&gt;describe&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;#determinePassingStatus&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;kd&quot;&gt;function&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(){&lt;/span&gt;

    &lt;span class=&quot;nx&quot;&gt;it&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;returns whether or not the student is passing&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;kd&quot;&gt;function&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(){&lt;/span&gt;
      &lt;span class=&quot;kd&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;grades&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;determineStudentPassingStatus&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;extractAssignmentGrades&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;assignments&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
      &lt;span class=&quot;kd&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;averageGrade&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;determineStudentPassingStatus&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;averageAssignmentGrade&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;grades&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
      &lt;span class=&quot;kd&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;passing&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;determineStudentPassingStatus&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;determinePassingStatus&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;averageGrade&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
      &lt;span class=&quot;nx&quot;&gt;expect&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;passing&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;).&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;to&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;be&lt;/span&gt;&lt;span class=&quot;p&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;p&quot;&gt;});&lt;/span&gt;
&lt;span class=&quot;err&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;span class=&quot;nx&quot;&gt;describe&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;#fromAssignments&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;kd&quot;&gt;function&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(){&lt;/span&gt;
    &lt;span class=&quot;kd&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;passing&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;err&quot;&gt; &lt;/span&gt;
    &lt;span class=&quot;nx&quot;&gt;it&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;returns the correct passing state&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;kd&quot;&gt;function&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(){&lt;/span&gt;
      &lt;span class=&quot;nx&quot;&gt;passing&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;determineStudentPassingStatus&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;fromAssignments&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;assignments&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
      &lt;span class=&quot;nx&quot;&gt;expect&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;passing&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;).&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;to&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;be&lt;/span&gt;&lt;span class=&quot;p&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;err&quot;&gt; &lt;/span&gt;
      &lt;span class=&quot;c1&quot;&gt;// overwrite to test false return&lt;/span&gt;
      &lt;span class=&quot;nx&quot;&gt;assignments&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;na&quot;&gt;grade&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;Grade&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mf&quot;&gt;0.5&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;grade&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;Grade&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mf&quot;&gt;0.4&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;grade&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;Grade&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mf&quot;&gt;0.8&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;grade&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;Grade&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mf&quot;&gt;0.6&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;passing&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;determineStudentPassingStatus&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;fromAssignments&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;assignments&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
      &lt;span class=&quot;nx&quot;&gt;expect&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;passing&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;).&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;to&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;be&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&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;p&quot;&gt;});&lt;/span&gt;
&lt;span class=&quot;err&quot;&gt; &lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;});&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

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

&lt;hr /&gt;

&lt;p&gt;В следующем посте мы рассмотрим объекты-формы.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/articles-assets/footer/l/l-4.jpg&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Подписывайтесь на &lt;a href=&quot;http://feeds.feedburner.com/anton-shuvalov/FJHar&quot;&gt;РСС&lt;/a&gt;.
Всем добра!&lt;/em&gt;&lt;/p&gt;

&lt;p class=&quot;photo-author&quot;&gt;&lt;em&gt;фото: &lt;a href=&quot;https://www.flickr.com/photos/shuttermanic/&quot;&gt;shuttermanic&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;
</content>
  </entry>
  
  <entry>
    <title>Паттерн «объект-значение»</title>
    <updated>2014-08-03T00:00:00+00:00</updated>
    
      <id>http://shuvalov.info/2014/08/03/7-patterns-to-refactor-javascript-applications-value</id>
      <link href="http://shuvalov.info/2014/08/03/7-patterns-to-refactor-javascript-applications-value"/>
    
      <content type="html" xml:base="http://shuvalov.info/">&lt;p&gt;&lt;img src=&quot;/assets/articles-assets/footer/l/l-1.jpg&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;

&lt;p class=&quot;photo-author&quot;&gt;&lt;em&gt;фото: &lt;a href=&quot;https://www.flickr.com/photos/shuttermanic/&quot;&gt;shuttermanic&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;17 октября 2012 года Bryan Helmkamp, основатель &lt;a href=&quot;https://codeclimate.com/&quot;&gt;Code Climate&lt;/a&gt; написал
&lt;a href=&quot;http://blog.codeclimate.com/blog/2012/10/17/7-ways-to-decompose-fat-activerecord-models/&quot;&gt;пост&lt;/a&gt; описывающий 7 паттернов для рефакторинга толстых &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ActiveRecord&lt;/code&gt;-моделей
в Ruby on Rails. Здесь, в Crush &amp;amp; Lovely, у всех Rails-разработчиков этот пост
является основным ориентиром для написания модульного, лаконичного, выразительного
и тестируемого кода.&lt;/p&gt;

&lt;p&gt;В этой серии статей мы расскажем о подобных концепциях в JavaScript. Как и работа
Bryan Helmkamp, эта серия так же применима к моделям данных, и не менее полезна.
Начнем с паттерна «объект-значение».&lt;/p&gt;

&lt;h2 id=&quot;паттерны-рефакторинга-javascript-приложений&quot;&gt;Паттерны рефакторинга JavaScript-приложений&lt;/h2&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;a href=&quot;/2014/08/03/7-patterns-to-refactor-javascript-applications-value/&quot;&gt;Объект-значение&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;/2014/08/04/7-patterns-to-refactor-javascript-applications-service-object/&quot;&gt;Объект-сервис&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;/2014/08/05/7-patterns-to-refactor-javascript-applications-form/&quot;&gt;Объект-форма&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;/2014/08/20/7-patterns-to-refactor-javascript-applications-query&quot;&gt;Объект-запрос&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;/2014/09/09/7-patterns-to-refactor-javascript-applications-view/&quot;&gt;Объект-представление&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;Объект-политика&lt;/li&gt;
  &lt;li&gt;Декораторы&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;объект-значение&quot;&gt;Объект-значение&lt;/h2&gt;

&lt;p&gt;В статье Brayan’а объект-значение описывается как &lt;em&gt;«простой объект, который
сравнивается по значению, а не по идентификатору»&lt;/em&gt;. Поскольку в JavaScript все
объекты передаются по ссылке, подобных примеров, за исключением примитивов, нет
ни в ECMAScript 5, ни даже в Harmony. Например:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-javascript&quot; data-lang=&quot;javascript&quot;&gt;  &lt;span class=&quot;kd&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;foo&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;Number&lt;/span&gt;&lt;span class=&quot;p&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;kd&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;bar&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;Number&lt;/span&gt;&lt;span class=&quot;p&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;nx&quot;&gt;foo&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;===&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;bar&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;// =&amp;gt; false&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;В этом примере примитивы сохраняются в переменные &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;foo&lt;/code&gt; и &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;bar&lt;/code&gt;, которые равны
по значению, но, технически, эти примитивы являются объектами. Конструктор &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Number&lt;/code&gt;,
не смотря на то, что он создает примитивный элемент, создаст «простой  JavaScript-Object
в старом стиле» (&lt;a href=&quot;https://ru.wikipedia.org/wiki/POJO&quot;&gt;POJO&lt;/a&gt;), потому переменные сравниваются по ссылке, а не по
значению и не будут равны между собой, хотя имеют одинаковое значение.&lt;/p&gt;

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

&lt;h3 id=&quot;пример&quot;&gt;Пример&lt;/h3&gt;

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

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-javascript&quot; data-lang=&quot;javascript&quot;&gt;&lt;span class=&quot;kd&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;_&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;require&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;underscore&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;err&quot;&gt; &lt;/span&gt;
&lt;span class=&quot;kd&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;Grade&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;function&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;percentage&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;this&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;percentage&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;percentage&lt;/span&gt;&lt;span class=&quot;p&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;grade&lt;/span&gt; &lt;span class=&quot;o&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;grade&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;percentage&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;span class=&quot;nx&quot;&gt;Grade&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;prototype&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;_&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;extend&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;Grade&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;prototype&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;span class=&quot;na&quot;&gt;grades&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;na&quot;&gt;letter&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;A&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;minimumPercentage&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;mf&quot;&gt;0.9&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;passing&lt;/span&gt;&lt;span class=&quot;p&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;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;letter&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;B&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;minimumPercentage&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;mf&quot;&gt;0.8&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;passing&lt;/span&gt;&lt;span class=&quot;p&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;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;letter&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;C&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;minimumPercentage&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;mf&quot;&gt;0.7&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;passing&lt;/span&gt;&lt;span class=&quot;p&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;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;letter&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;D&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;minimumPercentage&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;mf&quot;&gt;0.6&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;passing&lt;/span&gt;&lt;span class=&quot;p&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;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;letter&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;F&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;minimumPercentage&lt;/span&gt;&lt;span class=&quot;p&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;na&quot;&gt;passing&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&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;err&quot;&gt; &lt;/span&gt;
  &lt;span class=&quot;na&quot;&gt;passingGradeLetters&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;function&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;_&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;chain&lt;/span&gt;&lt;span class=&quot;p&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;grades&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;).&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;where&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;({&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;passing&lt;/span&gt;&lt;span class=&quot;p&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;nx&quot;&gt;pluck&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;letter&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;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;err&quot;&gt; &lt;/span&gt;
  &lt;span class=&quot;na&quot;&gt;grade&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;function&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;percentage&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;_&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;find&lt;/span&gt;&lt;span class=&quot;p&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;grades&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;function&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;grade&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;percentage&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;grade&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;minimumPercentage&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;err&quot;&gt; &lt;/span&gt;
  &lt;span class=&quot;na&quot;&gt;letterGrade&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;function&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;k&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;grade&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;letter&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;span class=&quot;na&quot;&gt;isPassing&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;function&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;k&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;grade&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;passing&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;},&lt;/span&gt;
&lt;span class=&quot;err&quot;&gt; &lt;/span&gt;
  &lt;span class=&quot;na&quot;&gt;isImprovementFrom&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;function&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;grade&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;k&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;isBetterThan&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;grade&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;span class=&quot;na&quot;&gt;isBetterThan&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;function&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;grade&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;k&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;percentage&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;grade&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;percentage&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;span class=&quot;na&quot;&gt;valueOf&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;function&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;k&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;percentage&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;span class=&quot;p&quot;&gt;});&lt;/span&gt;
&lt;span class=&quot;err&quot;&gt; &lt;/span&gt;
&lt;span class=&quot;nx&quot;&gt;module&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;exports&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;Grade&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;Подобная структура дает дополнительное преимущество, делая ваш код более
выразительным. К примеру, теперь можно пистать так:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-javascript&quot; data-lang=&quot;javascript&quot;&gt;&lt;span class=&quot;kd&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;firstStudent&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;grade&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;Grade&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mf&quot;&gt;0.45&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;var&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;secondStudent&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;grade&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;Grade&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mf&quot;&gt;0.70&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;span class=&quot;nx&quot;&gt;firstStudent&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;grade&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;isPassing&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;//=&amp;gt; false&lt;/span&gt;
&lt;span class=&quot;nx&quot;&gt;firstStudent&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;grade&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;isBetterThan&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;secondStudent&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;grade&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;);&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;//=&amp;gt; false&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;Перед тем как интегрировать объекты-значения в приложение, стоит
отметить несколько вещей:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Методы &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;valueOf&lt;/code&gt; и &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;toString&lt;/code&gt; выполняют &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/valueOf&quot;&gt;специальную роль&lt;/a&gt;, и рекомендуются
для создания собственных объектов-значений. Применив его в &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Grade&lt;/code&gt;-объекте выше,
мы добавили ему поддержку стандартного ECMAScript-синтаксиса, что позволило нам
писать такие конструкции:&lt;/li&gt;
&lt;/ul&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-javascript&quot; data-lang=&quot;javascript&quot;&gt;&lt;span class=&quot;kd&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;myGrade&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;Grade&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mf&quot;&gt;0.65&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
&lt;span class=&quot;nx&quot;&gt;alert&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;My Grade is &lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;myGrade&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;!&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;c1&quot;&gt;// alerts, 'My Grade is 0.65!'&lt;/span&gt;
&lt;span class=&quot;err&quot;&gt; &lt;/span&gt;
&lt;span class=&quot;kd&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;myOtherGrade&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;Grade&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mf&quot;&gt;0.75&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
&lt;span class=&quot;nx&quot;&gt;myGrade&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;myOtherGrade&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;// true&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;К сожалению, даже если два различных объекта возвращают одинаковое значение
с помощью &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;valueOf&lt;/code&gt;, они все равно не будут равны.&lt;/p&gt;
&lt;ul&gt;
  &lt;li&gt;
    &lt;p&gt;При конвертировании объекта-значения с помощью &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;JSON.stringify&lt;/code&gt;, согласно
конвенции, используется &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;toJSON&lt;/code&gt;-метод, возвращающий значение, которое
будет использовано при конвертировании в строку. Если же метод &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;toJSON&lt;/code&gt;
не определен, то будет использован &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;valueOf&lt;/code&gt;. Если &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;valueOf&lt;/code&gt; нет — объект будет
конвертирован как &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Object&lt;/code&gt;, что, зачастую, не желательно.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;Хороший паттерн — использовать &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;valueOf&lt;/code&gt; для возвращения значения, с которым
объект был инициализирован, что позволяет воссоздать этот объект с другой
стороны транспорта, что очень полезно если приложение имеет клиент и сервер,
между которыми передаются объекты-значения. Используя простое значение объекта
на входе и на выходе, вы можете взаимодействовать с объектом-значением на сервере,
затем отправить значение на клиент, используя &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;valueOf&lt;/code&gt;, и воссоздать там объект
заново.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;Если вы предпочитаете более функциональный подход к объектам-значениям, то вы
можете добавить методы в функцию-конструктор вместо ее прототипа. Посмотрите
на следующий пример:&lt;/p&gt;
  &lt;/li&gt;
&lt;/ul&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-javascript&quot; data-lang=&quot;javascript&quot;&gt;		&lt;span class=&quot;nx&quot;&gt;Grade&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;equal&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;function&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;grade1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;grade2&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;grade1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;valueOf&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;grade2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;valueOf&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;span class=&quot;kd&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;myFirstGrade&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;Grade&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt; &lt;span class=&quot;mf&quot;&gt;0.7&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
		&lt;span class=&quot;kd&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;mySecondGrade&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;Grade&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt; &lt;span class=&quot;mf&quot;&gt;0.7&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
		&lt;span class=&quot;nx&quot;&gt;Grade&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;equal&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;myFirstGrade&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;mySecondGrade&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;// =&amp;gt; true&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

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

&lt;h3 id=&quot;тестирование&quot;&gt;Тестирование&lt;/h3&gt;

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

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-javascript&quot; data-lang=&quot;javascript&quot;&gt;&lt;span class=&quot;kd&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;Grade&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;require&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;./grade&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;kd&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;grade1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;kd&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;grade2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;err&quot;&gt; &lt;/span&gt;
&lt;span class=&quot;nx&quot;&gt;describe&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;Grade&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;kd&quot;&gt;function&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;span class=&quot;nx&quot;&gt;describe&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;#isPassing&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;kd&quot;&gt;function&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;span class=&quot;nx&quot;&gt;it&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;returns true if grade is passing&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;kd&quot;&gt;function&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;grade1&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;Grade&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mf&quot;&gt;0.8&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
      &lt;span class=&quot;nx&quot;&gt;expect&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;grade1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;isPassing&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()).&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;to&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;be&lt;/span&gt;&lt;span class=&quot;p&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;p&quot;&gt;});&lt;/span&gt;
&lt;span class=&quot;err&quot;&gt; &lt;/span&gt;
    &lt;span class=&quot;nx&quot;&gt;it&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;returns false if grade is not passing&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;kd&quot;&gt;function&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;grade1&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;Grade&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mf&quot;&gt;0.58&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
      &lt;span class=&quot;nx&quot;&gt;expect&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;grade1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;isPassing&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()).&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;to&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;be&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&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;err&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;span class=&quot;nx&quot;&gt;describe&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;#letterGrade&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;kd&quot;&gt;function&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;span class=&quot;nx&quot;&gt;it&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;returns correct letter for percentage&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;kd&quot;&gt;function&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;grade1&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;Grade&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mf&quot;&gt;0.8&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
      &lt;span class=&quot;nx&quot;&gt;expect&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;grade1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;letterGrade&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()).&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;to&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;equal&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;B&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;p&quot;&gt;});&lt;/span&gt;
&lt;span class=&quot;err&quot;&gt; &lt;/span&gt;
    &lt;span class=&quot;nx&quot;&gt;it&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;returns A for 100 percent&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;kd&quot;&gt;function&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;grade1&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;Grade&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
      &lt;span class=&quot;nx&quot;&gt;expect&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;grade1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;letterGrade&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()).&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;to&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;equal&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;A&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;p&quot;&gt;});&lt;/span&gt;
&lt;span class=&quot;err&quot;&gt; &lt;/span&gt;
    &lt;span class=&quot;nx&quot;&gt;it&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;returns F for 0 percent&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;kd&quot;&gt;function&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;grade1&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;Grade&lt;/span&gt;&lt;span class=&quot;p&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;expect&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;grade1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;letterGrade&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()).&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;to&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;equal&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;F&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;p&quot;&gt;});&lt;/span&gt;
&lt;span class=&quot;err&quot;&gt; &lt;/span&gt;
    &lt;span class=&quot;nx&quot;&gt;it&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;returns F for anything lower than 0.6&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;kd&quot;&gt;function&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;grade1&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;Grade&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mf&quot;&gt;0.4&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
      &lt;span class=&quot;nx&quot;&gt;expect&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;grade1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;letterGrade&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()).&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;to&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;equal&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;F&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;p&quot;&gt;});&lt;/span&gt;
&lt;span class=&quot;err&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;span class=&quot;nx&quot;&gt;describe&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;#passingGradeLetters&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;kd&quot;&gt;function&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;span class=&quot;nx&quot;&gt;it&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;returns all passing letters&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;kd&quot;&gt;function&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;grade1&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;Grade&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mf&quot;&gt;0.8&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
      &lt;span class=&quot;nx&quot;&gt;expect&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;grade1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;passingGradeLetters&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()).&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;to&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;have&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;members&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;A&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;B&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;C&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;D&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;p&quot;&gt;});&lt;/span&gt;
&lt;span class=&quot;err&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;span class=&quot;nx&quot;&gt;describe&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;#isImprovementFrom&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;kd&quot;&gt;function&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;span class=&quot;nx&quot;&gt;it&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;returns true if grade is better than comparison grade&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;kd&quot;&gt;function&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;grade1&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;Grade&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mf&quot;&gt;0.8&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
      &lt;span class=&quot;nx&quot;&gt;grade2&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;Grade&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mf&quot;&gt;0.7&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
      &lt;span class=&quot;nx&quot;&gt;expect&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;grade1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;isImprovementFrom&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;grade2&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;)).&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;to&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;be&lt;/span&gt;&lt;span class=&quot;p&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;p&quot;&gt;});&lt;/span&gt;
&lt;span class=&quot;err&quot;&gt; &lt;/span&gt;
    &lt;span class=&quot;nx&quot;&gt;it&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;returns false if grades are equal&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;kd&quot;&gt;function&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;grade1&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;Grade&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mf&quot;&gt;0.7&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
      &lt;span class=&quot;nx&quot;&gt;grade2&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;Grade&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mf&quot;&gt;0.7&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
      &lt;span class=&quot;nx&quot;&gt;expect&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;grade1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;isImprovementFrom&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;grade2&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;)).&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;to&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;be&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&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;err&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;span class=&quot;nx&quot;&gt;describe&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;#isBetterThan&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;kd&quot;&gt;function&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(){&lt;/span&gt;
&lt;span class=&quot;err&quot;&gt; &lt;/span&gt;
    &lt;span class=&quot;nx&quot;&gt;it&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;returns true if grade is better than comparison grade&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;kd&quot;&gt;function&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;grade1&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;Grade&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mf&quot;&gt;0.8&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
      &lt;span class=&quot;nx&quot;&gt;grade2&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;Grade&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mf&quot;&gt;0.7&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
      &lt;span class=&quot;nx&quot;&gt;expect&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;grade1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;isImprovementFrom&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;grade2&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;)).&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;to&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;be&lt;/span&gt;&lt;span class=&quot;p&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;p&quot;&gt;});&lt;/span&gt;
&lt;span class=&quot;err&quot;&gt; &lt;/span&gt;
    &lt;span class=&quot;nx&quot;&gt;it&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;returns false if grades are equal&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;kd&quot;&gt;function&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;grade1&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;Grade&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mf&quot;&gt;0.7&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
      &lt;span class=&quot;nx&quot;&gt;grade2&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;Grade&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mf&quot;&gt;0.7&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
      &lt;span class=&quot;nx&quot;&gt;expect&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;grade1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;isImprovementFrom&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;grade2&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;)).&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;to&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;be&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&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;err&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;span class=&quot;p&quot;&gt;});&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

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

&lt;hr /&gt;

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

&lt;p&gt;&lt;img src=&quot;/assets/articles-assets/footer/l/l-2.jpg&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Подписывайтесь на &lt;a href=&quot;http://feeds.feedburner.com/anton-shuvalov/FJHar&quot;&gt;РСС&lt;/a&gt;.
Всем добра и вкусняшек!&lt;/em&gt;&lt;/p&gt;

&lt;p class=&quot;photo-author&quot;&gt;&lt;em&gt;фото: &lt;a href=&quot;https://www.flickr.com/photos/shuttermanic/&quot;&gt;shuttermanic&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

</content>
  </entry>
  
  <entry>
    <title>Музыка для работы</title>
    <updated>2014-08-01T00:00:00+00:00</updated>
    
      <id>http://shuvalov.info/2014/08/01/soundcloud-sets</id>
      <link href="http://shuvalov.info/2014/08/01/soundcloud-sets"/>
    
      <content type="html" xml:base="http://shuvalov.info/">&lt;p&gt;&lt;img src=&quot;/assets/articles-assets/features/feature-music.jpg&quot; alt=&quot;Музыка для работы&quot; /&gt;&lt;/p&gt;

&lt;p class=&quot;photo-author&quot;&gt;&lt;em&gt;фото: &lt;a href=&quot;https://www.flickr.com/photos/joshua_schnable/&quot;&gt;Joshua Schnable&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Мои плейлисты: теплый glitch, нежные девичьи голоса, интересная электроника и chillwave:&lt;/p&gt;

&lt;ul class=&quot;articles-list&quot;&gt;
  
    &lt;li class=&quot;articles-list__item&quot;&gt;
  
  &lt;a class=&quot;articles-list__link&quot; href=&quot;/2015/03/07/sc-workset-5&quot;&gt;
    Музыка для работы #5
  &lt;/a&gt;
  
  &lt;div class=&quot;articles-list__description&quot;&gt;
    Немного мурашек по спине…
  &lt;/div&gt;
&lt;/li&gt;

  
    &lt;li class=&quot;articles-list__item&quot;&gt;
  
  &lt;a class=&quot;articles-list__link&quot; href=&quot;/2014/12/10/sc-workset-4&quot;&gt;
    Музыка для работы #4
  &lt;/a&gt;
  
  &lt;div class=&quot;articles-list__description&quot;&gt;
    Трогательный chillwave, dream pop &amp;amp; glich
  &lt;/div&gt;
&lt;/li&gt;

  
    &lt;li class=&quot;articles-list__item&quot;&gt;
  
  &lt;a class=&quot;articles-list__link&quot; href=&quot;/2014/08/25/sc-workset-3&quot;&gt;
    Музыка для работы #3
  &lt;/a&gt;
  
  &lt;div class=&quot;articles-list__description&quot;&gt;
    Chillwave, glitch, dream pop и немного breakcore/IDM
  &lt;/div&gt;
&lt;/li&gt;

  
    &lt;li class=&quot;articles-list__item&quot;&gt;
  
  &lt;a class=&quot;articles-list__link&quot; href=&quot;/2014/06/23/sc-workset-2&quot;&gt;
    Музыка для работы #2
  &lt;/a&gt;
  
  &lt;div class=&quot;articles-list__description&quot;&gt;
    Chillwave, glitch, dream pop и сладкие девичьи голоса
  &lt;/div&gt;
&lt;/li&gt;

  
    &lt;li class=&quot;articles-list__item&quot;&gt;
  
  &lt;a class=&quot;articles-list__link&quot; href=&quot;/2014/05/05/sc-workset-1&quot;&gt;
    Музыка для работы #1
  &lt;/a&gt;
  
  &lt;div class=&quot;articles-list__description&quot;&gt;
    Ambient, idm, glitch и электроника для хардворкеров
  &lt;/div&gt;
&lt;/li&gt;

  
&lt;/ul&gt;

&lt;p&gt;&lt;em&gt;Подписывайтесь на &lt;a href=&quot;http://feeds.feedburner.com/anton-shuvalov/FJHar&quot;&gt;РСС&lt;/a&gt;,
чтобы не пропустить новые публикации!&lt;/em&gt;&lt;/p&gt;

</content>
  </entry>
  
  <entry>
    <title>Как yield изменит Node.js</title>
    <updated>2014-08-01T00:00:00+00:00</updated>
    
      <id>http://shuvalov.info/2014/08/01/node-yield</id>
      <link href="http://shuvalov.info/2014/08/01/node-yield"/>
    
      <content type="html" xml:base="http://shuvalov.info/">&lt;p&gt;&lt;img src=&quot;/assets/articles-assets/nodejs_logo_green.jpg&quot; alt=&quot;'Как yield изменит Node.js'&quot; /&gt;&lt;/p&gt;

&lt;p&gt;С выходом версии v0.11.2 Node.js обзавелся поддержкой &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Iterators_and_Generators&quot;&gt;v8-генераторов&lt;/a&gt;.
Генераторы не легки для понимания, но, в общем, это что-то вроде оберток над
функциями, которые могут выполняться множество раз, продолжая выполнение
в различных местах функции.&lt;/p&gt;

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

&lt;h3 id=&quot;использование-yield&quot;&gt;Использование yield&lt;/h3&gt;

&lt;p&gt;Пример кода заменяет тысячу слов, так что давайте смотреть.
Нам понадобится Node v.0.11.2, которую легко установить с помощью &lt;a href=&quot;https://github.com/creationix/nvm&quot;&gt;nvm&lt;/a&gt;
(&lt;em&gt;прим. переводчика: мне больше нравится &lt;a href=&quot;https://github.com/visionmedia/n&quot;&gt;n&lt;/a&gt;&lt;/em&gt;).&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;nvm &lt;span class=&quot;nb&quot;&gt;install &lt;/span&gt;0.11.2&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;Мы будем использовать основанный на промисах сервер под названием &lt;a href=&quot;https://github.com/machjs/mach&quot;&gt;mach&lt;/a&gt;,
и библиотеку для работы с промисами — &lt;a href=&quot;https://github.com/kriskowal/q&quot;&gt;Q&lt;/a&gt;. Вам нужно установить оба модуля
через npm, если вы это еще не сделали.&lt;/p&gt;

&lt;p&gt;Затем, так как мы используем новейшие фичи из v8, нам нужно указать флаг
&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;--harmony&lt;/code&gt; при запуске Node.&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;node &lt;span class=&quot;nt&quot;&gt;--harmony&lt;/span&gt; ./generators.js&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;Давайте создадим функцию &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;sleep()&lt;/code&gt;, которая принимает время ожидания
в миллисекундах и возвращает промис, который разрешится по истечению времени.&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-javascript&quot; data-lang=&quot;javascript&quot;&gt;&lt;span class=&quot;kd&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;sleep&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;millis&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;var&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;deferredResult&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;Q&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;defer&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;();&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;kd&quot;&gt;function&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;deferredResult&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;resolve&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;millis&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;deferredResult&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;promise&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;/figure&gt;

&lt;p&gt;Типичный сервер на основе коллбеков будет использовать чейнинг промиса,
примерно так:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-javascript&quot; data-lang=&quot;javascript&quot;&gt;&lt;span class=&quot;kd&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;mach&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;require&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;../lib&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;kd&quot;&gt;var&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;nx&quot;&gt;mach&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;stack&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;();&lt;/span&gt;
&lt;span class=&quot;kd&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;Q&lt;/span&gt;    &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;require&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;q&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;nx&quot;&gt;app&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;run&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kd&quot;&gt;function&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;request&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;sleep&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;2000&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;).&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;then&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kd&quot;&gt;function&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;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;Good day to you sir&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;p&quot;&gt;});&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;});&lt;/span&gt;

&lt;span class=&quot;nx&quot;&gt;mach&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;serve&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;app&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;3333&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;А теперь сделаем то же самое, но с генераторами. Определим функцию-генератор
через нотацию со знаком &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;*&lt;/code&gt;. Внутри такой функции мы можем использовать &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;yield&lt;/code&gt;,
передав ему &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;sleep()&lt;/code&gt;-промис.&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-javascript&quot; data-lang=&quot;javascript&quot;&gt;&lt;span class=&quot;nx&quot;&gt;app&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;run&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;Q&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;async&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kd&quot;&gt;function&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;nx&quot;&gt;request&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;yield&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;sleep&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;2000&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;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;Good day to you sir&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;p&quot;&gt;}));&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;Как только &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;yield&lt;/code&gt; будет вызван, выполнение функции остановится и перейдет
обратно к &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Q.async()&lt;/code&gt;. Когда промис будет разрешен, Q обеспечит возврат
к выполнению генератора. В нашем случае, это произойдет как только сработает
таймаут. &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Q.async()&lt;/code&gt;, в свою очередь, так же возвращает промис в mach,
который обрабатывает запросы к node-серверу.&lt;/p&gt;

&lt;h3 id=&quot;yield-деле&quot;&gt;yield деле&lt;/h3&gt;

&lt;p&gt;Пример со &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;sleep()&lt;/code&gt; может показаться бесполезным, так что давайте посмотрим
что-нибудь получше. Скажем, доступ к обработанному содержимому запроса. Mach
возвращает его в виде промиса с помощью метода &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;request.parseContent()&lt;/code&gt;. Так
как это промис, мы можем передать его прямо в &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;yield&lt;/code&gt;:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-javascript&quot; data-lang=&quot;javascript&quot;&gt;&lt;span class=&quot;nx&quot;&gt;app&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;run&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;Q&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;async&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kd&quot;&gt;function&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;nx&quot;&gt;request&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;var&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;body&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;yield&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;request&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;parseContent&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;JSON&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;stringify&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;body&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;/figure&gt;

&lt;p&gt;С использованием &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;yield&lt;/code&gt; ваши обработчики становятся проще. Еще один пример
с сохранением модели.&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-javascript&quot; data-lang=&quot;javascript&quot;&gt;&lt;span class=&quot;nx&quot;&gt;app&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;post&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;/users&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;nx&quot;&gt;Q&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;async&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kd&quot;&gt;function&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;nx&quot;&gt;request&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;var&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;user&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;new&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;request&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;params&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;k&quot;&gt;yield&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;save&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;JSON&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;stringify&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;p&quot;&gt;);&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;else&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;mi&quot;&gt;422&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;/figure&gt;

&lt;h3 id=&quot;развитие-yield&quot;&gt;Развитие yield&lt;/h3&gt;

&lt;p&gt;Мне приятно думать, что &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;yield&lt;/code&gt; способен изменить написанные в традиционном
спагетти-стиле node-приложения, сделав их чище. Я просто не могу дождаться
поддержки браузеров, хотя, пожалуй, это произойдет еще не скоро.&lt;/p&gt;

&lt;p&gt;Полный пример использования Mach и генераторов вы можете найти в моём &lt;a href=&quot;https://github.com/maccman/mach/blob/master/prototypes/generators.js&quot;&gt;форке&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/articles-assets/footer/vader-1.jpg&quot; alt=&quot;Как yield изменит Node.js&quot; /&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Подписывайтесь на &lt;a href=&quot;http://feeds.feedburner.com/anton-shuvalov/FJHar&quot;&gt;РСС&lt;/a&gt;.
Всем добра!&lt;/em&gt;&lt;/p&gt;

&lt;p class=&quot;photo-author&quot;&gt;&lt;em&gt;фото: &lt;a href=&quot;https://www.flickr.com/photos/jdhancock/&quot;&gt;jdhancock&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

</content>
  </entry>
  
  <entry>
    <title>Open Source Dickishness</title>
    <updated>2014-07-31T00:00:00+00:00</updated>
    
      <id>http://shuvalov.info/2014/07/31/open-source-dickishness</id>
      <link href="http://shuvalov.info/2014/07/31/open-source-dickishness"/>
    
      <content type="html" xml:base="http://shuvalov.info/">
</content>
  </entry>
  
  <entry>
    <title>Ссылколог</title>
    <updated>2014-07-31T00:00:00+00:00</updated>
    
      <id>http://shuvalov.info/2014/07/31/linkolog</id>
      <link href="http://shuvalov.info/2014/07/31/linkolog"/>
    
      <content type="html" xml:base="http://shuvalov.info/">&lt;p&gt;&lt;img src=&quot;/assets/articles-assets/features/links.jpg&quot; alt=&quot;Ссылколог&quot; /&gt;&lt;/p&gt;

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

&lt;ul class=&quot;articles-list&quot;&gt;
  
    &lt;li class=&quot;articles-list__item&quot;&gt;
  
  &lt;a class=&quot;articles-list__link&quot; href=&quot;/2014/09/23/linkolog-9&quot;&gt;
    Ссылколог #9
  &lt;/a&gt;
  
  &lt;div class=&quot;articles-list__description&quot;&gt;
    Тайная гильдия, NPM@2.0, песочницы на SO и немного о console.log и Apple
  &lt;/div&gt;
&lt;/li&gt;

  
    &lt;li class=&quot;articles-list__item&quot;&gt;
  
  &lt;a class=&quot;articles-list__link&quot; href=&quot;/2014/09/15/linkolog-8&quot;&gt;
    Ссылколог #8
  &lt;/a&gt;
  
  &lt;div class=&quot;articles-list__description&quot;&gt;
    Полезный плагин для photoshop, шрифт от Mozila, инструменты для мобильного тестирования, this в javascript, и не только это
  &lt;/div&gt;
&lt;/li&gt;

  
    &lt;li class=&quot;articles-list__item&quot;&gt;
  
  &lt;a class=&quot;articles-list__link&quot; href=&quot;/2014/09/01/linkolog-7&quot;&gt;
    Ссылколог-7
  &lt;/a&gt;
  
  &lt;div class=&quot;articles-list__description&quot;&gt;
    Курс по функциональному JS, CSS в GitHub, работа с памятью в JS, vimcasts и бесплатные книги по UX
  &lt;/div&gt;
&lt;/li&gt;

  
    &lt;li class=&quot;articles-list__item&quot;&gt;
  
  &lt;a class=&quot;articles-list__link&quot; href=&quot;/2014/07/21/linkolog-6&quot;&gt;
    Ссылколог-6
  &lt;/a&gt;
  
  &lt;div class=&quot;articles-list__description&quot;&gt;
    Три ссылки о типографике
  &lt;/div&gt;
&lt;/li&gt;

  
    &lt;li class=&quot;articles-list__item&quot;&gt;
  
  &lt;a class=&quot;articles-list__link&quot; href=&quot;/2014/05/08/linkolog-5&quot;&gt;
    Ссылколог-5
  &lt;/a&gt;
  
  &lt;div class=&quot;articles-list__description&quot;&gt;
    Подборка интересных материалов о дизайне и JavaScript
  &lt;/div&gt;
&lt;/li&gt;

  
    &lt;li class=&quot;articles-list__item&quot;&gt;
  
  &lt;a class=&quot;articles-list__link&quot; href=&quot;/2014/04/29/linkolog-4&quot;&gt;
    Ссылколог-4
  &lt;/a&gt;
  
  &lt;div class=&quot;articles-list__description&quot;&gt;
    Подборка интересных материалов о дизайне, JavaScript и управлении проектами
  &lt;/div&gt;
&lt;/li&gt;

  
    &lt;li class=&quot;articles-list__item&quot;&gt;
  
  &lt;a class=&quot;articles-list__link&quot; href=&quot;/2014/04/21/links-3&quot;&gt;
    Ссылколог-3
  &lt;/a&gt;
  
  &lt;div class=&quot;articles-list__description&quot;&gt;
    Подборка интересных материалов о фронтенде, node.js и упралении разработкой.
  &lt;/div&gt;
&lt;/li&gt;

  
    &lt;li class=&quot;articles-list__item&quot;&gt;
  
  &lt;a class=&quot;articles-list__link&quot; href=&quot;/2014/04/14/links-2&quot;&gt;
    Ссылколог-2
  &lt;/a&gt;
  
  &lt;div class=&quot;articles-list__description&quot;&gt;
    Подборка интересных материалов о фронтенд, Linux'е и дизайне.
  &lt;/div&gt;
&lt;/li&gt;

  
    &lt;li class=&quot;articles-list__item&quot;&gt;
  
  &lt;a class=&quot;articles-list__link&quot; href=&quot;/2014/04/10/links-1&quot;&gt;
    Ссылколог-1
  &lt;/a&gt;
  
  &lt;div class=&quot;articles-list__description&quot;&gt;
    Подборка интересных материалов о фронтенде, дизайне и разных интересных штуках.
  &lt;/div&gt;
&lt;/li&gt;

  
&lt;/ul&gt;

&lt;p&gt;&lt;em&gt;Подписывайтесь на &lt;a href=&quot;http://feeds.feedburner.com/anton-shuvalov/FJHar&quot;&gt;РСС&lt;/a&gt;,
чтобы не пропустить новые публикации!&lt;/em&gt;&lt;/p&gt;

</content>
  </entry>
  
  <entry>
    <title>Ведущий мейнтейнер Express о его продаже</title>
    <updated>2014-07-31T00:00:00+00:00</updated>
    
      <id>http://shuvalov.info/2014/07/31/3-doug</id>
      <link href="http://shuvalov.info/2014/07/31/3-doug"/>
    
      <content type="html" xml:base="http://shuvalov.info/">&lt;p&gt;Я видел много обсуждений в Twitter, Github и других местах о последних
изменениях в Node.js проекте Express и его передаче из аккаунта visionmedia к
strongloop на GitHub, и я хотел бы поделиться своим мнением.&lt;/p&gt;

&lt;p&gt;Для начала, несколько моментов:&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;Я ничего не имею против StrongLoop Inc. (the Delaware corporation) и я
 уверен что они очень талантливы и мотивированы.&lt;/li&gt;
  &lt;li&gt;Я ничего не имею против TJ и я правда считаю хорошим то, что он получил
 что-то за ту большую работу, которую он вложил в Express и связанные с ним
 проекты на протяжении нескольких лет.&lt;/li&gt;
  &lt;li&gt;Я не получил и не хотел бы получать деньги за Express.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Да, TJ написал мне email о том, что StrongLoop собирается спонсировать
expressjs.com и писать документацию и обучающие материалы, и я принял именно
это за спонсорскую поддержку. Вероятно, здесь мы не совсем поняли друг друга:
я посчитал, что они просто разместят свое лого на сайте и/или в README репозитория, в разделе «спонсоры», в обмен на хорошую документацию, обучающие
материалы и тд.&lt;/p&gt;

&lt;p&gt;Я не знал, что репозитории на GitHub собираются куда-то переносить. Если бы
я знал, то я бы немного подготовился к этому, сменив линки, исправив бейджи,
настройки Travis CI, Coveralls.io и тд. но StrongLoop ничего не сказали о
своих намерениях о перемещении проекта «ведущему мейнтейнеру, и, разумеется,
никакая подготовительная работа, связанная с этим, не была выполнена.&lt;/p&gt;

&lt;p&gt;Что касается того, что я не участвовал в работе над Express после смены
владельца репозитория, я могу просто сказать, что чувствовал себя обманутым
StrongLoop. Как мне показалось, они просто ждали, что я буду продолжу свою
работу над express дальше, не зависимо от того, где он теперь разместился, ну,
и, конечно, бесплатно. Я даже не получил сообщения вроде: «Эй, Даг, мы купили
Express у TJ и мы ценим то, что ты сделал для этого проекта, и мы хотели бы
чтобы ты остался ведущим мейнтейнером в нем. Что мы могли бы сделать для этого?»&lt;/p&gt;

&lt;p&gt;Я провел много времени в своей жизни не просто делая коммиты в Express и
связанные с ним проекты(на них пришлось не так много времени), а так же
отвечая на каждый issue и pull request, открытый на GitHub. Я пытался работать
с людьми, чтобы решить их проблемы. Я наблюдал за #express и отвечал
на вопросы. На это я потратил просто огромное количество времени, и не похоже,
что StrongLoop, как новый владелец, заинтересован в трате любых собственных
ресурсов для того, чтобы продолжить эту работу, в отличии от сообщества,
которое готово и дальше этим заниматься бесплатно.&lt;/p&gt;

&lt;p&gt;Я не видел никого из StrongLoop, кто пытался поддержать issue-трекер перед
передачей прав, и до сих пор никто из StrongLoop не помогает в IRC-канале
проекта, ни в рассылке Google Groups. Я очень надеюсь, что компания, которая нацелена на получение прибыли будет что-то поддерживать самостоятельно, и
продолжит развивать проект. Я уверен, что они предпочтут помогать людям,
которым нужна поддержка по платным продуктам этой компании.&lt;/p&gt;
</content>
  </entry>
  
  <entry>
    <title>StrongLoop &amp; Express</title>
    <updated>2014-07-31T00:00:00+00:00</updated>
    
      <id>http://shuvalov.info/2014/07/31/2-strongLoop-and-express</id>
      <link href="http://shuvalov.info/2014/07/31/2-strongLoop-and-express"/>
    
      <content type="html" xml:base="http://shuvalov.info/">&lt;p&gt;&lt;img src=&quot;/assets/articles-assets/tj.jpg&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;

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

&lt;p&gt;Я чатился с ребятами из StrongLoop об улучшениях NodeJS, когда они преложили
идею «спонсорства» Express, понимая под этим компенсацию за фактическое
использование «бренда», а не исходного кода.&lt;/p&gt;

&lt;p&gt;Я собирался разделить компенсацию с Дугласом, так как он был основным
мейнтейнером Express в последнее время. Я сообщил ему об этом плане, написав
email:&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;Эй, чел! StrongLoop хотел бы стать «спонсором» (сделать брендинг
&lt;a href=&quot;http://expressjs.com/&quot;&gt;expressjs.com&lt;/a&gt;, например) и я подумал, почему бы и нет,
хаха, я доверяю им с тех пор, как они единственные кто работал над ядром
Node заботясь о том, чтобы сделать его удобным для пользователей, кроме того,
хотя я и не думаю, что это на самом деле что-то значит, они хотят улучшить
сайт, к примеру, добавив туда больше гайдов.&lt;/p&gt;

  &lt;p&gt;В любом случае, я хотел бы отправить тебе немного $$, потому что ты много
всего там сделал. У тебя есть paypal?&lt;/p&gt;
&lt;/blockquote&gt;

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

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

&lt;blockquote&gt;
  &lt;p&gt;Hey TJ&lt;/p&gt;

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

  &lt;p&gt;У меня есть PayPal-аккаунт, связанный с этим email-аккаунтом, хотя я не
очень заинтересован в деньгах, потому что не хочу чувствовать себя обязанным&lt;/p&gt;
&lt;/blockquote&gt;

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

&lt;p&gt;Так, что вот факты. Я надеюсь, вы сможете объяснить, что вам нужно, но писать
статьи, что я «тупица» это просто тупо.&lt;/p&gt;
</content>
  </entry>
  
  <entry>
    <title>TJ Holowaychuk продал ExpressJS</title>
    <updated>2014-07-31T00:00:00+00:00</updated>
    
      <id>http://shuvalov.info/2014/07/31/1-open-source-dickishness</id>
      <link href="http://shuvalov.info/2014/07/31/1-open-source-dickishness"/>
    
      <content type="html" xml:base="http://shuvalov.info/">&lt;p&gt;&lt;img src=&quot;/assets/articles-assets/expressjs.jpg&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;

&lt;p class=&quot;photo-author&quot;&gt;&lt;em&gt;фото: &lt;a href=&quot;https://www.flickr.com/photos/jdhancock/&quot;&gt;jdhancock&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Вчера, на удивление комьюнити ExpressJS, создатель фреймворка и мейнтейнер
фреймворка TJ Holowaychuk &lt;a href=&quot;https://github.com/strongloop/express/issues/2264#issuecomment-50567002&quot;&gt;продал&lt;/a&gt; проект &lt;a href=&quot;http://strongloop.com/strongblog/tj-holowaychuk-sponsorship-of-express/&quot;&gt;компании StrongLoop&lt;/a&gt;,
коммерческому NodeJS-стартапу. Передача проекта &lt;a href=&quot;https://github.com/strongloop/express/issues/2264#issuecomment-50474787&quot;&gt;шокировала активных мейнтейнеров
проекта&lt;/a&gt;, которые занимались поддержкой фреймворка без участия автора с января.
Из-за небрежной передачи прав на репозиторий мейнтейнеры лишились возможности 
вносить изменения в проект (позднее права восстановили).&lt;/p&gt;

&lt;p&gt;В &lt;a href=&quot;http://strongloop.com/strongblog/tj-holowaychuk-sponsorship-of-express/&quot;&gt;своем блоге&lt;/a&gt; StrongLoop описали передачу проекта как огромный шаг в его
развитии. В этом посте продажа проекта называется «передачей спонсорского пакета»
&lt;em&gt;(transfer of sponsorship)&lt;/em&gt;, но если все, что хотели сделать эти ребята — всего
лишь поддержка и помощь, то зачем потребовалось переносить проект?
Почему пост в блог, а не pull request был первым, что они сделали?&lt;/p&gt;

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

&lt;p&gt;Успех проектов с открытым исходным кодом не заслуга его создателя, 
а результат труда всех его контрибуторов и сообщества. Успех Express — это 
работа людей, которые участвовали в его разработке, а не одного человека,
даже если он &lt;a href=&quot;https://twitter.com/tjholowaychuk/status/494294255448236032&quot;&gt;«отвечает за ~95%+ проекта»&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Когда TJ Holowaychuk потерял интерес к поддержке Express, он поступил правильно,
отдав другим его поддержку и развитие. В тот момент проект, фактически, перестал 
ему принадлежать, даже не смотря на то, что он продолжал храниться в его
GitHub-аккаунте. Это вполне обычная практика, когда проект поддерживают другие
разработчики.&lt;/p&gt;

&lt;p&gt;Оставить проект под его оригинальным URL — хороший способ продолжить его
поддержку, отдавая почести автору. Но этот факт не может позволить автору,
молча, взять и забрать права назад, тем более с намерением продать проект
кому-либо. Не говоря уже о том, что Express уже имеет собственную 
&lt;a href=&quot;https://github.com/expressjs&quot;&gt;GitHub-организацию&lt;/a&gt;, готовую хранить проект у себя.&lt;/p&gt;

&lt;p&gt;Что делает эту передачу проекта особенно печальной, так это тот факт, что
права создателя были переданы компании, которая напрямую занимается монетизацией
ExpressJS, продавая как профессиональные сервисы так и продукты, построенные на
этом фреймворке. Благодаря возможности влиять на Express и его сообщество, 
StrongLoop получает несправедливое преимущество перед другими компаниями,
которые предоставляют подобные сервисы. Так же это создает потенциальный конфликт
интересов между продвижением Express и их коммерческим фреймворком LoopBack
(который так же основан на Express).&lt;/p&gt;

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

&lt;p&gt;&lt;em&gt;От переводчика: &lt;a href=&quot;/2014/08/31/strongLoop-and-express/&quot;&gt;вот ответ TJ о сложившейся ситуации&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

</content>
  </entry>
  
  <entry>
    <title>«Эмоциональный веб-дизайн», Аарон Уолтер</title>
    <updated>2014-07-30T00:00:00+00:00</updated>
    
      <id>http://shuvalov.info/2014/07/30/emotional-design</id>
      <link href="http://shuvalov.info/2014/07/30/emotional-design"/>
    
      <content type="html" xml:base="http://shuvalov.info/">
</content>
  </entry>
  
  <entry>
    <title>Фреймворк</title>
    <updated>2014-07-28T00:00:00+00:00</updated>
    
      <id>http://shuvalov.info/2014/07/28/framework</id>
      <link href="http://shuvalov.info/2014/07/28/framework"/>
    
      <content type="html" xml:base="http://shuvalov.info/">&lt;h2 id=&quot;идея&quot;&gt;Идея&lt;/h2&gt;

&lt;p&gt;Во время размышлений над архитектурой ExpressJS и KoaJS, мою голову посетила идея client side MV* фреймворка. Основная концепция и отличие от фреймворков, с которыми я работал — сверхмодульность: все компоненты, которые необходимы в проекте подключаются через &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Framework.use(module)&lt;/code&gt;, сам же фреймворк предоставляет исключительно скелет, строительные леса, которые обеспечивают только базовый API для работы подключаемых модулей.&lt;/p&gt;

&lt;p class=&quot;center-img&quot;&gt;&lt;img src=&quot;/assets/articles-assets/framework/loki.gif&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;

&lt;h2 id=&quot;плюсы&quot;&gt;Плюсы&lt;/h2&gt;

&lt;h3 id=&quot;простота&quot;&gt;Простота&lt;/h3&gt;

&lt;p&gt;Являясь развитием идей ConnectJS, Express в релизе версии 4.0 перестал включать в список своих зависимостей предка, тем самым избавился от большого количества middlewares, которые достались в наследство. KoaJS, являясь развитием идей первых двух фреймворков, не включает в себя даже механизм роутинга, оставляя решение этой задачи внешним модулям.&lt;/p&gt;

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

&lt;p&gt;То же самое вероятно сработает и в контексте клиенского MV* фреймворка. Я нахожу простоту — залогом гибкости и устойчивости концепции.&lt;/p&gt;

&lt;h3 id=&quot;гибкие-мажорные-обновления&quot;&gt;Гибкие мажорные обновления&lt;/h3&gt;

&lt;p&gt;Недавно Эдди Османи рассказал об &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Object.observable&lt;/code&gt; — API, позволяющем заменить биндинги, которые используются во всех MV* фреймворках на нативную реализацию, которая работает абсолютно прозрачно, поверх объектов, без необходимости бесконечных плеяд из вызовов getter’ов и setter’ов.&lt;/p&gt;

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

&lt;p&gt;Для сравнения, чтобы попробовать генераторы, скажем, в KoaJS, достаточно просто поставить послендюю unstable-версию NodeJS и запустить ее с флагом &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;—harmony&lt;/code&gt;. В браузере же так просто справиться с &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Object.Observable&lt;/code&gt; не получится.&lt;/p&gt;

&lt;p&gt;Если же иметь модульный фреймворк, то подключить, если можно так выразиться, unstable-реализацию можно всего лишь написав необходимый модуль, и подключив его к хост-фреймворку: &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Framework.use(webkitObservableModels)&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Готово.&lt;/p&gt;

&lt;h3 id=&quot;гибкие-минорные-обновления&quot;&gt;Гибкие минорные обновления&lt;/h3&gt;

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

&lt;h3 id=&quot;только-необходимое&quot;&gt;Только необходимое&lt;/h3&gt;

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

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

&lt;h3 id=&quot;open-source-friendly&quot;&gt;Open Source Friendly&lt;/h3&gt;

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

&lt;p&gt;Форк Backbone? Такое я последний раз слышал на YAC от SoundCloud. Популярный форк Angular? Ember? Этого я не слышал. Контрибутить в эти фреймворки не просто: у монолитной системы есть большое количество пользователей, которые не могут просто так перейти на другой API. Такой подход поддерживает интерфейсы для устаревших систем. Это бремя несколько ограничивает фреймворк в развитии.&lt;/p&gt;

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

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

&lt;h2 id=&quot;минусы&quot;&gt;Минусы&lt;/h2&gt;

&lt;ul&gt;
  &lt;li&gt;Порог входа. Модульность — это развитие простоты Backbone. Но, тут, как с Gulp и Grunt. Первый проще, но порог входа значительно выше.&lt;/li&gt;
  &lt;li&gt;Зависимость от качественного проектирования основной части фреймворка. Но эта проблема присутствует везде. Едва ли в этом случае она представляет что-то особенное.&lt;/li&gt;
  &lt;li&gt;Проблема качества сторонних модулей. Из-за низкого порога входа, этой проблеме подвержено все JS-коммьюнити.&lt;/li&gt;
  &lt;li&gt;И еще миллионы минусов, разумеется.&lt;/li&gt;
&lt;/ul&gt;

&lt;p class=&quot;center-img&quot;&gt;&lt;img src=&quot;/assets/articles-assets/framework/facepalm.jpg&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;

&lt;h2 id=&quot;итог&quot;&gt;Итог&lt;/h2&gt;

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

&lt;p class=&quot;center-img&quot;&gt;&lt;img src=&quot;/assets/articles-assets/framework/gendalf.gif&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;

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

</content>
  </entry>
  
  <entry>
    <title>Ссылколог-6</title>
    <updated>2014-07-21T00:00:00+00:00</updated>
    
      <id>http://shuvalov.info/2014/07/21/linkolog-6</id>
      <link href="http://shuvalov.info/2014/07/21/linkolog-6"/>
    
      <content type="html" xml:base="http://shuvalov.info/">&lt;p&gt;Пытаюсь после двухмесячного перерыва снова начать активно писать полезные штуки
в блог. На этот раз всего три ссылки, и все о типографике.&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;&lt;a href=&quot;http://nobelfaik.livejournal.com/64974.html&quot;&gt;«Памятка верстальщика. Основные ошибки при выключке текста по левому краю, по центру и по формату»&lt;/a&gt; —
очень интересная статья от &lt;a href=&quot;http://nobelfaik.livejournal.com/&quot;&gt;nobelfaik&lt;/a&gt; о выключке текста и основных
проблемах, с ней связанных.&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;http://nobelfaik.livejournal.com/65903.html&quot;&gt;«Выключка по формату: примеры, ошибки, как сделать»&lt;/a&gt; — продолжение первой
статьи. На этот раз речь идет об истории и особенностях выключки по ширине.
Кроме этого, автор рассказывает как добиться хорошей выключки по ширине
в Illustrator’е. Правда, я еще не придумал как такое потом в веб перевенести? :)&lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;a href=&quot;http://typejournal.ru/articles/ZIM-Review&quot;&gt;«Конгрев как символ тирании»&lt;/a&gt; — потрясающая статья из &lt;a href=&quot;http://typejournal.ru/&quot;&gt;журнала «Шрифт»&lt;/a&gt;
об истории советской архитиктуры и типографики.&lt;/p&gt;

    &lt;blockquote&gt;
      &lt;p&gt;Сей­час, по про­ше­ствии вре­ме­ни, ста­лин­ские ше­дев­ры ка­жут­ся пост­мо­дер­нист­ским
на­бо­ром ци­тат из раз­граб­лен­ной биб­лио­те­ки, скле­ен­ных па­фос­ны­ми встав­ка­ми
им­пер­ско-ком­му­ни­сти­че­ской идео­гра­фии.&lt;/p&gt;
    &lt;/blockquote&gt;
  &lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;em&gt;Подписывайтесь на &lt;a href=&quot;http://feeds.feedburner.com/anton-shuvalov/FJHar&quot;&gt;РСС&lt;/a&gt;.
Всем добра и штурмовиков&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/articles-assets/footer/trooper-6.jpg&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;

&lt;p class=&quot;photo-author&quot;&gt;&lt;em&gt;фото: &lt;a href=&quot;https://www.flickr.com/photos/jdhancock/&quot;&gt;jdhancock&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

</content>
  </entry>
  
  <entry>
    <title>Rambler</title>
    <updated>2014-07-04T00:00:00+00:00</updated>
    
      <id>http://shuvalov.info/2014/07/04/rambler</id>
      <link href="http://shuvalov.info/2014/07/04/rambler"/>
    
      <content type="html" xml:base="http://shuvalov.info/">&lt;p&gt;Уфф… Кажется, постепенно все приходит в норму, поэтому можно уже написать сюда.
В начале июня я оставил проект интерактивных книг в пермской Enaza. Работа
изменилась достаточно радикально — теперь я в живу Москве, работаю в Rambler и
пока что занимаюсь фронтендом &lt;a href=&quot;http://lenta.ru&quot;&gt;Ленты&lt;/a&gt; и ее проектов. Это очень даже
интересно, потому что за последний год мое развитие в направлении фронтенда было
стремительным, но несколько ограниченным рамками webkit-only проекта.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/articles-assets/rambler.jpg&quot; alt=&quot;Rambler&quot; /&gt;&lt;/p&gt;

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

&lt;ul&gt;
  &lt;li&gt;&lt;a href=&quot;https://github.com/shuvalov-anton/node-clusterize-cli&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;node-clusterize-cli&lt;/code&gt;&lt;/a&gt; — утилита для запуска и демонизации кластера
из nodejs-приложения без изменения его исходного кода;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://github.com/shuvalov-anton/microlog&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;microlog&lt;/code&gt;&lt;/a&gt; — маленький но гордый логгер с поддержкой форматов. Замена
монструозному &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;winston&lt;/code&gt;. Сейчас как раз думаю о мажорном релизе с поддержкой
транспортов, ну и с адекватным readme;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://github.com/shuvalov-anton/next-done&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;next-done&lt;/code&gt;&lt;/a&gt; — очень маленькая утилита для подсчета асинхронных коллбеков,
полезна как легковесная замена большому &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;async&lt;/code&gt;, в некоторых случаях;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://github.com/shuvalov-anton/grunt-clinch&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;grunt-clinch&lt;/code&gt;&lt;/a&gt; — плагин для grunt, собирающий CommonJS-модули для браузера,
с помощью &lt;a href=&quot;https://github.com/Meettya/clinch&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;clinch&lt;/code&gt;&lt;/a&gt;, в котором я, опять же открыл не мало ишью, и, наверное,
сделал его немного лучше;&lt;/li&gt;
  &lt;li&gt;ну и еще я сделал немного переводов, форков, фиксов, ишью в разные крутые проекты…&lt;/li&gt;
&lt;/ul&gt;

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

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

&lt;p&gt;Я точно так же буду стараться и дальше приносить пользу сообществу, но не ради
клеточек на GitHub, а ради того, для чего эти вещи и предназначены — для того,
чтобы приносить пользу людям, а в особенности мне :)&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;Year of contributions: 1,771 total&lt;br /&gt;
Longest streak: 198 days&lt;br /&gt;
Current streak: 6 days&lt;/p&gt;
&lt;/blockquote&gt;

</content>
  </entry>
  
  <entry>
    <title>Музыка для работы #2</title>
    <updated>2014-06-23T00:00:00+00:00</updated>
    
      <id>http://shuvalov.info/2014/06/23/sc-workset-2</id>
      <link href="http://shuvalov.info/2014/06/23/sc-workset-2"/>
    
      <content type="html" xml:base="http://shuvalov.info/">&lt;p&gt;&lt;img src=&quot;/assets/articles-assets/music/2.jpg&quot; alt=&quot;Музыка для работы&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Я продолжаю подбирать саунд-треки к обычному рабочему дню программиста:
chillwave, dream pop, chiptune, glitch, нежные девичьи голоса — все как надо.&lt;/p&gt;

&lt;div id=&quot;player&quot;&gt;&lt;/div&gt;

&lt;script&gt;
  (function() {
      var script = document.createElement(&quot;script&quot;);
      
      script.type = &quot;text/javascript&quot;;
      script.async = true;
      script.src = &quot;//sd.toneden.io/production/toneden.loader.js&quot;
      
      var entry = document.getElementsByTagName(&quot;script&quot;)[0];
      entry.parentNode.insertBefore(script, entry);
  }());
  
  ToneDenReady = window.ToneDenReady || [];
  ToneDenReady.push(function() {
      // Modify the dom and urls parameters to position
      // your player and select tracks/sets/artists to play.
      ToneDen.player.create({
          dom: '#player',
          urls: [
              'https://soundcloud.com/asheee/sets/workset-2'
          ],
          skin: 'aurora'
      });
  });
&lt;/script&gt;

&lt;p&gt;&lt;a href=&quot;https://soundcloud.com/asheee/sets/workset-2&quot;&gt;Ссылка на SoundCloud&lt;/a&gt;. Спасибо за комментарии к &lt;a href=&quot;/2014/05/05/sc-workset-1/&quot;&gt;прошлому треклисту&lt;/a&gt; —
я открыл для себя очень много интересного! Будет очень круто, если вы поделитесь
со мной треками под которые вам нравится работать :)&lt;/p&gt;

</content>
  </entry>
  
  <entry>
    <title>Читаемый код — самообман</title>
    <updated>2014-05-15T00:00:00+00:00</updated>
    
      <id>http://shuvalov.info/2014/05/15/clean-code</id>
      <link href="http://shuvalov.info/2014/05/15/clean-code"/>
    
      <content type="html" xml:base="http://shuvalov.info/">&lt;blockquote&gt;
  &lt;p&gt;Когда я вижу такой код &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;return (~ memo.indexOf(item) ? null : memo.push(item)), memo;&lt;/code&gt;
— хочется обратиться ко всем начинающим (или «продолжающим») JS разработчикам —
не пишите так никогда. Совсем никогда. Вы можете подумать, что это какой-то крутой,
«джедайский» код — который позволяет очень лаконично выразить вашу бизнес-логику, 
используя доступные только «гуру» «экзотические» операторы и конструкции. 
Это абсолютно не так.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p style=&quot;text-align:right;&quot;&gt;&lt;em&gt;мнение эксперта Хабрахабр.ру&lt;/em&gt;&lt;/p&gt;

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

&lt;p&gt;Ну как, не нужен — есть прописные истины: &lt;a href=&quot;https://ru.wikipedia.org/wiki/Don%27t_repeat_yourself&quot;&gt;DRY&lt;/a&gt;, &lt;a href=&quot;https://ru.wikipedia.org/wiki/KISS_(%D0%BF%D1%80%D0%B8%D0%BD%D1%86%D0%B8%D0%BF)&quot;&gt;KISS&lt;/a&gt;, маленькие методы,
тонкие контроллеры, паттерны проектирования, &lt;a href=&quot;http://www.jshint.com/&quot;&gt;линтинг&lt;/a&gt;, тесты, &lt;a href=&quot;https://ru.wikipedia.org/wiki/%D0%9A%D0%BE%D0%BB%D0%B8%D1%87%D0%B5%D1%81%D1%82%D0%B2%D0%BE_%D1%81%D1%82%D1%80%D0%BE%D0%BA_%D0%BA%D0%BE%D0%B4%D0%B0&quot;&gt;не ударяться в «однострочники»&lt;/a&gt;, 
&lt;a href=&quot;https://ru.wikipedia.org/wiki/%D6%E8%EA%EB%EE%EC%E0%F2%E8%F7%E5%F1%EA%E0%FF_%F1%EB%EE%E6%ED%EE%F1%F2%FC&quot;&gt;цикломатическая сложность&lt;/a&gt; и далее по списку. Все это, действительно, важно, потому что 
это делает код понятным и единообразным. Эти принципы, в силу разных причин (дедлайн, 
оплата за строки кода, пристрастие к героину и тд.), не вседа получается соблюдать, это нормально. 
Но, все равно, к этому нужно всеми силами стремиться.&lt;/p&gt;

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

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

&lt;p&gt;&lt;img src=&quot;/assets/articles-assets/darth-n-alien.jpg&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;

&lt;h2 id=&quot;стайлгайды&quot;&gt;Стайлгайды&lt;/h2&gt;

&lt;p&gt;Единообразие — это сверхзадача читаемого кода. Это идея, это «ради чего». 
Именно единообразие определяет подходящие лексемы и конструкции языка:
если команда использует тернарные операторы — пишешь их, если в коде есть
лексемы &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;~arr.indexOf(item)&lt;/code&gt; — используешь их. Если никто не говорит
на крутом джедайском кокни, то тебе тоже не стоит хвастаться. Для оттачивания
своего стиля есть GitHub, Open Source и разные диванные проекты по захвату мира
— там можно придерживаться своих правил, и лучше бы делать это, опять же,
единообразно. Главное, не забывать, что эксперименты это здорово, и проводить их
нужно в правильном месте.&lt;/p&gt;

&lt;p&gt;Вернемся же к этим великолепным тернаркам (вы ведь уже поняли по аватарке, что на
джедайском наречии я немного понимаю?). В JavaScript есть некоторые «неудобные
конструкции» — hoisting, автоподстановка точки с запятой, у которой найдется
пара стрел для всех двух ваших колен, а предназначение конструкций &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;;(function () {…})();&lt;/code&gt;
или &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;!function () {}();&lt;/code&gt; я разгадывал несколько месяцев. Но все это не значит, что этими
штуками грешновато пользоваться. Отнюдь! Только присмотритесь, сколько команд
не используют точку с запятой, сколько действительно великолепных JavaScript-разработчиков
пишут тернарные операторы вместо &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;if/else&lt;/code&gt; там, где это уместно. TJ Holowaychuk, Isaac Schlueter —
у каждого состоявшегося разработчика есть предпочтения, и это не просто нормально. Это отлично! А best-practices
к написанию плагинов для jQuery? Пишут же &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;;(function () {…})();&lt;/code&gt;, и ничего.&lt;/p&gt;

&lt;h2 id=&quot;читаемый-код&quot;&gt;«Читаемый» код&lt;/h2&gt;

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

&lt;p&gt;Если вы не знакомы с побитовым оператором &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;~&lt;/code&gt; — разберитесь с ним. Если вы 
знакомы, то в чем проблема запомнить лексему &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;~arr.indexOf()&lt;/code&gt;? Вы же не думаете,
что больше никто не будет ее писать, потому что она вам не нравится?&lt;/p&gt;

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

&lt;h2 id=&quot;возвращаясь-к-примеру&quot;&gt;Возвращаясь к примеру&lt;/h2&gt;

&lt;p&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;return (~ memo.indexOf(item) ? null : memo.push(item)), memo;&lt;/code&gt; даже мне 
кажется  довольно странной конструкцией. Я бы предпочел такой вариант:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-javascript&quot; data-lang=&quot;javascript&quot;&gt;&lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;~&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;memo&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;indexOf&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;item&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;memo&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;memo&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;concat&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;([&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;item&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]);&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;Смущают меня две вещи: null в одном из полей тернарного оператора — верный признак
задуматься, действительно ли он должен быть тернарным; запятую же после тернарки
я нахожу немного двусмысленной — в однострочнике немного неочевидно относится ли она
к третьему операнду тернарки, или она выполнится после всей конструкции, да и причина
ее возникновения — &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;push&lt;/code&gt;, который возвращет длинну нового массива вместо самого массива.&lt;/p&gt;

&lt;h2 id=&quot;итог&quot;&gt;Итог&lt;/h2&gt;

&lt;p&gt;В любом случае, указывать другим как писать код — это весело, но нужно иметь
свою голову на плечах и понимать причины тех или иных гайдов. А «читаемость» кода,
призывающая вас использовать пробелы между всеми словами, только &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;if/else&lt;/code&gt;, 
отбивать каждую строку кода двумя переводами строки и тд. — это не более чем
комформизм и вопрос привычки.&lt;/p&gt;

</content>
  </entry>
  
  <entry>
    <title>Ссылколог-5</title>
    <updated>2014-05-08T00:00:00+00:00</updated>
    
      <id>http://shuvalov.info/2014/05/08/linkolog-5</id>
      <link href="http://shuvalov.info/2014/05/08/linkolog-5"/>
    
      <content type="html" xml:base="http://shuvalov.info/">&lt;ol&gt;
  &lt;li&gt;&lt;a href=&quot;https://github.com/shopify/liquid/wiki/Liquid-for-Designers&quot;&gt;«Liquid for Designers»&lt;/a&gt; — совершенно случайно нашел хорошую документацию
по шаблонизатору Liquid, который используется в Jekyll.&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;http://paulradzkov.com/2014/web-fonts_license/&quot;&gt;«Веб-лицензии для платных шрифтов могут стоить вам дорого»&lt;/a&gt; —
Павел Радьков рассказывает о вопросе лицензии для веб-шрифтов. Раньше я как-то
даже и не задумывался над этим вопросом и был очень удивлен восокой ценой.&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;http://dmitrysoshnikov.com/tag/russian/&quot;&gt;«ECMA-262 by Dmitry Soshnikov»&lt;/a&gt; — очень полезные статьи о внутреннем
устройсте JavaScript. Дмитрий очень понятным языком объясняет такие непростые
моменты в JS, как &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;this&lt;/code&gt;, замыкания, область видимости, объект переменных.
Я считаю эти статьи обязательным к прочтению каждым JS-разработчиком.&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://medium.com/code-adventures/bafed6cc7979&quot;&gt;«Stop Abusing JSPerf»&lt;/a&gt; — небольшая статья на английском о преждевременной
оптимизации. Я сталкивался с тем, что под этим термином зачастую подразумевают
совершенно иные вещи — тесты, написание читаемого кода и проектирование(sic!).&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;http://jekyllrb.com/news/2014/05/06/jekyll-turns-2-0-0/&quot;&gt;«Jekyll 2.0»&lt;/a&gt;. Jekyll — движок для блога, который использует генерацию
статического контента. Сайты на Jekyll можно хостить на GitHub Pages, к примеру,
как это делаю я с этим самым блогом. Так вот, Jekyll наконец-то обновился до
новой мажорной версии: появились коллекции, поддержка Sass и CoffeeScript и
куча других очень крутых изменений.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;em&gt;Подписывайтесь на &lt;a href=&quot;http://feeds.feedburner.com/anton-shuvalov/FJHar&quot;&gt;РСС&lt;/a&gt;.
Всем добра и штурмовиков&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/articles-assets/footer/trooper-5.jpg&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;

&lt;p class=&quot;photo-author&quot;&gt;&lt;em&gt;фото: &lt;a href=&quot;https://www.flickr.com/photos/jdhancock/&quot;&gt;jdhancock&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

</content>
  </entry>
  
  <entry>
    <title>Музыка для работы #1</title>
    <updated>2014-05-05T00:00:00+00:00</updated>
    
      <id>http://shuvalov.info/2014/05/05/sc-workset-1</id>
      <link href="http://shuvalov.info/2014/05/05/sc-workset-1"/>
    
      <content type="html" xml:base="http://shuvalov.info/">&lt;p&gt;&lt;img src=&quot;/assets/articles-assets/music/1.jpg&quot; alt=&quot;Музыка для работы&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Иногда, во время работы я гоняю по кругу Nerevar Rising, иногда работаю под шаффл
из iTunes, а изредка и под бодрый deathcore или умиротворяющие мотеты, но больше
всего мне нравится писать код под сладкие девичьи голоса, замысловатые глитчи
и обволакивающе-сказочную атмосферу электронной музыки.&lt;/p&gt;

&lt;p&gt;Так от чего бы не сделать компиляцию самых крутых треков? Тем более, в моей ленте
на SoundCloud каждый день появляются десятки новых и не менее крутых!&lt;/p&gt;

&lt;div id=&quot;player&quot;&gt;&lt;/div&gt;

&lt;script&gt;
  (function() {
      var script = document.createElement(&quot;script&quot;);
      
      script.type = &quot;text/javascript&quot;;
      script.async = true;
      script.src = &quot;//sd.toneden.io/production/toneden.loader.js&quot;
      
      var entry = document.getElementsByTagName(&quot;script&quot;)[0];
      entry.parentNode.insertBefore(script, entry);
  }());
  
  ToneDenReady = window.ToneDenReady || [];
  ToneDenReady.push(function() {
      // Modify the dom and urls parameters to position
      // your player and select tracks/sets/artists to play.
      ToneDen.player.create({
          dom: '#player',
          urls: [
              'https://soundcloud.com/asheee/sets/workset-1'
          ],
          skin: 'mojave'
      });
  });
&lt;/script&gt;

&lt;p&gt;&lt;a href=&quot;https://soundcloud.com/asheee/sets/workset-1&quot;&gt;Ссылка на SoundCloud&lt;/a&gt;. А под какую музыку пишете код вы?&lt;/p&gt;

</content>
  </entry>
  
  <entry>
    <title>Ссылколог-4</title>
    <updated>2014-04-29T00:00:00+00:00</updated>
    
      <id>http://shuvalov.info/2014/04/29/linkolog-4</id>
      <link href="http://shuvalov.info/2014/04/29/linkolog-4"/>
    
      <content type="html" xml:base="http://shuvalov.info/">&lt;ol&gt;
  &lt;li&gt;&lt;a href=&quot;https://medium.com/p/70bb2d0d58be&quot;&gt;«Графический интерфейс»&lt;/a&gt; — Данил Ковчий о признаках хорошего дизайна,
системном подходе, чувстве формы, цвета и шрифта.&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;http://blog.antiflash.ru/?go=all/propisnye-istiny-proektirovaniya-interfeysov/&quot;&gt;«Прописные истины проектирования интерфейсов»&lt;/a&gt; — Антон Ловчиков
нескольких о паттернах и антипаттернах в дизайне. Главное, не следовать им
слепо, и не забывать о том, что все очень сильно зависит от конкретной
задачи.&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;http://www.quakejs.com/&quot;&gt;«QuakeJS»&lt;/a&gt; — порт Quake 3 — это отличный пример двух вещей: возможностей
браузерных игр на JavaScript,, портирования LLVM-кода на JavaScript
с помощью &lt;a href=&quot;https://github.com/kripken/emscripten&quot;&gt;emscripten&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://www.youtube.com/watch?v=iQaO-DJop7g&quot;&gt;«Не нравится — давай досвидания!»&lt;/a&gt; — Антон Волков из Alternativa
Platform рассказывает о причинах проблем с коммуникациями внутри компаний.&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://wakatime.com&quot;&gt;«WakaTime»&lt;/a&gt; — open-source сервис для сбора статистики о времени, проведенном
в IDE, а так же трекинга времени по конкретным языкам программирования.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;em&gt;Подписывайтесь на &lt;a href=&quot;http://feeds.feedburner.com/anton-shuvalov/FJHar&quot;&gt;РСС&lt;/a&gt;.
Всем добра и штурмовиков&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/articles-assets/footer/sw-1.jpg&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;

&lt;p class=&quot;photo-author&quot;&gt;&lt;em&gt;фото: &lt;a href=&quot;https://www.flickr.com/photos/jdhancock/&quot;&gt;jdhancock&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

</content>
  </entry>
  
  <entry>
    <title>Установка словарей на iOS без JailBreak</title>
    <updated>2014-04-28T00:00:00+00:00</updated>
    
      <id>http://shuvalov.info/2014/04/28/ios_dictionaries</id>
      <link href="http://shuvalov.info/2014/04/28/ios_dictionaries"/>
    
      <content type="html" xml:base="http://shuvalov.info/">&lt;h2 id=&quot;dictionaryappender&quot;&gt;Dictionary.Appender&lt;/h2&gt;

&lt;p&gt;Недавно я узнал как установить словари из Mac OS X на iOS. Самое забавное, что
&lt;a href=&quot;https://itunes.apple.com/us/app/dictionary.appender/id650562573&quot;&gt;dictionary.appender&lt;/a&gt;, с помощью которого можно устанавливать словари, был
выложен в App Store еще в мае 2013-го года. И вот, сижу я тут, в своем апреле
2014-го и думаю, до чего же крутая эта программа.&lt;/p&gt;

&lt;p&gt;Еще один интересный момент в том, что приложение не подключает явно приватные
API iOS, оно &lt;a href=&quot;http://stackoverflow.com/questions/23019109/programmatically-expanding-ios-dictionary-app-lexicons&quot;&gt;хитрит&lt;/a&gt;, получая доступ к нужным интерфейсам через зависимости
публичных фреймворков. Думаю, что этот момент, вместе с тем фактом, что
приложение опубликовано еще в 2013-ом году, позволяет надеяться, что эту
штуковину завтра не выпилят ко всем чертям из App Store.&lt;/p&gt;

&lt;h2 id=&quot;установка-словарей-на-ios&quot;&gt;Установка словарей на iOS&lt;/h2&gt;

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

&lt;p&gt;Процесс установки очень простой:&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;В iTunes нужно выбрать iPad/iPhone &amp;gt; Apps &amp;gt; File Sharing &amp;gt; Dict.append;&lt;/li&gt;
  &lt;li&gt;Нажать на кнопку «Add», и загрузить словари&lt;/li&gt;
  &lt;li&gt;На устройстве зайти в Dict.append, найти среди неактивных словарей загруженные
и нажать install.&lt;/li&gt;
  &lt;li&gt;Дождаться завершения установки и проверить работу.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;img src=&quot;/assets/articles-assets/ios-dictionaries.jpg&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Словари можно поискать &lt;a href=&quot;http://rutracker.org/forum/viewtopic.php?t=3132931&quot;&gt;здесь&lt;/a&gt;.&lt;/p&gt;

</content>
  </entry>
  
  <entry>
    <title>«Sony. Сделано в Японии», Акио Морита</title>
    <updated>2014-04-23T00:00:00+00:00</updated>
    
      <id>http://shuvalov.info/2014/04/23/akio-morita-sony</id>
      <link href="http://shuvalov.info/2014/04/23/akio-morita-sony"/>
    
      <content type="html" xml:base="http://shuvalov.info/">&lt;p style=&quot;width:280px; float:right;margin-left:1rem&quot;&gt;&lt;img src=&quot;/assets/articles-assets/akio-morita_sony.jpg&quot; alt=&quot;Отзыв о книге Акио Морита «Sony. Сделано в Японии»&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;em&gt;книга была опубликована в 1986 году&lt;/em&gt;).&lt;/p&gt;

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

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

&lt;p&gt;&lt;img src=&quot;/assets/articles-assets/america-vs-japan.jpg&quot; alt=&quot;Япония и Америка&quot; /&gt;&lt;/p&gt;

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

&lt;p&gt;Большая часть книги посвящена истории и философии компании Sony. Ценности, которые Акио Морита описал еще в 1986-ом актуальны и сейчас.&lt;/p&gt;

&lt;h4 id=&quot;о-философии-управления&quot;&gt;О философии управления&lt;/h4&gt;

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

&lt;h4 id=&quot;о-техпроцессе&quot;&gt;О техпроцессе&lt;/h4&gt;

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

&lt;h4 id=&quot;о-маркетинге-и-наивности&quot;&gt;О маркетинге и наивности&lt;/h4&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;h4 id=&quot;о-генри-форде&quot;&gt;О Генри Форде&lt;/h4&gt;

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

&lt;h3 id=&quot;о-киллер-фичах&quot;&gt;О киллер-фичах&lt;/h3&gt;

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

  &lt;p&gt;Через несколько дней я пригласил поиграть в гольф своего партнера по гольфу писателя Каору Седзи, и когда мы сели в машину, чтобы отправиться в мой клуб, я дал ему пару наушников и включил магнитофон. Я надел вторую пару наушников и наблюдал за выражением его лица. Он был удивлен и обрадован, услышав, как его жена пианистка Хироко Накамура исполняет концерт Грига для фортепиано. Он расплылся в улыбке и хотел что-то сказать, но не смог этого сделать, потому что мы оба сидели в наушниках. Я видел в этом потенциальную проблему. Я разрешил эту проблему, попросив своих сотрудников добавить к магнитофону кнопочный микрофон, чтобы два человека могли говорить друг с другом, не выключая музыки, так сказать, по «горячей линии связи».&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3 id=&quot;о-пивоте&quot;&gt;О пивоте&lt;/h3&gt;

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

&lt;h4 id=&quot;о-людях&quot;&gt;О людях&lt;/h4&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;h4 id=&quot;об-ошибках&quot;&gt;Об ошибках&lt;/h4&gt;

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

&lt;h2 id=&quot;заключение&quot;&gt;Заключение&lt;/h2&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;
</content>
  </entry>
  
  <entry>
    <title>Ссылколог-3</title>
    <updated>2014-04-21T00:00:00+00:00</updated>
    
      <id>http://shuvalov.info/2014/04/21/links-3</id>
      <link href="http://shuvalov.info/2014/04/21/links-3"/>
    
      <content type="html" xml:base="http://shuvalov.info/">&lt;p&gt;В этот раз всего четыре ссылки.&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;&lt;a href=&quot;http://bigspaceship.github.io/shine.js/&quot;&gt;«Библиотека для создания динамических теней на JavaScript»&lt;/a&gt; — крутая штука!&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;http://www.youtube.com/watch?v=d4hUeXxNzUA&quot;&gt;Доклад Бобука об управлении программистами&lt;/a&gt;.&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;http://www.richardrodger.com/monolithic-nodejs&quot;&gt;«Монолитный Node.js»&lt;/a&gt; — большая статья на английском о различиях
в проектировании приложений между Java и Node.js.&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;http://verakolotyuk.github.io/blog/2014/04/06/frontend-tools/&quot;&gt;«Выбор инструментов для фронтенд-разработки»&lt;/a&gt; — интересный пост
от Веры Колотюк о различных подходах, которые выбирают джуниоры, миддлы и
сеньоры.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;em&gt;Подписывайтесь на &lt;a href=&quot;http://feeds.feedburner.com/anton-shuvalov/FJHar&quot;&gt;РСС&lt;/a&gt;. 
Всем добра и штурмовиков&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/articles-assets/footer/trooper-4.jpg&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;

&lt;p class=&quot;photo-author&quot;&gt;&lt;em&gt;фото: &lt;a href=&quot;https://www.flickr.com/photos/jdhancock/&quot;&gt;jdhancock&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

</content>
  </entry>
  
  <entry>
    <title>Плагины для Sublime Text 3</title>
    <updated>2014-04-18T00:00:00+00:00</updated>
    
      <id>http://shuvalov.info/2014/04/18/sublime-text-3-plugins</id>
      <link href="http://shuvalov.info/2014/04/18/sublime-text-3-plugins"/>
    
      <content type="html" xml:base="http://shuvalov.info/">&lt;p&gt;&lt;img src=&quot;/assets/articles-assets/sublime.jpg&quot; alt=&quot;&amp;quot;Sublime Text 3&amp;quot;&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Еще несколько лет назад я был фанатом TextMate. Следуя заветам &lt;a href=&quot;http://www.ozon.ru/context/detail/id/24895168/&quot;&gt;Томаса и Ханта&lt;/a&gt;,
в этом редакторе я делал практически все, включая даже &lt;a href=&quot;/2012/06/23/Reading-mans-in-TextMate2/&quot;&gt;чтение манов&lt;/a&gt;. В то время
&lt;strong&gt;Sublime Text&lt;/strong&gt; лишь набирал популярность, и, в какой-то момент, я решил его
попробовать. В те времена с TextMate 2 творились странные вещи — эта версия,
в течение нескольких лет все еще была в альфе, и, похоже, не собиралась оттуда
выходить. Позднее, правда, TextMate стал опенсорсным, и разработка какое-то
время шла более активно, но я уже был далеко.&lt;/p&gt;

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

&lt;p&gt;И так…&lt;/p&gt;

&lt;h2 id=&quot;запуск-sublime-text-из-консоли&quot;&gt;Запуск Sublime Text из консоли&lt;/h2&gt;

&lt;p&gt;В Mac OS открыть любой файл или директорию из консоли в sublime можно так:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;open &lt;span class=&quot;nt&quot;&gt;-a&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;Sublime Text&quot;&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;.&lt;/span&gt;
&lt;span class=&quot;nb&quot;&gt;sudo &lt;/span&gt;open &lt;span class=&quot;nt&quot;&gt;-a&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;Sublime Text&quot;&lt;/span&gt; /etc/hosts&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;Для большего комфорта лучше использовать консольную утилиту, которая идет вкупе
с &lt;em&gt;Sublime Text&lt;/em&gt;. Устанавливается она так:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;&lt;span class=&quot;nb&quot;&gt;ln&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-s&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;/Applications/Sublime Text.app/Contents/SharedSupport/bin/subl&quot;&lt;/span&gt; /usr/local/bin/sublime&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;Кроме того, я сразу добавляю пару строк в &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;.zshrc&lt;/code&gt;:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;&lt;span class=&quot;nb&quot;&gt;alias &lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;s&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;'sublime'&lt;/span&gt; &lt;span class=&quot;c&quot;&gt;# теперь можно набирать `s .` вместо `sublime .`&lt;/span&gt;
&lt;span class=&quot;nb&quot;&gt;export &lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;EDITOR&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;'subl -w'&lt;/span&gt; &lt;span class=&quot;c&quot;&gt;# а так git commit будет открывать sublime вместо vi&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;h2 id=&quot;тема&quot;&gt;Тема&lt;/h2&gt;

&lt;p&gt;Практически во всех редакторах, с которыми я работаю, я использую тему
&lt;a href=&quot;http://joebergantine.com/projects/color-schemes/birds-of-paradise/&quot;&gt;Birds of Paradise&lt;/a&gt;. &lt;em&gt;Sublime&lt;/em&gt; не стал исключением, благо он умеет
импортировать темы из TextMate.&lt;/p&gt;

&lt;h2 id=&quot;линтинг&quot;&gt;Линтинг&lt;/h2&gt;

&lt;p&gt;Для линтинга JavaScript я использую &lt;a href=&quot;http://www.jshint.com/&quot;&gt;jshint&lt;/a&gt;. Для того, чтобы заставить
его работать в &lt;em&gt;sublime text 3&lt;/em&gt;, я использую комбинацию из двух плагинов:&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;&lt;a href=&quot;http://www.sublimelinter.com/en/latest/&quot;&gt;SublimeLinter&lt;/a&gt; — движок для большого количества различных линтеров;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://github.com/SublimeLinter/SublimeLinter-jshint&quot;&gt;SublimeLinter-jshint&lt;/a&gt; — собственно, сам линтер.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Мой &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;.jshintrc&lt;/code&gt; выглядит так &lt;em&gt;(в основном я пишу под nodejs)&lt;/em&gt;:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-javascript&quot; data-lang=&quot;javascript&quot;&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;browser&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;kc&quot;&gt;false&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;curly&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;kc&quot;&gt;true&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;expr&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;kc&quot;&gt;true&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;indent&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;kc&quot;&gt;false&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;jquery&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;kc&quot;&gt;false&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;laxcomma&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;kc&quot;&gt;true&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;laxbreak&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;kc&quot;&gt;true&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;maxcomplexity&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;mi&quot;&gt;10&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;maxdepth&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;mi&quot;&gt;3&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;maxparams&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;mi&quot;&gt;4&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;node&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;kc&quot;&gt;true&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;trailing&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;kc&quot;&gt;true&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;quotmark&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;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;single&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;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;strict&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;kc&quot;&gt;true&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;undef&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;kc&quot;&gt;true&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;Описание опций можно узнать &lt;a href=&quot;http://www.jshint.com/docs/options/&quot;&gt;здесь&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Кроме jshint-линтера можно присмотреться и к паре других: &lt;a href=&quot;https://github.com/SublimeLinter/SublimeLinter-jscs&quot;&gt;jscs&lt;/a&gt; и &lt;a href=&quot;https://github.com/SublimeLinter/SublimeLinter-csslint&quot;&gt;csslint&lt;/a&gt;.&lt;/p&gt;

&lt;h2 id=&quot;csscomb&quot;&gt;CSScomb&lt;/h2&gt;

&lt;p&gt;&lt;a href=&quot;http://csscomb.com/&quot;&gt;CSScomb&lt;/a&gt; — утилита для сортировки CSS-правил в селекторах не по алфавиту,
но по здравому смыслу, объединяя правила в логические группы. Последние полгода
я пишу на stylus, поэтому черной завистью завидую тем, кто может пользоваться
CSScomb и &lt;a href=&quot;https://github.com/csscomb/csscomb.js/issues/159&quot;&gt;жду, жду, жду, жду…&lt;/a&gt;&lt;/p&gt;

&lt;h2 id=&quot;git&quot;&gt;Git&lt;/h2&gt;

&lt;p&gt;Для интеграции с git мне хватает &lt;a href=&quot;http://www.jisaacks.com/gitgutter&quot;&gt;GitGutter&lt;/a&gt; — этот плагин отмечает еще
незакомиченные изменения в файле соответствующими значками на полях.&lt;/p&gt;

&lt;p&gt;Для всего остального я использую консоль и пайпы. К примеру, посмотреть &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;diff&lt;/code&gt;
всего коммита можно, набрав в терминале &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;git diff | s&lt;/code&gt;, так что мне вполне
хватает такой минималистичной интеграции.&lt;/p&gt;

&lt;h2 id=&quot;emmet&quot;&gt;Emmet&lt;/h2&gt;

&lt;p&gt;&lt;a href=&quot;http://emmet.io/&quot;&gt;Emmet&lt;/a&gt; — набор удобных сниппетов для html и css. Так, к примеру, лаконичное
&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;html:5&amp;gt;ul&amp;gt;li.item-$*5&amp;gt;span.title+span.author&lt;/code&gt; легким нажатием на &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;tab&lt;/code&gt; превращается в…&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-html&quot; data-lang=&quot;html&quot;&gt;&lt;span class=&quot;cp&quot;&gt;&amp;lt;!doctype html&amp;gt;&lt;/span&gt;
&lt;span class=&quot;nt&quot;&gt;&amp;lt;html&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;lang=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;en&quot;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;&amp;gt;&lt;/span&gt;
&lt;span class=&quot;nt&quot;&gt;&amp;lt;head&amp;gt;&lt;/span&gt;
  &lt;span class=&quot;nt&quot;&gt;&amp;lt;meta&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;charset=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;UTF-8&quot;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;&amp;gt;&lt;/span&gt;
  &lt;span class=&quot;nt&quot;&gt;&amp;lt;title&amp;gt;&lt;/span&gt;Document&lt;span class=&quot;nt&quot;&gt;&amp;lt;/title&amp;gt;&lt;/span&gt;
&lt;span class=&quot;nt&quot;&gt;&amp;lt;/head&amp;gt;&lt;/span&gt;
&lt;span class=&quot;nt&quot;&gt;&amp;lt;body&amp;gt;&lt;/span&gt;
  &lt;span class=&quot;nt&quot;&gt;&amp;lt;ul&amp;gt;&lt;/span&gt;
    &lt;span class=&quot;nt&quot;&gt;&amp;lt;li&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;class=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;item-1&quot;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;&amp;gt;&amp;lt;span&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;class=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;title&quot;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;&amp;gt;&amp;lt;/span&amp;gt;&amp;lt;span&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;class=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;author&quot;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;&amp;gt;&amp;lt;/span&amp;gt;&amp;lt;/li&amp;gt;&lt;/span&gt;
    &lt;span class=&quot;nt&quot;&gt;&amp;lt;li&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;class=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;item-2&quot;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;&amp;gt;&amp;lt;span&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;class=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;title&quot;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;&amp;gt;&amp;lt;/span&amp;gt;&amp;lt;span&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;class=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;author&quot;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;&amp;gt;&amp;lt;/span&amp;gt;&amp;lt;/li&amp;gt;&lt;/span&gt;
    &lt;span class=&quot;nt&quot;&gt;&amp;lt;li&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;class=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;item-3&quot;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;&amp;gt;&amp;lt;span&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;class=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;title&quot;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;&amp;gt;&amp;lt;/span&amp;gt;&amp;lt;span&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;class=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;author&quot;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;&amp;gt;&amp;lt;/span&amp;gt;&amp;lt;/li&amp;gt;&lt;/span&gt;
    &lt;span class=&quot;nt&quot;&gt;&amp;lt;li&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;class=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;item-4&quot;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;&amp;gt;&amp;lt;span&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;class=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;title&quot;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;&amp;gt;&amp;lt;/span&amp;gt;&amp;lt;span&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;class=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;author&quot;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;&amp;gt;&amp;lt;/span&amp;gt;&amp;lt;/li&amp;gt;&lt;/span&gt;
    &lt;span class=&quot;nt&quot;&gt;&amp;lt;li&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;class=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;item-5&quot;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;&amp;gt;&amp;lt;span&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;class=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;title&quot;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;&amp;gt;&amp;lt;/span&amp;gt;&amp;lt;span&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;class=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;author&quot;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;&amp;gt;&amp;lt;/span&amp;gt;&amp;lt;/li&amp;gt;&lt;/span&gt;
  &lt;span class=&quot;nt&quot;&gt;&amp;lt;/ul&amp;gt;&lt;/span&gt;
&lt;span class=&quot;nt&quot;&gt;&amp;lt;/body&amp;gt;&lt;/span&gt;
&lt;span class=&quot;nt&quot;&gt;&amp;lt;/html&amp;gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;h2 id=&quot;todoreview&quot;&gt;TodoReview&lt;/h2&gt;

&lt;p&gt;Я часто пишу todo-комментарии в коде, вроде такого: &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;/* TODO: переписать на промисы */&lt;/code&gt;.
&lt;a href=&quot;https://github.com/jonathandelgado/SublimeTodoReview&quot;&gt;TodoReview&lt;/a&gt; умеет находить все подобные коментарии в проекте и выводить их
в виде списка, чтобы можно было избавляться от технического долга систематически,
а не просто в очередной раз случайно наткнувшисть на оставленное замечание.&lt;/p&gt;

&lt;h2 id=&quot;sidebarenhancements&quot;&gt;SideBarEnhancements&lt;/h2&gt;

&lt;p&gt;&lt;a href=&quot;https://github.com/titoBouzout/SideBarEnhancements&quot;&gt;SideBarEnhancements&lt;/a&gt; учит не особенно-то и сговорчивый сайдбар sublime text’а
адекватному взаимодействию с файлами: копированию, вставке, удалению, и тд.&lt;/p&gt;

&lt;h2 id=&quot;разное&quot;&gt;Разное&lt;/h2&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;a href=&quot;https://github.com/SublimeText/WordCount&quot;&gt;WordCount&lt;/a&gt; — счетчик слов и символов в документе. Меленькая полезная
штука для оценки размера переводов и статей.&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://github.com/BoundInCode/AutoFileName&quot;&gt;autoFilename&lt;/a&gt; — удобный автокомплит путей к файлам.&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://github.com/jfromaniello/sublime-node-require&quot;&gt;sublime-node-require&lt;/a&gt; — удобная утилита для написания
&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;require()&lt;/code&gt;-конструкций в NodeJS. Предлагает список из всех установленных
в проекте модулей, автоматически подставляя правильные пути к ним.&lt;/li&gt;
  &lt;li&gt;Ну и куча всяких библиотек сниппетов и подсветок: &lt;em&gt;stylus, mocha, jade, html5, less,
handlebars, ect…&lt;/em&gt; Ссылки давать не буду, потому что они элементарно находятся
поиском.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;em&gt;На этом, кажется, все. Подписывайтесь на &lt;a href=&quot;http://feeds.feedburner.com/anton-shuvalov/FJHar&quot;&gt;РСС&lt;/a&gt;.
Всем добра и штурмовиков&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/articles-assets/footer/trooper-2.jpg&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;

&lt;p style=&quot;text-align:right&quot;&gt;&lt;em&gt;фото: &lt;a href=&quot;https://www.flickr.com/photos/jdhancock/&quot;&gt;jdhancock&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

</content>
  </entry>
  
  <entry>
    <title>Сфокусируйтесь!</title>
    <updated>2014-04-15T00:00:00+00:00</updated>
    
      <id>http://shuvalov.info/2014/04/15/resources</id>
      <link href="http://shuvalov.info/2014/04/15/resources"/>
    
      <content type="html" xml:base="http://shuvalov.info/">&lt;p&gt;&lt;img src=&quot;/assets/articles-assets/picrandom/trooper-hero.jpg&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Много воды утекло с тех пор, когда ученые начали понимать принципы работы
силы воли. Сейчас об этом можно найти много информации. К примеру, можно почесть
&lt;a href=&quot;http://www.ozon.ru/context/detail/id/19157509/&quot;&gt;«Силу привычки» Чарльза Дахигга&lt;/a&gt; или статью &lt;a href=&quot;http://www.uxfox.ru/your-app-makes-me-fat/&quot;&gt;«Я из-за вашего приложения полнею!»&lt;/a&gt;.
В общем-то, под впечатлением от Дахигга я это и пишу. Так вот, как мне кажется,
сила воли является одной из фундаментальных основ продуктивности, дизайна и,
в какой-то степени, осознание ее устройства помогает делать людей счастливее.&lt;/p&gt;

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

&lt;p&gt;&lt;img src=&quot;/assets/articles-assets/picrandom/trooper-1.jpg&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Можно подвести маленький итог. Сила воли — ресурс конечный, и тратится он
на концентрацию и переживания, с которыми сегодня приходится сталкиваться
практически постоянно: медленный непродуманный интерфейс, пробки, страх опоздания,
internet explorer 8, переключение фокуса, медленный 3G, социальные сети, мудак,
припарковшийся на тротуаре… Миллионы причин.&lt;/p&gt;

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

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

&lt;p&gt;&lt;em&gt;Подписывайтесь на &lt;a href=&quot;http://feeds.feedburner.com/anton-shuvalov/FJHar&quot;&gt;РСС&lt;/a&gt;. 
Всем добра и штурмовиков&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/articles-assets/footer/trooper-3.jpg&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;

&lt;p style=&quot;text-align:right&quot;&gt;&lt;em&gt;фото: &lt;a href=&quot;https://www.flickr.com/photos/jdhancock/&quot;&gt;jdhancock&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

</content>
  </entry>
  
  <entry>
    <title>Ссылколог-2</title>
    <updated>2014-04-14T00:00:00+00:00</updated>
    
      <id>http://shuvalov.info/2014/04/14/links-2</id>
      <link href="http://shuvalov.info/2014/04/14/links-2"/>
    
      <content type="html" xml:base="http://shuvalov.info/">&lt;ol&gt;
  &lt;li&gt;&lt;a href=&quot;http://typejournal.ru/articles/0039-Krichevsky-Manifesto&quot;&gt;«25 полемических суждений не в пользу шрифтоцентризма»&lt;/a&gt; — очень интересная
статья Владимира Кричевского о переоцененности роли шрифта в типографике.&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;http://www.opennet.ru/opennews/art.shtml?num=38016&quot;&gt;«Интервью с Алексеем Кузнецовым»&lt;/a&gt; — Алексей, один
из создателей сетевого стека Linux, рассказывает о пути до мейнтейнера Linux,
работе над ядром, зарождении Git, Линусе и других интересных вещах.&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;http://sixrevisions.com/css/css-effects-libraries/&quot;&gt;Небольшая подборка библиотек CSS-анимаций&lt;/a&gt;. Сайты с хорошей анимацией —
это очень круто! Главное не переборщить с этим.&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;http://eax.me/turnover/&quot;&gt;«Как зацепить и удержать программиста»&lt;/a&gt; — Александр Алексеев о том, почему
в одних компаниях интереснее других.&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;http://tenphi.me/article/13-04-2014-extends-natives&quot;&gt;Расширение Natives в JavaScript&lt;/a&gt; — Андрей Яманов о библиотеке Sugar.js 
и плюсах от расширения нативных объектов в JavaScript.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;em&gt;Подписывайтесь на &lt;a href=&quot;http://feeds.feedburner.com/anton-shuvalov/FJHar&quot;&gt;РСС&lt;/a&gt;. Всем добра и штурмовиков&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/articles-assets/footer/trooper-1.jpg&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;

</content>
  </entry>
  
  <entry>
    <title>Заметки по книге «Getting Real», 37Signals</title>
    <updated>2014-04-11T00:00:00+00:00</updated>
    
      <id>http://shuvalov.info/2014/04/11/getting-real</id>
      <link href="http://shuvalov.info/2014/04/11/getting-real"/>
    
      <content type="html" xml:base="http://shuvalov.info/">&lt;p style=&quot;width:280px; float:right;margin-left:1rem&quot;&gt;&lt;img src=&quot;/assets/articles-assets/getting-real.jpg&quot; alt=&quot;Programmer Grumpy Cat&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Я продолжаю разбирать старые заметки. На этот раз настал черед «Getting Real».
Эту книгу я прочитал где-то в начале зимы. Из книги можно вынести много всего
интересного, но как мне кажется, предназначена она скорее project owner’ам —
после прочтения появляется навязчивое желание запустить хороший проект. Но,
увы, у многих это желание натолкнется на реальность, которая, зачастую, не рада
таким порывам. &lt;em&gt;Ха-ха…&lt;/em&gt;&lt;/p&gt;

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

&lt;p&gt;Основная идея книги заключается в выпуске MVP-продукта в достаточно строго
ограниченное время. Для этого 37Signals предлагают уделить серьезное
внимание приоритетам задач, отложить в сторону свой перфекционизм и просто
выпустить пусть не идеальный, но рабочий продукт. Этой философии приоритетов и
ограничений подвергаются и все этапы создания проекта: дизайн, менеджмент,
разработка.&lt;/p&gt;

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

&lt;p&gt;Заметок оказалось не очень много. Честно говоря, я уже не помню почему.&lt;/p&gt;

&lt;h2 id=&quot;заметки&quot;&gt;Заметки&lt;/h2&gt;

&lt;h3 id=&quot;о-клиентах&quot;&gt;О клиентах&lt;/h3&gt;

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

&lt;h3 id=&quot;миссия-проекта-или-компании&quot;&gt;Миссия проекта или компании&lt;/h3&gt;

&lt;blockquote&gt;
  &lt;p&gt;&lt;strong&gt;Создавайте молитвы&lt;/strong&gt;. Организациям нужны указательные столбы. Им нужен план;
работникам каждый день нужно знать, когда они просыпаются, почему они
собираются идти на работу. Этот план должен быть кратким и сладким,
и затрагивать все: Почему вы существуете? Как это мотивируете? Я называю
это молитвой — &lt;strong&gt;описание в трех-четырех словах причин, по которым вы
существуете&lt;/strong&gt;. Гай Кавасаки&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3 id=&quot;о-внимании-к-деталям&quot;&gt;О внимании к деталям&lt;/h3&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;/blockquote&gt;

&lt;h3 id=&quot;о-масштабе-проекта&quot;&gt;О масштабе проекта&lt;/h3&gt;

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

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

&lt;p&gt;Подписывайтесь на &lt;a href=&quot;http://feeds.feedburner.com/anton-shuvalov/FJHar&quot;&gt;РСС&lt;/a&gt;, читайте &lt;a href=&quot;/&quot;&gt;другие статьи&lt;/a&gt;. 
Всем добра и котиков:&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/articles-assets/cats/2.jpg&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;
</content>
  </entry>
  
  <entry>
    <title>Ссылколог-1</title>
    <updated>2014-04-10T00:00:00+00:00</updated>
    
      <id>http://shuvalov.info/2014/04/10/links-1</id>
      <link href="http://shuvalov.info/2014/04/10/links-1"/>
    
      <content type="html" xml:base="http://shuvalov.info/">&lt;p&gt;Решил делать регулярные подборки интересных ссылок. По большей части, ссылки
будут по веб-разработке, JavaScript и дизайну, но, я постараюсь этим
не ограничиваться.&lt;/p&gt;

&lt;p&gt;Чтобы ничего не пропустить, подписывайтесь на &lt;a href=&quot;http://feeds.feedburner.com/anton-shuvalov/FJHar&quot;&gt;РСС-рассылку&lt;/a&gt;. На всякий случай,
вот котик:&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/articles-assets/linkolog-1.jpg&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;&lt;a href=&quot;http://frontender.info/partial-application-in-javascript-using-bind/&quot;&gt;Частичное применение функций в JavaScript с помощью bind()&lt;/a&gt; — любопытный
перевод статьи о каррировании функций в JS.&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://develop.re/&quot;&gt;Develop.re&lt;/a&gt; — Рахим запустил социальный аггрегатор ссылок
для разработчиков. Я уже узнал оттуда кучу ссылок на интересные блоги,
подкасты и другие ништяки.&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;http://vstarkov.ru/learning-programming/&quot;&gt;«Как научиться программировать с нуля?»&lt;/a&gt; — Вова Старков опубликовал небольшой
список полезных материалов для &lt;em&gt;«юнош бледных со взором горящим»&lt;/em&gt;.&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;http://addyosmani.com/blog/removing-unused-css/&quot;&gt;Spring-cleaning Unused CSS With Grunt, Gulp, Broccoli or Brunch&lt;/a&gt; —
Эдди Османи о рассказывает о своей утилите для удаления неиспользуемого CSS-кода
при сборке проекта.&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;http://scrollrevealjs.org/&quot;&gt;ScrollReveal.js&lt;/a&gt; — маленькая библиотека для простых scroll-driven анимаций.
Теперь и я использую ее, прямо в этом блоге.&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://github.com/akoenig/imacss&quot;&gt;imacss&lt;/a&gt; — CLI-утилита для компиляции изображений в CSS-файл с data-URI.&lt;/li&gt;
  &lt;li&gt;Список советов о пользовательском интерфейсе в трех частях: &lt;a href=&quot;http://habrahabr.ru/company/adv/blog/186846/&quot;&gt;один&lt;/a&gt;, &lt;a href=&quot;http://www.uxfox.ru/goodui1/&quot;&gt;два&lt;/a&gt;, &lt;a href=&quot;http://www.uxfox.ru/goodui2/&quot;&gt;три&lt;/a&gt;.&lt;/li&gt;
  &lt;li&gt;По &lt;a href=&quot;http://blog.codinghorror.com/the-principle-of-least-power/&quot;&gt;закону Этвуда&lt;/a&gt; любое приложение, которое может быть написано на JavaScript,
в конце концов, будет написано на JavaScript. Собственно, вот.
&lt;a href=&quot;http://glyphrstudio.com&quot;&gt;Glyphr Studio — бесплатный, редактор шрифтов написанный на JS&lt;/a&gt;.&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;http://www.minimallyminimal.com/blog/sony-walkman-tps-l2&quot;&gt;Эндрю Ким о Sony Walkman TPS-L2&lt;/a&gt; — хорошие фотографии хорошего дизайна
легендарного плеера Sony. Руководство Sony сомневалось в успехе этого продукта,
на что Акио Морита заявил: &lt;em&gt;«Если мы не продадим до конца года сто тысяч
проигрывателей, я уйду в отставку с поста председателя компании»&lt;/em&gt;.&lt;/li&gt;
&lt;/ol&gt;

</content>
  </entry>
  
  <entry>
    <title>Заметки по книге «Как пасти котов», Рейнвотер Дж.Ханк</title>
    <updated>2014-04-07T00:00:00+00:00</updated>
    
      <id>http://shuvalov.info/2014/04/07/herding-cats</id>
      <link href="http://shuvalov.info/2014/04/07/herding-cats"/>
    
      <content type="html" xml:base="http://shuvalov.info/">&lt;p&gt;&lt;img src=&quot;/assets/articles-assets/cat.jpg&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Рейнвотера я прочитал достаточно давно, но так и не собрался написать о ней.
И вот, недавно, разбирая mind map’ы по прочитанным в прошлом году книгам, я
наткнулся на заметки, которые я делал в процессе чтения.&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;Не удивляйтесь тому, что вы чувствуете себя некомфортно в новой роли.
Ощущение комфорта появится, наверное, через месяцев 6 или 12.&lt;/li&gt;
  &lt;li&gt;Песики, преданно смотрящие в глаза не нужны. Нужны хорошие программисты,
не смотря на все их странности.&lt;/li&gt;
  &lt;li&gt;Важные навыки руководителя — это наставничество, терпение и
проницательность.&lt;/li&gt;
  &lt;li&gt;Элегантность — это достижимое совершенство.&lt;/li&gt;
  &lt;li&gt;70% стоимости ПО — это сопровождение. &lt;em&gt;Как следствие, этим можно оправдать
и тесты и элегантный код. С последним, правда, есть нюансы&lt;/em&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;/li&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;li&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;/li&gt;
  &lt;li&gt;Для встречи с коллективом хватит одного раза в неделю.&lt;/li&gt;
  &lt;li&gt;45 минут на совещание более чем достаточно.&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;/li&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;li&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;/li&gt;
  &lt;li&gt;&lt;em&gt;Не стоит постоянно отвлекаться на skype&lt;/em&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;a href=&quot;http://www.ozon.ru/context/detail/id/5605699/&quot;&gt;Ссылка на Ozon&lt;/a&gt;&lt;/p&gt;

</content>
  </entry>
  
  <entry>
    <title>Автоматизация задач с помощью npm run</title>
    <updated>2014-04-05T00:00:00+00:00</updated>
    
      <link href="http://frontender.info/task_automation_with_npm_run/"/>
    
      <content type="html" xml:base="http://shuvalov.info/">
</content>
  </entry>
  
  <entry>
    <title>Мысли о RESTful API</title>
    <updated>2014-04-03T00:00:00+00:00</updated>
    
      <id>http://shuvalov.info/2014/04/03/restful-api</id>
      <link href="http://shuvalov.info/2014/04/03/restful-api"/>
    
      <content type="html" xml:base="http://shuvalov.info/">&lt;p&gt;Я не буду писать о том, что RESTful ни на что не годится, и место его где-то
в анналах истории, среди неудачных экспериментов. Но вот свое уверенное
«Awesome!» по отношению к нему станет немного более сдержанным. Вообще, &lt;a href=&quot;/2014/03/02/boobs-driven-development/&quot;&gt;с моим
отношением к категоричностям&lt;/a&gt;, меня очень и очень радует, что я обнаружил
очередное бревно в своем глазу.&lt;/p&gt;

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

&lt;p&gt;К примеру, у нас есть метод, который по маршруту &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;/users/:userId&lt;/code&gt; возвращает,
скажем, такой объект:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-javascript&quot; data-lang=&quot;javascript&quot;&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;nl&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;String&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;nx&quot;&gt;surname&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;String&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;nx&quot;&gt;nickame&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;String&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
  &lt;span class=&quot;nx&quot;&gt;friends&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;type&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;String&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;na&quot;&gt;ref&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;User&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;p&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;И вот, появилась у нас задача — кроме массива &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;id&lt;/code&gt; друзей, покоящегося в поле
&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;friends&lt;/code&gt;, получать еще и их имена и ники — нет проблем! У нас же RESTful! Мы
просто воспользуемся нашим известным маршрутом, и выполним запрос &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;/users/:userId&lt;/code&gt;
для каждого дружеского &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;id&lt;/code&gt;. А позднее, разработчик API допишет новый
метод для получения массива всех друзей друзей. Или не напишет — все ведь и так
замечательно работает.&lt;/p&gt;

&lt;p&gt;А графы? Мы ведь можем написать приложение которое будет рекурсивно запрашивать
&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;id&lt;/code&gt; друзей и строить граф связей. Право слово, это великолепно!&lt;/p&gt;

&lt;p&gt;Серьезно. Представьте, смог бы я сделать что-то подобное, если бы у меня
не было такого метода, а был бы какой-нибудь &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;/init-app&lt;/code&gt;, возвращающий мне
пользователя, его друзей и еще пару полезных штук, на основе информации,
попавшей в сессию после авторизации? Думаю, это было бы не легко. Добавим
толику хаоса — наша система будет эволюционировать, и вероятность
того, что метод &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;/init-app&lt;/code&gt; серьезно поменяется гораздо выше, чем у метода
&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;/users/:userId&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;И вот я сижу и смотрю на iOS-приложение, которое, только во время открытия,
шлет около двадцати запросов на мой замечательный RESTful-сервер. Сижу и думаю,
не лучше ли сделать парочку комплексных методов, которые бы решали конкретные
задачи, далекие от воздушных замков RESTful API? Что будет важнее в условиях
сомнительного качества 3G: гибкость REST или гораздо меньшие транспортные расходы
в комплексном API?&lt;/p&gt;

&lt;p&gt;А может быть я просто не умею RESTful?&lt;/p&gt;

</content>
  </entry>
  
  <entry>
    <title>Радости и печали программистов</title>
    <updated>2014-03-31T00:00:00+00:00</updated>
    
      <id>http://shuvalov.info/2014/03/31/brooks-motivation</id>
      <link href="http://shuvalov.info/2014/03/31/brooks-motivation"/>
    
      <content type="html" xml:base="http://shuvalov.info/">&lt;p&gt;&lt;img src=&quot;/assets/articles-assets/brooks-cover.jpg&quot; alt=&quot;Мифический человеко-месяц&quot; class=&quot;img-right&quot; /&gt;
Отсылку к этой цитате впервые я обнаружил в книге Ханка Рейнвотера «Как пасти котов»,
где она была дана тезисно, в сжатом виде.&lt;/p&gt;

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

&lt;p&gt;И вот, я решил исправить эту досадную оплошность и, заодно, поделиться с вами
этой замечательной цитатой.&lt;/p&gt;

&lt;blockquote&gt;

  &lt;h3 id=&quot;радости-профессии&quot;&gt;Радости профессии&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;/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;h3 id=&quot;печали-профессии&quot;&gt;Печали профессии&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;/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;/blockquote&gt;
</content>
  </entry>
  
  <entry>
    <title>Коллекция мотивирующих фильмов</title>
    <updated>2014-03-20T00:00:00+00:00</updated>
    
      <id>http://shuvalov.info/2014/03/20/my-favorite-movies</id>
      <link href="http://shuvalov.info/2014/03/20/my-favorite-movies"/>
    
      <content type="html" xml:base="http://shuvalov.info/">&lt;p&gt;Хочу поделиться списком фильмов, которые произвели на меня сильное впечатление.
Истории этих фильмов реальны, хотя некоторые приукрашены режиссерами, поставленны
под нужным углам, выстроенны с точки зрения правильного драматического развития,
саспенса, катарсиса, и других хитрых режиссерских штук, но все таки, эти истории, черт
подери, остаются реальными. Это потрясает.&lt;/p&gt;

&lt;h2 id=&quot;indie-games-the-movie&quot;&gt;&lt;a href=&quot;http://www.kinopoisk.ru/film/661199/&quot;&gt;Indie Games: The Movie&lt;/a&gt;&lt;/h2&gt;

&lt;div class=&quot;triptych&quot;&gt;
  &lt;img class=&quot;triptych__left&quot; src=&quot;/assets/articles-assets/movies/indie-poster.jpg&quot; alt=&quot;&quot; /&gt;
  &lt;img class=&quot;triptych__right-top&quot; src=&quot;/assets/articles-assets/movies/indie-1.jpg&quot; alt=&quot;&quot; /&gt;
  &lt;img class=&quot;triptych__right-bottom&quot; src=&quot;/assets/articles-assets/movies/indie-2.jpg&quot; style=&quot;&quot; alt=&quot;&quot; /&gt;
&lt;/div&gt;

&lt;p&gt;История трех инди-игр: Super Meat Boy, FEZ и Braid. Я пересматривал этот фильм
три раза. Меня восхищает увлеченность этих людей, которую вряд ли
можно сопоставить с любым энтерпрайзом: эти люди живут своей игрой
настолько сильно, что даже не верится что такое вообще возможно.&lt;/p&gt;

&lt;h2 id=&quot;senna&quot;&gt;&lt;a href=&quot;http://www.kinopoisk.ru/film/573209/&quot;&gt;Senna&lt;/a&gt;&lt;/h2&gt;

&lt;div class=&quot;triptych&quot;&gt;
  &lt;img class=&quot;triptych__right&quot; src=&quot;/assets/articles-assets/movies/senna-poster.jpg&quot; alt=&quot;&quot; /&gt;
  &lt;img class=&quot;triptych__left-top&quot; src=&quot;/assets/articles-assets/movies/senna-1.jpg&quot; alt=&quot;&quot; /&gt;
  &lt;img class=&quot;triptych__left-bottom&quot; src=&quot;/assets/articles-assets/movies/senna-2.jpg&quot; style=&quot;&quot; alt=&quot;&quot; /&gt;
&lt;/div&gt;

&lt;p&gt;Документальный фильм. Аэртон Сенна — один из выдающихся гонщиков F1. 
Целеустремленность этого человека впечатляет.&lt;/p&gt;

&lt;h2 id=&quot;presspauseplay&quot;&gt;&lt;a href=&quot;http://www.kinopoisk.ru/film/579234/&quot;&gt;PressPausePlay&lt;/a&gt;&lt;/h2&gt;

&lt;div class=&quot;triptych&quot;&gt;
  &lt;img class=&quot;triptych__left&quot; src=&quot;/assets/articles-assets/movies/presspauseplay-poster.jpg&quot; alt=&quot;&quot; /&gt;
  &lt;img class=&quot;triptych__right-top&quot; src=&quot;/assets/articles-assets/movies/presspauseplay-1.jpg&quot; alt=&quot;&quot; /&gt;
  &lt;img class=&quot;triptych__right-bottom&quot; src=&quot;/assets/articles-assets/movies/presspauseplay-2.jpg&quot; style=&quot;&quot; alt=&quot;&quot; /&gt;
&lt;/div&gt;

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

&lt;h3 id=&quot;пираты-силиконовой-долины&quot;&gt;&lt;a href=&quot;http://www.kinopoisk.ru/film/95636/&quot;&gt;Пираты силиконовой долины&lt;/a&gt;&lt;/h3&gt;

&lt;div class=&quot;triptych&quot;&gt;
  &lt;img class=&quot;triptych__right&quot; src=&quot;/assets/articles-assets/movies/pirates-poster.jpg&quot; alt=&quot;&quot; /&gt;
  &lt;img class=&quot;triptych__left-top&quot; src=&quot;/assets/articles-assets/movies/pirates-1.jpg&quot; alt=&quot;&quot; /&gt;
  &lt;img class=&quot;triptych__left-bottom&quot; src=&quot;/assets/articles-assets/movies/pirates-2.jpg&quot; style=&quot;&quot; alt=&quot;&quot; /&gt;
&lt;/div&gt;

&lt;p&gt;История двух людей и двух компаний. Apple и Microsoft. Джобс и Гейтс.&lt;/p&gt;

&lt;h3 id=&quot;tpb-afk-the-pirate-bay-away-from-keyboard&quot;&gt;&lt;a href=&quot;http://www.kinopoisk.ru/film/731222/&quot;&gt;TPB AFK: The Pirate Bay Away from Keyboard&lt;/a&gt;&lt;/h3&gt;

&lt;div class=&quot;triptych&quot;&gt;
  &lt;img class=&quot;triptych__left&quot; src=&quot;/assets/articles-assets/movies/tpbafk-poster.jpg&quot; alt=&quot;&quot; /&gt;
  &lt;img class=&quot;triptych__right-top&quot; src=&quot;/assets/articles-assets/movies/tpbafk-1.jpg&quot; alt=&quot;&quot; /&gt;
  &lt;img class=&quot;triptych__right-bottom&quot; src=&quot;/assets/articles-assets/movies/tpbafk-2.jpg&quot; style=&quot;&quot; alt=&quot;&quot; /&gt;
&lt;/div&gt;

&lt;p&gt;История торрент-трекера The Pirate Bay и команды, которая работала над ним.&lt;/p&gt;

&lt;h3 id=&quot;objectified&quot;&gt;&lt;a href=&quot;http://www.kinopoisk.ru/film/453105/&quot;&gt;Objectified&lt;/a&gt;&lt;/h3&gt;

&lt;div class=&quot;triptych&quot;&gt;
  &lt;img class=&quot;triptych__right&quot; src=&quot;/assets/articles-assets/movies/objectified-poster.jpg&quot; alt=&quot;&quot; /&gt;
  &lt;img class=&quot;triptych__left-top&quot; src=&quot;/assets/articles-assets/movies/objectified-1.jpg&quot; alt=&quot;&quot; /&gt;
  &lt;img class=&quot;triptych__left-bottom&quot; src=&quot;/assets/articles-assets/movies/objectified-2.jpg&quot; style=&quot;&quot; alt=&quot;&quot; /&gt;
&lt;/div&gt;

&lt;p&gt;Фильм о разностороннем мире промышленного дизайна.&lt;/p&gt;

&lt;h3 id=&quot;minecraft-история-mojang&quot;&gt;&lt;a href=&quot;http://www.kinopoisk.ru/film/732205/&quot;&gt;Minecraft: История Mojang&lt;/a&gt;&lt;/h3&gt;

&lt;div class=&quot;triptych&quot;&gt;
  &lt;img class=&quot;triptych__left&quot; src=&quot;/assets/articles-assets/movies/minecraft-poster.jpg&quot; alt=&quot;&quot; /&gt;
  &lt;img class=&quot;triptych__right-top&quot; src=&quot;/assets/articles-assets/movies/minecraft-1.jpg&quot; alt=&quot;&quot; /&gt;
  &lt;img class=&quot;triptych__right-bottom&quot; src=&quot;/assets/articles-assets/movies/minecraft-2.jpg&quot; style=&quot;&quot; alt=&quot;&quot; /&gt;
&lt;/div&gt;

&lt;p&gt;Еще один фильм об играх. Minecraft, пожалуй, игра-легенда.&lt;/p&gt;

&lt;h3 id=&quot;helvetica&quot;&gt;&lt;a href=&quot;http://www.kinopoisk.ru/film/261122/&quot;&gt;Helvetica&lt;/a&gt;&lt;/h3&gt;

&lt;div class=&quot;triptych&quot;&gt;
  &lt;img class=&quot;triptych__right&quot; src=&quot;/assets/articles-assets/movies/helvetica-poster.jpg&quot; alt=&quot;&quot; /&gt;
  &lt;img class=&quot;triptych__left-top&quot; src=&quot;/assets/articles-assets/movies/helvetica-1.jpg&quot; alt=&quot;&quot; /&gt;
  &lt;img class=&quot;triptych__left-bottom&quot; src=&quot;/assets/articles-assets/movies/helvetica-2.jpg&quot; style=&quot;&quot; alt=&quot;&quot; /&gt;
&lt;/div&gt;

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

&lt;p&gt;Будет очень круто, если в комментариях вы поделитесь впечатлившими вас фильмами.
Особенно, если они о настоящих историях.&lt;/p&gt;
</content>
  </entry>
  
  <entry>
    <title>Первый ленточный магнитофон Sony</title>
    <updated>2014-03-19T00:00:00+00:00</updated>
    
      <id>http://shuvalov.info/2014/03/19/sony</id>
      <link href="http://shuvalov.info/2014/03/19/sony"/>
    
      <content type="html" xml:base="http://shuvalov.info/">&lt;p&gt;Несколько дней назад я начал читать книгу Акио Мориты «Sony. Сделано в Японии»,
и вот сегодня я наткнулся но очень интересный отрывок. «Горькое
разочарование», о котором пишет Морита, подчас настигает как стартапы, так и
огромные компании, пустившиеся в погоню за инновациями. Речь идет об одной из
самых обидных из проблем, с которыми можно столкнуться на этом тернистом пути.&lt;/p&gt;

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

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

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

&lt;p&gt;Дальше я еще не прочитал, но мне стало очень интересно, что бы было, если бы
история компании Sony закончилась после этой неудачи?&lt;/p&gt;
</content>
  </entry>
  
  <entry>
    <title>О сиськах и о программировании</title>
    <updated>2014-03-02T00:00:00+00:00</updated>
    
      <id>http://shuvalov.info/2014/03/02/boobs-driven-development</id>
      <link href="http://shuvalov.info/2014/03/02/boobs-driven-development"/>
    
      <content type="html" xml:base="http://shuvalov.info/">&lt;p&gt;Когда мне было лет четырнадцать, в угоду возрасту, мы часто говорили с друзьями
о девочках. В одном из таких разговоров, речь зашла о силиконовых сиськах. И 
вот мы начали всячески порицать это дело с видом бравых хирургов: неестественно
трогать, выглядит отстойно, для здоровья вредно, да вообще плохо это.&lt;/p&gt;

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

&lt;p&gt;Nuff said.&lt;/p&gt;

&lt;p&gt;Изо дня в день, в различных разговорах о программировании, я слышу мнения
диванных экспертов: «JavaScript решает проблемы, которых до него
не существовало!», «MongoDB — это круто, но потом нужно будет все же
нормальную базу сделать», «NodeJS — течет, и его никто не использует, а если 
использует, то в очень редких случаях», «PHP — отстой, там на каждый запрос 
новый тред», «Erlang — единственный нормальный язык», «Он — интроверт, 
интровертам нельзя управлять людьми», «У нас дороги плохие, а вот в Америке-то 
не так!» и тд.&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;
</content>
  </entry>
  
  <entry>
    <title>Попробовал в TDD. Люто-бешено доставляет</title>
    <updated>2014-02-17T00:00:00+00:00</updated>
    
      <id>http://shuvalov.info/2014/02/17/TDD</id>
      <link href="http://shuvalov.info/2014/02/17/TDD"/>
    
      <content type="html" xml:base="http://shuvalov.info/">&lt;p&gt;На самом деле — нет. Немного не TDD. Думаю, что правильнее назвать это 
стремлением к 100%-покрытию кода тестами: у меня нет «красненьких» и 
«зелененьких» этапов и рефакторинга после n-ного цикла. А иногда (бог ты мой)
я пишу код до написания тестов.&lt;/p&gt;

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

&lt;h2 id=&quot;однажды-в-подъезде-друзья-предложили-мне-попробовать-тесты&quot;&gt;Однажды в подъезде друзья предложили мне попробовать тесты…&lt;/h2&gt;

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

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;npm i &lt;span class=&quot;nt&quot;&gt;-S&lt;/span&gt; my-awesome-module&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;Большинство модулей, которые я находил в npm или на GitHub имели тесты. Более
того, они использовали CI-сервис «Travis», который автоматически тестировал
каждый коммит и пулл-реквест. Тогда мне это казалось каким-то излишеством.
Я помню, как я разбирался с устройством LocomotiveJS, и &lt;a href=&quot;https://github.com/jaredhanson/utils-merge&quot;&gt;наткнулся на модуль&lt;/a&gt;,
который я затем показывал друзьям и говорил: «Ребята! Я решил писать так!».&lt;/p&gt;

&lt;p&gt;Шутил, значит.&lt;/p&gt;

&lt;p&gt;Вообще, код &lt;a href=&quot;https://github.com/jaredhanson/&quot;&gt;@jaredhanson&lt;/a&gt; мне очень нравится. Изучая его я заметил, что
некоторые тесты — всего лишь проверка типа в &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;module.exports&lt;/code&gt;.&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-javascript&quot; data-lang=&quot;javascript&quot;&gt;&lt;span class=&quot;kd&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;merge&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;require&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;../index&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;nx&quot;&gt;describe&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;utils-merge&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;kd&quot;&gt;function&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;it&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;should export function&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;kd&quot;&gt;function&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;expect&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;merge&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;).&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;to&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;be&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;a&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;function&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;p&quot;&gt;});&lt;/span&gt;
  
&lt;span class=&quot;p&quot;&gt;});&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;Тут-то я и задумал попробовать тесты. Написать такую штуку можно очень быстро.
А «Travis.CI», прогнав тест, скажет мне наверняка — глупой ошибки синтаксиса
в коде нет. Кроме того, очень быстро можно написать assert’ы, которые будут
проверять соответствие результатов нашим ожиданиям.&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-javascript&quot; data-lang=&quot;javascript&quot;&gt;&lt;span class=&quot;nx&quot;&gt;describe&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;merge&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;kd&quot;&gt;function&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;describe&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;an object&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;kd&quot;&gt;function&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;var&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;a&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;foo&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;bar&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;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;b&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;bar&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;baz&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;kd&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;o&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;merge&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;a&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;b&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
    
    &lt;span class=&quot;nx&quot;&gt;it&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;should merge properties into first object&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;kd&quot;&gt;function&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;expect&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;Object&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;keys&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;a&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)).&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;to&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;have&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;mi&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
      &lt;span class=&quot;nx&quot;&gt;expect&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;a&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;foo&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;).&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;to&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;be&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;equal&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;bar&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;nx&quot;&gt;expect&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;a&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;bar&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;).&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;to&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;be&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;equal&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;baz&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;p&quot;&gt;});&lt;/span&gt;
    
    &lt;span class=&quot;nx&quot;&gt;it&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;should return first argument&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;kd&quot;&gt;function&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;expect&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;o&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;).&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;to&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;be&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;equal&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;a&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;c1&quot;&gt;// ...&lt;/span&gt;

&lt;span class=&quot;p&quot;&gt;});&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;Сейчас в моем проекте есть файл с тестами поведения API ExpressJS в котором
около 1500 строк. Большинство из них — assert’ы, написанные банальной 
копипастой. Нет, это не очень-то правильно. Да, это работает.&lt;/p&gt;

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

&lt;h2 id=&quot;коллеги-я-вот-приду-сейчас-домой-и-точно-напишу-документацию&quot;&gt;Коллеги, я вот приду сейчас домой и точно напишу документацию!&lt;/h2&gt;

&lt;p&gt;Еще одна полезная особенность тестов — это документация. Идея писать тесты
на свой код посетила меня еще и потому, что я стал с завидной регулярностью
находить себя читающим тесты, а не докуменацию. А началось это с того, что я,
разбираясь с MongooseJS, не смог понять, почему же в моем случае &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;.populate()&lt;/code&gt;
работает совсем не так, как я этого ожидал. Тесты, в отличии от документации,
оказались более полными. Возможно, даже более понятными.&lt;/p&gt;

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

&lt;p&gt;Вот только, в отличии от документации, тесты всегда актуальны. 1:0, 
документация!&lt;/p&gt;

&lt;h2 id=&quot;эти-ваши-состояния-потока&quot;&gt;Эти ваши «состояния потока»&lt;/h2&gt;

&lt;p&gt;Я помню, как еще год назад мне приходилось держать в голове детали устройства
системы, чтобы понимать, в каком месте может появиться брешь при добавлении
очередной фичи. Затем, значит, во время разработки фичи я, достаточно регулярно
сталкивался с непроясненными требованиями: «В каком виде возвращать значения?»,
«Боже мой! Мы же не договорились, как он загрузит файл! А вдруг…», «В ТЗ ничего
об этом не было, а я забыл спросить менеджера!»… Все это вырывало мой аватар
из состояния «потока», и перемещало его в сказочно-прекрасное состояние
«ПАНИКААА!!!111121 МНЕ ЖЕ ЗАВТРА НАДО!!!!1». Да и вообще, регулярно отвлекаясь
на чтение обычно весьма косноречивых ТЗ, я так боюсь расплескать свою чашу
концентрации.&lt;/p&gt;

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

&lt;p&gt;А еще я ленив. Сейчас я вспоминаю, как я «тестировал» другое приложение, тоже
на express, в Postman, руками отправляя запросы, вглядываясь в прыгающие
в глазах буквы и цифры в теле ответа. Все это отнимает драгоценную 
концентрацию, &lt;a href=&quot;http://www.uxfox.ru/your-app-makes-me-fat/&quot;&gt;я становлюсь толстым&lt;/a&gt;. А если подумать, сколько полезного 
времени уходит на это? Ведь тестировать приходится не один, и даже не 10 раз.&lt;/p&gt;

&lt;h2 id=&quot;сейчас-мы-тут-костылик-напишем-но-завтра-обязательно-все-исправим&quot;&gt;Сейчас мы тут костылик напишем, но завтра обязательно все исправим&lt;/h2&gt;

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

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

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

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

&lt;p&gt;&lt;img src=&quot;https://raw2.github.com/shuvalov-anton/anton-shuvalov.info/gh-pages/assets/articles-assets/tests.jpg&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;

&lt;h2 id=&quot;кода&quot;&gt;Кода&lt;/h2&gt;

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

&lt;p&gt;А теперь я бы хотел попросить вас, друзья, о совете. Очевидно, что TDD — это
не просто набор тестов. Так же очевидно, что люди, которые разработали эту
методологию — отличные ребята. Я бы хотел попросить вас, друзья, посоветовать
мне книгу, которую стоит обязательно прочитать, чтобы нормально научиться «в TDD».&lt;/p&gt;

</content>
  </entry>
  
  <entry>
    <title>Gulp или Grunt, да всё равно</title>
    <updated>2014-02-04T00:00:00+00:00</updated>
    
      <link href="http://frontender.info/gulp-grunt-whatever/"/>
    
      <content type="html" xml:base="http://shuvalov.info/">
</content>
  </entry>
  
  <entry>
    <title>Реализация оператора new в JavaScript</title>
    <updated>2014-01-20T00:00:00+00:00</updated>
    
      <id>http://shuvalov.info/2014/01/20/operator-new</id>
      <link href="http://shuvalov.info/2014/01/20/operator-new"/>
    
      <content type="html" xml:base="http://shuvalov.info/">&lt;p&gt;Вот небольшой фрагмент кода, который очень грубо реализует логику работы 
оператора new в JavaScript.&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-javascript&quot; data-lang=&quot;javascript&quot;&gt;&lt;span class=&quot;kd&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;newOperator&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;Constr&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;args&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;var&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;thisValue&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;Object&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;create&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;Constr&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;prototype&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;// (1)&lt;/span&gt;
  &lt;span class=&quot;kd&quot;&gt;var&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;nx&quot;&gt;Constr&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;apply&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;thisValue&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;args&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;k&quot;&gt;typeof&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;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;object&lt;/span&gt;&lt;span class=&quot;dl&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;result&lt;/span&gt; &lt;span class=&quot;o&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;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;c1&quot;&gt;// (2)&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;thisValue&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;/figure&gt;

&lt;ol&gt;
  &lt;li&gt;Прототип нового объекта, порождаемого конструктором &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Constr&lt;/code&gt;, — это &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Constr.prototype&lt;/code&gt;.&lt;/li&gt;
  &lt;li&gt;В реализации конструктора можно переопределить стандартное поведение, когда
оператор &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;new&lt;/code&gt; возвращает &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;this&lt;/code&gt;, возвращая объект. Это может быть полезным,
когда конструктор должен вернуть инстанс суб-конструктора.&lt;/li&gt;
&lt;/ol&gt;
</content>
  </entry>
  
  <entry>
    <title>Перевод книги Эдди Османи «Паттерны для масштабируемых JavaScript-приложений»</title>
    <updated>2014-01-18T00:00:00+00:00</updated>
    
      <link href="http://largescalejs.ru"/>
    
      <content type="html" xml:base="http://shuvalov.info/">
</content>
  </entry>
  
  <entry>
    <title>node-clusterize-cli — кластеризация NodeJS web-сервера</title>
    <updated>2014-01-13T00:00:00+00:00</updated>
    
      <link href="http://habrahabr.ru/post/208914/"/>
    
      <content type="html" xml:base="http://shuvalov.info/">&lt;p&gt;Последние полгода я занимаюсь разработкой достаточно большого web-приложения,
под капотом которого ревет и дымится NodeJS. Когда дело дошло до деплоя
на продакшн я задумался: «почему бы мне не использовать несколько тредов
с инстансом приложения?».&lt;/p&gt;

&lt;p&gt;Реализовав кластер, я увидел, что производительность от его использования
возросла &lt;a href=&quot;https://gist.github.com/shuvalov-anton/8399476&quot;&gt;в 1,5 раза&lt;/a&gt;, что очень даже не плохо,
учитывая малый объем потраченных усилий. Но я решил не останавливаться на этом,
и сделать удобный CLI для работы с кластером, чтобы отвязать код, который
отвечает за запуск кластера от конкретного приложения. Кроме того, очень
хотелось демонизировать кластер, чтобы он висел себе молча в процессах, поднимал
упавшие воркеры, писал в логи, и никого больше не отвлекал.&lt;/p&gt;

&lt;p&gt;Так появился &lt;a href=&quot;https://github.com/shuvalov-anton/node-clusterize-cli&quot;&gt;node-clusterize-cli&lt;/a&gt;.&lt;/p&gt;

&lt;h3 id=&quot;механизм-работы&quot;&gt;Механизм работы&lt;/h3&gt;

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

&lt;h3 id=&quot;использование&quot;&gt;Использование&lt;/h3&gt;

&lt;p&gt;В общем-то, все банально:&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;// Установка глобального модуля
$ npm i -g node-clusterize-cli
// Запуск кластера
$ clusterize --app ./app.js --workers 32 --log ./cluster.log
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Так же, для удобства есть метод для получения списка запущенных кластеров,
и метод для их убийства:&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;// фактически, алиас `ps -eo pid,comm | grep &quot;clusterize master&quot;`
$ clusterize list 
53416 app.js
// алиас на `kill -9 CLUSTER_PID`
$ clusterize kill 53416
&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;clusterize -h&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;https://github.com/shuvalov-anton/node-clusterize-cli&quot;&gt;репозиторий на GitHub&lt;/a&gt;
&lt;a href=&quot;https://gist.github.com/shuvalov-anton/8399476&quot;&gt;Логи нагрузочных тестов ab&lt;/a&gt;&lt;/p&gt;

</content>
  </entry>
  
  <entry>
    <title>Make Streak, Not Holywars</title>
    <updated>2013-12-15T00:00:00+00:00</updated>
    
      <id>http://shuvalov.info/2013/12/15/make-streak-not-holywars</id>
      <link href="http://shuvalov.info/2013/12/15/make-streak-not-holywars"/>
    
      <content type="html" xml:base="http://shuvalov.info/">&lt;p&gt;В какой-то момент я присмотрелся к панели «Your Contributions» в своем 
&lt;a href=&quot;https://github.com/shuvalov-anton/&quot;&gt;профайле на GitHub&lt;/a&gt;. Помню, я тогда подумал что-то типа: «Какого черта
мой аккаунт выглядит так заброшенно!? Это же не так!»&lt;/p&gt;

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

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

&lt;h2 id=&quot;npm&quot;&gt;NPM&lt;/h2&gt;

&lt;p&gt;Последние полгода я пишу под NodeJS. В комплекте с Node идет отличный менеджер
зависимостей — «&lt;a href=&quot;https://npmjs.org/&quot;&gt;npm&lt;/a&gt;». Как благородный NodeJS-кун, я, конечно же, что-то
там &lt;a href=&quot;https://npmjs.org/~shuvalov-anton&quot;&gt;публикую&lt;/a&gt;. Обычно, это небольшие и достаточно независимые компоненты которые
я планирую довести до ума и применить где-то еще. Вот только выношу я что-то
достаточно редко. Обычно лень.&lt;/p&gt;

&lt;h2 id=&quot;лень&quot;&gt;Лень&lt;/h2&gt;

&lt;p&gt;Да, лень! Лень обдумать ответственность компонента. Лень чистить его от хлама.
Лень выносить в независимый модуль. Лень его потом поддерживать. Сам смотри:&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;Скачивай репозиторий,&lt;/li&gt;
  &lt;li&gt;вноси правки,&lt;/li&gt;
  &lt;li&gt;заливай на GitHub,&lt;/li&gt;
  &lt;li&gt;публикуй в npm,&lt;/li&gt;
  &lt;li&gt;обновляй зависимость в своем проекте.&lt;/li&gt;
&lt;/ol&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;Я думаю, что по большей части, проблему поддержки модулей можно решить тестами
и граммотным проектированием. И первому и второму можно научиться в процессе. 
Ну ошибешься ты при проектировании API, ну придется тебе что-то там серьезно
менять. Отлично! Намотаешь на ус.&lt;/p&gt;

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

&lt;ol&gt;
  &lt;li&gt;Сама необходимость создавать независимые модули помогает развивать навык проектирования.&lt;/li&gt;
  &lt;li&gt;Так как ты работаешь не с монолитным крепко связанным гордиевым узлом кода, 
а с набором модулей, то ошибки становятся более локализованными, 
следовательно легче анализировать те или иные факапы.&lt;/li&gt;
  &lt;li&gt;Фидбек от пользователей, пулл-реквесты, комьюнити, если конечно, повезет.&lt;/li&gt;
  &lt;li&gt;Приятно получить сообщение: «Ты идиот! Неужели ты не знал о библиотеке X,
которая делает в точности то же самое, только лучше!?». Сидишь ты в своем
вакууме, создаешь не пойми что, а тут человек показал, что, дескать, все это
за тебя уже сделали. А ты такой не в курсе.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Мне нравится то что я делаю, и я хочу делать это лучше. Поэтому, 30 дней назад,
я решил уделять больше внимания опенсорсу.&lt;/p&gt;

&lt;h2 id=&quot;итоги&quot;&gt;Итоги&lt;/h2&gt;

&lt;p&gt;В течение последних 30 дней я ежедневно что-то писал на GitHub. Гарантированный
результат, который я получу за это — опыт. Если это окажется не единственным,
что я получу в итоге — я буду визжать как сучка от радости!&lt;/p&gt;

&lt;p&gt;За этот месяц я наконец-то хоть как-то разобрался с юнит-тестами, узнал, как
создавать CLI с помощью NodeJS, наконец-то отрефакторил свой блог, написал
плагин для GruntJS, пару переводов во &lt;a href=&quot;http://frontender.info/&quot;&gt;Frontender Magazine&lt;/a&gt;. Кроме того, я
выяснил и опробовал на практике кучу тонкостей языка, пополнил свои сниппеты,
сделал пару полезных утилит, и обзавелся массой интересных идей.&lt;/p&gt;

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

&lt;p&gt;&lt;img src=&quot;/assets/articles-assets/suck-you.jpg&quot; alt=&quot;'Sucking at something is the first step to becoming sorta good at something'&quot; /&gt;&lt;/p&gt;

</content>
  </entry>
  
  <entry>
    <title>JavaScript, apply, массивы</title>
    <updated>2013-12-07T00:00:00+00:00</updated>
    
      <id>http://shuvalov.info/2013/12/07/apply</id>
      <link href="http://shuvalov.info/2013/12/07/apply"/>
    
      <content type="html" xml:base="http://shuvalov.info/">&lt;p&gt;Совсем недавно увидел, как &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;.apply&lt;/code&gt; может выступать адаптером для функций,
которые не принимают аргументы в виде массива. Самый простой пример — это
обертка над… Предположим &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Array.push&lt;/code&gt;:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-javascript&quot; data-lang=&quot;javascript&quot;&gt;&lt;span class=&quot;kd&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;arr&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;Array&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;();&lt;/span&gt;
&lt;span class=&quot;nx&quot;&gt;arr&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;pushAndLog&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;function&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;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;nx&quot;&gt;arguments&lt;/span&gt;&lt;span class=&quot;p&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;push&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&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;arr&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;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
&lt;span class=&quot;nx&quot;&gt;arr&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;pushAndLog&lt;/span&gt;&lt;span class=&quot;p&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;mi&quot;&gt;3&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;4&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&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;nx&quot;&gt;arr&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;// [1,[2,3,4]]&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;Как видно, arguments так и отправились массивом. Отправить 
каждый элемент массива как аргумент функции поможет &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;.apply&lt;/code&gt;:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-javascript&quot; data-lang=&quot;javascript&quot;&gt;&lt;span class=&quot;kd&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;arr&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;Array&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;();&lt;/span&gt;
&lt;span class=&quot;nx&quot;&gt;arr&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;pushAndLog&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;function&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;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;nx&quot;&gt;arguments&lt;/span&gt;&lt;span class=&quot;p&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;push&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;apply&lt;/span&gt;&lt;span class=&quot;p&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;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;arr&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;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
&lt;span class=&quot;nx&quot;&gt;arr&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;pushAndLog&lt;/span&gt;&lt;span class=&quot;p&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;mi&quot;&gt;3&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;4&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&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;nx&quot;&gt;arr&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;// [1,2,3,4]&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;h2 id=&quot;примеры&quot;&gt;Примеры&lt;/h2&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-javascript&quot; data-lang=&quot;javascript&quot;&gt;&lt;span class=&quot;cm&quot;&gt;/**
 * https://github.com/shuvalov-anton/express-mvc-routes/
 *
 * Здесь .apply используется для вызова app[method] с заранее 
 * неизвестным количеством аргументов.
 */&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;prototype&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;createRoute&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;function&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;options&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;var&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;args&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;var&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;nx&quot;&gt;options&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;urls&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;o&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&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;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;--&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;args&lt;/span&gt;&lt;span class=&quot;p&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;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;options&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;urls&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;args&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&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;options&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;middlewares&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;options&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;controller&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;args&lt;/span&gt;&lt;span class=&quot;p&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;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;options&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;controller&lt;/span&gt;&lt;span class=&quot;p&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;app&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;options&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;method&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;].&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;apply&lt;/span&gt;&lt;span class=&quot;p&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;app&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;args&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;/figure&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-javascript&quot; data-lang=&quot;javascript&quot;&gt;&lt;span class=&quot;cm&quot;&gt;/**
 * http://www.2ality.com/2013/11/initializing-arrays.html
 * 
 * А вот еще пример посложнее. .apply здесь используется для генерации
 * массива со значениями по умолчанию [0,1,2, ...]
 */&lt;/span&gt;
&lt;span class=&quot;kd&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;arr&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;Array&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;apply&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;nb&quot;&gt;Array&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;10&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;kd&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;x&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;span class=&quot;k&quot;&gt;return&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;/code&gt;&lt;/pre&gt;&lt;/figure&gt;
</content>
  </entry>
  
  <entry>
    <title>Если в терминале не работают приложения node.js </title>
    <updated>2013-12-06T00:00:00+00:00</updated>
    
      <id>http://shuvalov.info/2013/12/06/nodejs-path</id>
      <link href="http://shuvalov.info/2013/12/06/nodejs-path"/>
    
      <content type="html" xml:base="http://shuvalov.info/">&lt;p&gt;Для того, чтобы научить node.js приложения работать в консоли придется добавить
в переменную окружения &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;$PATH&lt;/code&gt; путь к приложениям nodejs.&lt;/p&gt;

&lt;p&gt;Один из способов сделать это — добавить следующую строку в файл &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;~/.profiles&lt;/code&gt;:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;&lt;span class=&quot;nb&quot;&gt;export &lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;PATH&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;/usr/local/share/npm/bin/:&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;$PATH&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;
</content>
  </entry>
  
  <entry>
    <title>Как работает event loop в Node.js</title>
    <updated>2013-12-03T00:00:00+00:00</updated>
    
      <link href="http://frontender.info/understanding-the-node-js-event-loop/"/>
    
      <content type="html" xml:base="http://shuvalov.info/">
</content>
  </entry>
  
  <entry>
    <title>Правильные модули</title>
    <updated>2013-11-22T00:00:00+00:00</updated>
    
      <link href="http://frontender.info/modules-the-right-way/"/>
    
      <content type="html" xml:base="http://shuvalov.info/">
</content>
  </entry>
  
  <entry>
    <title>Basic-авторизация в Express.js</title>
    <updated>2013-11-13T00:00:00+00:00</updated>
    
      <link href="http://habrahabr.ru/post/201924/"/>
    
      <content type="html" xml:base="http://shuvalov.info/">
</content>
  </entry>
  
  <entry>
    <title>Как устроен Passport.js</title>
    <updated>2013-11-07T00:00:00+00:00</updated>
    
      <link href="http://habrahabr.ru/post/201206/"/>
    
      <content type="html" xml:base="http://shuvalov.info/">
</content>
  </entry>
  
  <entry>
    <title>Дизайнер, архитектор, разработчик</title>
    <updated>2013-11-04T00:00:00+00:00</updated>
    
      <link href="http://habrahabr.ru/post/200746/"/>
    
      <content type="html" xml:base="http://shuvalov.info/">
</content>
  </entry>
  
  <entry>
    <title>Сравнение скорости выполнения функций в JavaScript</title>
    <updated>2013-10-24T00:00:00+00:00</updated>
    
      <id>http://shuvalov.info/2013/10/24/profiling</id>
      <link href="http://shuvalov.info/2013/10/24/profiling"/>
    
      <content type="html" xml:base="http://shuvalov.info/">&lt;h2 id=&quot;что-круче-числа-или-строки&quot;&gt;Что круче: числа или строки?&lt;/h2&gt;

&lt;p&gt;Часто возникает желание узнать, что же все-таки круче: «A» или «B». Например,
сегодня я задумался — насколько медленнее работает поиск по подстроке против
чисел. Да-да, именно так «насколько медленнее…». Задача — реализация прав
доступа.&lt;/p&gt;

&lt;h2 id=&quot;экспозиция&quot;&gt;Экспозиция&lt;/h2&gt;

&lt;ul&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;Unix Way&lt;/strong&gt;: права задаются в виде восьмеричного числа, которое 
конвертируется в двоичное, и каждый разряд этого числа отвечает за определенный
тип прав. Например 5 в восмеричной — это 101 в двоичной. И теперь по порядку: 
1 — администрирование, 0 — нет редактирования, 1 — чтение.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;Строки&lt;/strong&gt;: права задаются в виде строки которая состоит из букв «rwa», 
где «r» — чтение, «w» — редактирование, «a» — администрирование.&lt;/p&gt;
  &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Для меня было очевидно, что поиск по подстроке должен быть медленнее,
чем «простая математика». Но мне было интересно, на сколько медленнее.
Я ждал каких-то космических значений, ибо гениальное unix-way решение выглядело
очень по-гиковски. Мне казалось, что разница должна была быть в раза в три.&lt;/p&gt;

&lt;h2 id=&quot;как-узнать-что-же-круче&quot;&gt;Как узнать, что же круче?!&lt;/h2&gt;

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

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-javascript&quot; data-lang=&quot;javascript&quot;&gt;&lt;span class=&quot;cm&quot;&gt;/** 
 * from: habrahabr.ru/ somewhere in comments
 * Полезная штука для того, чтобы оценить какой оператор или конструкция быстрее.
 */&lt;/span&gt;
&lt;span class=&quot;kd&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;count&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;q&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;){&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;profile&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;while&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;q&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;nx&quot;&gt;f&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;console&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;profileEnd&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;function&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;f1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;x&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;k&quot;&gt;typeof&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;x&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;undefined&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;p&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;kd&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;f2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;x&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;k&quot;&gt;typeof&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;x&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;===&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;undefined&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;p&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;nx&quot;&gt;count&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;f1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;10000000000&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
&lt;span class=&quot;nx&quot;&gt;count&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;f2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;10000000000&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;h2 id=&quot;нууу1-что-круче111один&quot;&gt;Нууу!!1 Что круче??!!111один&lt;/h2&gt;

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

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-javascript&quot; data-lang=&quot;javascript&quot;&gt;&lt;span class=&quot;kd&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;count&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;q&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;){&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;profile&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;while&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;q&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;nx&quot;&gt;f&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;console&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;profileEnd&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;function&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;f1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;x&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;){&lt;/span&gt;
    &lt;span class=&quot;kd&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;data&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;mi&quot;&gt;7&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;5&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&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;var&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;data&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;var&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;r&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;data&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;r&lt;/span&gt;&lt;span class=&quot;p&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;o&quot;&gt;==&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&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;read&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;false&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
      &lt;span class=&quot;nx&quot;&gt;r&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&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;mi&quot;&gt;1&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;write&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;false&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
      &lt;span class=&quot;nx&quot;&gt;r&lt;/span&gt;&lt;span class=&quot;p&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;o&quot;&gt;==&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&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;admin&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;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;p&quot;&gt;}&lt;/span&gt;


&lt;span class=&quot;kd&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;f2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;x&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;){&lt;/span&gt;
    &lt;span class=&quot;kd&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;data&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;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;r&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;rw&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;rwa&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;for&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kd&quot;&gt;var&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;data&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;var&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;r&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;data&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;o&quot;&gt;~&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;r&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;indexOf&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;r&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;p&quot;&gt;?&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;read&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;false&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;o&quot;&gt;~&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;r&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;indexOf&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;w&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;p&quot;&gt;?&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;write&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;false&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;o&quot;&gt;~&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;r&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;indexOf&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;a&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;p&quot;&gt;?&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;admin&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;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;p&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;nx&quot;&gt;count&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;f1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;10000000&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
&lt;span class=&quot;nx&quot;&gt;count&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;f2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;10000000&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;h2 id=&quot;отвечай1&quot;&gt;Отвечай!!!!1&lt;/h2&gt;

&lt;p&gt;Неожиданно, все вышло совсем не так. Числа знатно прососали буквам.
Мир никогда не будет прежним. Смотрите сами:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;strong&gt;Unix Way&lt;/strong&gt;: 5962ms&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Строки&lt;/strong&gt;: 4989ms&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;мораль&quot;&gt;Мораль&lt;/h2&gt;

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

&lt;h2 id=&quot;на-самом-деле-нет&quot;&gt;На самом деле нет&lt;/h2&gt;

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

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-javascript&quot; data-lang=&quot;javascript&quot;&gt;&lt;span class=&quot;kd&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;f1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;x&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;){&lt;/span&gt;
    &lt;span class=&quot;kd&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;data&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;mi&quot;&gt;7&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;5&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&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;var&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;data&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;var&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;r&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;data&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;r&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;amp;&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&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;read&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;false&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
      &lt;span class=&quot;nx&quot;&gt;r&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;amp;&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;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;write&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;false&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
      &lt;span class=&quot;nx&quot;&gt;r&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;amp;&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;4&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;admin&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;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;p&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;И тогда-то числа и начнут знатно нагибать строки. Примерно раз в 20.&lt;/p&gt;

&lt;p&gt;Это вернуло мне веру в мир.&lt;/p&gt;
</content>
  </entry>
  
  <entry>
    <title>Классификация русского текста с помощью Natural на NodeJS</title>
    <updated>2013-09-14T00:00:00+00:00</updated>
    
      <link href="http://habrahabr.ru/post/193738/"/>
    
      <content type="html" xml:base="http://shuvalov.info/">
</content>
  </entry>
  
  <entry>
    <title>Опыт работы с GruntJS</title>
    <updated>2013-09-09T00:00:00+00:00</updated>
    
      <link href="http://habrahabr.ru/post/193092/"/>
    
      <content type="html" xml:base="http://shuvalov.info/">
</content>
  </entry>
  
  <entry>
    <title>Что посмотреть JavaScript разработчику</title>
    <updated>2013-08-20T00:00:00+00:00</updated>
    
      <id>http://shuvalov.info/2013/08/20/video</id>
      <link href="http://shuvalov.info/2013/08/20/video"/>
    
      <content type="html" xml:base="http://shuvalov.info/">&lt;p&gt;Поделюсь небольшой подборкой полезных видео по JavaScript.&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;a href=&quot;http://discover-devtools.codeschool.com/&quot;&gt;Курс по инспектору Chrome&lt;/a&gt; — 
  очень полезный интерактивный курс по работе с инспектором. От основ 
  до хардкорных штук, типа профилирования памяти.&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;http://learn.javascript.ru/nodejs-screencast&quot;&gt;Скринкасты по NodeJS на русском языке&lt;/a&gt; — высшие скринкасты по NodeJS 
  от создателя &lt;a href=&quot;http://javascript.ru&quot;&gt;javascript.ru&lt;/a&gt;.&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;http://video.yandex.ru/users/ya-events/view/1233/?cauthor=ya-events&amp;amp;cid=90&quot;&gt;Что помогает нам писать качественный JavaScript-код?&lt;/a&gt; — 
  Дмитрий Щадей из Яндекса рассказыает об использовании JSHint, CSS Lint, 
  Git Hooks, code review и pull requests во благо проекта.&lt;/li&gt;
&lt;/ul&gt;

</content>
  </entry>
  
  <entry>
    <title>Инструменты frontend-разработчика. Утилиты</title>
    <updated>2013-08-17T00:00:00+00:00</updated>
    
      <id>http://shuvalov.info/2013/08/17/tools</id>
      <link href="http://shuvalov.info/2013/08/17/tools"/>
    
      <content type="html" xml:base="http://shuvalov.info/">&lt;p&gt;Я думаю что будет полезно, если я расскажу об инструментах, которые я использую
в работе. По крайней мере, если меня спросят: «Какие знания могут пригодиться
разработчику интерфейсов», то я смогу сослаться на этот пост.&lt;/p&gt;

&lt;h2 id=&quot;утилиты&quot;&gt;Утилиты&lt;/h2&gt;

&lt;h3 id=&quot;oh-my-zsh&quot;&gt;OH-MY-ZSH&lt;/h3&gt;

&lt;p&gt;ZSH — это интерактивный шелл, гораздо более удобный, чем bash. &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;oh-my-zsh&lt;/code&gt; — это
фреймворк для ZSH с огромным количеством всевозможных плагинов и удобных штук,
которые делают работу в консоли намного проще.&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;a href=&quot;https://github.com/robbyrussell/oh-my-zsh&quot;&gt;Сайт проекта&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://github.com/miripiruni/dotfiles&quot;&gt;dotfiles от miripiruni с хорошими конфигами для oh-my-zsh&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h3 id=&quot;git&quot;&gt;Git&lt;/h3&gt;

&lt;p&gt;Git — отличная система контроля версий. Если вам нечего скрывать — то можно 
хостить репозитории со своими проектами на &lt;a href=&quot;http://github.com&quot;&gt;GitHub&lt;/a&gt;. Мне
очень нравится.&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;a href=&quot;http://git-scm.com/&quot;&gt;Сайт проекта&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;http://githowto.com/ru/git_how_to&quot;&gt;Хороший учебник на русском языке&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;http://git-scm.com/book/ru&quot;&gt;Перевод книги «Pro Git»&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h3 id=&quot;grunt&quot;&gt;Grunt&lt;/h3&gt;

&lt;p&gt;Grunt — это инструмент для сборки javascript проектов из командной строки
с использованием задач. Не совру, если скажу, что плагины для Grunt.js есть
под любую задачу. Недавно я видел &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;yo&lt;/code&gt;-генератор, в котором Grunt.js
использовался для коммита файлов в git. Деплой проекта, компиляция шаблонов
(jade, mustache, все что угодно), css-препроцессинг — на все есть плагины.&lt;/p&gt;

&lt;p&gt;Советую быть осторожней с этой штукой. Вызывает привыкание.&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;a href=&quot;http://gruntjs.com/&quot;&gt;Сайт проекта&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;http://video.yandex.ru/users/ya-events/view/1018/&quot;&gt;Хороший, но немного устаревший доклад Артёма Сапегина&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h3 id=&quot;jshint&quot;&gt;JSHint&lt;/h3&gt;

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

&lt;ul&gt;
  &lt;li&gt;&lt;a href=&quot;http://www.jshint.com/&quot;&gt;Сайт проекта&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://github.com/SublimeLinter/SublimeLinter&quot;&gt;Плагин для Sublime Text 2&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://github.com/shuvalov-anton/.dotfiles/blob/master/.jshintrc&quot;&gt;Мой настройки для JSHint&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h3 id=&quot;csscomb&quot;&gt;CSSComb&lt;/h3&gt;

&lt;p&gt;CSSComb — инструмент для логической сортировки CSS-правил. Я абсолютно согласен
с автором, что сортировать css правила по алфавату — за гранью добра и зла. 
Хуже только не сортировать правила вовсе. Этот инструмент поможет во все проекте 
придерживаться единого порядка в CSS, не затрачивая на это больших усилий&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;a href=&quot;http://csscomb.ru/&quot;&gt;Сайт проекта&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://vimeo.com/channels/wstdays/34212051&quot;&gt;Доклад автора&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h3 id=&quot;yeoman-generators&quot;&gt;Yeoman Generators&lt;/h3&gt;

&lt;p&gt;Yeoman Generators — это инструмент для генерации базовой структуры(скафолда) 
приложений. Генераторов много. Backbone, Angular, Node, Knockout, Grunt, AMD, 
CoffeeScript. NodeJS утилиы, сайты, плагины для GruntJS… MVC, MVVM… 
С помощью YO можно создавать и расширять структуру проекта буквально одной 
командой.&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;a href=&quot;http://yeoman.io/generators.html&quot;&gt;Сайт проекта&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://github.com/yeoman/generator-backbone&quot;&gt;generator-backbone&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h3 id=&quot;nodejs-и-npm&quot;&gt;NodeJS и NPM&lt;/h3&gt;

&lt;p&gt;NodeJS — это JavaScript на сервере. Сверхбыстрый, сверхгибкий. В гибкости
не последнюю роль играет &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;npm&lt;/code&gt; — пакетный менеджер для node.js. Во-первых, 
в нем есть все. А во вторых, все чего нет в &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;npm&lt;/code&gt; можно написать и выложить
туда.&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;a href=&quot;http://nodejs.org/&quot;&gt;Сайт NodeJS&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;a href=&quot;http://npmjs.org/&quot;&gt;Сайт NPM&lt;/a&gt;&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;http://learn.javascript.ru/nodejs-screencast&quot;&gt;Отличный скринкаст от автора javascrit.ru&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;hr /&gt;

&lt;p&gt;Я постараюсь дополнять этот пост, чтобы ничего не забыть&lt;/p&gt;
</content>
  </entry>
  
  <entry>
    <title>Как создать npm пакеты</title>
    <updated>2013-04-19T00:00:00+00:00</updated>
    
      <link href="http://habrahabr.ru/post/177465/"/>
    
      <content type="html" xml:base="http://shuvalov.info/">
</content>
  </entry>
  
  <entry>
    <title>Стеки и очереди в JavaScript</title>
    <updated>2013-03-21T00:00:00+00:00</updated>
    
      <id>http://shuvalov.info/2013/03/21/stack-and-queue</id>
      <link href="http://shuvalov.info/2013/03/21/stack-and-queue"/>
    
      <content type="html" xml:base="http://shuvalov.info/">&lt;p&gt;Так получилось, что я только недавно узнал о &lt;em&gt;стеках&lt;/em&gt; и &lt;em&gt;очередях&lt;/em&gt;. Точнее, раньше 
я знал, что они существуют, и думал, что это одно и то же. Сначала я узнал о том,
что &lt;em&gt;стек&lt;/em&gt; — &lt;em&gt;не очередь&lt;/em&gt;, затем я узнал о реализации стека
с помощью “push” и “pop”. А потом я захотел таких же простых методов, 
но для реализации &lt;em&gt;очереди на JavaScript&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;Итак…&lt;/p&gt;

&lt;h2 id=&quot;стек-в-javascript&quot;&gt;Стек в JavaScript&lt;/h2&gt;

&lt;blockquote&gt;
  &lt;p&gt;&lt;em&gt;Стек&lt;/em&gt; (англ. stack — стопка) — структура данных, представляющая из себя список
элементов организованных по принципу LIFO (англ. last in — first out, «последним
пришёл — первым вышел»).
Чаще всего принцип работы стека сравнивают со стопкой тарелок: чтобы взять вторую
сверху, нужно снять верхнюю.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;div style=&quot;text-align:right;font-style:italic;&quot;&gt;Википедия&lt;/div&gt;

&lt;h3 id=&quot;реализация-стека-в-javascript&quot;&gt;Реализация стека в JavaScript&lt;/h3&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-javascript&quot; data-lang=&quot;javascript&quot;&gt;&lt;span class=&quot;kd&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;stack&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;c1&quot;&gt;// []&lt;/span&gt;
&lt;span class=&quot;nx&quot;&gt;stack&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;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;first&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;c1&quot;&gt;// stack === [&quot;first&quot;]&lt;/span&gt;
&lt;span class=&quot;nx&quot;&gt;stack&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;mi&quot;&gt;10&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;20&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;  &lt;span class=&quot;c1&quot;&gt;// stack === [&quot;first&quot;, 10, 20]&lt;/span&gt;
&lt;span class=&quot;kd&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;el&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;stack&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;pop&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;();&lt;/span&gt;  &lt;span class=&quot;c1&quot;&gt;// stack === [&quot;first&quot;, 10] &amp;amp;&amp;amp; el === 20&lt;/span&gt;
&lt;span class=&quot;nx&quot;&gt;stack&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;mi&quot;&gt;2&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;       &lt;span class=&quot;c1&quot;&gt;// stack === [&quot;first&quot;, 10, 2]&lt;/span&gt;
&lt;span class=&quot;nx&quot;&gt;el&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;stack&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;pop&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;();&lt;/span&gt;      &lt;span class=&quot;c1&quot;&gt;// stack === [&quot;first&quot;, 10] &amp;amp;&amp;amp; el === 2&lt;/span&gt;
&lt;span class=&quot;nx&quot;&gt;el&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;stack&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;pop&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;();&lt;/span&gt;      &lt;span class=&quot;c1&quot;&gt;// stack === [&quot;first&quot;] el = 10&lt;/span&gt;
&lt;span class=&quot;nx&quot;&gt;el&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;stack&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;pop&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;();&lt;/span&gt;      &lt;span class=&quot;c1&quot;&gt;// stack === [] &amp;amp;&amp;amp; el === &quot;first&quot;&lt;/span&gt;
&lt;span class=&quot;nx&quot;&gt;el&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;stack&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;pop&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;();&lt;/span&gt;      &lt;span class=&quot;c1&quot;&gt;// stack === [] &amp;amp;&amp;amp; typeof el === &quot;undefined&quot;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;h1 id=&quot;очередь-в-javascript&quot;&gt;Очередь в JavaScript&lt;/h1&gt;

&lt;blockquote&gt;
  &lt;p&gt;&lt;em&gt;Очередь&lt;/em&gt; — структура данных с дисциплиной доступа к элементам «первый пришёл — 
  первый вышел» (FIFO, First In — First Out). Добавление элемента (принято
  обозначать словом enqueue — поставить в очередь) возможно лишь в конец
  очереди, выборка — только из начала очереди (что принято называть словом
  dequeue — убрать из очереди), при этом выбранный элемент из очереди удаляется.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;div style=&quot;text-align:right;font-style:italic;&quot;&gt;Википедия&lt;/div&gt;

&lt;h3 id=&quot;реализация-очереди-в-javascript&quot;&gt;Реализация очереди в JavaScript&lt;/h3&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-javascript&quot; data-lang=&quot;javascript&quot;&gt;&lt;span class=&quot;kd&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;queue&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;c1&quot;&gt;// []&lt;/span&gt;
&lt;span class=&quot;nx&quot;&gt;queue&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;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;first&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;c1&quot;&gt;// queue === [&quot;first&quot;]&lt;/span&gt;
&lt;span class=&quot;nx&quot;&gt;queue&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;mi&quot;&gt;10&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;20&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;   &lt;span class=&quot;c1&quot;&gt;// queue === [&quot;first&quot;, 10, 20]&lt;/span&gt;
&lt;span class=&quot;kd&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;el&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;queue&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;shift&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;();&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;// queue === [10, 20] &amp;amp;&amp;amp; el === &quot;first&quot;&lt;/span&gt;
&lt;span class=&quot;nx&quot;&gt;queue&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;mi&quot;&gt;2&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;        &lt;span class=&quot;c1&quot;&gt;// queue === [10, 20, 2]&lt;/span&gt;
&lt;span class=&quot;nx&quot;&gt;el&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;queue&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;shift&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;();&lt;/span&gt;     &lt;span class=&quot;c1&quot;&gt;// queue === [20, 2] &amp;amp;&amp;amp; el === 10&lt;/span&gt;
&lt;span class=&quot;nx&quot;&gt;el&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;queue&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;shift&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;();&lt;/span&gt;     &lt;span class=&quot;c1&quot;&gt;// queue === [2] &amp;amp;&amp;amp; el === 20&lt;/span&gt;
&lt;span class=&quot;nx&quot;&gt;el&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;queue&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;shift&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;();&lt;/span&gt;     &lt;span class=&quot;c1&quot;&gt;// queue === [] &amp;amp;&amp;amp; el === 2&lt;/span&gt;
&lt;span class=&quot;nx&quot;&gt;el&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;queue&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;shift&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;();&lt;/span&gt;     &lt;span class=&quot;c1&quot;&gt;// queue === [] &amp;amp;&amp;amp; typeof el === &quot;undefined&quot;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;Так же &lt;strong&gt;очередь в javascript&lt;/strong&gt; можно организовать с помощью &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;unshift&lt;/code&gt; и &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;pop&lt;/code&gt;,
получиться точно так же, только последний элемент окажется в начале, а первый
в конце, что немного не привычно.&lt;/p&gt;
</content>
  </entry>
  
  <entry>
    <title>Установка PhoneGap. iOS</title>
    <updated>2013-03-02T00:00:00+00:00</updated>
    
      <id>http://shuvalov.info/2013/03/02/phonegap</id>
      <link href="http://shuvalov.info/2013/03/02/phonegap"/>
    
      <content type="html" xml:base="http://shuvalov.info/">&lt;link rel=&quot;stylesheet&quot; href=&quot;/assets/css/phonegap.css&quot; /&gt;

&lt;div class=&quot;phonegap&quot;&gt;
  &lt;div class=&quot;sky&quot;&gt;
    &lt;img class=&quot;bot&quot; src=&quot;http://31808.selcdn.ru/it-prm/pics/phonegap_bot.png&quot; /&gt;
  &lt;/div&gt;
&lt;/div&gt;

&lt;p&gt;Задокументирую создание нового проекта &lt;strong&gt;xcode&lt;/strong&gt; с помощью &lt;strong&gt;phonegap&lt;/strong&gt;.&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;&lt;a href=&quot;http://phonegap.com/&quot;&gt;скачать PhoneGap&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;Создать папку для проектов. Например, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;~/Desktop/phonegap&lt;/code&gt;&lt;/li&gt;
  &lt;li&gt;Создать проект&lt;/li&gt;
&lt;/ol&gt;

&lt;div class=&quot;language-plaintext highlight-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;/путь/до/phonegap/lib/ios/bin/create &quot;путь до проекта&quot; &quot;имя пакета&quot; &quot;имя проекта&quot;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h3 id=&quot;пример&quot;&gt;Пример&lt;/h3&gt;

&lt;div class=&quot;language-plaintext highlight-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;mkdir ~/Desktop/phonegap
~/Downloads/phonegap-2.5.0/lib/ios/bin/create ~/Desktop/phonegap/helloworld org.apache.cordova.helloworld helloworld
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

</content>
  </entry>
  
  <entry>
    <title>Скринкасты по основам верстки на русском языке</title>
    <updated>2013-02-22T00:00:00+00:00</updated>
    
      <id>http://shuvalov.info/2013/02/22/dive_into_markup</id>
      <link href="http://shuvalov.info/2013/02/22/dive_into_markup"/>
    
      <content type="html" xml:base="http://shuvalov.info/">&lt;p&gt;&lt;img src=&quot;http://31808.selcdn.ru/it-prm/pics/html-markup.png&quot; alt=&quot;html верстка&quot; class=&quot;img-center&quot; /&gt;&lt;/p&gt;

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

&lt;p&gt;Примечательно, что автор использует &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;linux&lt;/code&gt;, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;emacs&lt;/code&gt; и &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;zen-coding&lt;/code&gt;. Последний 
я считаю особенно полезным в верстке. Так же интересно понаблюдать на что 
способен &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;emacs&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Немного неожиданно увидеть &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;strict xhtml&lt;/code&gt; в &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;doctype&lt;/code&gt;, да и теплый аналоговый
метод создания &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;border-radius&lt;/code&gt; с помощью спрайтов и png сейчас уже редкость,
но в целом скринкасты достаточно подробны, а порог вхождения минимальный.&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;http://psd2cms.ru/&quot; style=&quot;text-align:center;display:block;margin-top:20px;margin-bottom:30px;&quot;&gt;PSD2CMS.RU&lt;/a&gt;&lt;/p&gt;
</content>
  </entry>
  
  <entry>
    <title>Как к Mac OS X подключить HDD от DD-WRT</title>
    <updated>2013-02-10T00:00:00+00:00</updated>
    
      <id>http://shuvalov.info/2013/02/10/mount-dd-wrt-hdd</id>
      <link href="http://shuvalov.info/2013/02/10/mount-dd-wrt-hdd"/>
    
      <content type="html" xml:base="http://shuvalov.info/">&lt;p&gt;Пару лет назад я поставил на свой DIR300 прошивку DD-WRT. Потом был 
ASUS WL500, к которому я подключил HDD, поставил transmission и открыл 
к диску доступ по &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;samba&lt;/code&gt;. Позднее я сменил роутер на Netgear 3500L. Диск
остался прежним. Ну и за пару лет там накопилось много хлама. За упорство, 
с которым роутер раздавал купленые на humblebundle игры (sic!), ему нужно поставить
памятник при жизни.&lt;/p&gt;

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

&lt;p&gt;Не так давно &lt;a href=&quot;/2013/01/05/homeserver_intro/&quot;&gt;я сделал из старого ненужного PC сервер и спрятал его в чулан&lt;/a&gt;.
Я поставил на него &lt;a href=&quot;/2013/01/28/debian-squeeze-transmission/&quot;&gt;transmission&lt;/a&gt;, &lt;a href=&quot;/2013/01/16/ddwrt-vpn/&quot;&gt;настроил vpn&lt;/a&gt; до своей домашней сети,
удалил uTorrent с MacBook и поставил вместо него Transmission Remote GUI. 
До файлов всегда можно дотянуться через стабильную самбу, да и в перспективе я
планирую доставить пару 2TB дисков для файлового архива. Вся эта система работает
достаточно удобно, и я решил что пора бы перекинуть торренты с роутера на сервер.
Но вдруг оказалось, что эта процедура не такая уж и простая — Mac OS просто
не понимала что за файловая система к ней подключена. Изначально я пришел к
неправильному выводу и решил, что DD-WRT использует файловую систему JFFS2
на всех дисках кроме свопа. Гугл не предолжил никакого адекватного решения.
Качать 100GB через падающую каждые 10 минут samba мне ни как не хотелось.&lt;/p&gt;

&lt;p&gt;Сегодня я решил попытаться поднять на роутере ProFTP и скинуть через него файлы,
вроде как процесс не сильно отличается от настройки VPN, а там все было очень
легко. ProFTP я настроил, подключился к HDD, но не увидел там ни одного файла.
Я начал подумывать о том, что бы отложить переезд на еще один неопределенный срок.
Прокручивая эти мысли я зашел в настройки USB на роутере, что бы проверить, тот
ли каталог я показываю по FTP. Каталог был тот. Но я заметил, что файловая
система там была не JFFS2, а Ext3. Смонтировать Ext3 диск на Mac OS вполне
себе реально.&lt;/p&gt;

&lt;h2 id=&quot;mac-os-x-mountain-lion-и-ext3&quot;&gt;Mac OS X Mountain Lion и Ext3&lt;/h2&gt;

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

&lt;p&gt;&lt;a href=&quot;http://osxfuse.github.com/&quot; rel=&quot;nofollow&quot; target=&quot;_blank&quot;&gt;OSXFuse&lt;/a&gt; — &lt;a href=&quot;https://github.com/osxfuse/osxfuse/downloads&quot;&gt;Скачать&lt;/a&gt;&lt;br /&gt;
&lt;a href=&quot;http://alperakcan.org/?open=projects&amp;amp;project=fuse-ext2&quot; rel=&quot;nofollow&quot; target=&quot;_blank&quot;&gt;Fuse-ext2&lt;/a&gt; — &lt;a href=&quot;http://prdownloads.sourceforge.net/fuse-ext2/fuse-ext2-0.0.7.dmg?download&quot;&gt;Скачать&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Fuse-ext2 использует MacFuse для работы. Но MacFuse не работает ни в 
Mac OS X Lion, ни в Mountain Lion. OSXFuse — это более
современная версия MacFuse, которая лишена этих проблем, но это не значит,
что Fuse-ext2 будет с работать с OSXFuse. К счастью, OSXFuse содержит
&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;MacFUSE Compatibility Layer&lt;/code&gt;. Для того, что бы все заработало, OSXFuse
нужно установить с этим параметром.&lt;/p&gt;

&lt;p&gt;Готово. Все установлено. Теперь достаточно вытащить диск из роутера и включить
его в MacBook. Диск смонтируется автоматически. Возможно, понадобится
перезагрузка. Мне не понадобилась. Мой диск смонтировался только на чтение,
вероятно это связано с правами доступа, вероятно это особенность драйверов.
Я решил не выяснять подробности, потому что этого мне было достаточно.&lt;/p&gt;

</content>
  </entry>
  
  <entry>
    <title>Установка transmission</title>
    <updated>2013-01-28T00:00:00+00:00</updated>
    
      <id>http://shuvalov.info/2013/01/28/debian-squeeze-transmission</id>
      <link href="http://shuvalov.info/2013/01/28/debian-squeeze-transmission"/>
    
      <content type="html" xml:base="http://shuvalov.info/">&lt;p&gt;Установка &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;transmission-daemon&lt;/code&gt; — штука достаточно простая. Для начала 
я обновлил пакеты.&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;sudo aptitude update
&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;transmission-daemon&lt;/code&gt;&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;aptitude search transmission-daemon
&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;/etc/apt/sources.list&lt;/code&gt; нужно дописать подходящий репозиторий. К примеру&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;deb http://ftp.de.debian.org/debian squeeze main
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Затем заново обновить порты&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;sudo aptitude update
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;И установить transmission&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;sudo aptitude install transmission-daemon
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Скорее всего в процессе установки понадобится подтвердить установку
зависимостей.&lt;/p&gt;

&lt;h2 id=&quot;настройка-transmission&quot;&gt;Настройка transmission&lt;/h2&gt;

&lt;p&gt;Прежде чем править файл с настройками нужно остановить демон — при перезагрузке
файл настроек затирается на предыдущий.&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;/etc/init.d/transmission-daemon stop
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Файл с настройками лежит здесь:&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;/etc/transmission-daemon/settings.json 
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Для корректной работы сервиса я изменил следующие настройки:&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;{
  &quot;download-dir&quot;: &quot;/home/user/torrents&quot;,
  &quot;rpc-bind-address&quot;: &quot;192.168.1.101&quot;,
  &quot;rpc-enabled&quot;: true,
  &quot;rpc-port&quot;: 9091, 
  &quot;rpc-whitelist-enabled&quot;: false, 
  &quot;rpc-username&quot;: &quot;User&quot;, 
  &quot;rpc-password&quot;: &quot;Password&quot;,
  &quot;umask&quot;: &quot;002&quot;
}
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;После того, как изменения в файле сохранены — transmission нужно запустить&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;/etc/init.d/transmission-daemon start
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h2 id=&quot;transmission-remote-gui&quot;&gt;Transmission Remote GUI&lt;/h2&gt;

&lt;p&gt;Для того, что бы реже вспоминать о сервере с торрент-клиентом я сделал так:
директория в которую качаются торренты доступна через &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;samba&lt;/code&gt;, а для подключения
к transmission я использую &lt;a href=&quot;http://code.google.com/p/transmisson-remote-gui/&quot;&gt;Transmission Remote GUI&lt;/a&gt;. Его
легко можно назначить дефолтным приложением для открытия torrent-файлов, тогда
скачивание торрентов не будет сильно отличаться от utorrent’а.&lt;/p&gt;

</content>
  </entry>
  
  <entry>
    <title>MacBook и монитор</title>
    <updated>2013-01-19T00:00:00+00:00</updated>
    
      <id>http://shuvalov.info/2013/01/19/apple-screens</id>
      <link href="http://shuvalov.info/2013/01/19/apple-screens"/>
    
      <content type="html" xml:base="http://shuvalov.info/">&lt;p&gt;&lt;img src=&quot;http://31808.selcdn.ru/it-prm/pics/apple_displays.png&quot; alt=&quot;Работа с несколькими мониторами в Mac OS X&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Поделюсь опытом использования MacBook Pro с дополнительным монитором.&lt;/p&gt;

&lt;h2 id=&quot;переходники&quot;&gt;Переходники&lt;/h2&gt;

&lt;p&gt;В MacBook Pro бывает два типа разъемов: Mini DisplayPort и Thunderbolt.
Последний обратно совместим с первым. То есть, что бы подключить внешний
монитор к MacBook Pro нужно купить переходник с Mini Display Port на нужный
разьем. Переходники бывают оригинальные и китайские. Оригинальные стоят около
2.000 рублей, китайские же стоят около 300 рублей. Китайские уступают
качеством разъемов и пайки — такого мне хватило на год, после чего он, похоже,
начал люфтить и монитор подключался раза с двадцатого. Хотя, возможно, такая
проблема есть у оригинальных.&lt;/p&gt;

&lt;h2 id=&quot;нативное-управление-окнами&quot;&gt;Нативное управление окнами&lt;/h2&gt;

&lt;p&gt;В Mac OS X существует такое понятие как рабочий стол. Если работать с одним
монитором, то рабочий стол, это, практически, состояние экрана ноутбука
содержащее открытые приложения. Между этими состояниями можно переключаться,
смахиванием в четыре пальца на трэкпаде. Приложения, в свою очередь можно
перемещать между рабочими столами. Рабочие столы можно перемещать между собой.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;http://31808.selcdn.ru/it-prm/pics/mac-screens.png&quot; alt=&quot;Рабочие столы в mac os x&quot; /&gt;&lt;/p&gt;

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

&lt;p&gt;Apple предусмотрели базовые функции для привязки приложений к рабочим столам.
&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;/p&gt;

&lt;p&gt;&lt;img src=&quot;http://31808.selcdn.ru/it-prm/pics/allscreens.jpg&quot; alt=&quot;Рабочие столы в mac os x&quot; /&gt;&lt;/p&gt;

&lt;h2 id=&quot;приложения-для-управления-окнами&quot;&gt;Приложения для управления окнами&lt;/h2&gt;

&lt;p&gt;Есть очень много приложений для того, что бы привязать управление окнами
к определенным горячим клавишам. Сейчас я пользуюсь бесплатной программой
&lt;strong&gt;Spectacle&lt;/strong&gt;. Кроме нее я бы выделил &lt;strong&gt;Size Up&lt;/strong&gt;, и &lt;strong&gt;Better touch tools&lt;/strong&gt;.&lt;/p&gt;

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

</content>
  </entry>
  
  <entry>
    <title>Настройка VPN на роутере с DD-WRT</title>
    <updated>2013-01-16T00:00:00+00:00</updated>
    
      <id>http://shuvalov.info/2013/01/16/ddwrt-vpn</id>
      <link href="http://shuvalov.info/2013/01/16/ddwrt-vpn"/>
    
      <content type="html" xml:base="http://shuvalov.info/">&lt;p&gt;Расскажу о том, как настроить VPN-сервер на DD-WRT. VPN — это, вообще, очень
интересная штука. Для меня, польза от VPN это  шифрование траффика и безопасный
доступ к домашней сети и к сервисам, которые в этой сети расположены.&lt;/p&gt;

&lt;p&gt;Настроить VPN на DDWRT очень просто. Для начала нужно в web-интерфейсе роутера
зайти в &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Services &amp;gt; VPN&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;http://31808.selcdn.ru/it-prm/pics/vpn-ddwrt.png&quot; rel=&quot;nofollow&quot;&gt;&lt;img src=&quot;http://31808.selcdn.ru/it-prm/pics/vpn-ddwrt.png&quot; alt=&quot;VPN Service в DD-WRT&quot; title=&quot;Настройка VPN на роутере с DD-WRT&quot; /&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;Переключатель напротив &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;PPTP Server&lt;/code&gt; должен стоять в режими &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Enable&lt;/code&gt;.&lt;/li&gt;
  &lt;li&gt;Поддержка &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Broadcast&lt;/code&gt; мне не нужна.&lt;/li&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Force MPPE Encription&lt;/code&gt; включу.&lt;/li&gt;
  &lt;li&gt;В &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;DNS1&lt;/code&gt; и &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;DNS2&lt;/code&gt; пропишу DNS-серверы Google: &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;8.8.8.8&lt;/code&gt; и &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;8.8.4.4&lt;/code&gt;.&lt;/li&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;WINS1&lt;/code&gt; будет равен &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;DNS1&lt;/code&gt;. &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;WINS2&lt;/code&gt; можно оставить пустым.&lt;/li&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Server IP&lt;/code&gt; &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;0.0.0.0&lt;/code&gt;, хотя, думаю, подойдет &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;127.0.0.1&lt;/code&gt; или внешний IP роутера, если он статичный.&lt;/li&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Client IP&lt;/code&gt; — это диапазон IP-адресов, которые присваиваются VPN-клиентам.&lt;/li&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;CHAP-Secrets&lt;/code&gt; — это логин и пароль для подключения к VPN серверу. 
Пишется так: &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;vpn_user * vpn_password *&lt;/code&gt;.&lt;/li&gt;
&lt;/ol&gt;

&lt;h2 id=&quot;настройка-vpn-на-mac&quot;&gt;Настройка VPN на MAC&lt;/h2&gt;

&lt;p&gt;&lt;a href=&quot;http://31808.selcdn.ru/it-prm/pics/mac-vpn.png&quot; rel=&quot;nofollow&quot;&gt;&lt;img src=&quot;http://31808.selcdn.ru/it-prm/pics/mac-vpn.png&quot; alt=&quot;Настройка VPN на Mac OS X&quot; title=&quot;Настройка VPN на MAC OS X&quot; /&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Для начала, нужно создать новое подключение. Делается это с помощью кнопки &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;+&lt;/code&gt; под списком существующих подключений. &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Interface&lt;/code&gt; — &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;VPN&lt;/code&gt;, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;VPN Type&lt;/code&gt; — &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;PPTP&lt;/code&gt;. Имя сервиса, естественно, любое. Дальше в настройках подключения нужно указать IP сервера &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Server Address&lt;/code&gt;, имя пользователя в &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Account Name&lt;/code&gt;, тип шифрования, и, нажав на &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Authentication Settings...&lt;/code&gt; выбрать тип авторизации — &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;password&lt;/code&gt; и ввести пароль.
&lt;br /&gt;&lt;br /&gt;
&lt;img src=&quot;http://31808.selcdn.ru/it-prm/pics/vpn-connection.png&quot; class=&quot;img-center&quot; /&gt;&lt;/p&gt;
</content>
  </entry>
  
  <entry>
    <title>Jekyll Bootstrap и Google Analytics</title>
    <updated>2013-01-13T00:00:00+00:00</updated>
    
      <id>http://shuvalov.info/2013/01/13/jekyll-and-analytics</id>
      <link href="http://shuvalov.info/2013/01/13/jekyll-and-analytics"/>
    
      <content type="html" xml:base="http://shuvalov.info/">&lt;p&gt;&lt;img src=&quot;http://31808.selcdn.ru/it-prm/pics/jekyll.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;

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

&lt;p&gt;Я решил разобраться и заставить аналитику работать как положено. Для этого я
пытался генерировать сайт с атрибутом &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;--safe&lt;/code&gt;. Именно так советовали на гитхабе.&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;jekyll --safe
&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;production_url&lt;/code&gt;
в конфиге. В файле &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;_includes/JB/analytics&lt;/code&gt; я написал такую штуку&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;{% if site.url == site.production_url %}
    {% if site.JB.analytics.google.tracking_id %}
        {% include JB/analytics-providers/google %}
    {% endif %}
    {% if site.JB.analytics.yandex.id %}
        {% include JB/analytics-providers/yandex %}
    {% endif %}
{% endif %}
&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;--url&lt;/code&gt;, соответствующим ссылке 
на продакшн, то подключаются скрипты аналитики. Я внес все это в &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Rakefile&lt;/code&gt;.&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;task :default =&amp;gt; :run
 
desc 'Deploy to server'
task :push =&amp;gt; :build do
    sh &quot;rsync -az --delete _site/ eva:/home/web/www/anton-shuvalov.info&quot;
end
 
desc 'Build for deploy'
task :build do
  sh &quot;jekyll --no-server --no-auto --url http://anton-shuvalov.info&quot;
end
 
desc 'Run server'
task :run do
    print &quot;&amp;gt; Starting jekyll...\n&quot;
  sh &quot;jekyll --server&quot;
end
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h2 id=&quot;яндекс-метрика-для-jekyll&quot;&gt;Яндекс метрика для Jekyll&lt;/h2&gt;

&lt;p&gt;Я изменил &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;_config.yml&lt;/code&gt;. Удалил лишних провайдеров аналитики и параметр,
который отвечал за то, какого провайдера использовать. Ну и я добавил
в конфиг яндекс.&lt;/p&gt;

&lt;p&gt;JB:
    …
    analytics :
    google : 
      tracking_id : ‘UA-26825614-2’
    yandex :
      id : ‘19212163’
    …&lt;/p&gt;

&lt;p&gt;Ну и, собственно, файл &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;_includes/JB/analitycs-providers/yandex&lt;/code&gt;:&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;  &amp;lt;script type=&quot;text/javascript&quot;&amp;gt;
    (function (d, w, c) {
      (w[c] = w[c] || []).push(function() {
        try {
          w.yaCounter{{ site.JB.analytics.yandex.id }} = new Ya.Metrika({
          id:{{ site.JB.analytics.yandex.id }},
          clickmap:true,
          trackLinks:true,
          accurateTrackBounce:true});
        } catch(e) { }
      });
     
      var n = d.getElementsByTagName(&quot;script&quot;)[0],
          s = d.createElement(&quot;script&quot;),
          f = function () { n.parentNode.insertBefore(s, n); };
          s.type = &quot;text/javascript&quot;;
          s.async = true;
          s.src = (d.location.protocol == &quot;https:&quot; ? &quot;https:&quot; : &quot;http:&quot;) + &quot;//mc.yandex.ru/metrika/watch.js&quot;;
     
      if (w.opera == &quot;[object Opera]&quot;) {
          d.addEventListener(&quot;DOMContentLoaded&quot;, f, false);
      } else { f(); }
    })(document, window, &quot;yandex_metrika_callbacks&quot;);
  &amp;lt;/script&amp;gt;
  &amp;lt;noscript&amp;gt;
    &amp;lt;div&amp;gt;
      &amp;lt;img src=&quot;//mc.yandex.ru/watch/{{ site.JB.analytics.yandex.id }}&quot; style=&quot;position:absolute; left:-9999px;&quot; alt=&quot;&quot; /&amp;gt;
    &amp;lt;/div&amp;gt;
  &amp;lt;/noscript&amp;gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

</content>
  </entry>
  
  <entry>
    <title>Как я использую статический IP</title>
    <updated>2013-01-08T00:00:00+00:00</updated>
    
      <id>http://shuvalov.info/2013/01/08/static_ip</id>
      <link href="http://shuvalov.info/2013/01/08/static_ip"/>
    
      <content type="html" xml:base="http://shuvalov.info/">&lt;p&gt;&lt;img src=&quot;http://31808.selcdn.ru/it-prm/pics/ip-address-with-mouse.png&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;

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

&lt;p&gt;Устройств и сервисов, которые я бы хотел видеть снаружи, у меня немного есть. А есть у меня роутер NetGear 3500L с DD-WRT на борту. В нем жесткий диск на 320Gb и торрент-клиент. И есть у меня домашний сервер, за состоянием которого я хочу иногда присматривать. Есть немного интересных штук, но я пока не добрался до них.&lt;/p&gt;

&lt;p&gt;Подытожу. Я хочу привязать к своему домену такие штуки, как:&lt;/p&gt;

&lt;ul&gt;
	&lt;li&gt;SSH сервера&lt;/li&gt;
	&lt;li&gt;Состояние сервера (webmin)&lt;/li&gt;
	&lt;li&gt;Веб-сервер (его пока не трогаю)&lt;/li&gt;
	&lt;li&gt;SSH роутера&lt;/li&gt;
	&lt;li&gt;Веб-интерфайс роутера&lt;/li&gt;
	&lt;li&gt;Торрент клиент&lt;/li&gt;
	&lt;li&gt;FTP-сервер (его тоже не трогаю)&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;план&quot;&gt;План&lt;/h2&gt;

&lt;p&gt;Во-первых, нужно привязать субдомены (например, torrents.anton-shuvalov.info, webmin.anton-shuvalov.info) к своему статическому IP адресу, потом подвинуть с 80 порта веб-интерфейс DD-WRT, а на 80-ом поднять nginx. На nginx пробросить прокси ко всем сервисам, вроде:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;torrents.anton-shuvalov.info &amp;gt; 192.168.0.1:9091&lt;/code&gt;&lt;/pre&gt;

&lt;h2 id=&quot;как-привязать-домен-к-ip&quot;&gt;Как привязать домен к IP&lt;/h2&gt;

&lt;p&gt;Привязка домена к IP делается с помощью &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;A записи&lt;/code&gt; на NS-сервере к которому привязан домен. Мой домен привязан к NS-серверам &lt;a href=&quot;http://selectel.ru&quot; rel=&quot;nofollow&quot;&gt;selectel&lt;/a&gt;. Создать там &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;A запись&lt;/code&gt; очень просто, хотя я не думаю, что где-то это будет сложнее. В панели управления нужно перейти на вкладку &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;домены&lt;/code&gt;, дальше выбрать домен, ну и нажать на кнопку “добавить запись”. В значении “хост” пишу &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;webmin.anton-shuvalov.info&lt;/code&gt;, “тип” — &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;A&lt;/code&gt;, “Значение” — указываю свой IP.&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;http://31808.selcdn.ru/it-prm/pics/selectel-domains.jpg&quot; rel=&quot;nofollow&quot;&gt;&lt;img src=&quot;http://31808.selcdn.ru/it-prm/pics/selectel-domains.jpg&quot; alt=&quot;&quot; /&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2 id=&quot;ssh&quot;&gt;SSH&lt;/h2&gt;

&lt;p&gt;На MacBook я создал пару профилей SSH — до консоли роутера, и до консоли домашнего сервера. Создаются такие профили в файле &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;~/.ssh/config&lt;/code&gt;. Два моих профиля выглядят примерно так:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;Host ayanami
	# My home server
	HostName myip
	RemoteForward 52698 127.0.0.1:52698 # для rmate
	User user
	Port 11132 # В DD-WRT нужно пробросить этот порт на локальный IP сервера на 22-ой порт
	
Host router
	# My home router
	HostName myip
	User root
	Port 22&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;В файле &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;/etc/hosts&lt;/code&gt; я сделал запись такого вида:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;44.144.244.233 myip # home&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Это нужно для того, что бы в конфиге SSH зарезолвить myip в корректный IP-адрес.&lt;/p&gt;

&lt;h2 id=&quot;настройка-dd-wrt&quot;&gt;Настройка DD-WRT&lt;/h2&gt;

&lt;p&gt;В DD-WRT нужно сделать две вещи для того, чтобы запрос к субдомену доходил до моего еще не установленного проксирующего сервера на nginx, который, собственно, и будет разбираться с тем, что и куда перенаправить.&lt;/p&gt;
&lt;ul&gt;
  &lt;li&gt;Во-первых нужно подвинуть веб-интерфейс с 80-ого порта на, например, 81-ый порт (есть альтернативный вариант — перевести веб-интерфейс с &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;http&lt;/code&gt; на &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;https&lt;/code&gt;, но я его не пробовал).&lt;/li&gt;
  &lt;li&gt;Во-вторых нужно пробросить 80-ый порт до сервера, на котором будет работать nginx.&lt;/li&gt;
&lt;/ul&gt;

&lt;h4 id=&quot;меняем-порт-веб-интерфейса&quot;&gt;Меняем порт веб-интерфейса&lt;/h4&gt;

&lt;p&gt;Что бы сменить порт интерфейса нужно выполнить в консоли роутера следующие строки&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;nvram set http_lanport=81
nvram commit
reboot&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;После перезагрузки интерфейс откроется по адресу &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;http://192.168.0.1:81&lt;/code&gt;.&lt;/p&gt;

&lt;h4 id=&quot;пробрасываем-80-ый-порт&quot;&gt;Пробрасываем 80-ый порт&lt;/h4&gt;

&lt;p&gt;Здесь нет ничего сложного. Нужная форма находится в &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;NAT/QoS &amp;gt; Port Forwarding&lt;/code&gt;. Слева направо название, входящий порт, протокол (TCP, UDP или оба), внутренний IP и его порт. Внутренний IP сервера у меня 192.16810.101, порт 80-ый.&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;http://31808.selcdn.ru/it-prm/pics/dd-wrt_port-forwerding.jpg&quot; rel=&quot;nofollow&quot;&gt;&lt;img src=&quot;http://31808.selcdn.ru/it-prm/pics/dd-wrt_port-forwerding.jpg&quot; alt=&quot;проброс портов dd-wrt&quot; /&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2 id=&quot;установа-nginx-в-debian&quot;&gt;Установа nginx в debian&lt;/h2&gt;

&lt;p&gt;Установка nginx была не особенно гладкой. Ну как, не особенно. Я решил поставить из &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;aptitude&lt;/code&gt;, после этого часа два пытался настроить &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;nginx proxy_pass&lt;/code&gt;, и, в итоге, измученного и злого, меня озорило:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;rei@ayanami:~/$ /usr/sbin/nginx  -v
nginx version: nginx/0.7.67&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Уже вышел &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;nginx/1.2.6&lt;/code&gt;. Версия в сорцах жутко смердила. 
Для того, что бы поставить актуальную версию, нужно добавить в &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;/etc/apt/sources.list&lt;/code&gt; следующие строчки:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;deb http://nginx.org/packages/debian/ squeeze nginx
deb-src http://nginx.org/packages/debian/ squeeze nginx&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Так как я ставлю ngixn исключительно для проксирования запросов внутрь моей локальной сети, то ни &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;php-fpm&lt;/code&gt;, ни &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;mysql&lt;/code&gt; я не устанавливаю. Следовательно я удалил старую версию с помощью &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;aptitude remove --purge nginx&lt;/code&gt;, а дальше все просто:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;sudo aptitude install nginx&lt;/code&gt;&lt;/pre&gt;

&lt;h2 id=&quot;nginx-proxy-pass&quot;&gt;nginx proxy pass&lt;/h2&gt;

&lt;p&gt;После того, как установка nginx на мой debian сервер успешно завершилась, нужно настроить проксирование запросов в мой маленький интранет. Для каждого субдомена нужно писать отдельный конфиг. Возможно в чем-то эти конфиги могут отличаться. У меня же они одинаковые. Конфигурация сервера помещается в директиву &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;http&lt;/code&gt;.&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;server {
  server_name router.anton-shuvalov.info; # субдомен
  listen 80;
  location / {
    proxy_pass http://192.168.1.1:81; # локальный адрес
    proxy_set_header Host $host;
    proxy_set_header X-Real-IP $remote_addr;
  }
}&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Я добавил такие конфиги для веб-интерфейса роутера и торрент-клиента.&lt;/p&gt;

&lt;h2 id=&quot;в-webmin-не-работают-cookies&quot;&gt;В Webmin не работают cookies&lt;/h2&gt;

&lt;p&gt;С webmin не заладилось. После того, как я настроил проксирование по адресу &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;webmin.anton-shuvalov.info&lt;/code&gt; меня встретила форма логина, но, введя имя пользователя и пароль, я увидел такую ошибку:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;Error - No cookies
	
Your browser does not support cookies, which are required for this web server to work in session authentication mode&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Надо отметить, что &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;proxy_pass&lt;/code&gt; у меня вел на &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;https://192.168.1.101:10000&lt;/code&gt;. Но на самом деле, SSL webmin’а нужно выключить. Для этого в файле &lt;code&gt;sudo rmate /etc/webmin/miniserv.conf&lt;/code&gt; нужно поменять &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ssl=1&lt;/code&gt; на &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ssl=0&lt;/code&gt;. Ну и ниже конфиг сервера в &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;/etc/nginx/nginx.conf&lt;/code&gt;:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;server {
  server_name webmin.anton-shuvalov.info; 
  listen 80;
  location / {
    proxy_pass http://192.168.1.1:10000;
    proxy_set_header Host $host;
    proxy_set_header X-Real-IP $remote_addr;
  }
}&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;После этого все должно было заработать. Хотя нет. Webmin очень расстроился из-за подозрительного домена, с которого я до него добрался. Во всех своих фреймах он только об этом и говорил мне. Что бы порадовать старика нужно зайти в webmin через локальный адрес, у меня это &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;192.168.1.101:10000&lt;/code&gt; перейти в &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Webmin &amp;gt; Настройка Webmin &amp;gt; Проверка ссылок&lt;/code&gt; и вписать, куда влезает, название своего домена. Что-то типа &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;webmin.anton-shuvalov.info&lt;/code&gt;. Теперь-то все.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;http://31808.selcdn.ru/it-prm/pics/webmin.jpg&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;

&lt;h2 id=&quot;реприза&quot;&gt;Реприза&lt;/h2&gt;

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

</content>
  </entry>
  
  <entry>
    <title>Домашний сервер. Первые шаги</title>
    <updated>2013-01-06T00:00:00+00:00</updated>
    
      <id>http://shuvalov.info/2013/01/06/server_day1</id>
      <link href="http://shuvalov.info/2013/01/06/server_day1"/>
    
      <content type="html" xml:base="http://shuvalov.info/">&lt;h2 id=&quot;установка-debian&quot;&gt;Установка Debian&lt;/h2&gt;

&lt;p&gt;Установка Debian не представляет из себя ничего сложного. На &lt;a href=&quot;http://www.debian.org/&quot; rel=&quot;nofollow&quot;&gt;официальном сайте&lt;/a&gt; я скачал дистрибутив для AMD64. Прожег диск, вставил его в привод сервера. Согласился с предложением BIOS загрузиться с CD. Когда инсталятор предложил мне выбрать пакеты для автоматической установки, я отметил только SSH-server.&lt;/p&gt;

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

&lt;p&gt;После перезагрузки я посмотрел IP с помощью &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ifconfig&lt;/code&gt;. В своем MacBook я открыл конфиг SSH.&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;mate ~/.ssh/config&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;И дописал в него свой новый сервер.&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;Host ayanami
&amp;#35; My home server
HostName 192.168.1.101
RemoteForward 52698 127.0.0.1:52698
User rei
Port 22&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Строчка &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;RemoteForward&lt;/code&gt; нужна для проброса порта обратно, с сервера на MacBook. Это пригодится мне при настройке rmate. И так, подключаюсь к серверу, и вижу шелл.&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;ssh ayanami&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;&lt;img src=&quot;http://31808.selcdn.ru/it-prm/pics/ssh_login_rei.jpg&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;

&lt;h2 id=&quot;rmate&quot;&gt;rmate&lt;/h2&gt;

&lt;p&gt;поставил по своей же &lt;a href=&quot;/2012/06/15/TextMate2-mate-and-rmate/&quot; rel=&quot;nofollow&quot;&gt;инструкции&lt;/a&gt; которую я писал в блог.&lt;/p&gt;

&lt;h2 id=&quot;ruby&quot;&gt;ruby&lt;/h2&gt;

&lt;p&gt;Ruby поставил из aptitude, нужен для того, что бы работал rmate.&lt;/p&gt;

&lt;h2 id=&quot;sudo&quot;&gt;Sudo&lt;/h2&gt;

&lt;p&gt;Sudo пригодится для того, что бы не сидеть под суперпользователем, и не перелогиниваться каждый раз, когда нужны привилегии root’а. Без проблем устанавливается через &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;apt-get&lt;/code&gt; или &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;aptitude&lt;/code&gt;.&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;rmate /etc/sudoers&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Под строкой &lt;code&gt;root ALL=(ALL) ALL&lt;/code&gt; нужно дописать&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;&amp;lt;user&amp;gt; ALL=(ALL) ALL&lt;/code&gt;&lt;/pre&gt;

&lt;h2 id=&quot;webmin&quot;&gt;webmin&lt;/h2&gt;

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

&lt;p&gt;Для установки с помощью APT нужно отредактировать файл &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;/etc/apt/sources.list&lt;/code&gt; и дописать туда&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;deb http://download.webmin.com/download/repository sarge contrib
deb http://webmin.mirror.somersettechsolutions.co.uk/repository sarge contrib&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Потом нужно добавить ключ к репозиторию.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;cd /tmp
wget http://www.webmin.com/jcameron-key.asc
apt-key add jcameron-key.asc&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Ну и теперь можно устанавливать&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;apt-get update
apt-get install webmin&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Все зависимости разрешаются автоматически. После набираю в браузере &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;http://server-ip:10000&lt;/code&gt; и видим веб-интерфейс webmin.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;http://31808.selcdn.ru/it-prm/pics/webmin.jpg&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;

&lt;h2 id=&quot;zsh&quot;&gt;zsh&lt;/h2&gt;

&lt;pre&gt;&lt;code&gt;sudo apt-get install zsh&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;После этого под каждым пользователем, который должен использовать zsh нужно сменить шелл:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;chsh&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;В появившемся диалоге нужно вписать&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;/bin/zsh&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Я пока что поставил первый попавшийся &lt;a href=&quot;http://blackdiv.livejournal.com/39996.html&quot; rel=&quot;nofollow&quot;&gt;конфиг&lt;/a&gt;:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;. /etc/zsh_command_not_found #подключаем стандартный вывод убунты 
autoload -U compinit # настраиваем автодополнение
compinit 
HISTFILE=~/.zhistory # устанавливаем файл истории для zsh
HISTSIZE=10000 # размер истории
SAVEHIST=10000 
setopt  APPEND_HISTORY # убираем повторы и пустые строки в истории
setopt  HIST_IGNORE_ALL_DUPS 
setopt  HIST_IGNORE_SPACE 
setopt  HIST_REDUCE_BLANKS 
setopt autocd # смену пути без команды cd
setopt CORRECT_ALL # корректировку ошибок
export PS1 NLSPATH PAGER MAIL LS_COLORS LS_OPTIONS LIBRARY_PATH \
            C_INCLUDE_PATH CPLUS_INCLUDE_PATH EDITOR TERM XFILESEARCHPATH # экспортируем всякие полезности
bindkey -e # устанавливаем клавиши как в e-macs
fc -R $HISTFILE # подгружаем старую историю
# если мы находимся под обычным пользователем то в приветствии, в конце будет - &amp;gt;  если под рутом то - #
if [[ $EUID == 0 ]]; then
PS1=$'%{\e[1;7m%}%n@%m:%~ #%{\e[1;0m%} ';
else
PS1=$'%{\e[1;7m%}%n@%m:%~ &amp;gt;%{\e[1;0m%} ';
fi
PROMPT=$PS1;
#и справа в качечтве приветствия выведем время.
RPROMPT=$'%{\e[1;34m%}%T%{\e[0m%}' 
#добавляем стандартные алиасы
alias ls='ls -F --color=auto'
alias ll='ls -l'
alias la='ls -A'
alias li='ls -ial'
alias lsd='ls -ld *(-/DN)'
#указываем пути к манам
manpath=&quot;/usr/man:/usr/share/man:\
/usr/local/man:/usr/X11R6/man:/opt/qt/doc&quot;
export MANPATH

&lt;/code&gt;&lt;/pre&gt;

</content>
  </entry>
  
  <entry>
    <title>Домашний сервер. Интро</title>
    <updated>2013-01-05T00:00:00+00:00</updated>
    
      <id>http://shuvalov.info/2013/01/05/homeserver_intro</id>
      <link href="http://shuvalov.info/2013/01/05/homeserver_intro"/>
    
      <content type="html" xml:base="http://shuvalov.info/">&lt;p&gt; &lt;img src=&quot;http://31808.selcdn.ru/it-prm/pics/Debian_logo.png&quot; class=&quot;img-center&quot; /&gt; &lt;br /&gt;&lt;/p&gt;

&lt;p&gt;В планах зреет переход на &lt;a href=&quot;http://aws.amazon.com/s3/pricing/&quot; rel=&quot;nofollow&quot;&gt;AWS Free Usage Tier&lt;/a&gt;. Сейчас мои сайты хостятся на &lt;a href=&quot;http://selectel.ru/&quot; rel=&quot;nofollow&quot;&gt;selectel.ru&lt;/a&gt; и эксперементирую я там же.&lt;/p&gt;

&lt;p&gt;После &lt;a href=&quot;/2012/12/31/wp2jekyll&quot;&gt;перехода на Jekyll&lt;/a&gt; необходимость в таком облачном сервере отпала. Точнее, необходимость разложилась на хостинг для статичных сайтов, плюс сервер для эксперементов. Первую необходимость как раз решает &lt;a href=&quot;http://aws.amazon.com/s3/pricing/&quot; rel=&quot;nofollow&quot;&gt;AWS Free Usage Tier&lt;/a&gt;, а для второй я решил использовать старый PC, который уже пару месяцев пылился в углу. А точнее:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;strong&gt;CPU&lt;/strong&gt;: AMD Phenom II X2 555 BE ( 2 cores 3.2GHz )&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;RAM&lt;/strong&gt;: 4GB ( 2GB x 2GB )&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;HDD&lt;/strong&gt;: 500GB&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;для-чего-все-это&quot;&gt;Для чего все это?&lt;/h2&gt;

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

&lt;p&gt;В блоге я постараюсь вести заметки о том, как я сделал домашний сервер. Описывать что, зачем и как делаю. Заметки можно просмотреть по тегу &lt;a href=&quot;/tags.html#homeserver-ref&quot;&gt;homeserver&lt;/a&gt;&lt;/p&gt;

</content>
  </entry>
  
  <entry>
    <title>Переезд с WordPress на Jekyll</title>
    <updated>2012-12-31T00:00:00+00:00</updated>
    
      <id>http://shuvalov.info/2012/12/31/wp2jekyll</id>
      <link href="http://shuvalov.info/2012/12/31/wp2jekyll"/>
    
      <content type="html" xml:base="http://shuvalov.info/">&lt;p&gt;&lt;img src=&quot;http://31808.selcdn.ru/it-prm/pics/jekyll.png&quot; alt=&quot;&quot; /&gt; 
&lt;br /&gt;
&lt;br /&gt;
Когда я завел блог я был уверен, что wordpress — это простая и легкая в освоении CMS. В целом так и есть. Да и большинство хостингов позволяют установить эту CMS в один клик. Первоначально я использовал как раз такой хостинг на &lt;a href=&quot;http://domain.com&quot; rel=&quot;nofollow&quot;&gt;domain.com&lt;/a&gt;. Позднее я перенес свой блог на облачный сервер &lt;a href=&quot;http://selectel.ru&quot; rel=&quot;nofollow&quot;&gt;selectel.ru&lt;/a&gt;, где я без особого труда самостоятельно установил WordPress. Так же в плюс этой CMS Я знаю 3 способа создать сайт на WordPress бесплатно.&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;Можно сделать это официально на &lt;a href=&quot;http://wordpress.com&quot; rel=&quot;nofollow&quot;&gt;wordpress.com&lt;/a&gt;, но там есть ряд ограничений (например, нельзя устанавливать свои темы и плагины)&lt;/li&gt;
  &lt;li&gt;Можно использовать &lt;a href=&quot;https://openshift.redhat.com/&quot; rel=&quot;nofollow&quot;&gt;OpenShift&lt;/a&gt; от RedHat, где в один клик можно создать сайт на WordPress без ограничений. По характеристикам сервера — этот вариант самый производительный&lt;/li&gt;
  &lt;li&gt;Воспользоваться популярным хостингом для веб-приложений &lt;a href=&quot;http://www.heroku.com/&quot; rel=&quot;nofollow&quot;&gt;heroku&lt;/a&gt;, для которого есть свой &lt;a href=&quot;https://github.com/mhoofman/wordpress-heroku&quot; rel=&quot;nofollow&quot;&gt;форк wordpress&lt;/a&gt; с postgreSQL.&lt;/li&gt;
&lt;/ol&gt;

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

&lt;p&gt;Достаточно быстро мной овладела мысль об избыточности WordPress для блога — большая БД, куча запросов, плагинов, кода. 
Мой блог работал не особенно быстро. По крайней мере не так быстро, как я бы хотел. Я периодически натыкался на различные интересные решения, например на &lt;a href=&quot;https://github.com/fletcher/MultiMarkdown-CMS&quot; rel=&quot;nofollow&quot;&gt;markdown-cms&lt;/a&gt;. В принципе, это такой же генератор статичных сайтов, как и Jekyll только менее удобный и на Perl. В то время подход основанный на генерации статичных страниц я не оценил. О Jekyll я слышал достаточно давно в контексте GitHub Pages. Как-то раз и я решил попробовать сделать свой сайт на github с помощью jekyll. Внезапно jekyll оказался очень простым и понятным. До работы с ним у меня не было опыта в ruby. Теперь же у меня есть большое желание углубиться в этот язык. Особенно мне понравился rakefile. Я много времени провел пытаясь понять как пользоваться makefile, но rakefile я освоил за 5 минут, и практически сразу начал использовать его в своих проектах. Для Jekyll в будущих проектах даже найдется место.&lt;/p&gt;

&lt;p&gt;Вернемся к переезду. Сеттинг:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;source: it-prm.com, хостится на selectel под nginx, php, wordpress&lt;/li&gt;
  &lt;li&gt;tagget: anton-shuvalov.info, plain-html, jekyll-bootstrap, хостится на selectel&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Свои статьи я храню в markdown, по этому их перенос на Jekyll занял минут 20. Написал rakefile с двумя тасками:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-ruby&quot; data-lang=&quot;ruby&quot;&gt;&lt;span class=&quot;n&quot;&gt;task&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:default&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:run&lt;/span&gt;

&lt;span class=&quot;c1&quot;&gt;# Push &lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;desc&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'Push site to server'&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;task&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:push&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;do&lt;/span&gt;
  &lt;span class=&quot;nb&quot;&gt;print&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;Push _site to server..&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\n&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;sh&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;rsync -az --delete _site/ eva:/home/web/www/anton-shuvalov.info&quot;&lt;/span&gt;
  &lt;span class=&quot;nb&quot;&gt;print&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;Done...&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\n&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;

&lt;span class=&quot;c1&quot;&gt;# Run&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;desc&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'Run server'&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;task&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:run&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;do&lt;/span&gt;
  &lt;span class=&quot;nb&quot;&gt;print&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;Starting jekyll...&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\n&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;sh&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;jekyll --server&quot;&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;В задаче &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;push&lt;/code&gt; &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;eva&lt;/code&gt; — это имя сервера, оно забито в конфиге ssh &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;~/.ssh/config&lt;/code&gt;:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;Host eva
HostName 88.88.88.88 &lt;span class=&quot;c&quot;&gt;# ip сервера&lt;/span&gt;
User shuvalov
Port 22&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;Для деплоя на сервер я набрал в консоли &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;rake push&lt;/code&gt; и через секунд 10 сайт открылся по адресу anton-shuvalov.info. Осталось настроить 301 редирект с it-prm.com на anton-shuvalov.info. В конфиге сайта в &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;/etc/nginx/sites-available/it-prm.com&lt;/code&gt; это выглядит так:&lt;/p&gt;

&lt;figure class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;server &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
  ...

  &lt;span class=&quot;c&quot;&gt;# Redirects to anton-shuvalov.info&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;(&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;$request_uri&lt;/span&gt; ~&lt;span class=&quot;k&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;/?p=803&quot;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt; 
    rewrite ^ http://anton-shuvalov.info/2012/12/05/backbone-screencasts/? permanent&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; 
  &lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;(&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;$request_uri&lt;/span&gt; ~&lt;span class=&quot;k&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;/?p=772&quot;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt; 
    rewrite ^ http://anton-shuvalov.info/2012/11/18/Textmate2-line-hate/? permanent&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; 
  &lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;(&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;$request_uri&lt;/span&gt; ~&lt;span class=&quot;k&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;/?p=753&quot;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt; 
    rewrite ^ http://anton-shuvalov.info/2012/11/09/.google-analitycs-avtime? permanent&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; 
  &lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;

  ...

  rewrite ^ http://anton-shuvalov.info? permanent&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
  
  ...
		
&lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/figure&gt;

&lt;p&gt;Ну вот и все. Перезагрузил nginx &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;sudo nginx -s reload&lt;/code&gt;, все заработало. Проверил редиректы руками — все правильно. Переезд закончен.&lt;/p&gt;

</content>
  </entry>
  
  <entry>
    <title>Jekyll REXML could not parse this XML/HTML</title>
    <updated>2012-12-21T00:00:00+00:00</updated>
    
      <id>http://shuvalov.info/2012/12/21/jekyll-iframe-bug</id>
      <link href="http://shuvalov.info/2012/12/21/jekyll-iframe-bug"/>
    
      <content type="html" xml:base="http://shuvalov.info/">&lt;p&gt;&lt;img src=&quot;http://31808.selcdn.ru/it-prm/pics/jekyll.png&quot; alt=&quot;&quot; /&gt;
&lt;br /&gt;&lt;br /&gt;&lt;/p&gt;

&lt;p&gt;В Jekyll я столкнулся с проблемой. Вставил в текст поста iframe:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;&amp;lt;iframe width=&quot;620px&quot; height=&quot;400px&quot; src=&quot;http://player.vimeo.com/video/55084406&quot; frameborder=&quot;0&quot; mozallowfullscreen allowFullScreen&amp;gt;&amp;lt;/iframe&amp;gt;&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;И получил вот такую такую ошибку:&lt;/p&gt;

&lt;pre class=&quot;markdown-html-error&quot; style=&quot;border: solid 3px red; background-color: pink&quot;&gt;REXML could not parse this XML/HTML: 
&amp;lt;iframe width=&quot;620px&quot; height=&quot;400px&quot; src=&quot;http://player.vimeo.com/video/123&quot; frameborder=&quot;0&quot; allowFullScreen&amp;gt;&amp;lt;/iframe&amp;gt;&lt;/pre&gt;

&lt;p&gt;Что бы избавиться от этой ошибки придется отказаться от использования &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;mozallowfullscreen&lt;/code&gt;, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;allowFullScreen&lt;/code&gt;. В результате код должен выглядеть так:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;&amp;lt;iframe width=&quot;620px&quot; height=&quot;400px&quot; src=&quot;http://player.vimeo.com/video/55084406&quot; frameborder=&quot;0&quot;&amp;gt;&amp;lt;/iframe&amp;gt;&lt;/code&gt;&lt;/pre&gt;

&lt;h2 id=&quot;плагин-для-vimeo-в-jekyll&quot;&gt;Плагин для vimeo в jekyll&lt;/h2&gt;

&lt;p&gt;Для того, что бы упростить себе жизнь я использую &lt;a href=&quot;https://gist.github.com/4414183&quot; rel=&quot;nofollow&quot;&gt;плагин для видео из vimeo&lt;/a&gt; — этот плагин учитывает проблему с парсингом HTML и содержит стили для того, что бы видео корректно меняло свой размер для мобильных устройств. Работает плагин просто — достаточно вставить в тело записи &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;{ % vimeo 55084406 % }&lt;/code&gt; подставив нужный id.&lt;/p&gt;

</content>
  </entry>
  
  <entry>
    <title>Интерлиньяж в TextMate2</title>
    <updated>2012-11-18T00:00:00+00:00</updated>
    
      <id>http://shuvalov.info/2012/11/18/Textmate2-line-hate</id>
      <link href="http://shuvalov.info/2012/11/18/Textmate2-line-hate"/>
    
      <content type="html" xml:base="http://shuvalov.info/">&lt;p&gt;&lt;img src=&quot;http://31808.selcdn.ru/it-prm/pics/textmate2LH.jpg&quot; class=&quot;img-center&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Долгое время не мог понять что не так со шрифтами в TextMate2. Сейчас определился — мне не нравится line-height в редакторе. Изменить высоту строк достаточно просто. Для этого в терминал я ввел следующие комманды:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;defaults write com.macromates.TextMate.preview fontAscentDelta -float 0
defaults write com.macromates.TextMate.preview fontLeadingDelta -float 0&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;По-умолчанию параметры используются со значением &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;1&lt;/code&gt;, так что вернуть все как было можно, набрав:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;defaults write com.macromates.TextMate.preview fontAscentDelta -float 1
defaults write com.macromates.TextMate.preview fontLeadingDelta -float 1&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;&lt;a href=&quot;https://github.com/textmate/textmate/issues/373&quot; rel=&quot;nofollow&quot;&gt;Источник&lt;/a&gt;&lt;/p&gt;

</content>
  </entry>
  
  <entry>
    <title>Как правильно считать время в Google Analytics</title>
    <updated>2012-11-09T00:00:00+00:00</updated>
    
      <id>http://shuvalov.info/2012/11/09/google-analitycs-avtime</id>
      <link href="http://shuvalov.info/2012/11/09/google-analitycs-avtime"/>
    
      <content type="html" xml:base="http://shuvalov.info/">&lt;p&gt;Очень часто в Google Analytics среднее время проведенное пользователем на сайте равно нулю. Это, по меньшей мере, странно — неужели пользователь перешел по ссылке и тут же ее закрыл?&lt;/p&gt;

&lt;h2 id=&quot;решение&quot;&gt;Решение&lt;/h2&gt;
&lt;p&gt;Все дело в том, что Google считает время между открытием страниц, соответственно пользователь, который просмотрел только одну страницу по подсчетам гугла проводит на ней 0 секунд. Для того, что бы считать время, проведенное пользователем на странице, правильно — можно периодически отправлять в Google Analytics сообщения. Самый простой способ — сделать это в цикле:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;var trackingByInterval = (function trackingByInterval () {
	var timerCallback = function timerCallback () {
		_gaq.push(['_trackEvent', 'Reading', 'every 5 sec']);
	}
	setInterval(timerCallback, 5000);
})();&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Ссылка на &lt;a href=&quot;https://gist.github.com/4044055&quot; rel=&quot;nofollow&quot;&gt;gist&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Этот код нужно добавить после скрипта Google Anaytics. Скрипт запускается при открытии страницы, и фиксирует время, проведенное пользователем на сайте с частотой дискретизации — 5 секунд.&lt;/p&gt;

</content>
  </entry>
  
  <entry>
    <title>pgadmin column &quot;datconfig&quot; does not exist</title>
    <updated>2012-11-06T00:00:00+00:00</updated>
    
      <id>http://shuvalov.info/2012/11/06/Postgres.app-and-pgadmin</id>
      <link href="http://shuvalov.info/2012/11/06/Postgres.app-and-pgadmin"/>
    
      <content type="html" xml:base="http://shuvalov.info/">&lt;p&gt;Пару дней назад установил &lt;a href=&quot;http://postgresapp.com&quot; rel=&quot;nofollow&quot;&gt;Postgres.app&lt;/a&gt; и &lt;a href=&quot;http://www.pgadmin.org&quot; rel=&quot;nofollow&quot;&gt;pgadmin v1.8.4&lt;/a&gt;. Но при попытке подключения из pgadmin  к БД получал ошибку&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;ERROR: Column &quot;datconfig&quot; does not exist&lt;/code&gt;&lt;/pre&gt;

&lt;h2 id=&quot;решение&quot;&gt;Решение&lt;/h2&gt;

&lt;p&gt;Проблема возникает из-за странной сортировки на сайте &lt;a href=&quot;http://www.postgresql.org/ftp/pgadmin3/release/&quot; rel=&quot;nofollow&quot;&gt;pgadmin&lt;/a&gt; и невнимательности %username%. pgadmin v1.8.4 кажется последней версией, но на самом деле в списке есть версии v1.10.* и старше. Для того, что бы избавиться от ошибки нужно использовать версию pgadmin v1.12.* или &lt;a href=&quot;http://www.postgresql.org/ftp/pgadmin3/release/v1.16.0/&quot; rel=&quot;nofollow&quot;&gt;старше&lt;/a&gt;.&lt;/p&gt;

</content>
  </entry>
  
  <entry>
    <title>Как писался PostgreSQL</title>
    <updated>2012-10-19T00:00:00+00:00</updated>
    
      <id>http://shuvalov.info/2012/10/19/kak-pisalsya-postgresql</id>
      <link href="http://shuvalov.info/2012/10/19/kak-pisalsya-postgresql"/>
    
      <content type="html" xml:base="http://shuvalov.info/">&lt;p&gt;&lt;img class=&quot;img-center&quot; src=&quot;http://31808.selcdn.ru/it-prm/pics/postgresql.png&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Разработка СУБД POSTRGES началась в 1986 году под руководством профессора Майкла Стоунбрейкера (Michael Stonebraker). Концепции системы и архитектурные решения представлены в &lt;a href=&quot;http://db.cs.berkeley.edu/papers/ERL-M85-95.pdf&quot; rel=&quot;nofollow&quot;&gt;THE DESIGN OF POSTGRES&lt;/a&gt;, &lt;a href=&quot;http://db.cs.berkeley.edu/papers/ERL-M87-13.pdf&quot; rel=&quot;nofollow&quot;&gt;The POSTGRES data model&lt;/a&gt;, &lt;a href=&quot;http://postgresql.ru.net/manual/biblio.html#STON87A&quot; rel=&quot;nofollow&quot;&gt;The design of the POSTGRES rules system&lt;/a&gt;, &lt;a href=&quot;http://db.cs.berkeley.edu/papers/ERL-M87-06.pdf&quot; rel=&quot;nofollow&quot;&gt;The design of the POSTGRES storage system&lt;/a&gt;.&lt;/p&gt;

&lt;h2 id=&quot;прототипы&quot;&gt;Прототипы&lt;/h2&gt;
&lt;p&gt;В первых версиях POSTGRES было большое количество архитектурных решений. Только после Версии 3 разработчики сконцентрировали свое внимание на переносимости и стабильности СУБД.&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Первый прототип заработал в 1987 и был продемонстрирован на Конференции ACM-SIGMOD  в 1988 году.&lt;/li&gt;
  &lt;li&gt;Второй прототип (Версия 1), описанный в &lt;a href=&quot;http://db.cs.berkeley.edu/papers/ERL-M90-34.pdf&quot; rel=&quot;nofollow&quot;&gt;The implementation of POSTGRES&lt;/a&gt; был выпущен в июне 1989 года.&lt;/li&gt;
  &lt;li&gt;Третий прототип (Версия 2), выпущен в Июне 1990 года.&lt;/li&gt;
  &lt;li&gt;Четвертый прототип (Версия 3) выпущен в 1991.&lt;/li&gt;
&lt;/ul&gt;

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

&lt;h2 id=&quot;переписывание&quot;&gt;Переписывание&lt;/h2&gt;
&lt;p&gt;В 1994, Эндрю Ю (Andrew Yu) и Джолли Чен (Jolly Chen) добавили в POSTGRES интерпретатор языка SQL. СУБД была полностью приведена к стандарту ANSI C и сократив свой размер на 25%. Были внесены многие внутренние изменения, которые увеличили производительность и обслуживаемость кода. Postgres95 был быстрее на 30-50% согласно Wisconsin Benchmark по сравнению с POSTGRES, Version 4.2. При разработке Postgres95 акцент ставился на обнаружение и понимание существующих проблем в коде сервера.&lt;/p&gt;

&lt;h2 id=&quot;postgresql&quot;&gt;PostgreSQL&lt;/h2&gt;

&lt;p&gt;В 1996 году было решено, что имя “Postgres95” не соответствует настоящему времени. Для проекта было выбрано название PostgreSQL. Если при разработке Postgres95 внимание разработчиков было сконцентирировано на обнаружении и понимании существующих проблем в коде сервера, то в PostgreSQL внимание сместилось на расширение возможностей и совместимости при продолжении работы во всех других областях.&lt;/p&gt;

&lt;h2 id=&quot;вывод&quot;&gt;Вывод&lt;/h2&gt;
&lt;p&gt;PostgreSQL — это весьма объемный проект. Путь между прототипом, и версией, имеющей четкую концепцию и всесторонне продуманные архитектурные решения у ребят из Беркли занял 10 лет.&lt;/p&gt;

</content>
  </entry>
  
  <entry>
    <title>Кэш и ненависть в iBooks</title>
    <updated>2012-10-11T00:00:00+00:00</updated>
    
      <id>http://shuvalov.info/2012/10/11/cache-and-hate-ibooks</id>
      <link href="http://shuvalov.info/2012/10/11/cache-and-hate-ibooks"/>
    
      <content type="html" xml:base="http://shuvalov.info/">&lt;p&gt;&lt;img class=&quot;img-center&quot; src=&quot;http://31808.selcdn.ru/it-prm/pics/hero_ibooks_author.png&quot; alt=&quot;iBooks Author&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Разрабатывая книгу в iBooks Author, я столкнулись с «необъяснимыми» проблемами с HTML5 AUDIO в написанных мной виджетах. Аудио то играло, то не играло, звук иногда пропадал после исправлений, которые не затрагивали ни JS, ни HTML, ни CSS ( например после замены дефисов на тире ). Долгим и, к сожалению, эмпирическим путем я установил корень проблемы — кириллица в имени файла книги и в имени файла виджета. Вроде бы все легко — переименовываем книгу, переименовываем виджет, профит! С файлом книги, естественно, проблем не возникло, а с виджетом все оказалось чуть-чуть сложнее.&lt;/p&gt;

&lt;h3 id=&quot;wtf-cache&quot;&gt;WTF?! Cache!&lt;/h3&gt;

&lt;p&gt;Никто не может просто взять и переименовать виджет. iBooks Author имеет свой механизм кэширования. Упрощенная модель кэша работает примерно так&lt;/p&gt;

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

&lt;p&gt;Можно очень долго пытаться добавить переименованый латиницей файл в книгу, но &lt;strong&gt;пока в код виджета не добавишь хотя бы один пробел — iBooks&lt;/strong&gt; не станет добавлять виджет, и вместо этого &lt;strong&gt;будет ссылаться на уже существующий файл, который не будет работать из-за кириллицы в названии.&lt;/strong&gt;&lt;/p&gt;
</content>
  </entry>
  
  <entry>
    <title>Как объеденить две медиатеки в iTunes</title>
    <updated>2012-10-09T00:00:00+00:00</updated>
    
      <id>http://shuvalov.info/2012/10/09/itunes-merge-libraries</id>
      <link href="http://shuvalov.info/2012/10/09/itunes-merge-libraries"/>
    
      <content type="html" xml:base="http://shuvalov.info/">&lt;p&gt;&lt;img class=&quot;img-center&quot; src=&quot;http://31808.selcdn.ru/it-prm/pics/itunes.jpg&quot; alt=&quot;iTunes&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Наконец я получил &lt;a href=&quot;http://www.mcetech.com/optibay/&quot; rel=&quot;nofollow&quot;&gt;optibay&lt;/a&gt;, и установил к SSD в своем MacBook Pro еще и HDD. 120Gb памяти в SSD уже не сдерживали меня, и я решил вернуть свою музыкальную коллекцию с внешнего диска обратно на MacBook. Большая и старая медиатека лежала на внешнем диске, а на SSD скопилась совсем небольшая медиатека, в которой я уже успел проставить рейтинги, да и статистику прослушиваний терять не хотелось.&lt;/p&gt;

&lt;h2 id=&quot;объединение-медиатек&quot;&gt;Объединение медиатек&lt;/h2&gt;

&lt;ol&gt;
  &lt;li&gt;Запускаю iTunes с той медиатекой, которую я хочу экспортировать. Для этого нужно запустить iTunes зажав &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;option&lt;/code&gt;, в появившемся окне выбрать &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Choose Library..&lt;/code&gt; и указать папку с медиатекой.&lt;/li&gt;
  &lt;li&gt;Экспорт медиатеки.&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;File &amp;gt; Library &amp;gt;  Export&lt;/code&gt;.&lt;/li&gt;
  &lt;li&gt;Запускаем iTunes с той медиатекой, в которую мы хотим импортировать первую. Как в первом пункте.&lt;/li&gt;
  &lt;li&gt;Импортируем медиатеку. &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;File &amp;gt; Library &amp;gt; Import Playlist&lt;/code&gt;.&lt;/li&gt;
&lt;/ol&gt;

</content>
  </entry>
  
  <entry>
    <title>BASH. Чем отличается which от whereis</title>
    <updated>2012-10-05T00:00:00+00:00</updated>
    
      <id>http://shuvalov.info/2012/10/05/bash-whereis-which</id>
      <link href="http://shuvalov.info/2012/10/05/bash-whereis-which"/>
    
      <content type="html" xml:base="http://shuvalov.info/">&lt;p&gt;&lt;img class=&quot;img-center&quot; src=&quot;http://31808.selcdn.ru/it-prm/pics/bash.png&quot; alt=&quot;Чем отличается which от whereis&quot; /&gt;&lt;/p&gt;

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

&lt;h2 id=&quot;which&quot;&gt;Which&lt;/h2&gt;

&lt;p&gt;Команда &lt;code&gt;which&lt;/code&gt; ищет приложение в пользовательской директории. Например: &lt;br /&gt;
&lt;pre&gt;&lt;code&gt;which git
/usr/local/bin/git&lt;/code&gt;&lt;/pre&gt;
&lt;/p&gt;

&lt;h4 id=&quot;ключи&quot;&gt;Ключи&lt;/h4&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;-a&lt;/code&gt; — возвращает список путей ко всем найденным программам.&lt;/li&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;-s&lt;/code&gt; — возвращает &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;0&lt;/code&gt; если хотя бы одна программа есть, и &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;1&lt;/code&gt; если ничего нет.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;whereis&quot;&gt;Whereis&lt;/h2&gt;

&lt;p&gt;Команда whereis ищет программы среди стандартных директорий и флагов не имеет. Пример:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;whereis git
/usr/bin/git&lt;/code&gt;&lt;/pre&gt;
</content>
  </entry>
  
  <entry>
    <title>Архитектура кода</title>
    <updated>2012-10-05T00:00:00+00:00</updated>
    
      <id>http://shuvalov.info/2012/10/05/Architecture-of-Source</id>
      <link href="http://shuvalov.info/2012/10/05/Architecture-of-Source"/>
    
      <content type="html" xml:base="http://shuvalov.info/">&lt;p&gt;&lt;img class=&quot;img-center&quot; src=&quot;http://31808.selcdn.ru/it-prm/pics/blueprint-1.jpg&quot; alt=&quot;Архитектура кода&quot; /&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;WTF?! Кто прав?&lt;/p&gt;
</content>
  </entry>
  
  <entry>
    <title>Ссылка на глоссарий в iBooks Author</title>
    <updated>2012-07-23T00:00:00+00:00</updated>
    
      <id>http://shuvalov.info/2012/07/23/iBooks-Author-Glossary-and-Placeholders</id>
      <link href="http://shuvalov.info/2012/07/23/iBooks-Author-Glossary-and-Placeholders"/>
    
      <content type="html" xml:base="http://shuvalov.info/">&lt;p&gt;Столкнулся с проблемой — iBooks Author не создавал ссылки на глоссарий. Проблема была в тексте.  По какой-то причине он оказался “заполнителем”.&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;http://31808.selcdn.ru/it-prm/pics/ibooks_placeholder.jpg&quot; rel=&quot;nofollow&quot;&gt;
	&lt;img src=&quot;http://31808.selcdn.ru/it-prm/pics/ibooks_placeholder.jpg&quot; width=&quot;100%&quot; /&gt;
&lt;/a&gt;&lt;/p&gt;

</content>
  </entry>
  
  <entry>
    <title>Отзыв о книге «Программист-прагматик»</title>
    <updated>2012-07-21T00:00:00+00:00</updated>
    
      <id>http://shuvalov.info/2012/07/21/The-Pragmatic-Programmer</id>
      <link href="http://shuvalov.info/2012/07/21/The-Pragmatic-Programmer"/>
    
      <content type="html" xml:base="http://shuvalov.info/">&lt;p&gt;&lt;img src=&quot;http://31808.selcdn.ru/it-prm/pics/tpp.jpg&quot; class=&quot;img-center&quot; width=&quot;275px&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Наконец-то я дочитал &lt;a href=&quot;http://pragprog.com/book/tpp/the-pragmatic-programmer&quot; rel=&quot;nofollow&quot;&gt;эту книгу&lt;/a&gt; и решил написать набольшой отзыв. Я честно признаюсь, что эта открыла мне глаза на разработку программ. Как выражаются сами авторы, они “отвечают на огромное количество вопросов с высоты птичьего полета”. Но эту книгу нельзя назвать поверхностной. Книга написана достаточно детально, что бы направить развитие программиста в нужную сторону. В книге были и непонятные мне главы - в основном, это касалось юнит-тестов.&lt;/p&gt;

&lt;p&gt;Я обязательно перечитаю эту книгу, потому что она великолепна.&lt;/p&gt;

</content>
  </entry>
  
  <entry>
    <title>Нумерация страниц в iBooks Author</title>
    <updated>2012-07-19T00:00:00+00:00</updated>
    
      <id>http://shuvalov.info/2012/07/19/iBooks-Page-numbering</id>
      <link href="http://shuvalov.info/2012/07/19/iBooks-Page-numbering"/>
    
      <content type="html" xml:base="http://shuvalov.info/">&lt;p&gt;&lt;img src=&quot;http://31808.selcdn.ru/it-prm/articles/19082012%20%D0%BD%D1%83%D0%BC%D0%B5%D1%80%D0%B0%D1%86%D0%B8%D1%8F%20%D1%81%D1%82%D1%80%D0%B0%D0%BD%D0%B8%D1%86%20%D0%B2%20ibooks%20author/pages_numbering.jpg&quot; alt=&quot;pic&quot; /&gt;&lt;/p&gt;

&lt;p&gt;В книгах используется нумерация страниц арабскими числами. Но в некоторых шаблонах
(например в “Preface”) iBooks author используется римская нумерация. Исправить
это очень просто. Выбрав неугодный layout параграфа, в &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;inspector &amp;gt; layout &amp;gt; numbering&lt;/code&gt;
высталвяем правильную нумерацию.&lt;/p&gt;

</content>
  </entry>
  
  <entry>
    <title>Что почитать веб-разработчику</title>
    <updated>2012-06-30T00:00:00+00:00</updated>
    
      <id>http://shuvalov.info/2012/06/30/to-read</id>
      <link href="http://shuvalov.info/2012/06/30/to-read"/>
    
      <content type="html" xml:base="http://shuvalov.info/">&lt;p&gt;&lt;img src=&quot;http://31808.selcdn.ru/it-prm/pics/moleskine.png&quot; width=&quot;275&quot; class=&quot;img-center&quot; style=&quot;margin-bottom:3em;&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Я решил составить список интересных ссылок, которые стоит почитать на выходных.
Основные темы - Textmate, JavaScript, CSS, ну и чуть-чуть о философии дизайна.&lt;/p&gt;

&lt;h2 id=&quot;frontend&quot;&gt;FrontEnd:&lt;/h2&gt;
&lt;ul&gt;
  &lt;li&gt;&lt;a href=&quot;http://bonsaiden.github.com/JavaScript-Garden/ru/&quot; title=&quot;JavaScript Гарден&quot; rel=&quot;nofollow&quot;&gt;JavaScript Гарден&lt;/a&gt; - &lt;a href=&quot;http://shamansir.madfire.net/&quot; rel=&quot;nofollow&quot;&gt;shaman.sir&lt;/a&gt;, &lt;a href=&quot;http://anton.shevchuk.name/&quot; rel=&quot;nofollow&quot;&gt;Антон Шевчук&lt;/a&gt;, &lt;a href=&quot;http://nixsolutions.com/&quot; rel=&quot;nofollow&quot;&gt;Максим Лозовой&lt;/a&gt;, &lt;a href=&quot;http://nixsolutions.com/&quot; rel=&quot;nofollow&quot;&gt;Елена Пашкова&lt;/a&gt; перевели на русский язык потрясающую документацию по всем темным углам JavaScript.&lt;/li&gt;
&lt;/ul&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;a href=&quot;http://www.slideshare.net/fullscreen/AddyOsmani/scalable-javascript-design-patterns/&quot; rel=&quot;nofollow&quot;&gt;JavaScript: patterns and antipatterns&lt;/a&gt; - отличная коллекция паттернов и анти-паттернов JavaScript от &lt;a href=&quot;http://www.blog.highub.com/&quot; rel=&quot;nofollow&quot;&gt;Shi Chuan&lt;/a&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;a href=&quot;http://www.slideshare.net/fullscreen/AddyOsmani/scalable-javascript-design-patterns/&quot; rel=&quot;nofollow&quot;&gt;Scalable JavaScript Design Patterns&lt;/a&gt; - великолепная презентация об основных паттернах проектирования в JavaScript от &lt;a href=&quot;http://addyosmani.com/blog/&quot; rel=&quot;nofollow&quot;&gt;Addy Osmani&lt;/a&gt;. Так же у Addy Osmani есть книга, глубже раскрывающая тему паттернов в JS: &lt;a href=&quot;http://addyosmani.com/resources/essentialjsdesignpatterns/book/&quot; rel=&quot;nofollow&quot;&gt;Learning JavaScript Design Patterns&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;a href=&quot;https://github.com/darcyclarke/Front-end-Developer-Interview-Questions&quot; rel=&quot;nofollow&quot;&gt;Front-end developer interview questions&lt;/a&gt; - Вопросы к собеседованию для frontend разработчиков от &lt;a href=&quot;http://darcyclarke.me/&quot; rel=&quot;nofollow&quot;&gt;Darcy Clarke&lt;/a&gt; и огромного числа соразработчиков. Основные темы - CSS, JS, jQuery, HTML.&lt;/li&gt;
&lt;/ul&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;a href=&quot;http://www.w3.org/TR/wai-aria/&quot; rel=&quot;nofollow&quot;&gt;Спецификация W3C по ARIA&lt;/a&gt; - ARIA уже в стадии Candidate Recommendation, так что стоит разобраться, что это такое.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;textmate&quot;&gt;TextMate&lt;/h2&gt;
&lt;ul&gt;
  &lt;li&gt;&lt;a href=&quot;http://tm2tips.tumblr.com/&quot; rel=&quot;nofollow&quot;&gt;Textmate 2 Tips&lt;/a&gt; - сайт с говорящим названием.&lt;/li&gt;
&lt;/ul&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;a href=&quot;https://github.com/textmate/&quot; rel=&quot;nofollow&quot;&gt;Textmate Repos&lt;/a&gt; - аккаунт macromates на GitHub. Поиски TextMate bundles стоит начать именно отсюда.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;дизайн&quot;&gt;Дизайн&lt;/h2&gt;
&lt;ul&gt;
  &lt;li&gt;&lt;a href=&quot;http://papardes.blogspot.com/2009/08/blog-post_1162.html&quot; rel=&quot;nofollow&quot;&gt;Планетарная клаустрафобия&lt;/a&gt; - архитектурный теоретик &lt;a href=&quot;http://www.blogger.com/profile/10975104695224234620&quot; rel=&quot;nofollow&quot;&gt;Александр Раппапорт&lt;/a&gt; рассказывает глобализации в дизайне и ее негативных последствиях.&lt;/li&gt;
&lt;/ul&gt;

</content>
  </entry>
  
  <entry>
    <title>Просмотр man-страниц в textmate</title>
    <updated>2012-06-23T00:00:00+00:00</updated>
    
      <id>http://shuvalov.info/2012/06/23/Reading-mans-in-TextMate2</id>
      <link href="http://shuvalov.info/2012/06/23/Reading-mans-in-TextMate2"/>
    
      <content type="html" xml:base="http://shuvalov.info/">&lt;p&gt;&lt;img src=&quot;http://31808.selcdn.ru/it-prm/pics/man.jpg&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;

&lt;h5 style=&quot;text-align:center !important;font-style:italic;&quot;&gt;мануал о том как использовать textmate для просмотра мануалов&lt;/h5&gt;

&lt;h2 id=&quot;man&quot;&gt;man&lt;/h2&gt;

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

&lt;h2 id=&quot;использование-textmate2-для-чтения-manов&quot;&gt;Использование textmate2 для чтения man’ов&lt;/h2&gt;

&lt;blockquote&gt;
  &lt;p&gt;&lt;em&gt;«Использовать один редактор — это хорошо».&lt;/em&gt;&lt;br /&gt;
Pragmatic Programmer&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Для меня, бесспорно, главным и единственным редактором кода является textmate2. Я попробую научить этот редактор читать маны. В этой статье речь пойдет именно о второй версии TextMate. У меня сейчас установлен TextMate Version 2.0 (9090).&lt;/p&gt;

&lt;h2 id=&quot;установка-бандла&quot;&gt;Установка бандла&lt;/h2&gt;

&lt;p&gt;Для начала я установил в TextMate &lt;a href=&quot;https://github.com/textmate/man-pages.tmbundle&quot; title=&quot;TextMate Man Pages Bundle&quot; rel=&quot;nofollow&quot;&gt;бандл для чтения man-страниц&lt;/a&gt;. Скачал, проверил, что название папки заканчивается на &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;.tmbundle&lt;/code&gt;. Скопировал бандл в папку.&amp;lt;pre&amp;gt;~/Library/Application Support/TextMate/Managed/Bundles
&amp;lt;/pre&amp;gt; Перезапустил TextMate.&lt;/p&gt;

&lt;h2 id=&quot;использование-бандла&quot;&gt;Использование бандла&lt;/h2&gt;
&lt;p&gt;Выбираю в меню &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Bundles-&amp;gt;Man Pages-&amp;gt;View Man Page&lt;/code&gt;. В появившемся окне набираю название shell-команды, например &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;man&lt;/code&gt;, и умиляюсь открывшейся TextMate man-страницей. Для того, что бы воспользоваться второй командой бандла - &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Visit man Page&lt;/code&gt; - нужно выделить какую-нибудь shell-команду в тексте. По нажатию на хоткей, либо выбрав в меню &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Bundles-&amp;gt;Man Pages-&amp;gt;Visit man Page&lt;/code&gt;, откроется новая вкладка со справкой по выделенной команде.&lt;/p&gt;

&lt;h3 id=&quot;для-гиков-и-перфекционистов--настройка-бандла&quot;&gt;Для гиков и перфекционистов:  настройка бандла&lt;/h3&gt;
&lt;p&gt;Для меня совершенно неудобно тянуться к тэчпаду или мыши, и выделять руками команду. Это лечится настройкой входных данных. Выбираю в меню &amp;lt;pre&amp;gt;Bundles-&amp;gt;Edit Bundles…-&amp;gt;Man Pages-&amp;gt;Menu Actions-&amp;gt;Visit Man Page&amp;lt;/pre&amp;gt; Слева в настройках нужно установить значение поля &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;input&lt;/code&gt; равным &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;word&lt;/code&gt;. 
Здесь же, в редакторе бандлов, можно настроить удобные хоткеи. Они задаются в поле &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Key Equivalent&lt;/code&gt;. Не стоит обделять гуманным сочетанием клавиш и &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;View Man Page&lt;/code&gt;. Да, что бы заставить хоткеи работать - мне пришлось удалить значение поля &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Scope Selector&lt;/code&gt;.&lt;/p&gt;

&lt;h2 id=&quot;учим-textmate-читать-маны-из-консоли&quot;&gt;Учим textmate читать маны из консоли.&lt;/h2&gt;

&lt;p&gt;И вроде бы, когда я пишу код в TextMate, все круто: если мне нужна справка - жму хоткей - читаю, просвещаюсь, жгу дальше дальше. Но что мне делать, если я тщетно пытаюсь заставить что-то работать прямо в консоли? Получается, что мне и man там же читать? Нет, это никуда не годится. Я решил использовать &lt;a href=&quot;https://github.com/textmate/man-pages.tmbundle/blob/master/Support/mman&quot; rel=&quot;nofollow&quot;&gt;bash-скрипт&lt;/a&gt;, на котором базируется бандл “Man Pages” как обертку к стандартной команде man.&lt;/p&gt;

&lt;p&gt;Для начала узнаем, где лежит оригинальный ман.&lt;br /&gt;
&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;which man&lt;/code&gt;&lt;br /&gt;
Скорее всего это &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;/usr/bin/man&lt;/code&gt;. Думаю, что бывают исключения.&lt;/p&gt;

&lt;p&gt;Для всех скриптов, к которым я лично приложил руку - у меня есть специальный каталог &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;~/.scripts&lt;/code&gt;. Каталог прописан в переменной окружения &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;$PATH&lt;/code&gt;. Я нахожу это удобным. Краткая инструкция о создании такого каталога:&lt;/p&gt;
&lt;pre&gt;
&lt;code&gt;mkdir ~/.scripts # Создаем директорию
mate ~/.profile  # Добавляем ее в $PATH&lt;/code&gt;
&lt;/pre&gt;
&lt;p&gt;В открывшемся окне TextMate нужно дописать строчку &amp;lt;pre&amp;gt;export PATH=$HOME/.scripts:$PATH
&amp;lt;/pre&amp;gt; Либо, если &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;export PATH&lt;/code&gt; уже есть, то дописать в нем, сразу после &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;=&lt;/code&gt; &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;$HOME/.scripts:&lt;/code&gt;. Создадим в &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;~/.scripts&lt;/code&gt; ссылку на наш скрипт:&lt;/p&gt;
&lt;pre&gt;
&lt;code class=&quot;bash&quot;&gt;ln -s /Users/shuvalov/Library/Application\ Support/TextMate/Managed/Bundles/textmate-man-pages.tmbundle/Support/mman ~/.scripts/man&lt;/code&gt;
&lt;/pre&gt;
&lt;p&gt;В этот момент, так как я определил директорию с нашим скриптом раньше всего, стандартный &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;man&lt;/code&gt; перестанет работать. Вместо него будет выполняться наш скрипт. Теперь осталось изменить в скрипте вызов &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;man&lt;/code&gt; на &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;/usr/bin/man&lt;/code&gt; (либо путь до оригинальной команды man). Отрываю файл &amp;lt;pre&amp;gt;&lt;code class=&quot;bash&quot;&gt;~/Library/Application\ Support/TextMate/Managed/Bundles/textmate-man-pages.tmbundle/Support/mman&lt;/code&gt;
&amp;lt;/pre&amp;gt; и отредактируем его. (&lt;a href=&quot;https://github.com/shuvalov-anton/dot-scripts/blob/a6e615ca211674b57a13a855e297dac3d7fa4c1f/man&quot; rel=&quot;nofollow&quot;&gt;мой пример&lt;/a&gt;).&lt;br /&gt;
Набираем &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;man man&lt;/code&gt; и видим результат труда - man-страница открывается в новом окне textmate, переливаясь чинной подсветкой синтаксиса.&lt;/p&gt;

&lt;p&gt;Напоследок. Если, просматривая man в textmate, нажать &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;shift+cmd+t&lt;/code&gt;, то откроется меню навигации по ману. Только вот, что бы заставить его работать, нужно в последней строчке скрипта изменить значение sleep на 180, продлив время жизни временной страницы:&lt;/p&gt;
&lt;pre&gt;
&lt;code&gt;(sleep 180; rm -f $tmp) &amp;gt; /dev/null 2&amp;gt;&amp;amp;1 &amp;lt;/dev/null &amp;amp;&lt;/code&gt;
&lt;/pre&gt;

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

</content>
  </entry>
  
  <entry>
    <title>Планетарная клаустрофобия</title>
    <updated>2012-06-19T00:00:00+00:00</updated>
    
      <id>http://shuvalov.info/2012/06/19/Planetary-Claustrophobia</id>
      <link href="http://shuvalov.info/2012/06/19/Planetary-Claustrophobia"/>
    
      <content type="html" xml:base="http://shuvalov.info/">&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;http://ru.wikipedia.org/wiki/%D0%A0%D0%B0%D0%BF%D0%BF%D0%B0%D0%BF%D0%BE%D1%80%D1%82,_%D0%90%D0%BB%D0%B5%D0%BA%D1%81%D0%B0%D0%BD%D0%B4%D1%80_%D0%93%D0%B5%D1%80%D0%B1%D0%B5%D1%80%D1%82%D0%BE%D0%B2%D0%B8%D1%87&quot; rel=&quot;nofollow&quot;&gt;Александр Раппапорт&lt;/a&gt;&lt;/p&gt;

</content>
  </entry>
  
  <entry>
    <title>mate и rmate в TextMate&amp;nbsp;2</title>
    <updated>2012-06-15T00:00:00+00:00</updated>
    
      <id>http://shuvalov.info/2012/06/15/TextMate2-mate-and-rmate</id>
      <link href="http://shuvalov.info/2012/06/15/TextMate2-mate-and-rmate"/>
    
      <content type="html" xml:base="http://shuvalov.info/">&lt;h2 id=&quot;введение&quot;&gt;Введение&lt;/h2&gt;

&lt;p&gt;Я полностью согласен с авторами книги &lt;a href=&quot;http://www.amazon.com/The-Pragmatic-Programmer-Journeyman-Master/dp/020161622X&quot;&gt;«The Pragmatic Programmer»&lt;/a&gt; &lt;a href=&quot;http://andy.pragprog.com/&quot;&gt;Andrew Hunt&lt;/a&gt;
и &lt;a href=&quot;http://pragdave.pragprog.com/&quot;&gt;David Thomas&lt;/a&gt; в том, что иметь один-единственный редактор текста для 
всего — это прекрасно. Таким редактором для меня является &lt;a href=&quot;http://blog.macromates.com/2011/textmate-2-0-alpha/&quot;&gt;textmate 2&lt;/a&gt;. 
Я стараюсь использовать его везде, где это возможно. В основном я работаю 
с JS, HTML, CSS и Markdown для статей и заметок. Бывает пишу PHP-код и
shell-скрипты. Изредка судьба, ухмыляясь, заставляет меня писать на pascal.
С помощью различных дополнений, область применения Textmate можно расширять
практически бесконечно.&lt;/p&gt;

&lt;p&gt;Textmate поставляется с двумя консольными скриптами &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;mate&lt;/code&gt; и &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;rmate&lt;/code&gt;. &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;mate&lt;/code&gt;
позволяет из терминала открыть файл в textmate. Выглядит это, к примеру,
так - &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;sudo mate /etc/hosts/&lt;/code&gt;. С помощью &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;rmate&lt;/code&gt; можно провернуть то-же самое,
но на удаленнам сервере.&lt;/p&gt;

&lt;p&gt;Раньше я ежедневно пользовался &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ssh&lt;/code&gt; или даже &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;sshfs&lt;/code&gt; для редактирования файлов
на сервере. С одной стороны перспектива редактирования кода в &lt;em&gt;vim&lt;/em&gt;-подобных
редакторах, с другой медленная скорость работы &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;sshfs&lt;/code&gt; как файловой системы.
В целом, удаленное редактирование файлов мне не импонировало ни тем, ни другим…&lt;/p&gt;

&lt;h2 id=&quot;mate&quot;&gt;Mate&lt;/h2&gt;

&lt;p&gt;В консоли Mac OS X существует команда &lt;a href=&quot;https://developer.apple.com/library/mac/#documentation/Darwin/Reference/ManPages/man1/open.1.html&quot;&gt;open&lt;/a&gt;, заменяющая в терминале двойной
клик по файлу. &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;open -a&lt;/code&gt; в терминале заменяет команду «открыть с помощью».
Например, что бы открыть из терминала в textmate файл, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;/etc/hosts&lt;/code&gt;, вполне
можно обойтись командой &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;open /etc/hosts/ -a TextMate&lt;/code&gt;. Несколько файлов
открываются командой&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;open ~/.bashrc ~/.profile -a TextMate
&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;open&lt;/code&gt; имеет несколько ограничений. Невозможно открыть файл
на определенной строке. Так же невозможно придержать консоль до закрытия файла.
Последнее ограничение не позволяет использовать textmate как внешний редактор,
например, для git или svn.&lt;/p&gt;

&lt;p&gt;По этому у textmate есть замена неповоротливому &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;open&lt;/code&gt; — это &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;mate&lt;/code&gt;. Скрипт
устанавливатется из textmate-preferences-terminal. &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;mate&lt;/code&gt; позволяет использовать
textmate из терминала, так как-будто это действительно консольное приложение.
Например, для того, что бы использовать его как внешний редактор для всех
консольных приложений просто добавим это в &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;./profile&lt;/code&gt;:&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;export EDITOR='mate -w'
&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;-w&lt;/code&gt; - заставляет терминал дождаться закрытия файла, перед продолжением.&lt;/p&gt;

&lt;h2 id=&quot;rmate&quot;&gt;Rmate&lt;/h2&gt;

&lt;h3 id=&quot;ssh-туннель&quot;&gt;SSH-туннель&lt;/h3&gt;

&lt;p&gt;Если говорить кратко - &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ssh&lt;/code&gt;-туннель перенаправляет траффик с определенного
порта на любой порт локальной машины посредством &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ssh&lt;/code&gt;-соединения. Создадим
туннель для того, что бы получить возможность редактировать файлы на сервере
с помощью textmate:&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;ssh -R 52698:localhost:52698 &amp;lt;user&amp;gt;@&amp;lt;server&amp;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;ssh&lt;/code&gt; подключения, для того, что бы
туннель всегда создавался автоматически, без ключа &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;-R&lt;/code&gt; и объявления
пробрасываемых портов.&lt;/p&gt;

&lt;p&gt;Для единственного сервера добавим следующие строки в &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;~/.ssh/config&lt;/code&gt;:&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;Host &amp;lt;адрес сервера&amp;gt;
RemoteForward 52698 localhost:52698
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Либо можно использовать тоннель как настройку по-умолчанию, для любого сервера:&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;Host *
RemoteForward 52698 localhost:52698
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h3 id=&quot;установка&quot;&gt;Установка&lt;/h3&gt;

&lt;p&gt;Создаем новый файл на сервере, скопируем в него содержимое rmate 
(&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;preferences &amp;gt; terminal: ссылка rmate &lt;/code&gt;) и дадим права на выполнение:&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;# rmate доступен всем пользователям
sudo vi /usr/local/bin/rmate
chmod +x /usr/local/bin/rmate

# rmate доступен только текущему пользователю (проверь, есть ли этот каталог в $PATH)
vi ~/bin/rmate
chmod +x ~/bin/rmate
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Альтернативный вариант - использовать команду scp для того, что бы залить скрипт
с локальной машины на сервер. Выглядит это примерно так:&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;scp /Applications/TextMate.app/Contents/Frameworks/Preferences.framework/Versions/A/Resources/rmate &amp;lt;пользователь&amp;gt;@&amp;lt;сервер&amp;gt;:/usr/local/bin/
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Вот и все. Больше нам не придется к этому возвращаться.&lt;/p&gt;

&lt;p&gt;Теперь можно использовать &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;rmate&lt;/code&gt; на сервере. Проверим, как он работает:&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;rmate ~/test.txt
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Мы должны увидеть новое окно textmate с пустым файлом. Напишем что-нибудь
в этом файле. После сохранения файл появится на сервере.&lt;/p&gt;

&lt;h3 id=&quot;известные-проблемы&quot;&gt;Известные проблемы&lt;/h3&gt;

&lt;h4 id=&quot;usrbinenv-ruby-no-such-file-or-directory&quot;&gt;/usr/bin/env: ruby: No such file or directory&lt;/h4&gt;

&lt;p&gt;На сервере не установлен ruby-интерпретатор. &lt;a href=&quot;http://mike.eire.ca/&quot;&gt;Michael Newton&lt;/a&gt; переписал 
&lt;a href=&quot;http://pastebin.com/GcSXtTW2&quot;&gt;rmate на php&lt;/a&gt;&lt;/p&gt;

&lt;h4 id=&quot;warning-remote-port-forwarding-failed-for-listen-port-52698&quot;&gt;Warning: remote port forwarding failed for listen port 52698&lt;/h4&gt;

&lt;p&gt;На сервере 52698 порт уже чем-то занят. Нужно отключиться от сервера, и создать
ssh-туннель используя другой порт:&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;ssh -R &amp;lt;мой-порт&amp;gt;:localhost:52698 &amp;lt;user&amp;gt;@&amp;lt;server&amp;gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Теперь, запуская rmate нужно так же указывать номер порта:&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;rmate -p &amp;lt;мой-порт&amp;gt; rmate_rocks.txt
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;В результате ssh-туннель будет пересылать данные с вашего порта на сервере
к порту 52698 на локальной машине. В настройках textmate ничего менять не нужно.&lt;/p&gt;

&lt;h3 id=&quot;заключение&quot;&gt;Заключение&lt;/h3&gt;

&lt;p&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;rmate&lt;/code&gt; и &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;mate&lt;/code&gt; расширяют возможности использования textmate до удаленных
серверов и консольных приложений. Здесь можно найти миллион замечательных
способов применения этого уютного редактора. Например, можно использовать
textmate для того, что бы писать комментарии к коммиту изменений на github:&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;export GIT_EDITOR=&quot;mate --name 'Git Commit Message' -w -l 1&quot;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

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

</content>
  </entry>
  
  <entry>
    <title>Установка rmate для TextMate2</title>
    <updated>2012-06-03T00:00:00+00:00</updated>
    
      <id>http://shuvalov.info/2012/06/03/Textmate2-rmate</id>
      <link href="http://shuvalov.info/2012/06/03/Textmate2-rmate"/>
    
      <content type="html" xml:base="http://shuvalov.info/">&lt;p&gt;Решил попробовать в деле одно из нововведений второй версии textmate - rmate. Для того, что бы заставить эту штуку работать нам понадобится:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Установить ruby на сервере.&lt;/li&gt;
  &lt;li&gt;Выполнить в терминале клиента:&lt;/li&gt;
&lt;/ul&gt;

&lt;pre&gt;scp /Applications/TextMate.app/Contents/Frameworks/Preferences.framework/Versions/A/Resources/rmate user@example.com:/usr/local/bin&lt;/pre&gt;

&lt;p&gt;Здесь мы отправляем на удаленный сервер скрипт, обеспечиващий работу комманды 
&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;rmate&lt;/code&gt; (адрес скрипта можно узнать кликнув на слово &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;rmate&lt;/code&gt; в &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;preferences &amp;gt; terminal&lt;/code&gt;).
&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;user@example.com&lt;/code&gt; — это адрес нашего сервера и пользователь, под которым мы
произведем запись файла.  &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;/usr/local/bin&lt;/code&gt; - это каталог, в котором находятся
наши приложения. Bash в первую очередь будет искать здесь то, что мы пытаемся
запустить в терминале. В принципе, можно указать любой другой каталог, но тогда
запускать &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;rmate&lt;/code&gt; придется либо явно указывая путь, либо добавив этот путь
в переменную окружения &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;$PATH&lt;/code&gt;.&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Для того что бы наш сервер мог делегировать редактирование файла редактору
на клиенте - нам нужно установить SSH-туннель. Делается это следующим образом:&lt;/li&gt;
&lt;/ul&gt;

&lt;pre&gt;ssh -R 52698:127.0.0.1:52698 user@example.com&lt;/pre&gt;

&lt;p&gt;где &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;user@example.com&lt;/code&gt; - имя пользователя и адрес удаленного сервера.&lt;/p&gt;

&lt;p&gt;Если в &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;~/.ssh/config&lt;/code&gt; клиента прописать:&lt;/p&gt;

&lt;pre&gt;Host example.com
RemoteForward 52698 127.0.0.1:52698&lt;/pre&gt;

&lt;p&gt;то тунель будет создаваться автоматически, без необходимости явно его объявлять.&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Проверить работу нашего скрипта, например, написав в консоли &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;rmate test.txt&lt;/code&gt;. К этому моменту у нас должен быть открыт textmate. Файл test.txt откроется в его новом окне, где его можно редактировать. Сохранив файл, выполним в консоли vim test.txt  и увидим в vim’е все изменения, которые мы внесли с помощью textmate.&lt;/li&gt;
&lt;/ul&gt;
</content>
  </entry>
  
  <entry>
    <title>Странные ссылки в iBooks</title>
    <updated>2012-05-24T00:00:00+00:00</updated>
    
      <id>http://shuvalov.info/2012/05/24/iBooks-Strange-links</id>
      <link href="http://shuvalov.info/2012/05/24/iBooks-Strange-links"/>
    
      <content type="html" xml:base="http://shuvalov.info/">&lt;p&gt;&lt;img class=&quot;img-center&quot; src=&quot;http://31808.selcdn.ru/it-prm/pics/hero_ibooks_author.png&quot; alt=&quot;iBooks Author&quot; /&gt;&lt;/p&gt;

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

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

&lt;ol&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;li&gt;…&lt;/li&gt;
  &lt;li&gt;Профит&lt;/li&gt;
&lt;/ol&gt;

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

&lt;blockquote&gt;
  &lt;p&gt;Выберите требуемый вариант во всплывающем меню «Ссылка на».&lt;/p&gt;
  &lt;ol&gt;
    &lt;li&gt;Веб-страницу Введите URL-адрес.&lt;/li&gt;
    &lt;li&gt;Сообщение e-mail Введите адрес электронной почты и строку темы.&lt;/li&gt;
    &lt;li&gt;Закладка Выберите закладку во всплывающем меню «Имя».  При отсутствии закладок во всплывающем меню «Имя» добавьте их согласно приведенной ниже инструкции.&lt;/li&gt;
    &lt;li&gt;Рисунок Выберите рисунок в списке «Имя». Для просмотра объектов определенного типа (например, всех фильмов или галерей) выберите требуемый вариант во всплывающем меню «Показать».&lt;/li&gt;
  &lt;/ol&gt;
&lt;/blockquote&gt;

&lt;p&gt;Остановимся подробней на пункте 4 со странным названием “рисунок”. Под таким
названием переводчики подразумевали все интерактивные элементы книги. Когда я
попытался использовать его впервые, то я увидел в списке объектов для ссылок
только тесты. Я решил почитать об этой странности, и наткнулся на книгу
издательства “O’Reily” &lt;a href=&quot;http://shop.oreilly.com/product/0636920025597.do&quot; rel=&quot;nofollow&quot;&gt;Publishing with iBooks Author&lt;/a&gt;. 
Как это ни странно, книга бесплатна. Скачав книгу, я нашел в ней параграф,
касающийся ссылок:&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;Author does make it easier to add links to labeled objects, like Galleries (see “Gallery” (page 59)), Media boxes
(see “Media” (page 60)), and Figures (see “Figures” (page 55)). Select the text that you want to turn into a link, and 
choose Insert → Hyperlink → Figure Reference. The Link Inspector opens, giving you a list of all the labeled objects 
in your book to choose from. Click the one you want to link to, and your clickable link is all set.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Ключевое слово - “&lt;em&gt;labeled&lt;/em&gt;”, то есть объект, должен обязательно иметь метку,
а все мои картинки, видео и презентации в книге этих меток не имели. Опять
обратимся к документации:&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;К любому объекту можно добавить заголовок или подпись (или заголовок и
подпись одновременно). Заголовок может содержать метку (например, Рисунок или
Галерея). Можно создавать пользовательские метки. Если создать для объекта
заголовок или подпись, объект будет отображаться в готовой книге и
в горизонтальной,  и в вертикальной ориентации. В вертикальной ориентации
объекты, имеющие заголовок или подпись, располагаются  вдоль левого края
страницы.&lt;/p&gt;
&lt;/blockquote&gt;

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

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

&lt;ol&gt;
  &lt;li&gt;В KeyNote любой объект может являться ссылкой. В iBooks только текст.&lt;/li&gt;
  &lt;li&gt;В KeyNote можно ссылаться на слайды(страницы), в iBooks только на определенные объекты (закладки, интерактивные оъекты с метками).&lt;/li&gt;
&lt;/ol&gt;
</content>
  </entry>
  
  <entry>
    <title>Сломаные заполнители в iBooks</title>
    <updated>2012-05-05T00:00:00+00:00</updated>
    
      <id>http://shuvalov.info/2012/05/05/iBooks-Broken-placeholders</id>
      <link href="http://shuvalov.info/2012/05/05/iBooks-Broken-placeholders"/>
    
      <content type="html" xml:base="http://shuvalov.info/">&lt;p&gt;&lt;img class=&quot;img-center&quot; src=&quot;http://31808.selcdn.ru/it-prm/pics/hero_ibooks_author.png&quot; alt=&quot;iBooks Author&quot; /&gt;&lt;/p&gt;

&lt;h2 id=&quot;начало&quot;&gt;Начало&lt;/h2&gt;

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

&lt;h2 id=&quot;факап&quot;&gt;Факап…&lt;/h2&gt;

&lt;p&gt;Проблема, с которой я сталкнулся, когда начал разрабатывать шаблоны — 
невозможность редактирования заполнителей на страницах. Это было странно. 
Я создавал необходимый блок в шаблоне страницы, заполнял его текстом. 
Согласно справке заходил в меню “формат” -&amp;gt; “дополнительные параметны” -&amp;gt; 
“Определить как заполнитель текста”. Вроде бы все должно было быть круто: 
бери и меняй заполнители там, где нужно, но не тут то было. Блок с текстом 
было просто невозможно выделить. Невозможно редактировать. Но ведь заполнитель 
текста нужен за тем, что бы его редактировать!?… Даже если не использовать 
заполнители, все равно текст, который я вставлял в шаблоны iBooks не поддавался 
правке на конечных страницах.&lt;/p&gt;

&lt;h2 id=&quot;где-решение&quot;&gt;Где решение?&lt;/h2&gt;

&lt;p&gt;В тот момент я так и не смог найти правильное решение, ни “курение манов”, ни гугл
не давали нужного ответа. А так как время - конечный ресурс, я отказался от 
заполнителей. Я использовал готовые шаблоны, меняя их под свои нужды.
Часто я все равно сталкивался с проблемой редактирования объектов из шаблона на
странице. Спасая себя магическим сочетанием клавиш “cmd+z”, я сделал более-менее
приемлимый шаблон. Для интерактивного-контента я сделал главу, куда поместил все 
стилизованные виджеты и элементы. Добавлять их в книгу я решил копи-пастом. 
Можно работать, хотя и не так удобно, как вышло бы с нормально работающими 
шаблонами.&lt;/p&gt;

&lt;p&gt;Недавно, смотря закладки по тегу “iBooks” в &lt;a href=&quot;http://pinboard.in&quot; rel=&quot;nofollow&quot;&gt;pinboard&lt;/a&gt;, 
наткнулся на статью о том, &lt;a href=&quot;http://www.davidebarranca.com/2012/04/ibooks-author-fullscreen-images/&quot; rel=&quot;nofollow&quot;&gt;
как получить действительно полноэкранное изображение.&lt;/a&gt; 
Без лишних рамок, заголовков и описаний. Внезапно, в конце статьи я нашел 
решение своей старой проблемы с заполнителями.&lt;/p&gt;

&lt;h2 id=&quot;отгадка&quot;&gt;Отгадка&lt;/h2&gt;

&lt;p&gt;Для того, что бы заполнитель функционировал правильно необходимо выставить еще 
один параметр. В целом схема такая:&lt;/p&gt;
&lt;ol&gt;
  &lt;li&gt;Формат – Дополнительные параметры – Определить как
заполнитель (медиа-файлов или текста).&lt;/li&gt;
  &lt;li&gt;В разделе инспектора “макет” нужно выставить чекбокс “редактируемы 
на страницах использующих этот макет”.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Я потратил много полезного времени из-за того, что не знал этого решения. 
Из-за того, что в документации к iBooks author не нашел упоминания о нужном 
чекбоксе. Но я рад, что я теперь знаю правильное решение. Теперь я могу 
использовать шаблоны.&lt;/p&gt;
</content>
  </entry>
  
  <entry>
    <title>Почему я учу NODE.JS</title>
    <updated>2012-05-02T00:00:00+00:00</updated>
    
      <id>http://shuvalov.info/2012/05/02/Why-I-am-Learning-Node</id>
      <link href="http://shuvalov.info/2012/05/02/Why-I-am-Learning-Node"/>
    
      <content type="html" xml:base="http://shuvalov.info/">&lt;p&gt;Как многие (если не все), знают, я пишу на python. Пишу каждый день, и мне это
нравится. Ради веселья и  опыта я начал писать на django, и перенес на него
множество строк нативного питона.&lt;/p&gt;

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

&lt;p&gt;Я посасывал в HTML, CSS, и JavaScript.&lt;/p&gt;

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

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

&lt;p&gt;Что ж… Я несколько лет не придавал должного значения JS, теперь же я решил
наверстать упущенное, и погрузился в изучение языка. Я поставил себе цель — стать
опытным js-разработчиком, и уметь:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Использовать некоторые из новых JS-фрэймворков и инструментов (node, backbone, knockout… )&lt;/li&gt;
  &lt;li&gt;Принимать участие в разработке тех js-проектов, которые мне интересны.&lt;/li&gt;
  &lt;li&gt;Писать свой собственный js код, как server side, так и client side, не чувствуя себя тупицей.&lt;/li&gt;
  &lt;li&gt;Быть в теме всей этой шумихи вокруг js.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;К этому моменту, я имел хорошее представление о концепциях программирования.
Первая вещь, которую я сделал - прочитал «&lt;a href=&quot;http://www.amazon.com/gp/product/0596517742/ref=as_li_ss_tl?ie=UTF8&amp;amp;tag=rdegges-20&amp;amp;linkCode=as2&amp;amp;camp=1789&amp;amp;creative=390957&amp;amp;creativeASIN=0596517742&quot;&gt;Javascript: The Good Parts&lt;/a&gt;». Это
было несколько недель назад, и, до сих пор, я не мог найти хорошей возможности
применить полученные знания на практике.&lt;/p&gt;

&lt;p class=&quot;note&quot;&gt;&lt;em&gt;Если ты - опытный программист, и у тебя есть желание получше разобраться
с JS, то вряд ли есть лучшей способ, чем «JavaScript: The Good Parties».
Эта книга очень приятная, короткая и содержательная. В первую очередь я советую
прочитать эту книгу.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Так вот… Я раздумывал о подходящем месте для применения своего нового javasrcipt-фу,
и остановился на &lt;a href=&quot;http://nodejs.org/&quot;&gt;nodejs&lt;/a&gt;. В прошлом я писал большое количество консольных
приложений, поэтому меня воротило от бесконечной перезагрузки страниц в браузере,
необходимой для отладки своего кода. Nodejs стал подходящим выбором в этом отношении.&lt;/p&gt;

&lt;p&gt;Если кто-то не знаком с node.js - это серверный javascript интерпретатор,
позовляющий работать с js прямо из командной строки, как с ruby и perl. В комплекте
с node.js идет отличный пакетный менеджер — &lt;a href=&quot;http://npmjs.org/&quot;&gt;npm&lt;/a&gt;, позволяющий легко отправлять,
скачивать и устанавливать js-модули.&lt;/p&gt;

&lt;p&gt;Раньше я прочитал много &lt;a href=&quot;http://teddziuba.com/2011/10/node-js-is-cancer.html&quot;&gt;негативных отзывов о nodejs&lt;/a&gt;, но теперь я могу им
только удивляться, ведь node чертовски крут! Я еще не использовал его для создания
веб-сайтов или чего-то подобного, но он реально делает js очень простым для
таких ребят как я - матерых backend программистов, которые хотят разобраться
с JavaScript’ом без глупых барьеров (да-да, сейчас я смотрю именно на вас, браузеры).&lt;/p&gt;

&lt;p&gt;У node есть отличный пакетный менеджер, тонны потрясных модулей, огромное
сообщество разработчиков, и отличная документация. Я написал свой первый модуль
&lt;a href=&quot;https://github.com/telephonyresearch/node-opencnam&quot;&gt;node-opencnam&lt;/a&gt; меньше чем за час. Это безумно круто!&lt;/p&gt;

&lt;p&gt;Я проделал путь от нулевой отметки до публично доступного модуля меньше, чем
за 60 минут!&lt;/p&gt;

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

&lt;p&gt;Я буду держать вас в курсе.&lt;/p&gt;

&lt;p class=&quot;note&quot;&gt;&lt;em&gt;В эти выходные я начал читать книгу «&lt;a href=&quot;http://www.nodebeginner.org/&quot;&gt;Node Beginner Book&lt;/a&gt;»&lt;/em&gt;.&lt;/p&gt;

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