<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:wfw="http://wellformedweb.org/CommentAPI/" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:sy="http://purl.org/rss/1.0/modules/syndication/" xmlns:slash="http://purl.org/rss/1.0/modules/slash/">
  <channel>
    <language>ru</language>
    <title>Коротко о главном</title>
    <description>Короткие понятные ответы на часто задаваемые IT-вопросы.</description>
    <link>https://tproger.ru/explain</link>
    <atom:link href="https://tproger.ru/explain/feed" rel="self" type="application/rss+xml"/>
    <lastBuildDate>Sat, 03 Oct 2026 23:31:13 GMT</lastBuildDate>
    <sy:updatePeriod>hourly</sy:updatePeriod>
    <sy:updateFrequency>12</sy:updateFrequency>
    <image>
      <title>Коротко о главном</title>
      <link>https://tproger.ru</link>
      <url>https://tproger.ru/apple-touch-icon.png</url>
    </image>
    <item>
      <title>Pip: как устанавливать пакеты в Python</title>
      <link>https://tproger.ru/explain/pip-kak-ustanavlivat-pakety-v-python</link>
      <comments>https://tproger.ru/explain/pip-kak-ustanavlivat-pakety-v-python?scrollTo=tproger-comments</comments>
      <dc:creator><![CDATA[Олег Борисенков]]></dc:creator>
      <guid isPermaLink="true">https://tproger.ru/explain/pip-kak-ustanavlivat-pakety-v-python</guid>
      <description><![CDATA[<p>Менеджер пакетов pip входит в Python 2.7.9 и 3.4 и новее: как проверить его наличие, установить скрипт вручную и управлять пакетами.</p><p>— Читать дальше «<a rel="follow" href="https://tproger.ru/explain/pip-kak-ustanavlivat-pakety-v-python">Pip: как устанавливать пакеты в Python</a>»</p>]]></description>
      <category><![CDATA[Python]]></category>
      <category><![CDATA[Для начинающих]]></category>
      <category><![CDATA[Windows]]></category>
      <category><![CDATA[Коротко о главном]]></category>
      <slash:comments>0</slash:comments>
      <pubDate>Thu, 17 Dec 2020 14:57:45 GMT</pubDate>
      <content:encoded><![CDATA[<p>Pip — менеджер пакетов для <a href="https://tproger.ru/articles/what-python-is-good-for/">Python</a>, работа с ним осуществляется через командную строку. Pip не нужно устанавливать отдельно, если вы пользуетесь Python версии 2.7.9 и новее или версии 3.4 и новее. Если pip установлен, то можно ввести в командную строку:</p><p>Команды статье указаны для Windows, работа с pip в Linux может отличаться.</p><p>Вы получите справку по основным командам.</p><h2>Установка pip для Python</h2><p>Если pip не установлен, то нужно скачать <a href="https://bootstrap.pypa.io/">скрипт</a>. Выбирайте папку с номером вашей версии Python. После этого в командной строке перейдите в папку со скриптом и выполните команду:</p><p>Если pip установлен в папку ProgramFiles, то вам нужно запускать командную строку от администратора.</p><p>Если вы установили pip, но все равно получаете ошибку в консоли, нужно указать путь к файлу pip.exe в переменной Path. Для этого зайдите в свойства компьютера&gt;Дополнительные параметры системы&gt;Переменные среды. Здесь (в зависимости о версии Windows) либо добавьте путь к уже существующему через точку с запятой, либо просто нажмите создать и скопируйте путь в новое поле.</p><p>Если вам нужно обновить pip напишите в командной строке:</p><h2>Управление пакетами</h2><p>Чтобы выполнить установку пакета с сайта <a href="https://pypi.org/">pypi.org</a> введите в консоли:</p><p>Если вам нужно использовать несколько версий pip, то нужную можно указать так (начиная с версии pip 0.8):</p><p>Таким же образом можно выбирать версию Python:</p><p>Pip версии 1.5 и выше следует указывать так:</p><p>Чтобы обновить пакет введите:</p><p>Для удаления пакета используйте команду uninstall:</p><p>Флаг -m используется для того чтобы запустить установленный модуль, как скрипт (если написать pip без -m вы можете получить ошибку).</p><p>Вывести список всех установленных пакетов в файл можно с помощью :</p><p>При наличии такого файла, можно устанавливать пакеты группами:</p><p>Необходимые пакеты можно найти не заходя на сайт pyPi.org (в данный момент <a href="https://habr.com/ru/news/t/533484/">недоступно</a>):</p><p>Чтобы узнать подробности об установленном пакете введите:</p><p>Проверить установлены ли все зависимости для ваших пакетов можно так:</p><p>Теперь, с этими знаниями, вы можете самостоятельно скачать пакет cowsay, зайти в python, и ввести этот текст:</p><p>Готово! У вас есть говорящая консольная корова:</p><figure><img src="https://media.tproger.ru/uploads/2020/12/cowsay.png" alt="" /></figure>]]></content:encoded>
    </item>
    <item>
      <title>Как создать объект для обработки событий в JavaScript?</title>
      <link>https://tproger.ru/explain/kak-sozdat-obekt-dlja-obrabotki-sobytij-v-javascript</link>
      <comments>https://tproger.ru/explain/kak-sozdat-obekt-dlja-obrabotki-sobytij-v-javascript?scrollTo=tproger-comments</comments>
      <dc:creator><![CDATA[Олег Борисенков]]></dc:creator>
      <guid isPermaLink="true">https://tproger.ru/explain/kak-sozdat-obekt-dlja-obrabotki-sobytij-v-javascript</guid>
      <description><![CDATA[<p>События JavaScript делают веб-приложения интерактивными: addEventListener принимает тип события, коллбэк и параметр options или useCapture.</p><p>— Читать дальше «<a rel="follow" href="https://tproger.ru/explain/kak-sozdat-obekt-dlja-obrabotki-sobytij-v-javascript">Как создать объект для обработки событий в JavaScript?</a>»</p>]]></description>
      <category><![CDATA[JavaScript]]></category>
      <category><![CDATA[Для начинающих]]></category>
      <category><![CDATA[Коротко о главном]]></category>
      <slash:comments>0</slash:comments>
      <pubDate>Thu, 17 Dec 2020 09:24:39 GMT</pubDate>
      <content:encoded><![CDATA[<p>Чтобы создавать интерактивные веб-приложения нужно использовать события JavaScript. Как они работают?</p><p>Вы указываете нужный тип события, добавляете коллбэк, и теперь можете обрабатывать клики, нажатия клавиш, прокрутку и другие события.</p><p>Например, чтобы обработать нажатие кнопки, можно использовать следующий код:</p><p>Этот код обращается к DOM, находит указанный элемент, и добавляет обработчик события click используя addEventListener.</p><p>В соответствии с <a href="https://developer.mozilla.org/en-US/docs/Web/API/EventTarget/addEventListener">документацией DOM,</a> target.addEventListener может иметь следующие параметры:</p><p>addEventListener принимает: тип события, коллбэк и параметр options/useCapture. Подробнее о возможных значениях параметров в <a href="https://developer.mozilla.org/en-US/docs/Web/API/EventTarget/addEventListener">документации событий JavaScript</a>.</p><p>Параметр listener может быть не только функцией но и объектом.</p><h2>Обработка событий JavaScript с помощью addEventListener и EventListener</h2><p>MDN описывает listener так:</p><blockquote>listener может быть объектом реализующим интерфейс EventListener или JavaScript функцией</blockquote><p>В ранней версии спецификации событий DOM (до HTML5), описан интерфейс EventListener. Реализующие его объекты должны содержать метод handeEvent. Они могут использоваться с addEventListener.</p><p>Это код класса EventHandler. Инициализированные объекты обработчиков событий могут быть переданы в addEventListener. Обработчик считает количество событий нужного типа. Попробуйте этот код на CodePen. Вся информация хранится в самом объекте и код работает без внешних переменных. Мне нравится этот паттерн, он пригодится для работы с последовательными событиями.</p><p>MDN говорит, что интерфейс EventListener поддерживается большинством браузеров и вы можете безопасно передавать реализующие его объекты в addEventListener. Когда их нужно передавать? Объясню на примере:</p><p>Конструктор класса MyComponent принимает элемент DOM в качестве аргумента и сам добавляет\удаляет его обработчики событий JavaScript. Класс реализует интерфейс EventListener, а следовательно вы можете передавать this в addEventListener.</p><p>Для того чтобы ваш интерфейс был удобным и интерактивным, важно не только использовать события JavaScript, но и учитывать размер области нажатия. Подробнее о том, как помочь юзеру не промахнуться, читайте в статье: <a href="https://tproger.ru/articles/clickable-area/">«Хотел кликнуть, но не смог: как правильно настроить размер области клика»</a>.</p>]]></content:encoded>
    </item>
    <item>
      <title>Протоколы передачи данных: что это, какие бывают и в чём различия?</title>
      <link>https://tproger.ru/explain/protokoly-peredachi-dannyh-chto-jeto-kakie-byvajut-i-v-chjom-razlichija</link>
      <comments>https://tproger.ru/explain/protokoly-peredachi-dannyh-chto-jeto-kakie-byvajut-i-v-chjom-razlichija?scrollTo=tproger-comments</comments>
      <dc:creator><![CDATA[Александр Ланский]]></dc:creator>
      <guid isPermaLink="true">https://tproger.ru/explain/protokoly-peredachi-dannyh-chto-jeto-kakie-byvajut-i-v-chjom-razlichija</guid>
      <description><![CDATA[<p>Сетевые протоколы задают правила обмена данными в интернете. Разбор основных из них, начиная с IP — ненадёжного протокола без установки соединения.</p><p>— Читать дальше «<a rel="follow" href="https://tproger.ru/explain/protokoly-peredachi-dannyh-chto-jeto-kakie-byvajut-i-v-chjom-razlichija">Протоколы передачи данных: что это, какие бывают и в чём различия?</a>»</p>]]></description>
      <category><![CDATA[Интернет]]></category>
      <category><![CDATA[Сетевые протоколы]]></category>
      <category><![CDATA[Коротко о главном]]></category>
      <slash:comments>0</slash:comments>
      <pubDate>Wed, 09 Dec 2020 08:33:01 GMT</pubDate>
      <content:encoded><![CDATA[<p>Интернет очень большой и комплексный. Но на базовом уровне это всего лишь связь между различными компьютерами (не только персональными). Эта связь представляет из себя сетевые протоколы передачи данных — набор правил, который определяет порядок и особенности передачи информации для конкретных случаев.</p><p>Протоколов большое множество. Про основные из них рассказано далее.</p><h2>IP — Internet Protocol</h2><p>Протокол передачи, который первым объединил отдельные компьютеры в единую сеть. Самый примитивный в этом списке. Он является ненадёжным, т. е. не подтверждает доставку пакетов получателю и не контролирует целостность данных. По протоколу IP передача данных осуществляется без установки соединения.</p><p>Основная задача этого протокола — маршрутизация <a href="https://ru.wikipedia.org/wiki/%D0%94%D0%B0%D1%82%D0%B0%D0%B3%D1%80%D0%B0%D0%BC%D0%BC%D0%B0">датаграмм</a>, т. е. определение пути следования данных по узлам сети.</p><p>Популярная версия на текущий момент — IPv4 с 32-битными адресами. Это значит, что в интернете могут хранится 4.29 млрд адресов IPv4. Число большое, но не бесконечное. Поэтому существует версия IPv6, которая поможет решить проблему переполнения адресов, ведь уникальных IPv6 будет 2 ^ 128 адресов (число с 38 знаками).</p><h2>TCP/IP — Transmission Control Protocol/Internet Protocol</h2><p>Это стек протоколов TCP и IP. Первый обеспечивает и контролирует надёжную передачу данных и следит за её целостностью. Второй же отвечает за маршрутизацию для отправки данных. Протокол TCP часто используется более комплексными протоколами.</p><h2>UDP — User Datagram Protocol</h2><p>Протокол, обеспечивающий передачу данных без предварительного создания соединения между ними. Этот протокол является ненадёжным. В нём пакеты могут не только не дойти, но и прийти не по порядку или вовсе продублироваться.</p><p>Основное преимущество UDP протокола заключается в скорости доставки данных. Именно поэтому чувствительные к сетевым задержкам приложения часто используют этот тип передачи данных.</p><h2>FTP — File Transfer Protocol</h2><p>Протокол передачи файлов. Его использовали ещё в 1971 году — задолго до появления протокола IP. На текущий момент этим протоколом пользуются при удалённом доступе к хостингам. FTP является надёжным протоколом, поэтому гарантирует передачу данных.</p><p>Этот протокол работает по принципу клиент-серверной архитектуры. Пользователь проходит аутентификацию (хотя в отдельных случаях может подключаться анонимно) и получает доступ к файловой системе сервера.</p><h2>DNS</h2><p>Это не только система доменных имён (Domain Name System), но и протокол, без которого эта система не смогла бы работать. Он позволяет клиентским компьютерам запрашивать у DNS-сервера IP-адрес какого-либо сайта, а также помогает обмениваться базами данных между серверами DNS. В работе этого протокола также используются TCP и UDP.</p><h2>HTTP — HyperText Transfer Protocol</h2><p>Изначально протокол передачи HTML-документов. Сейчас же он используется для передачи произвольных данных в интернете. Он является протоколом клиент-серверного взаимодействия без сохранения промежуточного состояния. В роли клиента чаще всего выступает веб-браузер, хотя может быть и, например, поисковый робот. Для обмена информацией протокол HTTP в большинстве случаев использует TCP/IP.</p><p>HTTP имеет расширение HTTPS, которое поддерживает шифрование. Данные в нём передаются поверх криптографического протокола <a href="https://ru.wikipedia.org/wiki/TLS">TLS</a>.</p><h2>NTP — Network Time Protocol</h2><p>Не все протоколы передачи нужны для обмена классического вида информацией. NTP — протокол для синхронизации локальных часов устройства со временем в сети. Он использует <a href="https://ru.wikipedia.org/wiki/%D0%90%D0%BB%D0%B3%D0%BE%D1%80%D0%B8%D1%82%D0%BC_%D0%9C%D0%B0%D1%80%D0%B7%D1%83%D0%BB%D0%BB%D0%BE">алгоритм Марзулло</a>. Благодаря нему протокол выбирает более точный источник времени. NTP работает поверх UDP — поэтому ему удаётся достигать большой скорости передачи данных. Протокол достаточно устойчив к изменениям задержек в сети.</p><p>Последняя версия NTPv4 способна достигать точности 10мс в интернете и до 0,2мс в локальных сетях.</p><h2>SSH — Secure SHell</h2><p>Протокол для удалённого управления операционной системой с использованием TCP. В SSH шифруется весь трафик, причём с возможностью выбора алгоритма шифрования. В основном это нужно для передачи паролей и другой важной информации.</p><p>Также SSH позволяет обрабатывать любые другие протоколы передачи. Это значит, что кроме удалённого управления компьютером, через протокол можно пропускать любые файлы или даже аудио/видео поток.</p><p>SSH часто применяется при работе с хостингами, когда клиент может удалённо подключиться к серверу и работать уже оттуда.</p>]]></content:encoded>
    </item>
    <item>
      <title>Логические операторы: И, ИЛИ, РАВНО и другие</title>
      <link>https://tproger.ru/explain/logicheskie-operatory-i-ili-ravno-i-drugie</link>
      <comments>https://tproger.ru/explain/logicheskie-operatory-i-ili-ravno-i-drugie?scrollTo=tproger-comments</comments>
      <dc:creator><![CDATA[Олег Борисенков]]></dc:creator>
      <guid isPermaLink="true">https://tproger.ru/explain/logicheskie-operatory-i-ili-ravno-i-drugie</guid>
      <description><![CDATA[<p>Что такое логические операторы. Рассматриваем основные виды: И, ИЛИ, РАВНО и другие. Рассматриваем применение и основные задачи логических операторов ✔ Tproger</p><p>— Читать дальше «<a rel="follow" href="https://tproger.ru/explain/logicheskie-operatory-i-ili-ravno-i-drugie">Логические операторы: И, ИЛИ, РАВНО и другие</a>»</p>]]></description>
      <category><![CDATA[Для начинающих]]></category>
      <category><![CDATA[Основные принципы программирования]]></category>
      <category><![CDATA[Коротко о главном]]></category>
      <slash:comments>0</slash:comments>
      <pubDate>Mon, 07 Dec 2020 11:04:16 GMT</pubDate>
      <content:encoded><![CDATA[<p>Логические операторы — это специальные символы (или сочетания символов), которые изменяют или комбинируют логические значения типа Boolean — true и false. Их используют чтобы создавать сложные условия, например в <a href="https://tproger.ru/explain/tipy-ciklov-v-jazykah-programmirovanija-for-foreach-while-i-do-while">циклах</a>.</p><h2>Общее описание логических операторов</h2><p>Логические операторы позволяют создавать условия, которые определяют поведение программы в зависимости от того, истинны или ложны входные данные. Программирование часто включает принятие решений — в каких случаях выполнять ту или иную операцию, а логические операторы являются ключевым инструментом для этого. Они помогают строить сложные логические выражения, используя более простые условия.</p><p>В зависимости от вида задачи, программисты используют операторы для сравнения значений, проверки истинности, объединения или исключения условий. Логические операторы делятся на несколько категорий, каждая из которых имеет свою специфику применения.</p><h2>Логические операторы</h2><h3>Оператор НЕ (!, not)</h3><p>Выражение вида !true равно false и наоборот. Оператор ! (не) инвертирует логическое значение, это унарный оператор (применяется к одному операнду), он помещается перед операндом. Если условие истинно, то результат применения оператора отрицания будет ложным, и наоборот. Например, если a = true, то выражение !a даст false.</p><p>Например:</p><h3>Оператор И (&amp;&amp;, and)</h3><p>Оператор &amp;&amp; — это оператор логического умножения. Выражение вида a &amp;&amp; b будет равно true только тогда, когда и а и b равны true. Если хотя бы один из операндов окажется ложным, результат будет false. Данный оператор используется, когда необходимо, чтобы выполнялись несколько условий одновременно.</p><h3>Оператор ИЛИ (||, or)</h3><p>Оператор || — это оператор логического сложения. Выражение a || b будет равно true, когда или a, или b (или оба) равен true. Это полезно, когда нужно проверить, выполняется ли хотя бы одно из нескольких условий.</p><p>В сложных условиях оператор || помогает упростить проверки, позволяя гибко обрабатывать ситуации, когда истинность только одного условия уже достаточна для выполнения действия.</p><h3>Оператор исключающее ИЛИ (^, xor)</h3><p>Выражение a ^ b будет равно true, когда только один из операндов имеет значение true. Подробно о применении xor рассказывается в статье <b>«</b>Практика применения XOR в программировании<b></b><b>»</b></p><h3>Операторы сравнения</h3><p>Операторы сравнения позволяют проверять равенство или неравенство между двумя значениями. Эти операторы часто используются в условных операторах, таких как while и for. Рассмотрим два ключевых оператора сравнения.</p><ol><li><b>Оператор эквивалентности (==)</b> — проверяет и сравнивает два значения. Выражение a == b будет равно true, когда a и b имеют одинаковые значения. Например, выражение 5 == 5 вернёт true, так как оба значения одинаковы.</li><li><b>Оператор неравенства (!=)</b> — проверяет, разные ли два значения. Выражение a != b будет равно true, когда a и b имеют разные значения. Пример: 5 != 3 вернёт true, так как числа не равны.</li></ol><figure><img src="https://media.tproger.ru/uploads/2020/12/bool.png" alt="«Логические операторы: И, ИЛИ, РАВНО и другие»" /></figure><p>Эти операторы используются для создания логического условия в программах, что позволяет динамически изменять поведение системы.</p><h2>Приоритет логических операторов</h2><ol><li>Оператор эквивалентности — ==, оператор неравенства — !=.</li><li>Оператор отрицания — !.</li><li>Оператор И — &amp;&amp;.</li><li>Оператор исключающее ИЛИ — ^.</li><li>Оператор ИЛИ — ||.</li></ol><p>Предлагаем вам пройти тест и узнать, насколько хорошо вы разобрались с логическими операторами:</p>]]></content:encoded>
    </item>
    <item>
      <title>Типы циклов в языках программирования: for, foreach, while и do while</title>
      <link>https://tproger.ru/explain/tipy-ciklov-v-jazykah-programmirovanija-for-foreach-while-i-do-while</link>
      <comments>https://tproger.ru/explain/tipy-ciklov-v-jazykah-programmirovanija-for-foreach-while-i-do-while?scrollTo=tproger-comments</comments>
      <dc:creator><![CDATA[Олег Борисенков]]></dc:creator>
      <guid isPermaLink="true">https://tproger.ru/explain/tipy-ciklov-v-jazykah-programmirovanija-for-foreach-while-i-do-while</guid>
      <description><![CDATA[<p>Цикл состоит из условия и тела, а каждое повторение называется итерацией. Как работают циклы for и foreach и чем они отличаются от while.</p><p>— Читать дальше «<a rel="follow" href="https://tproger.ru/explain/tipy-ciklov-v-jazykah-programmirovanija-for-foreach-while-i-do-while">Типы циклов в языках программирования: for, foreach, while и do while</a>»</p>]]></description>
      <category><![CDATA[Для начинающих]]></category>
      <category><![CDATA[Языки программирования]]></category>
      <category><![CDATA[Коротко о главном]]></category>
      <slash:comments>0</slash:comments>
      <pubDate>Mon, 07 Dec 2020 07:50:45 GMT</pubDate>
      <content:encoded><![CDATA[<p>В программировании различные типы циклов применяются для того, чтобы повторить некоторое действие нужное количество раз. Например <a href="https://tproger.ru/translations/sorting-for-beginners/#:~:text=%D0%9F%D1%83%D0%B7%D1%8B%D1%80%D1%8C%D0%BA%D0%BE%D0%B2%D0%B0%D1%8F%20%D1%81%D0%BE%D1%80%D1%82%D0%B8%D1%80%D0%BE%D0%B2%D0%BA%D0%B0&amp;text=%D0%A1%D0%BE%D1%80%D1%82%D0%B8%D1%80%D0%BE%D0%B2%D0%BA%D0%B0%20%D0%BF%D1%83%D0%B7%D1%8B%D1%80%D1%8C%D0%BA%D0%BE%D0%BC%20%E2%80%94%20%D1%8D%D1%82%D0%BE%20%D1%81%D0%B0%D0%BC%D1%8B%D0%B9%20%D0%BF%D1%80%D0%BE%D1%81%D1%82%D0%BE%D0%B9,%D0%B8%D0%B7%20%D0%BD%D0%B5%D0%BE%D1%82%D1%81%D0%BE%D1%80%D1%82%D0%B8%D1%80%D0%BE%D0%B2%D0%B0%D0%BD%D0%BD%D1%8B%D1%85%20%D0%B2%20%D0%BA%D0%BE%D0%BD%D0%B5%D1%86%20%D0%BC%D0%B0%D1%81%D1%81%D0%B8%D0%B2%D0%B0.">отсортировать элементы массива</a> или найти <a href="https://ru.wikipedia.org/wiki/Факториал">факториал числа</a>. Цикл состоит из условия и тела цикла. Код, находящийся в теле, выполняется, когда условие равно true. Каждое повторение цикла называется итерацией.</p><h2>Типы циклов</h2><h3>Цикл For</h3><p>i — это переменная-счётчик, которая сначала равна нулю. До тех пор, пока она меньше 10, выполняется тело цикла, затем счетчик увеличивается на единицу. For — цикл с предусловием. Это значит, что сначала проверяется условие, и если оно true, то тело выполняется. В скобках объявляется тип переменной счётчика и её начальное значение. Затем указывается условие конца цикла и способ, которым изменяется значение счётчика.</p><h3>Цикл Foreach (или совместный цикл)</h3><p>Тело этого цикла выполнится для каждого элемента коллекции. В переменной element будет доступен по очереди каждый элемент массива array.</p><h3>Цикл While</h3><p>Относится к тому же типу циклов, что и For, — цикл с предусловием. С его помощью можно создать безусловный цикл, например while(1) — бесконечный цикл. Чтобы его закончить, нужно использовать служебное слово break.</p><h3>Цикл Do While</h3><p>Do While относится к типу циклов с постусловием. Однако здесь код выполнится как минимум один раз, даже если условие false.</p><h3>Вложенные циклы</h3><p>Циклы можно помещать внутрь друг друга. Это удобно для перебора многомерных коллекций. Код в примере выше выведет в консоль значение каждого элемента из двумерного массива array.</p><h2>Операторы циклов</h2><h3>Break</h3><p>Оператор break используется для досрочного выхода из цикла. Когда программа встречает break, цикл немедленно завершается и начинает выполняться код, следующий за циклом.</p><h3>Continue</h3><p>Оператор Continue даёт циклу команду выйти из текущей итерации и перейти к следующей.</p><p>Этот код выведет в консоль все нечетные числа из диапазона от 0 до 10:</p>]]></content:encoded>
    </item>
    <item>
      <title>Типизация языков программирования: разбираемся в основах</title>
      <link>https://tproger.ru/explain/tipizacija-jazykov-programmirovanija-razbiraemsja-v-osnovah</link>
      <comments>https://tproger.ru/explain/tipizacija-jazykov-programmirovanija-razbiraemsja-v-osnovah?scrollTo=tproger-comments</comments>
      <dc:creator><![CDATA[Мария Кривоченко]]></dc:creator>
      <guid isPermaLink="true">https://tproger.ru/explain/tipizacija-jazykov-programmirovanija-razbiraemsja-v-osnovah</guid>
      <description><![CDATA[<p>Типизация языков программирования‌ ‌определяет,‌ ‌как‌ ‌вы‌ ‌будете‌ ‌работать‌ ‌с‌ ‌типами‌ ‌переменных. Рассказываем о ней подробнее.</p><p>— Читать дальше «<a rel="follow" href="https://tproger.ru/explain/tipizacija-jazykov-programmirovanija-razbiraemsja-v-osnovah">Типизация языков программирования: разбираемся в основах</a>»</p>]]></description>
      <category><![CDATA[Языки программирования]]></category>
      <category><![CDATA[Динамическая типизация]]></category>
      <category><![CDATA[Коротко о главном]]></category>
      <slash:comments>0</slash:comments>
      <pubDate>Thu, 03 Dec 2020 09:09:43 GMT</pubDate>
      <content:encoded><![CDATA[<p>Типизация языков программирования ‌—‌ ‌это‌ ‌то,‌ ‌как‌ ‌различные‌ ‌языки‌ ‌распознают‌ ‌типы‌ ‌переменных.‌ ‌Она‌ ‌определяет,‌ ‌как‌ ‌вы‌ ‌будете‌ ‌работать‌ ‌с‌ ‌типами‌ ‌переменных:‌ ‌нужно‌ ‌ли‌ ‌их‌ ‌задавать‌ ‌изначально,‌ ‌можно‌ ‌ли‌ ‌изменять‌ ‌и‌ ‌так‌ ‌далее.‌ ‌</p><h2>Виды‌ ‌типизации‌</h2><p>Языки‌ ‌программирования‌ ‌бывают‌ ‌типизированными‌ ‌и‌ ‌нетипизированными‌ ‌(бестиповыми).‌ ‌</p><p>Бестиповая‌ ‌типизация‌ ‌в‌ ‌основном‌ ‌присуща‌ ‌старым‌ ‌и‌ ‌низкоуровневым‌ ‌языкам‌ ‌программирования,‌ ‌например‌ ‌‌Forth.‌ ‌‌Все‌ ‌данные‌ ‌в‌ ‌таких‌ ‌языках‌ ‌считаются‌ ‌цепочками‌ ‌бит‌ ‌произвольной‌ ‌длины‌ ‌и,‌ ‌как‌ ‌следует‌ ‌из‌ ‌названия,‌ ‌не‌ ‌делятся‌ ‌на‌ ‌типы.‌ ‌Работа‌ ‌с‌ ‌ними‌ ‌труднее,‌ ‌и‌ ‌при‌ ‌чтении‌ ‌кода‌ ‌не‌ ‌всегда‌ ‌ясно,‌ ‌о‌ ‌каком‌ ‌типе‌ ‌переменной‌ ‌идет‌ ‌речь.‌ ‌Это‌ ‌можно‌ ‌исправить,‌ ‌написав‌ ‌комментарии‌ ‌к‌ ‌коду.‌</p><p>При‌ ‌этом‌ ‌у‌ ‌нетипизированных‌ ‌языков‌ ‌немало‌ ‌плюсов.‌ ‌В‌ ‌них‌ ‌можно‌ ‌совершать‌ ‌операции‌ ‌с‌ ‌любыми‌ ‌данными,‌ ‌и‌ ‌код‌ ‌получается‌ ‌более‌ ‌эффективным.‌ ‌</p><p>Перейдём‌ ‌к‌ ‌типизированным языкам.‌ ‌</p><h3>Статическая‌ ‌и‌ ‌динамическая‌ ‌типизация‌ ‌</h3><p>Особенность‌ ‌языков‌ ‌программирования‌ ‌со‌ ‌статической‌ ‌типизацией‌ ‌в‌ ‌том,‌ ‌что‌ ‌проверка‌ типов‌ ‌начинается‌ ‌на‌ ‌стадии‌ ‌компиляции.‌ ‌Компиляторы‌ ‌ищут‌ ‌ошибки‌ ‌ещё‌ ‌до‌ ‌запуска‌ программы,‌ ‌и‌ ‌вам‌ ‌не‌ ‌нужно‌ ‌раз‌ ‌за‌ ‌разом‌ ‌запускать‌ ‌её,‌ ‌чтобы‌ выяснить,‌ ‌что‌ ‌пошло‌ ‌не‌ ‌так.‌ ‌Благодаря‌ ‌этому‌ ‌статически‌ ‌типизированные языки программирования ‌зачастую‌ ‌быстрее.‌ ‌Кроме‌ ‌того,‌ ‌тип‌ ‌для‌ ‌переменной‌ ‌можно‌ ‌назначить‌ ‌только‌ ‌один‌ ‌раз.‌ ‌Например‌ ‌‌в‌ ‌Java‌ ‌такая‌ ‌запись‌ ‌вызовет‌ ‌ошибку‌ ‌на‌ ‌этапе‌ ‌компиляции:‌ ‌</p><p>В‌ ‌свою‌ ‌очередь,‌ ‌языки‌ ‌с‌ ‌динамической‌ ‌типизацией‌ ‌ищут‌ ‌ошибки‌ ‌на‌ ‌стадии‌ ‌исполнения.‌ ‌В‌ ‌них‌ ‌можно‌ ‌задать‌ ‌разные‌ ‌типы‌ ‌для‌ ‌одной‌ ‌и‌ ‌той‌ ‌же‌ ‌переменной,‌ ‌и‌ ‌они‌ ‌более‌ ‌гибкие.‌ ‌Например, в‌ ‌Python‌ ‌возможна‌ ‌такая‌ ‌запись,‌ ‌и‌ ‌ошибки‌ ‌не‌ ‌будет:‌ ‌</p><p>К‌ ‌тому‌ ‌же‌ ‌их‌ ‌проще‌ ‌освоить.‌ ‌Почитайте‌ ‌больше‌ ‌о‌ ‌том,‌ ‌чем‌ ‌хороши‌ ‌‌<a href="https://tproger.ru/translations/appeal-of-dynamically-typed-languages/">динамически‌ ‌типизированные‌ ‌языки</a>‌.‌ ‌</p><h3>Сильная‌ ‌и‌ ‌слабая‌ ‌типизация‌ ‌</h3><p>В‌ ‌слабо‌ ‌типизированных‌ ‌языках‌ ‌программирования‌ ‌можно‌ ‌смешивать‌ ‌разные‌ ‌типы‌ ‌данных. Так‌ ‌код‌ ‌получается‌ ‌короче‌ ‌—‌ ‌язык‌ ‌«старается‌»‌ ‌сам‌ ‌выполнять‌ ‌операции‌ ‌преобразования‌ ‌с‌ ‌разными‌ ‌типами.‌ ‌Впрочем,‌ ‌в‌ ‌таком‌ ‌случае‌ ‌не‌ ‌всегда‌ ‌ясно,‌ ‌как‌ ‌поведёт‌ ‌себя‌ ‌программа.‌ ‌Например,‌ ‌в‌ ‌JavaScript‌ ‌возможна‌ ‌такая‌ ‌запись:‌ ‌</p><p>При‌ ‌сильной‌ ‌или‌ ‌строгой‌ ‌типизации,‌ ‌как‌ ‌в‌ ‌Python,‌ ‌язык‌ ‌не‌ ‌позволяет‌ ‌смешивать‌ ‌разные‌ ‌типы‌ ‌—‌ ‌то‌ ‌есть,‌ ‌если‌ ‌вы‌ ‌обозначили‌ ‌переменную‌ ‌как‌ ‌число,‌ ‌то‌ ‌добавить‌ ‌к‌ ‌ней‌ ‌строку‌ ‌уже‌ ‌не‌ ‌получится:‌ ‌ ‌</p><p>Языки‌ ‌с‌ ‌сильной‌ ‌типизацией‌ ‌надёжнее.‌ ‌Да и‌ ‌программист,‌ ‌прописывая‌ ‌все‌ ‌преобразования‌ ‌вручную,‌ ‌лучше‌ ‌понимает,‌ ‌как‌ ‌работает‌ ‌его‌ ‌код.‌ ‌</p><h3>Явная‌ ‌и‌ ‌неявная‌ ‌типизация‌ ‌</h3><p>В‌ ‌языках‌ ‌программирования‌ ‌с‌ ‌явной‌ ‌типизацией‌ ‌типы‌ ‌переменных‌ ‌и‌ ‌возвращаемых‌ ‌значений‌ ‌функций‌ ‌нужно‌ ‌задавать.‌ ‌Это‌ ‌дольше,‌ ‌но‌ ‌так‌ ‌проще‌ ‌определять,‌ ‌что‌ ‌значат‌ ‌все‌ ‌данные,‌ ‌а‌ ‌программисту‌ ‌не‌ ‌придётся‌ ‌запоминать‌ ‌или‌ ‌записывать‌ ‌отдельно‌ ‌каждое‌ ‌значение.‌ ‌В‌ ‌языке‌ ‌С‌ ‌переменную‌ ‌нужно‌ ‌записывать‌ ‌так:‌ ‌</p><p>int‌ ‌a‌ ‌=‌ ‌7</p><p>При‌ ‌неявной‌ ‌типизации‌ ‌тип‌ ‌переменной‌ ‌определяется‌ ‌интерпретатором‌ ‌или‌ ‌компилятором,‌ ‌поэтому‌ ‌записи‌ ‌в‌ ‌таких‌ ‌языках‌ ‌короче.‌ ‌Иногда‌ ‌они‌ ‌позволяют‌ ‌вручную‌ ‌указывать‌ ‌типы‌ ‌значений,‌ ‌как‌ ‌в‌ ‌Haskell‌ ‌или‌ ‌Python.‌ ‌В‌ ‌Python‌ ‌возможна‌ ‌такая‌ ‌запись,‌ ‌ведь‌ ‌язык‌ ‌сам‌ ‌определит,‌ ‌что‌ ‌это‌ ‌целое‌ ‌число:‌ ‌</p><p>a‌ ‌‌=‌‌ ‌7‌‌</p><h2>Типизация‌ ‌в‌ ‌разных‌ ‌языках‌ ‌программирования‌ ‌</h2><figure><img src="https://media.tproger.ru/uploads/2020/12/Green-and-Black-Corporate-Comparison-Chart-kopija-1-e1606838150926.png" alt="" /></figure><p>Разные‌ ‌категории ‌могут‌ ‌пересекаться.‌ ‌Обычно‌ ‌языку‌ ‌программирования‌ ‌присуще‌ ‌одно‌ ‌значение‌ ‌из‌ ‌каждой‌ ‌группы:‌ ‌он‌ ‌может‌ ‌быть‌ ‌сильным‌ ‌или‌ ‌слабым,‌ ‌явным‌ ‌или‌ ‌неявным.‌ ‌Но‌ ‌есть‌ ‌несколько‌ ‌исключений.‌ ‌Так,‌ ‌Python‌ ‌с‌ ‌аннотациями‌ ‌может‌ ‌поддерживать‌ ‌явную‌ ‌типизацию‌,‌ ‌а‌ ‌язык‌ ‌D,‌ ‌наоборот,‌ ‌‌—‌ ‌неявную.‌ ‌С#‌ ‌поддерживает‌ ‌динамическую‌ ‌типизацию‌ ‌благодаря‌ ‌ключевым‌ ‌словам‌ ‌‌dynamic‌ ‌и‌ ‌var,‌ ‌Delphi‌ ‌—‌ ‌благодаря‌ ‌типу‌ ‌Variant,‌ ‌а‌ ‌С++‌ ‌—‌ ‌‌с‌ ‌помощью‌ ‌библиотеки‌ ‌Boost‌ ‌и‌ ‌имеет‌ ‌одновременно‌ ‌черты‌ ‌языка‌ ‌с‌ ‌сильной‌ ‌и‌ ‌<br />слабой‌ ‌типизацией.‌</p>]]></content:encoded>
    </item>
    <item>
      <title>Лямбда-выражения в Java — что это такое, зачем нужны и как выглядят</title>
      <link>https://tproger.ru/explain/ljambda-vyrazhenija-v-java-chto-jeto-takoe-zachem-nuzhny-i-kak-vygljadjat</link>
      <comments>https://tproger.ru/explain/ljambda-vyrazhenija-v-java-chto-jeto-takoe-zachem-nuzhny-i-kak-vygljadjat?scrollTo=tproger-comments</comments>
      <dc:creator><![CDATA[Олег Борисенков]]></dc:creator>
      <guid isPermaLink="true">https://tproger.ru/explain/ljambda-vyrazhenija-v-java-chto-jeto-takoe-zachem-nuzhny-i-kak-vygljadjat</guid>
      <description><![CDATA[<p>Лямбда-выражения или анонимные функции встречаются во многих языках программирования. Рассказываем про лямбда-выражения в Java с примерами.</p><p>— Читать дальше «<a rel="follow" href="https://tproger.ru/explain/ljambda-vyrazhenija-v-java-chto-jeto-takoe-zachem-nuzhny-i-kak-vygljadjat">Лямбда-выражения в Java — что это такое, зачем нужны и как выглядят</a>»</p>]]></description>
      <category><![CDATA[Java]]></category>
      <category><![CDATA[Для начинающих]]></category>
      <category><![CDATA[Коротко о главном]]></category>
      <slash:comments>0</slash:comments>
      <pubDate>Mon, 30 Nov 2020 08:20:23 GMT</pubDate>
      <content:encoded><![CDATA[<p>Лямбда-выражения встречаются в разных языках программирования: JavaScript, PHP, C# и других. В этой статье поговорим о лямбда-выражениях в Java.</p><p>Лямбда-выражения или анонимные функции — это блоки кода с параметрами, которые можно вызвать из другого места программы. Они называются анонимными, потому что в отличие от функций, у них нет имён. Слово «лямбда» пришло из лямбда-исчисления, которое придумал <a href="https://ru.wikipedia.org/wiki/%D0%A7%D1%91%D1%80%D1%87,_%D0%90%D0%BB%D0%BE%D0%BD%D0%B7%D0%BE">профессор Алонзо Чёрч</a>. Он использовал греческую букву лямбда (λ), чтобы отметить параметры.</p><h2>Лямбда-выражения в Java</h2><ul><li>Присутствуют начиная с 8 версии.</li><li>Являются анонимными классами, реализующими метод функционального интерфейса.</li><li>Имеют доступ только к final (или effectively final) переменным из охватывающей области видимости (для потокобезопасности).</li><li>Не могут возвращать значение в каких-то ветках, а в других не возвращать.</li><li>Позволяют уменьшить количество кода и повысить его читаемость.</li></ul><h2>Примеры синтаксиса лямбда-выражений в Java</h2><p>Лямбда-выражения в Java состоят из параметров и стрелки —&gt; отделяющей тело функции. Скобки нужны, если параметров 0 или больше одного. Для однострочных лямбд ключевое слово return не обязательно.</p><p>(список параметров) -&gt; тело лямбды</p><h3>Без параметров</h3><p>Этот код выведет в консоль текст: «Привет мир!».</p><h3>C параметром</h3><p>В этом примере лямбда-выражение используется для обработки нажатия кнопки.</p><h3>С несколькими параметрами</h3><p>Здесь лямбда-выражение склеивает строки.</p>]]></content:encoded>
    </item>
    <item>
      <title>Hard skills и soft skills — какие навыки нужны программисту</title>
      <link>https://tproger.ru/explain/hard-skills-i-soft-skills-kakie-navyki-nuzhny-programmistu</link>
      <comments>https://tproger.ru/explain/hard-skills-i-soft-skills-kakie-navyki-nuzhny-programmistu?scrollTo=tproger-comments</comments>
      <dc:creator><![CDATA[Мария Кривоченко]]></dc:creator>
      <guid isPermaLink="true">https://tproger.ru/explain/hard-skills-i-soft-skills-kakie-navyki-nuzhny-programmistu</guid>
      <description><![CDATA[<p>Жёсткие и гибкие навыки влияют на задачи, срок испытательного периода, зарплату и отношения с коллегами, а также на реакцию работодателя на резюме.</p><p>— Читать дальше «<a rel="follow" href="https://tproger.ru/explain/hard-skills-i-soft-skills-kakie-navyki-nuzhny-programmistu">Hard skills и soft skills — какие навыки нужны программисту</a>»</p>]]></description>
      <category><![CDATA[Работа]]></category>
      <category><![CDATA[Навыки]]></category>
      <category><![CDATA[Коротко о главном]]></category>
      <slash:comments>0</slash:comments>
      <pubDate>Fri, 27 Nov 2020 13:08:43 GMT</pubDate>
      <content:encoded><![CDATA[<p>Hard skills и soft skills помогают заранее понять, чего ждать от будущего работника, а также влияют на ваши будущие задачи, время испытательного срока, зарплату и отношения с коллегами. Ещё «жёсткие» и «гибкие» навыки определяют, как скоро работодатель обратит внимание на ваше резюме, позовёт ли на собеседование и даст ли работу. Рассказываем, что такое hard skills и soft skills.</p><h2>Что такое «hard skills»?</h2><p>Hard skills — это навыки, которые получают в школе и вузе, на курсах, на рабочем месте и так далее. Часто их проверяют перед собеседованием с помощью тестовых заданий.</p><p>У каждой специальности свои «жёсткие» навыки. Например, архитектор должен знать, как использовать программное обеспечение для построения макетов, бухгалтер — работать с 1С, а переводчик — говорить на иностранном языке и знать особенности литературного или технического перевода.</p><p>Как правило, «жёсткие» навыки — это основные требования к работнику. По ним наниматель определяет, как вы справитесь с должностными обязанностями. Часто рекрутеры ищут кандидатов на должность по hard skills, используя названия навыков как ключевые слова в поиске. Откройте вакансии и посмотрите, какие требования к кандидатам повторяются в них чаще всего, и какие стоят на первом месте — скорее всего, именно они важны для нанимателя. На них стоит обратить внимание и включить в разделы «навыки» и «опыт».</p><h2>Что такое «soft skills»?</h2><p>Soft skills определяют уровень эмоционального интеллекта, ответственность, умение общаться с людьми и работать в команде, — в общем, характеризуют работника как личность.</p><p>«Гибкие» навыки сложнее оценить через резюме. Обычно рекрутер или работодатель смотрит на soft skill потенциального работника во время личного разговора. Здесь играет роль то, вовремя ли вы пришли на собеседование, сильно ли нервничаете, как общаетесь и отвечаете на вопросы.</p><p>Кстати, исследование LinkedIn показало, что 57% нанимателей ставят «гибкие» навыки выше «жёстких».</p><h2>Какие навыки важны сегодня?</h2><p>По данным LinkedIn, самые востребованные hard skills сегодня:</p><ul><li>блокчейн;</li><li>облачные вычисления;</li><li>анализ данных;</li><li>работа с искусственным интеллектом;</li><li>UX-дизайн</li><li>бизнес-аналитика;</li><li>интернет-маркетинг;</li><li>продажи;</li><li>вычислительные методы;</li><li>создание видео.</li></ul><p>Ещё популярны знание языков программирования, владение иностранными языками, <a href="https://tproger.ru/articles/english-for-it/">хотя бы английским</a>, SEO-оптимизация, знание программ MS Office и Adobe.</p><p>Самые востребованные soft skills:</p><ul><li>креативность;</li><li>эмоциональный интеллект;</li><li>умение работать в команде;</li><li>нацеленность на результат;</li><li>умение адаптироваться;</li><li>активное слушание (умение вникать в слова собеседника);</li><li>уважение к работе и готовность соблюдать трудовую этику.</li></ul><p>Сюда же входят знакомые коммуникабельность, стрессоустойчивость, готовность учиться, умение принимать решения и управлять коллективом, критическое мышление и многое другое.</p><h2>Как развить hard skills и soft skills?</h2><p>«Жёсткие» навыки — это профессионализм. Их улучшают с помощью работы, дополнительных курсов, книг и подкастов по теме. Ещё можно обратиться к более компетентным сотрудникам: подскажут что и как стоит подтянуть.</p><p>«Гибким» навыкам сложнее обучиться, чем «жёстким». Чтобы развить их, нужно постоянно общаться, учиться работать в команде и не нервничать перед публичными выступлениями. А также постоянно анализировать, что вы говорите и пишете, насколько вы грамотны и хорошо ли различаете формальный и неформальный тип общения, деловые переписки и флуд в рабочем чате.</p><p>Важный навык — креативность. Его помогут развить участие в брейнштормах, книги и фильмы которые будут вдохновлять на новые идеи. Ещё важно общение с творческими людьми — они научат мыслить нестандартно.</p>]]></content:encoded>
    </item>
    <item>
      <title>Стили именования переменных и функций. Используйте их все</title>
      <link>https://tproger.ru/explain/naming-variables-and-functions-use-them-all</link>
      <comments>https://tproger.ru/explain/naming-variables-and-functions-use-them-all?scrollTo=tproger-comments</comments>
      <dc:creator><![CDATA[Олег Борисенков]]></dc:creator>
      <guid isPermaLink="true">https://tproger.ru/explain/naming-variables-and-functions-use-them-all</guid>
      <description><![CDATA[<p>camelCase и другие соглашения помогают понять тип сущности с первого взгляда — идеального единого формата в программировании не существует.</p><p>— Читать дальше «<a rel="follow" href="https://tproger.ru/explain/naming-variables-and-functions-use-them-all">Стили именования переменных и функций. Используйте их все</a>»</p>]]></description>
      <category><![CDATA[Кодстайл]]></category>
      <category><![CDATA[Лучшая практика]]></category>
      <category><![CDATA[Коротко о главном]]></category>
      <slash:comments>0</slash:comments>
      <pubDate>Wed, 18 Nov 2020 09:46:21 GMT</pubDate>
      <content:encoded><![CDATA[<p>Чтобы обеспечить легкую читаемость кода программисты используют разные стили именования для разных типов объектов, функций и переменных. Именно поэтому нет какого-то одного «идеального» формата. Выбор уместного стиля поможет быстро понять к какому типу относится сущность в коде, но не забывайте и о том, что имя должно объяснять что делает это сущность. Мы расскажем какой стиль существует для каждой из возможных ситуаций.</p><p>В программировании пробел является зарезервированным символом, поэтому все названия обходятся без него. Чтобы строки без пробелов всё же напоминали естественный язык и нужны все эти кейсы.</p><h2>camelCase (dromedaryCase)</h2><p>Каждое слово, кроме первого, начинается с большой буквы.<br />Применяется для именования переменных и функций в большинстве языков.</p><figure><img src="https://media.tproger.ru/uploads/2020/11/camelCase-1.png" alt="" /></figure><h2>PascalCase (CamelCase, StudlyCase)</h2><p>В этом стиле каждое слово начинается с заглавной буквы. Обычно используется для названий классов.</p><figure><img src="https://media.tproger.ru/uploads/2020/11/PascalCase-1.png" alt="" /></figure><h2>snake_case (pothole_case)</h2><p>Вместо пробела ставится нижнее подчёркивание. Используется в основном для имён полей баз данных, переменных и функций.</p><figure><img src="https://media.tproger.ru/uploads/2020/11/snake_case.png" alt="" /></figure><h2>SCREAMING_SNAKE_CASE (MACRO_CASE, CONSTANT_CASE)</h2><p>Тот же snake_case, только буквы всегда в верхнем регистре. Обычно используется для именования констант.</p><figure><img src="https://media.tproger.ru/uploads/2020/11/SCREAMING_SNAKE_CASE.png" alt="" /></figure><h2>kebab-case (dash-case, lisp-case)</h2><p>В этом случае пробел заменяется дефисом. Используется в URL и CSS. В языке Lisp так пишутся любые названия. Примеры:</p><p>background-color</p><h2>TRAIN-CASE (COBOL-CASE, SCREAMING-KEBAB-CASE)</h2><p>Все буквы в верхнем регистре, соединены дефисом. Применяется в языке COBOL для всех названий. Пример:</p><p>PROGRAM-ID</p><h2>Train-Case (HTTP-Header-Case)</h2><p>Каждое слово с большой буквы, соединены дефисом. Стиль названий HTTP заголовков. Пример:</p><p>Content-Length</p><h2>flatcase</h2><p>Все слова в нижнем регистре, без пробелов. Используется в тегах. Пример:</p><p>#stayhome</p>]]></content:encoded>
    </item>
    <item>
      <title>Почему у вас проблемы от высокого CLS и как их исправить</title>
      <link>https://tproger.ru/explain/cls-problem-solving</link>
      <comments>https://tproger.ru/explain/cls-problem-solving?scrollTo=tproger-comments</comments>
      <dc:creator><![CDATA[Алексей Михайлишин]]></dc:creator>
      <guid isPermaLink="true">https://tproger.ru/explain/cls-problem-solving</guid>
      <description><![CDATA[<p>Cumulative Layout Shift — одна из ключевых метрик технической оптимизации Google: произвольные сдвиги элементов могут вызвать просадку сайта в выдаче.</p><p>— Читать дальше «<a rel="follow" href="https://tproger.ru/explain/cls-problem-solving">Почему у вас проблемы от высокого CLS и как их исправить</a>»</p>]]></description>
      <category><![CDATA[SEO]]></category>
      <category><![CDATA[Веб-разработка]]></category>
      <category><![CDATA[Оптимизация]]></category>
      <category><![CDATA[Фронтенд]]></category>
      <category><![CDATA[Коротко о главном]]></category>
      <slash:comments>0</slash:comments>
      <pubDate>Fri, 09 Oct 2020 11:27:17 GMT</pubDate>
      <content:encoded><![CDATA[<p>Проблемы с CLS могут повлечь за собой просадку сайта в поисковой выдаче Google. Почему? Дело в том, что <a href="https://web.dev/cls/">Cumulative Layout Shift</a> или совокупный сдвиг вёрстки — одна из ключевых метрик оценки технической оптимизации сайтов в Google.</p><p>Суть в том, что любые элементы на странице не должны произвольно менять своё положение в процессе загрузки. Это выглядит не очень красиво и посетитель может промахнуться по кнопке, как на видео ниже.</p><p>Чем больше суммарная площадь таких «прыгающих» элементов и чем дальше они «прыгают», тем хуже будет метрика CLS. В идеале она должна быть равна нулю.</p><p>В сентябре 2020 года наша команда разработки окончательно победила Cumulative Layout Shift — контент больше не смещается при загрузке. Некоторые проблемы с CLS всё ещё остались, но 75-й перцентиль за 7 дней нулевой:</p><figure><img src="https://media.tproger.ru/uploads/2020/10/Untitled-14.png" alt="" /></figure><p>По таблице видно, что у нас завышена задержка первого ввода (<a href="https://web.dev/fid/">First Input Delay</a>) на мобильных и опасный тренд по времени отрисовки контента (<a href="https://web.dev/lcp/">Largest Contentful Paint</a>) — над этим мы поработаем. Google, однако, считает, что проблем нет уже сейчас:</p><figure><img src="https://media.tproger.ru/uploads/2020/10/Untitled-16.png" alt="" /></figure><figure><img src="https://media.tproger.ru/uploads/2020/10/Untitled-15.png" alt="" /></figure><p>Поделюсь ключевыми приёмами по работе над избавлением от сдвигов контента. В нашем случае 90% проблем решилось довольно просто и свелось к трём правилам.</p><h2>Приём для решения проблем с CLS #1</h2><figure><img src="https://media.tproger.ru/uploads/2020/10/Snimok-jekrana-2020-10-09-v-0.15.31.png" alt="" /></figure><p>Если размеры элемента известны заранее, то их надо прописать явно. Например, блок счётчика комментариев, закладок и лайков у нас подгружается динамически, но высота иконок известна заранее и её можно прямо задать в CSS.<br /></p><h2>Приём для решения проблем с CLS #2</h2><p>Если вы загружаете контент после «скелета» страницы, то вставляйте на место контента плейсхолдер с высотой 100vh, который будет удерживать подвал вне экрана. Когда контент подтянется, удалите плейсхолдер. Пример: <a href="https://tproger.ru/jobs/">страница вакансий</a>.</p><h2>Приём для решения проблем с CLS #3</h2><p>Отображайте динамически подгружаемые блоки в том порядке, в котором они не смещают другие блоки. Либо дождитесь загрузки всех блоков и покажите их одновременно. Пример: <a href="https://tproger.ru/">у нас на главной</a> в правом сайдбаре на десктопе.</p><p>Для диагностики удобно использовать <a href="https://developers.google.com/web/tools/chrome-devtools">DevTools</a> в Google Chrome. Установите эмуляцию медленного Интернет-соединения и поставьте галку Layout Shift Regions на вкладке Rendereing. Либо используйте отладчик Performance, недавно он научился выделять области со сдвигами контента.</p>]]></content:encoded>
    </item>
    <item>
      <title>Микроконтроллер и микропроцессор — в чём разница?</title>
      <link>https://tproger.ru/explain/difference-between-mc-and-mpu</link>
      <comments>https://tproger.ru/explain/difference-between-mc-and-mpu?scrollTo=tproger-comments</comments>
      <dc:creator><![CDATA[Александр Ланский]]></dc:creator>
      <guid isPermaLink="true">https://tproger.ru/explain/difference-between-mc-and-mpu</guid>
      <description><![CDATA[<p>Микроконтроллер размещает на одном кристалле вычислительное устройство, ПЗУ и ОЗУ, а также часто содержит порты, таймеры и интерфейсы.</p><p>— Читать дальше «<a rel="follow" href="https://tproger.ru/explain/difference-between-mc-and-mpu">Микроконтроллер и микропроцессор — в чём разница?</a>»</p>]]></description>
      <category><![CDATA[История IT]]></category>
      <category><![CDATA[Hardware]]></category>
      <category><![CDATA[Коротко о главном]]></category>
      <slash:comments>0</slash:comments>
      <pubDate>Thu, 29 Aug 2019 09:37:57 GMT</pubDate>
      <content:encoded><![CDATA[<p>В составе разных электронных устройств часто встречаются как микроконтроллеры, так и микропроцессоры. Оба этих компонента берут из памяти команды и по ним выполняют логические и арифметические операции, работая при этом с устройствами ввода/вывода и прочей периферией. Так в чём тогда разница?</p><h2>Микроконтроллер</h2><p>Микроконтроллер — (далее МК) это микросхема, предназначенная для программного управления электронными схемами. МК выполняется на одном кристалле. На нём расположено как вычислительное устройство, так и ПЗУ и ОЗУ. Кроме этого, в составе МК чаще всего находятся порты ввода/вывода, таймеры, <a href="https://ru.wikipedia.org/wiki/%D0%90%D0%BD%D0%B0%D0%BB%D0%BE%D0%B3%D0%BE-%D1%86%D0%B8%D1%84%D1%80%D0%BE%D0%B2%D0%BE%D0%B9_%D0%BF%D1%80%D0%B5%D0%BE%D0%B1%D1%80%D0%B0%D0%B7%D0%BE%D0%B2%D0%B0%D1%82%D0%B5%D0%BB%D1%8C">АЦП</a>, последовательные и параллельные интерфейсы. В некоторых даже можно заметить Wi-Fi-/Bluetooth-модуль и даже поддержку NFC.</p><p>Первый патент на микроконтроллер был выдан в 1971 году компании <a href="https://ru.wikipedia.org/wiki/Texas_Instruments">Texas Instruments</a>. Инженеры этой компании предложили размещать на кристалле не только процессор, но и память с устройствами ввода/вывода.</p><figure><img src="https://media.tproger.ru/uploads/2019/08/circuit_mc.png" alt="" /></figure><p>Несмотря на то, что всё необходимое для работы микроконтроллера в нём уже есть, иногда они используются в паре с внешними периферийными устройствами. К примеру, когда внутренней ПЗУ не хватает (или она попросту отсутствует), подключают внешнюю. Именно так сделали с микроконтроллерами серии ESP. У ESP8266 встроенной памяти нет вообще, а у ESP32 есть незначительные 448 КБ. Поэтому к ним в корпус (точнее под радиатор) помещается flash-память ёмкостью 1–16 МБ.</p><p>Тогда почему бы не сделать какой-нибудь портативный компьютер на основе микроконтроллера? Дело в том, что вычислительной мощности у МК чаще всего достаточно мало. Её хватает на управление например, системой полива, микроволновкой или же каким-нибудь станком.</p><p>Например, одна из мощных плат платформы Arduino — Due. Она находится под управлением 32-битного AVR-микроконтроллера AT91SAM3X8E. Его тактовая частота 84 МГц. Постоянной памяти тут 512 КБ, а оперативной — 96 КБ. МК имеет 54 цифровых GPIO (12 из которых с поддержкой ШИМ), 12 аналоговых входов и 2 аналоговых выхода (ЦАП). Тут так же присутствуют различные интерфейсы, такие как UART, SPI, I2C.</p><p>Не смотря на такие незначительные характеристики, микроконтроллеры очень популярны. Они используются там, где не требуется большой вычислительной мощности — робототехника, контроллеры теплиц, бытовая техника.</p><h2>Микропроцессор</h2><p>С микропроцессором (далее МП) дела обстоят немного иначе. Он содержит в себе арифметико-логическое устройство, блок синхронизации и управления, запоминающие устройство, регистры и шину. То есть МП содержит в себе только то, что непосредственно понадобится для выполнения арифметический и логических операций. Все остальные комплектующие (ОЗУ, ПЗУ, устройства ввода/вывода, интерфейсы) нужно подключать извне.</p><figure><img src="https://media.tproger.ru/uploads/2019/08/img-IpY0lC.png" alt="" /></figure><p>Первые микропроцессоры появились тоже в начале 70-х. Самым популярным на тот момент считался <a href="https://ru.wikipedia.org/wiki/4004">4004</a>. Это микропроцессор, разработанный компанией Intel и представленный 15 ноября 1971 года. Он имел внушающие на тот период характеристики:</p><ul><li>2300 транзисторов;</li><li>тактовая частота — 740 кГц;</li><li>разрядность регистров и шины — 4 бита;</li><li>техпроцесс — 10 мкм;</li><li>площадь кристалла: — 12 мм².</li></ul><p>К слову, 4004 был выполнен в обычном DIP-16 корпусе. Этот МП является самой популярной микросхемой для коллекционирования. Некоторые экземпляры продаются по 400 $ за штуку. Менее раритетные стоят около 250 $.</p><p>Уже через пару лет 8-битные МП позволили создавать первые бытовые микрокомпьютеры.</p><p>Естественно, тут преимуществом является то, что к МП можно на выбор подключать разную периферию с разными характеристиками (что не во всех случаях можно на МК). Второе основное отличие микропроцессора от микроконтроллера в том, что МП имеют больше вычислительной мощности. Их не имеет смысла ставить в микроволновки и «умные» лампочки. Микропроцессоры применяют там, где вычислительная мощность МК уже не справляется — игровые приставки, сложные вычислительные устройства и приборы, гаджеты.</p><p>Получается, чтобы обеспечить работоспособность микропроцессора, нужно подключить ему хотя бы минимальный набор периферии. Минусы:</p><ol><li>Размер — если в случае МК всё уже находится в одном корпусе, то минимальный набор элементов для работы МП занимает больше места.</li><li>Цена — обычно, вся «сборка» комплектующих для МП выходит гораздо дороже «голых» микроконтроллеров.</li></ol><p>Плюсы:</p><ol><li>Производительность — микропроцессоры обладают большей производительностью, чем микроконтроллеры.</li><li>Выбор — в случае МП у вас есть возможность подобрать комплектующие. Это позволит поставить более подходящую под ваши цели периферию.</li></ol><h2>Применение</h2><p>Микроконтроллер обладает явной простотой: требуется меньше аппаратного обеспечения, с ним легче работать на программном уровне, да и стоимость начинается с копеек. Но эта простота касается и производительности. Как говорилось выше, микроконтроллер не способен обеспечить высокую производительность наравне с микропроцессорами. Микропроцессоры хоть и требуют внешней коммутации «железа» и относительно МК сложны в работе, но они уже спокойно могут применяться в более сложных устройствах.</p><p>Однако иногда в сети появляются умельцы, которые впихивают в микроконтроллер ESP32 <a href="https://youtu.be/y6PP_IBbOTY">DOOM</a> и даже <a href="https://www.youtube.com/watch?v=ekf_NLcXuLk">эмулятор NES-игр</a>.</p>]]></content:encoded>
    </item>
    <item>
      <title>В чём разница между шифрованием, кодированием и хешированием?</title>
      <link>https://tproger.ru/explain/difference-between-encryption-coding-and-hashing</link>
      <comments>https://tproger.ru/explain/difference-between-encryption-coding-and-hashing?scrollTo=tproger-comments</comments>
      <dc:creator><![CDATA[Варвара Николаева]]></dc:creator>
      <guid isPermaLink="true">https://tproger.ru/explain/difference-between-encryption-coding-and-hashing</guid>
      <description><![CDATA[<p>Хеширование, шифрование и кодирование легко перепутать, но каждое решает свою задачу — от проверки целостности данных до защиты сообщений.</p><p>— Читать дальше «<a rel="follow" href="https://tproger.ru/explain/difference-between-encryption-coding-and-hashing">В чём разница между шифрованием, кодированием и хешированием?</a>»</p>]]></description>
      <category><![CDATA[Криптография]]></category>
      <category><![CDATA[Для начинающих]]></category>
      <category><![CDATA[Коротко о главном]]></category>
      <slash:comments>0</slash:comments>
      <pubDate>Wed, 14 Aug 2019 10:10:31 GMT</pubDate>
      <content:encoded><![CDATA[<p>Мы невольно используем шифрование, хеширование и кодирование каждый день. Эти понятия кажутся похожими, их довольно легко перепутать, но на самом деле каждое из них используется с определённой целью и имеет свои особенности.</p><h2>Хеширование</h2><p>Начнём с самого простого — хеширования. Хеширование — это преобразование входных данных в уникальную последовательность символов, из которой невозможно получить исходное сообщение. Самый яркий пример использования — для проверки целостности. Если изменить в исходном файле или тексте хоть один бит, в результате получим новую уникальную последовательность.</p><p>Примеры хешей: <a href="https://ru.wikipedia.org/wiki/MD5">MD5</a>, семейство SHA.</p><h2>Шифрование</h2><p>Кодирование и шифрование немного сложнее различать между собой, иногда эти слова могут использоваться, как синонимы. Но важно запомнить, что у них абсолютно разные цели. Смысл шифрования — сделать исходное сообщение нечитаемым для любого, кто не владеет ключом. Старые или уязвимые шифры легко взламываются, хотя их цель была именно в том, чтобы скрыть содержание сообщения.</p><p>Примеры шифров: <a href="https://ru.wikipedia.org/wiki/%D0%A8%D0%B8%D1%84%D1%80_%D0%A6%D0%B5%D0%B7%D0%B0%D1%80%D1%8F">шифр Цезаря</a>, <a href="https://ru.wikipedia.org/wiki/Advanced_Encryption_Standard">AES</a>.</p><h2>Кодирование</h2><p>Кодирование — это преобразование входных данных в определённую последовательность бит или заданных символов для удобства дальнейшей работы. Самый простой пример — преобразовать текст в <a href="https://ru.wikipedia.org/wiki/%D0%9A%D0%BE%D0%B4_%D0%A5%D1%8D%D0%BC%D0%BC%D0%B8%D0%BD%D0%B3%D0%B0">код Хэмминга</a> для дальнейшей передачи по линиям электросвязи. По линии электросвязи нельзя передать буквы, а возможности аналогового сигнала достаточно ограничены, что не позволяет использовать алфавит из 33 букв, но передать битовую последовательность можно. Также этот код самоконтролирующийся и самокорректирующийся, что позволяет исправить некоторые ошибки, которые могут возникнуть при помехах во время передачи данных.</p><p>Примеры кодов: <a href="https://ru.wikipedia.org/wiki/ASCII">кодировка ASCII</a>, Морзе.</p><h2>Применение</h2><p>Таким образом, при передаче сообщения через интернет:</p><ul><li>кодирование используется, чтобы передать сообщение и его смогли прочитать на разных устройствах;</li><li>шифрование используется, чтобы ваше сообщение не смог прочитать никто посторонний;</li><li>хеширование используется, чтобы никто не смог незаметно изменить ваше сообщение.</li></ul>]]></content:encoded>
    </item>
    <item>
      <title>Как работает процессор?</title>
      <link>https://tproger.ru/explain/how-cpu-works</link>
      <comments>https://tproger.ru/explain/how-cpu-works?scrollTo=tproger-comments</comments>
      <dc:creator><![CDATA[Александр Ланский]]></dc:creator>
      <guid isPermaLink="true">https://tproger.ru/explain/how-cpu-works</guid>
      <description><![CDATA[<p>Устройство управления и арифметико-логическое устройство, память, регистры и инструкции — кратко и доступно об основных компонентах процессора.</p><p>— Читать дальше «<a rel="follow" href="https://tproger.ru/explain/how-cpu-works">Как работает процессор?</a>»</p>]]></description>
      <category><![CDATA[Для начинающих]]></category>
      <category><![CDATA[Hardware]]></category>
      <category><![CDATA[Коротко о главном]]></category>
      <slash:comments>0</slash:comments>
      <pubDate>Thu, 04 Jul 2019 10:01:43 GMT</pubDate>
      <content:encoded><![CDATA[<p>Инструмент проще, чем машина. Зачастую инструментом работают руками, а машину приводит в действие паровая сила или животное.</p><p>Компьютер тоже можно назвать машиной, только вместо паровой силы здесь электричество. Но программирование сделало компьютер таким же простым, как любой инструмент.</p><p>Процессор — это сердце/мозг любого компьютера. Его основное назначение — арифметические и логические операции, и прежде чем погрузиться в дебри процессора, нужно разобраться в его основных компонентах и принципах их работы.</p><h2>Два основных компонента процессора</h2><h3>Устройство управления</h3><p>Устройство управления (УУ) помогает процессору контролировать и выполнять инструкции. УУ сообщает компонентам, что именно нужно делать. В соответствии с инструкциями он координирует работу с другими частями компьютера, включая второй основной компонент — арифметико-логическое устройство (АЛУ). Все инструкции вначале поступают именно на устройство управления.</p><p>Существует два типа реализации УУ:</p><ul><li>УУ на жёсткой логике (англ. hardwired control units). Характер работы определяется внутренним электрическим строением — устройством печатной платы или кристалла. Соответственно, модификация такого УУ без физического вмешательства невозможна.</li><li>УУ с микропрограммным управлением (англ. microprogrammable control units). Может быть запрограммирован для тех или иных целей. Программная часть сохраняется в памяти УУ.</li></ul><p>УУ на жёсткой логике быстрее, но УУ с микропрограммным управлением обладает более гибкой функциональностью.</p><h3>Арифметико-логическое устройство</h3><p>Это устройство, как ни странно, выполняет все арифметические и логические операции, например сложение, вычитание, логическое ИЛИ и т. п. АЛУ состоит из логических элементов, которые и выполняют эти операции.</p><p>Большинство логических элементов имеют два входа и один выход.</p><p>Ниже приведена схема полусумматора, у которой два входа и два выхода. A и B здесь являются входами, S — выходом, C — переносом (в старший разряд).</p><figure><img src="https://media.tproger.ru/user-uploads/23823/2023-12-24/03ff00ee-f81d-45eb-93ed-65bb3a5c669f.png" alt="" /><figcaption>Схема арифметического полусумматора</figcaption></figure><h2>Хранение информации — регистры и память</h2><p>Как говорилось ранее, процессор выполняет поступающие на него команды. Команды в большинстве случаев работают с данными, которые могут быть промежуточными, входными или выходными. Все эти данные вместе с инструкциями сохраняются в регистрах и памяти.</p><h3>Регистры</h3><p>Регистр — минимальная ячейка памяти данных. Регистры состоят из триггеров (англ. latches/flip-flops). Триггеры, в свою очередь, состоят из логических элементов и могут хранить в себе 1 бит информации.</p><p>Прим. перев. Триггеры могут быть синхронные и асинхронные. Асинхронные могут менять своё состояние в любой момент, а синхронные только во время положительного/отрицательного перепада на входе синхронизации.</p><p>По функциональному назначению триггеры делятся на несколько групп:</p><ul><li>RS-триггер: сохраняет своё состояние при нулевых уровнях на обоих входах и изменяет его при установке единице на одном из входов (Reset/Set — Сброс/Установка).</li><li>JK-триггер: идентичен RS-триггеру за исключением того, что при подаче единиц сразу на два входа триггер меняет своё состояние на противоположное (счётный режим).</li><li>T-триггер: меняет своё состояние на противоположное при каждом такте на его единственном входе.</li><li>D-триггер: запоминает состояние на входе в момент синхронизации. Асинхронные D-триггеры смысла не имеют.</li></ul><p>Для хранения промежуточных данных ОЗУ не подходит, т. к. это замедлит работу процессора. Промежуточные данные отсылаются в регистры по шине. В них могут храниться команды, выходные данные и даже адреса ячеек памяти.</p><figure><img src="https://media.tproger.ru/user-uploads/23823/2023-12-24/f7d30718-35fd-4511-8b40-8c6c08c403b5.png" alt="" /><figcaption>Принцип действия RS-триггера</figcaption></figure><h3>Память (ОЗУ)</h3><p>ОЗУ (оперативное запоминающее устройство, англ. RAM) — это большая группа этих самых регистров, соединённых вместе. Память у такого хранилища непостоянная и данные оттуда пропадают при отключении питания. ОЗУ принимает адрес ячейки памяти, в которую нужно поместить данные, сами данные и флаг записи/чтения, который приводит в действие триггеры.</p><p>Прим. перев. Оперативная память бывает статической и динамической — SRAM и DRAM соответственно. В статической памяти ячейками являются триггеры, а в динамической — конденсаторы. SRAM быстрее, а DRAM дешевле.</p><h2>Команды (инструкции)</h2><p>Команды — это фактические действия, которые компьютер должен выполнять. Они бывают нескольких типов:</p><ul><li>Арифметические: сложение, вычитание, умножение и т. д.</li><li>Логические: И (логическое умножение/конъюнкция), ИЛИ (логическое суммирование/дизъюнкция), отрицание и т. д.</li><li>Информационные: move, input, outptut, load и store.</li><li>Команды перехода: goto, if ... goto, call и return.</li><li>Команда останова: halt.</li></ul><p>Прим. перев. На самом деле все арифметические операции в АЛУ могут быть созданы на основе всего двух: сложение и сдвиг. Однако чем больше базовых операций поддерживает АЛУ, тем оно быстрее.</p><p>Инструкции предоставляются компьютеру на языке ассемблера или генерируются компилятором высокоуровневых языков.</p><p>В процессоре инструкции реализуются на аппаратном уровне. За один такт одноядерный процессор может выполнить одну элементарную (базовую) инструкцию.</p><p>Группу инструкций принято называть набором команд (англ. instruction set).</p><h2>Тактирование процессора</h2><p>Быстродействие компьютера определяется тактовой частотой его процессора. Тактовая частота — количество тактов (соответственно и исполняемых команд) за секунду.</p><p>Частота нынешних процессоров измеряется в ГГц (Гигагерцы). 1 ГГц = 10⁹ Гц — миллиард операций в секунду.</p><p>Чтобы уменьшить время выполнения программы, нужно либо оптимизировать (уменьшить) её, либо увеличить тактовую частоту. У части процессоров есть возможность увеличить частоту (разогнать процессор), однако такие действия физически влияют на процессор и нередко вызывают перегрев и выход из строя.</p><h2>Выполнение инструкций</h2><p>Инструкции хранятся в ОЗУ в последовательном порядке. Для гипотетического процессора инструкция состоит из кода операции и адреса памяти/регистра. Внутри управляющего устройства есть два регистра инструкций, в которые загружается код команды и адрес текущей исполняемой команды. Ещё в процессоре есть дополнительные регистры, которые хранят в себе последние 4 бита выполненных инструкций.</p><p>Ниже рассмотрен пример набора команд, который суммирует два числа:</p><ol><li>LOAD_A 8. Это команда сохраняет в ОЗУ данные, скажем, &lt;1100 1000&gt;. Первые 4 бита — код операции. Именно он определяет инструкцию. Эти данные помещаются в регистры инструкций УУ. Команда декодируется в инструкцию load_A — поместить данные 1000 (последние 4 бита команды) в регистр A.</li><li>LOAD_B 2. Ситуация, аналогичная прошлой. Здесь помещается число 2 (0010) в регистр B.</li><li>ADD B A. Команда суммирует два числа (точнее прибавляет значение регистра B в регистр A). УУ сообщает АЛУ, что нужно выполнить операцию суммирования и поместить результат обратно в регистр A.</li><li>STORE_A 23. Сохраняем значение регистра A в ячейку памяти с адресом 23.</li></ol><p>Вот такие операции нужны, чтобы сложить два числа.</p><h2>Шина</h2><p>Все данные между процессором, регистрами, памятью и I/O-устройствами (устройствами ввода-вывода) передаются по шинам. Чтобы загрузить в память только что обработанные данные, процессор помещает адрес в шину адреса и данные в шину данных. Потом нужно дать разрешение на запись на шине управления.</p><h2>Кэш</h2><p>У процессора есть механизм сохранения инструкций в кэш. Как мы выяснили ранее, за секунду процессор может выполнить миллиарды инструкций. Поэтому если бы каждая инструкция хранилась в ОЗУ, то её изъятие оттуда занимало бы больше времени, чем её обработка. Поэтому для ускорения работы процессор хранит часть инструкций и данных в кэше.</p><p>Если данные в кэше и памяти не совпадают, то они помечаются <a href="https://ru.wikipedia.org/wiki/%D0%93%D1%80%D1%8F%D0%B7%D0%BD%D1%8B%D0%B9_%D0%B1%D0%B8%D1%82">грязными битами</a> (англ. dirty bit).</p><h2>Поток инструкций</h2><p>Современные процессоры могут параллельно обрабатывать несколько команд. Пока одна инструкция находится в стадии декодирования, процессор может успеть получить другую инструкцию.</p><p>Однако такое решение подходит только для тех инструкций, которые не зависят друг от друга.</p><p>Если процессор многоядерный, это означает, что фактически в нём находятся несколько отдельных процессоров с некоторыми общими ресурсами, например кэшем.</p><p>Если хотите узнать о процессорах больше, посмотрите, <a href="https://tproger.ru/articles/processors-architectures-review/">какие бывают популярные архитектуры: CISC, RISC, MISC и другие и виды</a>.</p>]]></content:encoded>
    </item>
    <item>
      <title>Введение в форензику</title>
      <link>https://tproger.ru/explain/introduction-to-computer-forensics</link>
      <comments>https://tproger.ru/explain/introduction-to-computer-forensics?scrollTo=tproger-comments</comments>
      <dc:creator><![CDATA[Klara Oswald]]></dc:creator>
      <guid isPermaLink="true">https://tproger.ru/explain/introduction-to-computer-forensics</guid>
      <description><![CDATA[<p>Компьютерная криминалистика — наука о цифровых доказательствах: методы поиска, получения и закрепления улик при расследовании компьютерных преступлений.</p><p>— Читать дальше «<a rel="follow" href="https://tproger.ru/explain/introduction-to-computer-forensics">Введение в форензику</a>»</p>]]></description>
      <category><![CDATA[Linux]]></category>
      <category><![CDATA[Инструменты]]></category>
      <category><![CDATA[Информационная безопасность]]></category>
      <category><![CDATA[Коротко о главном]]></category>
      <slash:comments>0</slash:comments>
      <pubDate>Mon, 03 Jun 2019 08:33:48 GMT</pubDate>
      <content:encoded><![CDATA[<p>Компьютерная криминалистика (форензика) — прикладная наука о раскрытии преступлений, связанных с компьютерной информацией, об исследовании цифровых доказательств, методах поиска, получения и закрепления таких доказательств. Она состоит из трёх частей:</p><ul><li>Сбор данных — процесс получения информации из первоисточника без их повреждения или изменения. Для этого есть множество инструментов в зависимости от ОС и других особенностей, в статье рассмотрим инструменты на основе Linux.</li><li>Сохранение данных — полученные цифровые улики должны быть сохранены в своем первоначальном состоянии, используя криптографические алгоритмы хэширования.</li><li>Анализ данных — интерпретация данных и извлечение информации из них.</li></ul><h2>Сбор данных</h2><p>Если подозреваемый установил руткиты для уничтожения улик по команде, существует вероятность потери важного контента. В таких случаях применяется <a href="https://en.wikipedia.org/wiki/Chain_of_custody">цепочка хранения доказательств</a> — документ с информацией о том, как обрабатывались улики, для дальнейшей отчётности. Цепочка начинается с обработки улик.</p><p>Перед началом нужна подготовка:</p><ul><li>загрузочный диск или флешка, поскольку инструментам подозреваемых нельзя доверять;</li><li>мощная машина для следователя.</li></ul><p>Сначала нужно получить данные, которые наиболее изменчивы. На самом деле они изменяются уже при их сборе, поэтому надо постараться оставить как можно меньше следов. Это сложная задача, поскольку обычные инструменты могут внести изменения в исследуемую среду. Например, использование команды cp изменит время последнего доступа к исходному файлу. Рассмотрим некоторые инструменты.</p><p>Эта команда выведет список всех открытых файлов, принадлежащих любым активным процессам. Её можно использовать с различными параметрами. Например, lsof -i IP_adress будет перечислять список интернет-соединений, принадлежащих данному IP-адресу. Она также поможет найти вредоносные процессы, которые используют скрытые дисковые пространства.</p><p>Netcat использует сетевые подключения для чтения и записи через протоколы TCP или UDP. Эту команду можно использовать для передачи или извлечения данных на рабочую станцию эксперта.</p><p>Также стоит взглянуть на uname -a, ifconfig, date и uptime. Всё это может пригодиться для сбора улик. Можно проверить, подключён ли злоумышленник к целевой машине, используя w.</p><p>Для считывания памяти можно использовать <a href="https://github.com/504ensicsLabs/LiME">lime</a> — <a href="https://ru.wikipedia.org/wiki/Загружаемый_модуль_ядра">загружаемый модуль ядра</a>, который позволяет извлекать данные из энергозависимой памяти Linux.</p><p>Для энергонезависимых данных следует использовать dd. Этот инструмент встроен в большинство систем Linux. Допустим, для подготовки экспертного диска и затирания /dev/hda одними нулями можно использовать dd if=/dev/zero of=example. Скопировать улики можно следующим образом: dd if=stuff of=evidence/stuff.dd. Если использовать dd с netcat, сначала устанавливается слушатель, а затем ему отправляются данные.</p><p>Терминал слушателя:</p><p>Терминал отправителя:</p><h2>Сохранение данных</h2><p>Для сохранения доказательств экспертиза использует криптографические алгоритмы хеширования . Суть компьютерной криминалистики — доказать, что улики совпадают с первоисточником, для этого достаточно вычислить хеши. Если хеши одинаковы, два файла должны быть одинаковыми.</p><p>Для этого хорошо подойдёт <a href="https://ru.wikipedia.org/wiki/MD5">MD5</a> или <a href="https://ru.wikipedia.org/wiki/SHA-1">SHA</a>. Рассмотрим команду md5sum. Создадим файл ex_file, содержащий строку «hello there». Прочтём исходное содержимое с помощью cat, а затем вычислим хеш.</p><p>Если изменить файл, например, добавив в строку «hiya», хеш изменится.</p><p>Совсем другое дело, если есть два файла с одинаковым содержимым, но разными именами.</p><p>Как можно видеть, хеш одинаковый. Другим примером этого является изменение разрешений.</p><p>Хеш остался прежним.</p><h2>Анализ данных</h2><p>Получение полезной информации из данных является важной задачей. Начать можно с определения разделов с помощью fdisk our_device. После этого можно использовать dd для выделения наиболее примечательных разделов. С помощью инструмента <a href="https://en.wikipedia.org/wiki/The_Sleuth_Kit">Sleuthkit</a> получаем файл с информацией о разделах (команда mmls our_file.dd). Можно определить тип носителя с помощью опции -t (команда mmls -t dos our_file.dd). Для монтирования образов можно использовать mount. Монтирование должно быть только в режиме чтения (read-only).</p><p>Не менее важная вещь — <a href="https://en.wikipedia.org/wiki/MAC_times">MAC</a>. Этот инструмент даёт доступ к нужной информации, например, дате создания или изменения файлов. Такую проверку следует проводить в начале экспертизы, так как такая информация очень чувствительна к изменениям. Используйте комбинацию команд fls и mactime.</p><p>Мы рассмотрели лишь малую часть инструментов для компьютерной криминалистики. В форензике очень важно умело владеть инструментами операционной системы. Если вы хотите лучше изучить Linux, советуем эту <a href="https://tproger.ru/books/linux/">подборку книг</a>.</p>]]></content:encoded>
    </item>
    <item>
      <title>Latency: значения задержек, которые стоит знать каждому программисту</title>
      <link>https://tproger.ru/explain/latency-numbers</link>
      <comments>https://tproger.ru/explain/latency-numbers?scrollTo=tproger-comments</comments>
      <dc:creator><![CDATA[Никита Прияцелюк]]></dc:creator>
      <guid isPermaLink="true">https://tproger.ru/explain/latency-numbers</guid>
      <description><![CDATA[<p>Таблица задержек распространённых операций: кеш процессора быстрее оперативной памяти, а она — жёсткого диска, и это помогает писать эффективный код.</p><p>— Читать дальше «<a rel="follow" href="https://tproger.ru/explain/latency-numbers">Latency: значения задержек, которые стоит знать каждому программисту</a>»</p>]]></description>
      <category><![CDATA[Оптимизация]]></category>
      <category><![CDATA[Коротко о главном]]></category>
      <slash:comments>0</slash:comments>
      <pubDate>Thu, 16 May 2019 09:12:44 GMT</pubDate>
      <content:encoded><![CDATA[<p>Все операции, выполняемые компьютером, занимают определённое время. Чем ниже уровень, на котором операция происходит, тем она быстрее, и наоборот. Например, работать с кешем процессора быстрее, чем с оперативной памятью. Она, в свою очередь, быстрее жёсткого диска.</p><p>Зная, сколько времени занимают те или иные операции, можно создавать более эффективные программы. В таблице представлены значения задержек для самых распространённых операций.</p><figure><img src="https://media.tproger.ru/user-uploads/33794/2024-02-19/b5f83c15-72d0-46a8-a07e-570f2b7973b1.png" alt="" /></figure><p>*предполагается использование SSD со скоростью 1 ГБ/с.</p><figure><img src="https://media.tproger.ru/uploads/2019/05/latencies.jpg" alt="" /></figure>]]></content:encoded>
    </item>
    <item>
      <title>Основные принципы работы протокола SSH</title>
      <link>https://tproger.ru/explain/a-top-down-introduction-to-ssh</link>
      <comments>https://tproger.ru/explain/a-top-down-introduction-to-ssh?scrollTo=tproger-comments</comments>
      <dc:creator><![CDATA[Евгений Туренко]]></dc:creator>
      <guid isPermaLink="true">https://tproger.ru/explain/a-top-down-introduction-to-ssh</guid>
      <description><![CDATA[<p>SSH — протокол для управления удалёнными компьютерами по сети. Разбор шагов, из которых складывается сеанс, и проверки прав клиента на доступ к хосту.</p><p>— Читать дальше «<a rel="follow" href="https://tproger.ru/explain/a-top-down-introduction-to-ssh">Основные принципы работы протокола SSH</a>»</p>]]></description>
      <category><![CDATA[Для начинающих]]></category>
      <category><![CDATA[Сетевые протоколы]]></category>
      <category><![CDATA[Коротко о главном]]></category>
      <slash:comments>0</slash:comments>
      <pubDate>Tue, 23 Apr 2019 08:14:20 GMT</pubDate>
      <content:encoded><![CDATA[<p>В этой статье мы рассмотрим, как работает SSH, как он используется для безопасной связи с удалёнными компьютерами и как компьютеры устанавливают и настраивают сеанс.</p><h2>Что такое SSH?</h2><p><a href="https://ru.wikipedia.org/wiki/SSH">SSH</a> — сокращение от «secure shell» (безопасная оболочка). Это протокол, который чаще всего используют для управления удалёнными компьютерами по сети.</p><h2>Как устанавливается сессия SSH?</h2><p>Есть несколько шагов, которые нужно пройти, чтобы начать SSH-сеанс между компьютерами.</p><ol><li>Сначала нужно обеспечить безопасный способ обмена сообщениями между компьютерами, то есть настроить зашифрованный канал.</li><li>Далее нужно проверить целостность данных, отправляемых клиентом.</li><li>После этого проверяется подлинность клиента.</li></ol><p>После этих трёх шагов мы можем безопасно общаться с удалённым компьютером, делиться секретными данными, а также проверить, есть ли у клиента разрешение на доступ к хосту. Каждый из разделов ниже будет более подробно описывать эти действия.</p><h2>Настройка зашифрованного канала</h2><p>Вся информация, отправляемая с использованием SSH, зашифрована. Обе стороны должны знать и понимать способ шифрования.</p><p>Для шифрования передаваемых данных используется <a href="https://ru.wikipedia.org/wiki/%D0%A1%D0%B8%D0%BC%D0%BC%D0%B5%D1%82%D1%80%D0%B8%D1%87%D0%BD%D0%BE%D0%B5_%D1%88%D0%B8%D1%84%D1%80%D0%BE%D0%B2%D0%B0%D0%BD%D0%B8%D0%B5">симметричное шифрование</a>. Суть данного подхода заключается в том, что оба компьютера имеют одинаковый ключ шифрования, который называется «симметричный ключ». Симметричное шифрование работает очень хорошо, но только до тех пор, пока сторонние не имеют доступа к ключу.</p><p>Один компьютер может создать ключ и отправить в виде сообщения через интернет. Но сообщение ещё не будет зашифровано, поэтому любой, кто перехватит его, сразу же сможет расшифровать все следующие сообщения.</p><p>Решение этой проблемы состоит в использовании протокола обмена ключами <a href="https://ru.wikipedia.org/wiki/Протокол_Диффи_—_Хеллмана">Диффи-Хеллмана</a>. Оба компьютера создают свой закрытый и открытый ключ. Вместе они образуют пару ключей. Компьютеры делятся своими открытыми ключами друг с другом через интернет. Используя свой закрытый и чужой открытый ключ, стороны могут независимо сгенерировать одинаковый симметричный ключ.</p><h2>Верификация</h2><p>Следующий этап процесса установки сеанса SSH заключается в проверке того, что данные не были подделаны во время их передачи и что другой компьютер действительно является тем, за кого себя выдаёт.</p><p>Для верификации используют хеш-функцию. Это математическая функция, которая принимает входные данные и создаёт строку фиксированного размера.</p><p>Важной особенностью этой функции является то, что практически невозможно определить входные данные, зная лишь результат её работы.</p><p>После того как клиент и хост сгенерировали свои симметричные ключи, клиент использует хеш-функцию для генерации HMAC, что означает «код аутентификации сообщений, использующий хеширование». Клиент отправит этот HMAC на сервер для верификации.</p><p>Функция хеширования использует:</p><ul><li>симметричный ключ клиента,</li><li>порядковый номер пакета,</li><li>содержимое сообщения (зашифрованное).</li></ul><p>Когда хост получает HMAC, он может использовать ту же самую хеш-функцию с этими тремя компонентами:</p><ul><li>собственный (идентичный клиентскому) симметричный ключ;</li><li>порядковый номер пакета;</li><li>зашифрованное сообщение.</li></ul><p>Если сформированный хеш совпадает с HMAC, полученным от клиента, то мы можем быть уверены, что подключаемый компьютер — это компьютер с симметричным ключом, потому что только хост и клиент знают симметричный ключ, а другие компьютеры — нет.</p><p>Прелесть этого подхода в том, что мы не просто проверили личность клиента и убедились, что данные не были подделаны, но мы сделали это без передачи какой-либо секретной информации.</p><h2>Аутентификация</h2><p>Даже если мы используем симметричные ключи для безопасного общения, мы не знаем, имеет ли подключающийся компьютер разрешение на доступ к содержимому хоста. Для того чтобы проверить это, необходимо произвести аутентификацию.</p><p>Многие используют аутентификацию по паролю. Клиент отправляет хосту зашифрованное сообщение, содержащее пароль. Хост его расшифровывает и ищет пароль в базе данных, чтобы удостовериться, есть ли у клиента разрешение на доступ. Использование пароля для аутентификации допустимо, но имеет свои недостатки, так как необходимо хранить все пароли на сервере.</p><p>Более безопасной является аутентификация по сертификату. Сформировав сертификат, клиент единожды вводит пароль для доступа к серверу и отправляет ему открытую часть сертификата. В дальнейшем ввод пароля не требуется. Этот подход считается более безопасным, чем просто использование пароля, поскольку не подразумевает хранение секрета пользователя на хосте.</p><h2>Заключение</h2><p>SSH — это важный инструмент, используемый для удалённого управления другими компьютерами. Он безопасен, поскольку оба компьютера могут шифровать и дешифровать сообщения с использованием симметричных ключей.</p>]]></content:encoded>
    </item>
    <item>
      <title>Что такое DNS? Введение в систему доменных имён</title>
      <link>https://tproger.ru/explain/domain-name-system</link>
      <comments>https://tproger.ru/explain/domain-name-system?scrollTo=tproger-comments</comments>
      <dc:creator><![CDATA[Евгений Туренко]]></dc:creator>
      <guid isPermaLink="true">https://tproger.ru/explain/domain-name-system</guid>
      <description><![CDATA[<p>Система доменных имён сопоставляет имя хоста с IP-адресом конкретной машины. Разновидности DNS-запросов, типы DNS-серверов и виды DNS-записей.</p><p>— Читать дальше «<a rel="follow" href="https://tproger.ru/explain/domain-name-system">Что такое DNS? Введение в систему доменных имён</a>»</p>]]></description>
      <category><![CDATA[Для начинающих]]></category>
      <category><![CDATA[Интернет]]></category>
      <category><![CDATA[Сервер]]></category>
      <category><![CDATA[Коротко о главном]]></category>
      <slash:comments>0</slash:comments>
      <pubDate>Sun, 24 Mar 2019 09:16:42 GMT</pubDate>
      <content:encoded><![CDATA[<p>Если вы хоть немного имели дело с интернетом и компьютерными сетями, то наверняка слышали о системе доменных имён (DNS). Прочитав статью узнаете, как это всё работает.</p><p>Само имя хоста не даст никакой информации о нахождении конкретной машины, с которой вы собираетесь связаться, поскольку все соединения происходят по IP-адресам.</p><p>Сервер доменных имён — это устройство, которое сопоставляет имя хоста с IP-адресом конкретной машины/железа.</p><p>В этой статье будет рассказано о деталях различных DNS-запросов, типах DNS-серверов и о разновидностях DNS-записей.</p><h2>DNS-резолвер</h2><p>Это компьютеры, которые провайдеры используют для поиска в их базе данных конкретного узла, запрашиваемого пользователем. Когда данные получены, пользователь перенаправляется на соответствующий IP-адрес. Резолверы играют крайне важную роль в DNS.</p><p>DNS-резолвер кэширует информацию. К примеру, сайт example.com расположен на машине с IP-адресом 35.195.226.230. Поэтому кэши резолверов со всего мира будут содержать следующее соответствие: example.com→35.195.226.230.</p><p>Считается, что в будущем сайт может переместиться на любой другой хост с другим IP, скажем, 35.192.247.235. Кэши DNS-резолверов по всему миру некоторое время будут хранить прежний IP-адрес. Это может привести к недоступности сайта, пока изменения не дойдут до всех DNS.</p><blockquote>Время, в течение которого запись хранится в резолвере, называется TTL (time to live).</blockquote><p>Его можно установить в панели управления сервиса, на котором приобретался домен.</p><h2>Типы DNS-серверов</h2><h3>Корневой DNS-сервер</h3><p>Это DNS-сервер, который хранит в себе адреса всех TLD-серверов (TLD — top-level domain, домен верхнего уровня). По пути от имени хоста до IP-адреса запрос сначала попадает на корневой DNS-сервер.</p><p>Существует 13 корневых DNS-серверов:</p><figure><img src="https://media.tproger.ru/uploads/2019/03/DNS-explained-pic-1.jpg" alt="" /></figure><p>Это не означает, что существует только 13 машин, которые обрабатывают все запросы со всего мира — существуют и второстепенные серверы, по которым распределяется трафик.</p><h3>TLD-серверы</h3><p>Эти серверы связаны с доменами верхнего уровня (TLD). Обычно они идут после корневых DNS-серверов. В TLD-серверах содержится информация о домене верхнего уровня конкретного хоста.</p><p>Скажем, если вы запросите IP-адрес хоста tproger.ru, то будет опрашиваться тот TLD-сервер, который соответствует домену .ru. TLD-сервер возвращает адрес авторитативного DNS-сервера для резолвера.</p><p>Теперь возникает вопрос — откуда TLD-серверы знают адрес авторитативных серверов? Ответ прост — после того, как вы покупаете любой домен у регистраторов вроде Godaddy или Namecheap, регистраторы привязывают авторитативные серверы к TLD-серверу.</p><p>Сейчас некоторые провайдеры предоставляют возможность использовать сторонние авторитативные серверы. Вы можете выбрать конкретный авторитативный сервер имён у регистратора.</p><h3>Авторитативный DNS-сервер</h3><p>Запрос на эти серверы поступает в самую последнюю очередь. Эти серверы хранят фактические записи типа A, NS, CNAME, TXT, и т. п.</p><p>Авторитативные DNS-серверы по возможности возвращают IP-адреса хостов. Если сервер этого сделать не может — он выдаёт ошибку, и на этом поиск IP-адреса по серверам заканчивается.</p><h2>Типы DNS-запросов</h2><p>Существует 3 типа DNS-запросов:</p><ol><li>Рекурсивный: подобные запросы выполняют пользователи к резолверу. Собственно, это первый запрос, который выполняется в процессе DNS-поиска. Резолвером чаще всего выступает ваш интернет провайдер или сетевой администратор.</li><li>Нерекурсивные: в нерекурсивных запросах резолвер сразу возвращает ответ без каких-либо дополнительных запросов на другие сервера имён. Это случается, если в локальном DNS-сервере закэширован необходимый IP-адрес либо если запросы поступают напрямую на авторитативные серверы, что позволяет избежать рекурсивных запросов.</li><li>Итеративный: итеративные запросы выполняются, когда резолвер не может вернуть ответ, потому что он не закэширован. Поэтому он выполняет запрос на корневой DNS-сервер. А тот уже знает, где найти фактический TLD-сервер.</li></ol><p>К примеру, если вы пытаетесь получить IP-адрес medium.com, то корневой доменный сервер выдаст адрес TLD-сервера для .com. Этот адрес корневой сервер вернёт резолверу. После этого резолвер опросит TLD-сервер. TLD-сервер может не знать нужный IP-адрес, зато он может дать адрес авторитативного DNS-сервера для <a href="https://medium.com/">medium.com</a>.</p><p>Попробуем рассмотреть этот процесс на рисунке:</p><figure><img src="https://media.tproger.ru/uploads/2019/03/DNS-explained-pic-3.jpg" alt="" /></figure><p>Разберём рисунок выше:</p><ol><li>Пользователь выполняет запрос к резолверу для поиска IP-адреса. Это рекурсивный запрос.</li><li>Резолвер по возможности просматривает свой кэш на наличие необходимого IP-адреса.</li><li>Если у резолвера есть необходимый IP-адрес, то он возвращает его.</li><li>В противном случае резолвер выполняет итеративный запрос на корневой DNS-сервер. Корневой DNS-сервер ищет нужный TLD для запрашиваемого адреса. К примеру, если хост — medium.com, то TLD — .com. Корневой DNS-сервер находит адрес .com-домена и возвращает ответ резолверу.</li><li>Теперь резолвер выполняет итеративный запрос на TLD-сервер, чтобы получить необходимый IP-адрес. TLD-сервер возвращает адрес авторитативного сервера для запрашиваемого хоста.</li><li>Авторитативный сервер хранит фактические записи сопоставления имени хоста с IP-адресом, который возвращается резолверу (тот, в свою очередь, возвращает его пользователю).</li><li>Если на авторитативном сервере нужной записи не существует, то возвращается ошибка «DNS_PROBE_FINISHED_NXDOMAIN».</li><li>Для всех серверов, через которые проходит запрос, результат кэшируется, и в случае повторного запроса результат уже будет на сервере.</li><li>В среднем для DNS-поиска потребуется около 4 запросов, но время этого поиска будет составлять всего несколько миллисекунд.</li></ol><h2>Что в итоге?</h2><p>Даже если вы измените запись у регистраторов, внесение изменений на резолверах всего мира займёт какое-то время. Этот процесс может длиться от 24 до 72 часов, но обычно завершается быстрее, т. к. за это время TTL-записи у провайдеров успевает истечь.</p>]]></content:encoded>
    </item>
    <item>
      <title>О методологии Agile простыми словами</title>
      <link>https://tproger.ru/explain/agile-is-simple</link>
      <comments>https://tproger.ru/explain/agile-is-simple?scrollTo=tproger-comments</comments>
      <dc:creator><![CDATA[Анастасия Лидер]]></dc:creator>
      <guid isPermaLink="true">https://tproger.ru/explain/agile-is-simple</guid>
      <description><![CDATA[<p>Просто и понятно объясняем, как функционирует Agile — гибкая методология работы над проектом, а также чем Scrum отличается от Kanban.</p><p>— Читать дальше «<a rel="follow" href="https://tproger.ru/explain/agile-is-simple">О методологии Agile простыми словами</a>»</p>]]></description>
      <category><![CDATA[Методологии разработки]]></category>
      <category><![CDATA[Agile]]></category>
      <category><![CDATA[Коротко о главном]]></category>
      <slash:comments>0</slash:comments>
      <pubDate>Fri, 07 Sep 2018 16:18:08 GMT</pubDate>
      <content:encoded><![CDATA[<p>Давно слышите о том, что Agile — это классная и удобная методология для разработчиков софта, но вас пугают внушительные и подробные мануалы? В этой статье мы коротко и просто объясним, в чём суть этого подхода.</p><p>Agile — итеративный подход при работе над проектом. Знать об Эджайле полезно тем, кто уже работает в IT, и тем, кто только планирует <a href="https://tproger.ru/articles/kak-stat-programmistom/">стать айтишником</a>. Ваша команда выпускает проект маленькими шагами с самого начала, а не показывает уже готовый продукт в самом конце.</p><p><a href="https://ru.wikipedia.org/wiki/%D0%93%D0%B8%D0%B1%D0%BA%D0%B0%D1%8F_%D0%BC%D0%B5%D1%82%D0%BE%D0%B4%D0%BE%D0%BB%D0%BE%D0%B3%D0%B8%D1%8F_%D1%80%D0%B0%D0%B7%D1%80%D0%B0%D0%B1%D0%BE%D1%82%D0%BA%D0%B8">Википедия описывает</a> гибкую методологию разработки так:</p><blockquote>“Серия подходов к разработке программного обеспечения, ориентированных на использование итеративной разработки, динамическое формирование требований и обеспечение их реализации в результате постоянного взаимодействия внутри самоорганизующихся рабочих групп, состоящих из специалистов различного профиля”.</blockquote><h2>Почему именно Agile?</h2><p>TL;DR — чтобы подстраиваться под постоянно меняющиеся требования.</p><p>Agile как подход признаёт, что у людей не очень с планированием и оцениванием. И в этом нет ничего плохого. Не имеет значения, насколько вы опытны, всё равно всегда остаётся что-то, что вы не могли предусмотреть или упустили из внимания.</p><p>Более традиционные подходы вроде Waterfall (каскадная модель) диктуют тотальное планирование, когда вы ничего не можете сделать, если этого нет в плане.</p><p>В любом проекте, будь то программное обеспечение, маркетинговая кампания или рекрутинговая стратегия, появятся дополнительные возможности или поменяются требования. Особенно в случае с крупными проектами. Поэтому новые факторы приходится либо игнорировать (обычно неидеально), либо ужимать план, погружая работу в хаос. Так зачем тогда вообще планировать, правда?</p><p>А вот и нет! Предусмотрите всю неизвестность заранее, встроив её в рабочий процесс. Некоторые лучшие идеи не приходят в голову до тех пор, пока вы не зайдёте достаточно далеко.</p><h2>Что такое Agile?</h2><p>TL;DR — различные практики, которые помогут вам легче приспосабливаться и убеждать свою команду в том, что она всегда работает над чем-то важным.</p><blockquote>Agile — способность меняться легко и быстро.</blockquote><p>Эджайл это про то, как разбить ваш огромный проект на ряд маленьких задач (обычно их называют пользовательскими историями) и определить наиболее приоритетные.</p><p>Определение приоритетов очень важно, по сути это и есть самое главное в гибкой методологии разработки. Вам нужно убедиться, что команда сфокусирована на одном спринте или на наиболее важном на данный момент результате. Это будет гарантией того, что вы достигнете ваших бизнес-целей. Так ваша команда не потеряется в потоке запросов и требований и будет знать, что каждая подзадача, над которой она работает в данный момент, важна для прогресса всего проекта.</p><p>Пользовательские истории поставляются либо непрерывно, либо маленькими циклами, которые называются спринтами.</p><h2>Как работает Agile?</h2><p>TL;DR — Требования &gt; План &gt; Работа &gt; Ревью &gt; Повтор</p><p>Исходя из требований проекта составьте список всего, что должно произойти. Не переживайте, если забудете что-то, вы сможете добавить это позже.</p><p>Оцените каждый этап: по часам или по так называемым story point’ам (относительные оценки, которые выставляются в сравнении и отношении к другим историям). Есть вероятность, что результат будет несколько неточным и даст вам слабое представление о том, сколько времени займёт работа над проектом.</p><p>Установите приоритетность задач, самые важные — в начало очереди. Обычно в этой среде всё постоянно меняется, поэтому проверяйте приоритеты быстро и часто. Kanban очень реагирует на эту частоту. Scrum же основан на фиксированных циклах (спринтах), которые обычно длятся две недели.</p><p>Проанализируйте уже выполненную работу. Если вы не вписываетесь в план, увеличьте рабочую нагрузку над этим спринтом. Если такое случается постоянно, вы слишком амбициозны.</p><h2>Scrum vs Kanban</h2><p>TL;DR — это два основных фреймворка для Agile.</p><h3>Scrum</h3><ul><li>Деление работы на части, которые называются спринтами (обычно в спринте две недели);</li><li>Спринты планируются исходя из требований для этого конкретного момента времени;</li><li>Относительная оценка времени выполнения работ;</li><li>Ревью каждого спринта, чтобы понять, как он прошёл и что можно было бы улучшить;</li><li>Фидбек по поставляемому продукту;</li><li>Ежедневные собрания (очень короткие).</li></ul><h3>Kanban</h3><ul><li>Еженедельные собрания;</li><li>Непрерывная разработка;</li><li>Визуализация процесса на доске;</li><li>Решение сначала самых важных задач;</li><li>Поэтапные улучшения.</li></ul><h2>Заключение</h2><p>Самое важное — удовлетворить конечного потребителя, будь то ваш клиент, владелец продукта, ваш босс или вы сами. Охватить все изменяющиеся требования в процессе работы над проектом позволит ранний и многоэтапный выпуск. Это уменьшает риск, потому что вы застрахованы от того, что выпустите неподходящий продукт или в принципе так ничего и не выпустите.</p>]]></content:encoded>
    </item>
    <item>
      <title>5 способов выровнять HTML-элемент горизонтально и вертикально</title>
      <link>https://tproger.ru/explain/5-ways-to-center-html-element</link>
      <comments>https://tproger.ru/explain/5-ways-to-center-html-element?scrollTo=tproger-comments</comments>
      <dc:creator><![CDATA[Никита Прияцелюк]]></dc:creator>
      <guid isPermaLink="true">https://tproger.ru/explain/5-ways-to-center-html-element</guid>
      <description><![CDATA[<p>Подборка популярных приёмов центрирования элемента средствами CSS: от связки top и left с translate до flex с align-items и justify-content.</p><p>— Читать дальше «<a rel="follow" href="https://tproger.ru/explain/5-ways-to-center-html-element">5 способов выровнять HTML-элемент горизонтально и вертикально</a>»</p>]]></description>
      <category><![CDATA[Веб-разработка]]></category>
      <category><![CDATA[CSS]]></category>
      <category><![CDATA[HTML]]></category>
      <category><![CDATA[Коротко о главном]]></category>
      <slash:comments>0</slash:comments>
      <pubDate>Sun, 26 Aug 2018 10:45:20 GMT</pubDate>
      <content:encoded><![CDATA[<p>Каждый, кто работает с HTML/CSS, рано или поздно сталкивается с проблемой вертикального и горизонтального выравнивания элемента. Чтобы вы лишний раз не гуглили и не находили много разных вариантов, мы собрали здесь несколько самых популярных.</p><h3>Способ 1</h3><p>В <a href="https://caniuse.com/#feat=transforms2d">поддерживаемых браузерах</a> можно использовать top: 50%/left: 50% в сочетании с translateX(-50%) translateY(-50%) для динамического горизонтального/вертикального центрирования элемента:</p><p>Пример можно посмотреть <a href="http://jsfiddle.net/47x60k4w/">здесь</a>, а <a href="http://jsfiddle.net/47x60k4w/show">тут</a> можно увидеть полноэкранную версию.</p><h3>Способ 2</h3><p>В <a href="https://caniuse.com/#feat=flexbox">поддерживаемых браузерах</a> также можно присвоить свойству display значение flex и использовать align-items: center с justify-content: center для вертикального и горизонтального центрирования соответственно. Главное, не забудьте добавить вендорные префиксы (как в <a href="http://jsfiddle.net/yeaqrh48/">примере</a>), чтобы этот приём сработал в большем количестве браузеров:</p><p>Вот <a href="http://jsfiddle.net/yeaqrh48/">пример</a> и его <a href="http://jsfiddle.net/yeaqrh48/show">полноэкранная версия</a>.</p><h3>Способ 3</h3><p>В некоторых случаях вам будет нужно убедиться, что высота элемента html/body равна 100%.</p><p>Для вертикального выравнивания присвойте свойствам width и height родительского элемента значение 100% и добавьте display: table. В дочернем элементе измените значение display на table-cell и добавьте vertical-align: middle.</p><p>Для горизонтального выравнивания текста и других inline-элементов можно либо использовать text-align: center, либо margin: 0 auto, если вы имеете дело с блоковым элементом. Это должно сработать в <a href="https://caniuse.com/#feat=css-table">большинстве браузеров</a>:</p><p>Примеры доступны <a href="http://jsfiddle.net/sa088kb0/">здесь</a> и <a href="http://jsfiddle.net/sa088kb0/show/">здесь</a>.</p><h3>Способ 4</h3><p>Здесь предполагается, что высота текста заранее известна. В этом случае, например, 18px. Теперь нужно всего лишь присвоить свойству position элемента значение absolute и подвинуть сверху на 50% относительно родительского элемента. Наконец, свойству margin-top нужно присвоить отрицательное значение, равное половине высоты элемента:</p><p>За примерами <a href="http://jsfiddle.net/2epdqL5g/">сюда</a> и <a href="http://jsfiddle.net/2epdqL5g/show">сюда</a>. Этот вариант должен работать во всех поддерживаемых браузерах.</p><h3>Способ 5</h3><p>В некоторых случаях у родительского элемента фиксированная высота. Для вертикального выравнивания нужно всего лишь присвоить свойству line-height дочернего элемента высоту родительского. Хотя в некоторых случаях это будет работать, такой способ не стоит использовать, так как несколько строк текста <a href="http://jsfiddle.net/6rvdxbt9/">всё испортят</a>:</p><p>Пример можно посмотреть <a href="http://jsfiddle.net/6onex7jf/">здесь</a>.</p>]]></content:encoded>
    </item>
    <item>
      <title>Buffer overflow, buffer overrun и stack overflow: что это значит и в чём отличие</title>
      <link>https://tproger.ru/explain/overflow-overrun</link>
      <comments>https://tproger.ru/explain/overflow-overrun?scrollTo=tproger-comments</comments>
      <dc:creator><![CDATA[Евгений Туренко]]></dc:creator>
      <guid isPermaLink="true">https://tproger.ru/explain/overflow-overrun</guid>
      <description><![CDATA[<p>Buffer overflow — запись за границы буфера, buffer overrun — чтение, stack overflow — переполнение стека вызовов. В чём разница?</p><p>— Читать дальше «<a rel="follow" href="https://tproger.ru/explain/overflow-overrun">Buffer overflow, buffer overrun и stack overflow: что это значит и в чём отличие</a>»</p>]]></description>
      <category><![CDATA[Для начинающих]]></category>
      <category><![CDATA[Коротко о главном]]></category>
      <slash:comments>0</slash:comments>
      <pubDate>Sun, 03 Jun 2018 14:55:31 GMT</pubDate>
      <content:encoded><![CDATA[<p>Представьте буфер в виде массива. Переполнение буфера (<b>buffer overflow</b>) происходит тогда, когда вы пытаетесь поместить в массив больше элементов, чем он способен содержать. Проще говоря, речь идёт о <b>записи</b>.</p><p>Выход за границы буфера при чтении (<b>buffer overrun</b>) происходит, когда вы выполняете перебор элементов в буфере, выходя за его границы. Иначе говоря, речь идёт о <b>чтении</b>.</p><p>Переполнение стека (<b>stack overflow</b>) очень отличается от перечисленного выше. Большинство современных программных сред основано на стеках и в них используется структура данных стека для управления процессом выполнения программы. При каждом вызове функции новый элемент помещается в стек вызовов программы. При возврате же функции элемент извлекается из стека. При пустом стеке выполнение программы останавливается. Стек ограничен в размере, это значит, что вызов слишком большого количества функций одновременно может заполнить его. В данном случае вы получите переполнение стека. Самый распространённый метод переполнения стека — сделать так, чтобы функция вызывала саму себя (рекурсия).</p><p>Прим. перев.  Стек программы также можно рассматривать как буфер, и в этом смысле переполнение стека — один из видов переполнения буфера. В отличие от буферов, специально создаваемых программой для хранения данных, стек автоматически управляется операционной системой, и выход за его границы обычно происходит вследствие неограниченной рекурсии, а не ошибок при работе с индексами.</p>]]></content:encoded>
    </item>
    <item>
      <title>Что каждый программист должен знать о безопасности</title>
      <link>https://tproger.ru/explain/what-programmers-should-know-about-security</link>
      <comments>https://tproger.ru/explain/what-programmers-should-know-about-security?scrollTo=tproger-comments</comments>
      <dc:creator><![CDATA[Никита Прияцелюк]]></dc:creator>
      <guid isPermaLink="true">https://tproger.ru/explain/what-programmers-should-know-about-security</guid>
      <description><![CDATA[<p>Для каждого программиста есть минимум знаний по безопасности, включающий ключевые аспекты защиты приложений и перечень рекомендуемых книг.</p><p>— Читать дальше «<a rel="follow" href="https://tproger.ru/explain/what-programmers-should-know-about-security">Что каждый программист должен знать о безопасности</a>»</p>]]></description>
      <category><![CDATA[Безопасность]]></category>
      <category><![CDATA[Советы]]></category>
      <category><![CDATA[Коротко о главном]]></category>
      <slash:comments>0</slash:comments>
      <pubDate>Sat, 26 May 2018 15:35:19 GMT</pubDate>
      <content:encoded><![CDATA[<p>Многие начинающие программисты задаются вопросом: «каким минимумом знаний по безопасности должен обладать каждый разработчик или студент IT-шник?». Попробуем ответить на этот вопрос.</p><p>Вещи, которые всегда нужно держать в уме, если вы хотите создать безопасное приложение:</p><ul><li>Не доверяйте входным данным! <a href="http://www.ibm.com/developerworks/library/l-sp2.html">Проверяйте входные данные</a> из ненадёжных источников — используйте белые списки, а не чёрные.</li><li>Планируйте безопасность с самого начала — это не то, чем можно заняться напоследок.</li><li>Делайте своё приложение простым — сложность увеличивает вероятность дыр в безопасности.</li><li>Сведите вашу <a href="https://ru.wikipedia.org/wiki/%D0%9F%D0%BE%D0%B2%D0%B5%D1%80%D1%85%D0%BD%D0%BE%D1%81%D1%82%D1%8C_%D0%B0%D1%82%D0%B0%D0%BA%D0%B8">поверхность атаки</a> к минимуму.</li><li>Убедитесь, что ошибка во время работы приложения <a href="https://www.owasp.org/index.php/Fail_securely">не поставит под угрозу</a> его безопасность.</li><li><a href="https://www.us-cert.gov/bsi">Обеспечивайте безопасность</a> приложения на каждом этапе разработки.</li><li>Придерживайтесь принципа <a href="https://buildsecurityin.us-cert.gov/bsi/articles/knowledge/principles/351-BSI.html">наименьших привилегий</a>.</li><li>Используйте <a href="https://www.owasp.org/index.php/Threat_Risk_Modeling">моделирование угроз</a>.</li><li><a href="http://www.cgisecurity.com/owasp/html/ch04s09.html">Разделяйте привилегии</a>, чтобы было проще отследить источник проблемы.</li><li>Хранить секретные данные сложно, а все секретные данные, спрятанные в коде, быстро перестанут быть секретными.</li><li>Не создавайте свои механизмы шифрования.</li><li>Использование одного лишь шифрования не делает ваше приложение абсолютно безопасным — злоумышленники найдут другое слабое место, ведь безопасность любой системы всегда равна безопасности самого слабого звена.</li><li>Знайте и помните о <a href="https://www.linuxjournal.com/article/6701">переполнении буфера</a> и о том, как от него защититься.</li></ul><p>Существует несколько замечательных книг и статей на тему того, как сделать приложение безопасным:</p><ul><li><a href="https://www.amazon.com/dp/0735617228/?tag=stackoverflow17-20">Writing Secure Code 2nd Edition</a>.</li><li><a href="https://www.amazon.com/dp/020172152X/?tag=stackoverflow17-20">Building Secure Software: How to Avoid Security Problems the Right Way</a>.</li><li><a href="https://www.amazon.com/dp/0596003943/?tag=stackoverflow17-20">Secure Programming Cookbook</a>.</li><li><a href="https://docs.google.com/viewer?url=http://www.usenix.org/events/sec04/tech/slides/mcgraw.pdf">Exploiting Software</a>.</li><li><a href="http://www.cl.cam.ac.uk/~rja14/book.html">Security Engineering</a>.</li><li>Secure Programming for Linux and Unix HOWTO.</li></ul><p>Обучите ваших разработчиков лучшим практикам безопасности:</p><ul><li>Codebashing (платно)</li><li><a href="https://www.securityinnovation.com/training/application-security">Security Innovation</a> (платно)</li><li><a href="https://www.securitycompass.com/training/">Security Compass</a> (платно)</li><li><a href="https://www.owasp.org/index.php/OWASP/Training/OWASP_WebGoat_Project">OWASP WebGoat</a> (бесплатно)</li></ul><p>Хотите узнать о том, как защитить своё веб-приложение в более развёрнутой форме? Тогда загляните в <a href="https://tproger.ru/translations/webapp-security/">нашу статью</a>, там всё подробно расписано.</p>]]></content:encoded>
    </item>
    <item>
      <title>Словари и их методы в Python</title>
      <link>https://tproger.ru/explain/python-dictionaries</link>
      <comments>https://tproger.ru/explain/python-dictionaries?scrollTo=tproger-comments</comments>
      <dc:creator><![CDATA[Картофельный Повелитель]]></dc:creator>
      <guid isPermaLink="true">https://tproger.ru/explain/python-dictionaries</guid>
      <description><![CDATA[<p>Разбираем словари в Python: создание, получение данных, основные методы (get, update, pop, keys, values, items) и итерация. Примеры кода для начинающих.</p><p>— Читать дальше «<a rel="follow" href="https://tproger.ru/explain/python-dictionaries">Словари и их методы в Python</a>»</p>]]></description>
      <category><![CDATA[Для начинающих]]></category>
      <category><![CDATA[Python]]></category>
      <category><![CDATA[Коротко о главном]]></category>
      <slash:comments>0</slash:comments>
      <pubDate>Mon, 09 Apr 2018 12:16:02 GMT</pubDate>
      <content:encoded><![CDATA[<h2>Что такое словарь</h2><p>• Словарь в Python хранит данные в виде пар «ключ — значение» и позволяет быстро получать значение по ключу
• Ключами могут быть только неизменяемые (хэшируемые) типы: строки, числа, кортежи
• Основные методы: get(), update(), pop(), keys(), values(), items()
• Итерация по словарю перебирает ключи; для пар используйте items()</p><p>Словарь — неупорядоченная структура данных, которая позволяет хранить пары «ключ — значение». Словари входят в число <a href="https://tproger.ru/translations/python-data-types">основных типов данных Python</a>. Вот пример словаря на Python:</p><p>Данный словарь использует строки в качестве ключей, однако ключом может являться в принципе любой неизменяемый тип данных. Значением же конкретного ключа может быть что угодно. Вот ещё один пример словаря, где ключами являются числа, а значениями — строки:</p><p>Важное уточнение: если вы попробуете использовать изменяемый тип данных в качестве ключа, то получите ошибку:</p><p>Прим. перев.  На самом деле проблема не с изменяемыми, а с нехэшируемыми типами данных, но обычно это одно и то же.</p><h3>Получение данных из словаря</h3><p>Для получения значения конкретного ключа используются квадратные скобки []. Предположим, что в нашем словаре есть пара 'марафон': 26.</p><p>Опять же, вы получите ошибку, если попытаетесь получить значение по несуществующему ключу. Для избежания подобных ошибок существуют методы, о которых мы сейчас поговорим.</p><h3>Добавление и обновление ключей</h3><p>Добавление новых пар в словарь происходит достаточно просто:</p><p>Обновление существующих значений происходит абсолютно также:</p><h3>Удаление ключей</h3><p>Для удаления ключа и соответствующего значения из словаря можно использовать del</p><h2>Методы</h2><p>Словари в Python имеют множество различных полезных методов, которые помогут вам в работе с ними. Вот лишь некоторые из них:</p><h3>Update</h3><p>Метод update() пригодится, если нужно обновить несколько пар сразу. Метод принимает другой словарь в качестве аргумента.</p><p>Если вас интересует, почему данные в словаре расположены не в том порядке, в котором они были внесены в него, то это потому что словари не упорядочены.</p><h3>Get</h3><p>Метод get() возвращает значение по указанному ключу. Если указанного ключа не существует, метод вернёт None.</p><p>Метод можно использовать для проверки наличия ключей в словаре:</p><p>Также можно указать значение по умолчанию, которое будет возвращено вместо None, если ключа в словаре не окажется:</p><h3>Pop</h3><p>Метод pop() удаляет ключ и возвращает соответствующее ему значение.</p><h3>Keys</h3><p>Метод keys() возвращает коллекцию ключей в словаре.</p><h3>Values</h3><p>Метод values() возвращает коллекцию значений в словаре.</p><h3>Items</h3><p>Метод items() возвращает пары «ключ — значение».</p><h2>Итерация через словарь</h2><p>Вы можете провести итерацию по каждому ключу в словаре. Если вы только начинаете изучать Python, посмотрите <a href="https://tproger.ru/articles/python-roadmap">дорожную карту разработчика</a>.</p><p>Очевидно, вместо story_count можно использовать story_count.keys().</p><p>В примере кода ниже цикл for использует метод items() для получения пары «ключ — значение» на каждую итерацию.</p><h2>Часто задаваемые вопросы</h2><h3>Чем словарь отличается от списка в Python?</h3><p>Список хранит элементы по порядковому индексу (0, 1, 2...) и поддерживает <a href="https://tproger.ru/translations/python-sorting">сортировку</a>, а словарь — по произвольному ключу. Поиск по ключу в словаре выполняется за O(1), тогда как поиск элемента в списке — за O(n). Словарь удобен, когда нужно быстро находить данные по уникальному идентификатору, а список — когда важен порядок элементов.</p><h3>Можно ли использовать список как ключ словаря?</h3><p>Нет. Ключом словаря может быть только хэшируемый (неизменяемый) объект: строка, число, кортеж. Список является изменяемым типом, поэтому при попытке использовать его как ключ Python выбросит TypeError. Если нужно использовать набор значений в качестве ключа, преобразуйте список в кортеж.</p><h3>Как проверить, есть ли ключ в словаре?</h3><p>Самый простой способ — оператор in: выражение 'ключ' in my_dict вернёт True или False. Другой вариант — метод get(), который возвращает None (или указанное значение по умолчанию), если ключа нет в словаре. Метод get() удобнее, когда нужно сразу получить значение с запасным вариантом.</p><h3>Сохраняют ли словари порядок элементов?</h3><p>Начиная с Python 3.7, словари гарантированно сохраняют порядок вставки элементов. В более ранних версиях порядок не гарантировался, и для упорядоченных пар использовали collections.OrderedDict. В современном Python обычный dict полностью заменяет OrderedDict для большинства задач.</p><p>О словаре и других типах данных Python можно почитать в нашей <a href="https://tproger.ru/translations/python-data-types/">статье</a>.</p>]]></content:encoded>
    </item>
    <item>
      <title>Как правильно задавать вопросы, или "Проблема XY"</title>
      <link>https://tproger.ru/explain/xyproblem</link>
      <comments>https://tproger.ru/explain/xyproblem?scrollTo=tproger-comments</comments>
      <dc:creator><![CDATA[Vladimir Gabrinevski]]></dc:creator>
      <guid isPermaLink="true">https://tproger.ru/explain/xyproblem</guid>
      <description><![CDATA[<p>«Проблема XY» или «Проблема Молотка» — проблема тех, кто не умеет задавать правильные вопросы. Вместо того, чтобы спросить о самой проблеме, они спрашивают, как завершить одну из начатых попыток её решения (обычно неудачных) . Знакомо? Тогда читайте статью о том, что такое Проблема XY» и как продуктивно просить помощи.</p><p>— Читать дальше «<a rel="follow" href="https://tproger.ru/explain/xyproblem">Как правильно задавать вопросы, или "Проблема XY"</a>»</p>]]></description>
      <category><![CDATA[Лучшая практика]]></category>
      <category><![CDATA[Советы]]></category>
      <category><![CDATA[Коротко о главном]]></category>
      <slash:comments>0</slash:comments>
      <pubDate>Fri, 30 Mar 2018 10:00:23 GMT</pubDate>
      <content:encoded><![CDATA[<h3>Что за «Проблема XY»?</h3><p>Это ошибка, которая зачастую приводит к бессмысленной трате времени как просящего о помощи, так и тех, кто пытается ему отвечать. Её ещё называют «Проблемой Молотка». Суть её, если коротко, заключается в том, что люди склонны спрашивать о своих неудачных попытках решить проблему, а не о самой проблеме. В итоге получается примерно так:</p><ul><li>Человек хочет сделать X;</li><li>Он не знает, как сделать X, но догадывается, что к успеху может привести выполнение Y;</li><li>Тем не менее человек не знает и то, как сделать Y;</li><li>В этот момент он решает попросить помощи у других людей;</li><li>Все пытаются помочь человеку с проблемой Y, удивляясь и не понимая, зачем кому-то вообще это может быть нужно;</li><li>После длительных расспросов и ценой уймы потерянного времени наконец-то становится понятно, что человек на самом деле хотел решить X, а Y никак ему помочь не сможет.</li></ul><h3>А почему «Проблема Молотка»?</h3><p>Из-за наглядного, хоть и утрированного, примера:</p><figure><img src="https://media.tproger.ru/uploads/2016/12/firstSO-1024x371.png" alt="" /></figure><figure><img src="https://media.tproger.ru/uploads/2016/12/secondSO-1024x620.png" alt="" /></figure><h3>А можно каких-нибудь более жизненных примеров?</h3><p>Конечно:</p><blockquote>n00b: Как мне вывести последние три символа файла?feline: Ну, например, так: echo ${foo: -3}<br />feline: А зачем три символа? Что надо-то?<br />feline: Может, расширение файла?n00b: Да.feline: Так и говори прямо, чего хочешь!<br />feline: Не факт, что каждое имя файла имеет трехбуквенное расширение.<br />feline: Так что тупо взять три последних символа — это не решение проблемы.<br />feline: Нужно так: echo ${foo##*.}</blockquote><p>Или…</p><blockquote>Angela: ‘nmap -O -A 127.0.0.1’ возвращает несколько строк, начинающихся с ‘OS:’. Как изменить это?<br />Obama: Глянь в исходники nmap, отыщи то место, где оно определяет ось, и перепиши TCP/IP стек, чтобы тот ничем не выдавал nmap операционную систему.<br />Angela: Круто, но я ничего не знаю про api linux’а.<br />Obama: Очень жаль, но, похоже, кроме как переписать TCP/IP стек, никакого выхода нет.<br />Angela: Но мне ооочень нужно избежать подобных сообщений :с Может iptables мне поможет?<br />Obama: Ну, ты можешь просто не использовать обнаружение ОС, в чём проблема?<br />Angela: Я хочу, чтобы и другие не могли узнать, какая у меня операционка.</blockquote><h3>Да, похоже, так можно потерять немало времени. И какая же мораль?</h3><p>Чтобы избежать проблемы XY, стоит придерживаться следующих несложных правил:</p><ul><li>Предоставлять достаточно широкую информацию  о решаемом вопросе — кроме самого неудачного примера стоит написать, чего вы хотите добиться в целом;</li><li>Если кто-то просит у вас больше информации о проблеме, вероятно, стоит эту информацию предоставить;</li><li>Всегда пишите о том, что вы уже пробовали делать и почему от этого отказались. Это поможет точнее определить, что именно вам необходимо.</li></ul><p>И помните: если бы ваши догадки всегда оказывались верными, вам бы не нужна была помощь, верно?</p>]]></content:encoded>
    </item>
    <item>
      <title>Как заменить все одинаковые подстроки в строке на JavaScript</title>
      <link>https://tproger.ru/explain/replace-substrings-in-js</link>
      <comments>https://tproger.ru/explain/replace-substrings-in-js?scrollTo=tproger-comments</comments>
      <dc:creator><![CDATA[Никита Улыбин]]></dc:creator>
      <guid isPermaLink="true">https://tproger.ru/explain/replace-substrings-in-js</guid>
      <description><![CDATA[<p>Для замены всех подстрок в JavaScript подходят регулярные выражения или связка split и join. Первый способ работает вдвое быстрее второго.</p><p>— Читать дальше «<a rel="follow" href="https://tproger.ru/explain/replace-substrings-in-js">Как заменить все одинаковые подстроки в строке на JavaScript</a>»</p>]]></description>
      <category><![CDATA[Алгоритмы и структуры данных]]></category>
      <category><![CDATA[JavaScript]]></category>
      <category><![CDATA[Коротко о главном]]></category>
      <slash:comments>0</slash:comments>
      <pubDate>Mon, 12 Mar 2018 15:29:39 GMT</pubDate>
      <content:encoded><![CDATA[<p>В этот раз разберёмся, как можно заменить все одинаковые подстроки в конкретной строке. Допустим, у нас есть строчка:</p><p>var str = "Test abc test test abc test test test abc test test abc";</p><p>А наш код должен заменить, например, все подстроки abc в этой строке. Использовать метод replace не получится, ведь так мы заменим лишь самую первую подстроку abc.</p><p>Существует как минимум два оптимальных решения этой задачи: использование регулярных выражений и методов split и join.</p><p>Внимание: в приведённых ниже примерах мы решим данную задачу, переписывая встроенные в JavaScript методы. Это не самая лучшая практика и настоятельно не рекомендуется к использованию в реальных проектах. Мы же будем использовать её исключительно в демонстрационных целях.</p><h2>Метод первый – регулярные выражения</h2><h2>Метод второй – split и join</h2><p>Что касается производительности, то стоит отметить, что первое решение работает аж в два раза быстрее второго.</p><p>Однако существует загвоздка в решении с использованием регулярных выражений: предполагается, что пользователь не будет использовать зарезервированные для регулярных выражений символы в качестве первого параметра. Пользователи бывают разные и зачастую совершают не самые разумные поступки с нашими творениями, так что не будем рисковать и предотвратим этот вариант развития событий.</p><p>Нам нужна функция, которая будет форматировать аргумент search:</p><p>Всё, что остаётся, — вызвать функцию escapeRegExp в нашем String.prototype.replaceAll:</p>]]></content:encoded>
    </item>
    <item>
      <title>Какую структуру данных выбрать для реализации словаря</title>
      <link>https://tproger.ru/explain/data-structures-for-dictionary</link>
      <comments>https://tproger.ru/explain/data-structures-for-dictionary?scrollTo=tproger-comments</comments>
      <dc:creator><![CDATA[Евгений Туренко]]></dc:creator>
      <guid isPermaLink="true">https://tproger.ru/explain/data-structures-for-dictionary</guid>
      <description><![CDATA[<p>Бывает сложно подобрать оптимальную структуру данных под свою задачу. В этой статье мы расскажем вам о наиболее подходящей структуре данных для реализации словаря.</p><p>— Читать дальше «<a rel="follow" href="https://tproger.ru/explain/data-structures-for-dictionary">Какую структуру данных выбрать для реализации словаря</a>»</p>]]></description>
      <category><![CDATA[Алгоритмы и структуры данных]]></category>
      <category><![CDATA[Для начинающих]]></category>
      <category><![CDATA[Лучшая практика]]></category>
      <category><![CDATA[Для продолжающих]]></category>
      <category><![CDATA[Коротко о главном]]></category>
      <slash:comments>0</slash:comments>
      <pubDate>Sat, 24 Feb 2018 16:06:05 GMT</pubDate>
      <content:encoded><![CDATA[<p>Если вам нужно создать словарь, вероятно, вы уже задумывались над выбором структуры данных для хранения слов. Ваш выбор должен зависеть от задач, которые призвана решить эта структура.</p><h2>Хеш-таблица</h2><p>Если вы хотите просто сохранить слова, а потом проверить, есть среди них определённое или нет, то стандартная хеш-таблица без каких-либо других дополнений будет разумным выбором. Если количество элементов списка заранее известно, используйте <a href="https://goo.gl/XFPge3">идеальную хеш-таблицу</a>, чтобы получить наиболее высокую производительность и оптимальный размер хранимых данных.</p><h2>Дерево</h2><p>Если вам нужно узнать, существует ли данный префикс, поддерживая функцию быстрого поиска, то <a href="https://goo.gl/qKvTYW">префиксное дерево</a> — хороший вариант, хотя он может быть немного неэффективным с точки зрения размера хранимых файлов. Этот метод также поддерживает быстрые вставки и удаления. Кроме того, в нём допускается итерация в алфавитном порядке, которая в хеш-таблицах отсутствует.</p><h2>Граф</h2><p>Если в дополнение к вышесказанному известно, что список слов фиксирован, то подумайте над использованием <a href="https://goo.gl/GtM9vY">направленного ациклического графа</a> слов, который на самом деле является минимальным <a href="https://goo.gl/ozuQsp">детерминированным конечным автоматом</a>. Этот метод значительно компактнее, чем дерево, и поддерживает многие его операции.</p><h2>И ещё деревья</h2><p>Если вы хотите получить поведение, подобное методу дерева, но не хотите поплатиться за это не совсем оптимальным размером файлов, то <a href="https://en.wikipedia.org/wiki/Ternary_search_tree">троичное (тернарное) дерево поиска</a> — ещё одно достойное решение, собственно, как и <a href="https://goo.gl/3vQQEK">базисное дерево</a>. Эти структуры довольно разные, но при определённых обстоятельствах они могут быть лучше стандартного дерева.</p><p>Если оптимальный размер файла очень важен, но вам хочется использовать дерево, то обратите внимание на <a href="https://neerc.ifmo.ru/wiki/index.php?title=%D0%A1%D0%B6%D0%B0%D1%82%D0%BE%D0%B5_%D1%81%D1%83%D1%84%D1%84%D0%B8%D0%BA%D1%81%D0%BD%D0%BE%D0%B5_%D0%B4%D0%B5%D1%80%D0%B5%D0%B2%D0%BE">сжатое дерево</a>. Этот метод использует более медленную функцию поиска, но распределяет ресурсы рациональнее. Дерево из двухмерного массива может быть ещё одним альтернативным и компактным решением.</p><p>Если вы хотите использовать словарь для таких операций, как проверка орфографии, где требуется найти одни слова, похожие на другие, то в таком случае <a href="https://www.geeksforgeeks.org/bk-tree-introduction-implementation/">БК-дерево</a> — замечательный вариант.</p><p>Подробнее об алгоритмах и структурах данных:</p><ol><li><a href="https://tproger.ru/tag/algorithms/">Статьи, видеокурсы, визуализации</a>.</li><li><a href="https://tproger.ru/tag/algos-and-data-structs/">Раздел для новичков с объяснениями базы</a>.</li></ol>]]></content:encoded>
    </item>
    <item>
      <title>Git pull и git fetch — в чём разница?</title>
      <link>https://tproger.ru/explain/git-pull-and-git-fetch-whats-the-difference</link>
      <comments>https://tproger.ru/explain/git-pull-and-git-fetch-whats-the-difference?scrollTo=tproger-comments</comments>
      <dc:creator><![CDATA[Алексей Михайлишин]]></dc:creator>
      <guid isPermaLink="true">https://tproger.ru/explain/git-pull-and-git-fetch-whats-the-difference</guid>
      <description><![CDATA[<p>Узнайте разницу между git fetch и git pull с примерами команд. Когда fetch безопаснее pull, как связан git merge и pull --rebase. Читайте на Tproger.</p><p>— Читать дальше «<a rel="follow" href="https://tproger.ru/explain/git-pull-and-git-fetch-whats-the-difference">Git pull и git fetch — в чём разница?</a>»</p>]]></description>
      <category><![CDATA[Для начинающих]]></category>
      <category><![CDATA[Git]]></category>
      <category><![CDATA[Коротко о главном]]></category>
      <slash:comments>0</slash:comments>
      <pubDate>Wed, 21 Feb 2018 18:26:58 GMT</pubDate>
      <content:encoded><![CDATA[<p>git fetch и git pull — две команды <a href="https://tproger.ru/explain/chto-takoe-git-i-github--rukovodstvo-dlya-nachinayushhih">Git</a> для получения изменений из удалённого репозитория. Разберёмся, чем они отличаются — с примерами, которые можно повторить в терминале.</p><p><b>Ключевые выводы:</b>
— git fetch загружает изменения с удалённого репозитория, но не трогает рабочую копию и локальные ветки
— git pull = git fetch + git merge (по умолчанию)
— Используйте fetch, когда хотите сначала посмотреть, что изменилось
— Используйте pull, когда уверены, что конфликтов не будет
— git pull --rebase — альтернатива merge, которая сохраняет линейную историю</p><h2>Что делает git fetch</h2><p>git fetch скачивает новые коммиты, ветки и теги с удалённого репозитория в ваш локальный репозиторий. При этом ваша рабочая копия и текущая ветка <b>не меняются</b>.</p><p>Представьте, что вы работаете в ветке main. Коллега запушил три коммита. Чтобы увидеть его изменения, не сливая их в свой код:</p><p>В терминале вы увидите что-то вроде:</p><p>После этого новые коммиты окажутся в origin/main. Это <b>remote-tracking ветка</b> — локальная копия удалённой ветки main. Git хранит две версии: вашу локальную main (с вашими коммитами) и origin/main (зеркало того, что на сервере). git fetch обновляет только origin/main, ваша main остаётся нетронутой. Читайте также наш <a href="https://tproger.ru/articles/git-polnyj-putevoditel-ot-pervogo-kommita-do-prodvinutyh-wor">полный путеводитель по Git</a>.</p><p>Теперь можно посмотреть, что именно изменилось:</p><p>Если изменения вас устраивают, можно слить их вручную:</p><h3>Получение конкретной ветки</h3><p>По умолчанию git fetch origin загружает все ветки. Если нужна только одна:</p><h3>Получение всех удалённых репозиториев</h3><p>Если у вас несколько remote-ов (например, origin и upstream для форка):</p><h2>Что делает git pull</h2><p>git pull скачивает изменения <b>и сразу сливает</b> их в текущую ветку. Это удобно, но означает, что у вас не будет шанса посмотреть изменения перед слиянием.</p><p>Если коллега изменил те же файлы, что и вы — git pull может привести к конфликту слияния. В этом случае git остановится и попросит вас разрешить конфликты вручную.</p><h3>Пример: типичный рабочий день с git pull</h3><h3>Что происходит при конфликте</h3><p>Если git pull обнаруживает конфликт, вы увидите примерно такое:</p><p>Откройте файл с конфликтом — внутри вы увидите маркеры:</p><p>Код между &lt;&lt;&lt;&lt;&lt;&lt;&lt; HEAD и ======= — ваши изменения. Код между ======= и &gt;&gt;&gt;&gt;&gt;&gt;&gt; origin/main — изменения с сервера. Нужно оставить правильный вариант и удалить маркеры.</p><p>Дальше:</p><ol><li>Решить, какой код оставить (или объединить оба варианта)</li><li>Удалить маркеры конфликта</li><li>Добавить файл в индекс: git add src/utils.js</li><li>Завершить слияние: git commit</li></ol><h2>Как связаны git pull, git fetch и git merge</h2><p>По умолчанию git pull — это последовательность двух команд:</p><p>То есть pull делает всё то же самое, что fetch + merge, но в одну команду. Разница — только в контроле: с fetch вы можете посмотреть изменения перед слиянием.</p><h2>Пошаговый пример: fetch + merge vs pull</h2><p>Допустим, вы работаете в ветке feature/login, а коллега запушил изменения в main. Вам нужно подтянуть эти изменения.</p><h3>Вариант 1: безопасный (fetch + merge)</h3><h3>Вариант 2: быстрый (pull)</h3><p>Результат одинаковый. Но в первом варианте вы видели, какие коммиты прилетели, и могли решить — сливать или подождать. Подробнее об основах Git -- в нашей <a href="https://tproger.ru/translations/beginner-git-cheatsheet">шпаргалке для начинающих</a>.</p><h2>git pull --rebase — альтернатива merge</h2><p>По умолчанию git pull создаёт merge-коммит. Если вы хотите сохранить линейную историю без лишних merge-коммитов, используйте флаг --rebase:</p><p>Разница наглядно:</p><p>Если при --rebase возникнет конфликт, git остановится и предложит три варианта:</p><p>Обратите внимание: при конфликте во время rebase для продолжения используется git rebase --continue, а не git commit, как при обычном merge. Подробнее о rebase -- в статье <a href="https://tproger.ru/articles/git-rebase-vs-merge-kogda-chto-ispolzovat-i-v-chyom-raznica">git rebase vs merge: когда что использовать</a>.</p><p>Чтобы сделать --rebase поведением по умолчанию:</p><h2>Когда использовать git fetch, а когда git pull</h2><p>Вот практические ориентиры:</p><p><b>Используйте git fetch, когда:</b></p><ul><li>Хотите посмотреть, что изменилось, перед слиянием</li><li>Работаете в команде и не уверены в совместимости изменений</li><li>Нужно сравнить локальную и удалённую ветки</li><li>Пишете скрипты для CI/CD — fetch безопаснее, потому что не меняет рабочее дерево</li></ul><p><b>Используйте git pull, когда:</b></p><ul><li>Работаете один или изменения точно не конфликтуют</li><li>Утром начинаете работу и хотите быстро обновить ветку</li><li>Работаете с чистой веткой без локальных изменений</li></ul><h2>Полезные команды для работы с fetch и pull</h2><h2>Частые вопросы про git fetch и git pull</h2><h3>В чём разница между git fetch и git pull?</h3><p>git fetch загружает новые коммиты из удалённого репозитория в remote-tracking ветки (например, origin/main), но не трогает вашу рабочую копию и локальные ветки. git pull делает то же самое, но сразу сливает загруженные изменения в текущую ветку через git merge. Если вам важно сначала посмотреть, что изменилось — используйте fetch.</p><h3>Можно ли отменить git pull?</h3><p>Да. Если слияние ещё не завершено (например, вы в процессе разрешения конфликта), используйте:</p><p>Если git pull уже завершился и вы хотите откатиться — найдите нужную точку в reflog:</p><p><b>Внимание:</b> git reset --hard удаляет все незакоммиченные изменения в рабочей копии. Перед откатом убедитесь, что у вас нет несохранённых правок, или сделайте git stash.</p><h3>Чем git fetch отличается от git clone?</h3><p>git clone создаёт <b>новую</b> локальную копию удалённого репозитория целиком — со всей историей коммитов, ветками и настройками. Это делается один раз в начале работы с проектом. git fetch работает в <b>уже существующем</b> репозитории и только подтягивает свежие изменения, которые появились на сервере после последней синхронизации.</p><h3>Безопасен ли git fetch?</h3><p>Да. git fetch обновляет только remote-tracking ветки (origin/main, origin/feature/...) и объектную базу репозитория. Он не трогает ваши локальные ветки, рабочую копию и индекс — поэтому его можно запускать в любой момент без риска сломать текущую работу.</p><h3>Что лучше: pull --rebase или pull с merge?</h3><p>--rebase перебазирует ваши локальные коммиты поверх свежих с сервера, что даёт линейную историю без merge-коммитов — её удобнее читать и ревьюить. Обычный merge сохраняет точную хронологию ветвления, что может быть важно для аудита. Для большинства проектов --rebase предпочтительнее — если в вашей команде нет других договорённостей.</p><h2>Итоги</h2><p>Разница между git fetch и git pull — в степени контроля:</p><ul><li>git fetch — загружает изменения, но не применяет их. Вы решаете, что делать дальше</li><li>git pull — загружает и сразу сливает. Быстро, но без возможности предварительного обзора</li><li>git pull --rebase — загружает и перебазирует ваши коммиты поверх свежих. Чистая линейная история</li></ul><p>Если не уверены — начинайте с git fetch. Это безопасная команда, которая ничего не сломает. А когда убедитесь, что изменения вас устраивают — слейте их вручную через git merge.</p><p>Подробнее о работе с Git — в <a href="https://git-scm.com/docs/git-fetch">официальной документации git fetch</a> и <a href="https://git-scm.com/docs/git-pull">git pull</a>, а также в нашем <a href="https://tproger.ru/explain/chto-takoe-git-i-github--rukovodstvo-dlya-nachinayushhih">руководстве по Git для начинающих</a>.</p>]]></content:encoded>
    </item>
    <item>
      <title>Конкурентность и параллелизм — разные вещи</title>
      <link>https://tproger.ru/explain/concurrency-vs-parallelism</link>
      <comments>https://tproger.ru/explain/concurrency-vs-parallelism?scrollTo=tproger-comments</comments>
      <dc:creator><![CDATA[Евгений Туренко]]></dc:creator>
      <guid isPermaLink="true">https://tproger.ru/explain/concurrency-vs-parallelism</guid>
      <description><![CDATA[<p>Не все программисты знают, в чём разница между конкурентностью и параллелизмом. В этой статье мы на простом примере объясним, в чём же она заключается.</p><p>— Читать дальше «<a rel="follow" href="https://tproger.ru/explain/concurrency-vs-parallelism">Конкурентность и параллелизм — разные вещи</a>»</p>]]></description>
      <category><![CDATA[Обучение программированию]]></category>
      <category><![CDATA[Основные принципы программирования]]></category>
      <category><![CDATA[Коротко о главном]]></category>
      <slash:comments>0</slash:comments>
      <pubDate>Tue, 20 Feb 2018 18:13:31 GMT</pubDate>
      <content:encoded><![CDATA[<p>Может показаться, что нет никакой разницы между параллелизмом и конкурентностью, но это потому что вы не вникали в суть дела. Давайте попробуем понять, чем они отличаются.</p><p>Конкурентность — это выполнение задач за определённое время (например, есть 5 процессов и все они в сумме выполняются в течение 60 минут по очереди). Важная деталь заключается в том, что задачи необязательно выполняются одновременно, поэтому их можно разделить на более мелкие и чередующиеся.</p><figure><img src="https://media.tproger.ru/uploads/2018/02/Concurrency-vs-parallelism-pic-1.jpg" alt="" /></figure><p>Проведём аналогию: шеф-повар нарезает лук и иногда проверяет духовку. Ему нужно прекратить нарезать лук, чтобы подойти к духовке, а затем снова начать нарезать и повторять этот процесс до конца приготовления блюда.</p><p>Как вы заметили, конкурентность связана в большей степени с логистикой. Если бы её не было, то повар ждал бы пока приготовится мясо в духовке, чтобы начать нарезать лук.</p><p>Параллелизм — это выполнение задач в одно и то же время (например, есть 5 задач, каждая из них выполняется в течение 60 минут). Само название подразумевает, что они выполняются параллельно.</p><figure><img src="https://media.tproger.ru/uploads/2018/02/Concurrency-vs-parallelism-pic-2.jpg" alt="" /></figure><p>Вернёмся на кухню: теперь у нас есть два шеф-повара. Один следит за духовкой, а второй нарезает лук. Работа разделена, так как теперь на кухне трудятся два повара.</p><p>Параллелизм — подкласс конкурентности: перед выполнением нескольких одновременных задач вам нужно их сначала правильно организовать.</p><p>Что ещё можно почитать на эту тему:</p><ol><li><a href="https://www.braveclojure.com/concurrency/">Сакральное искусство параллельного и конкурентного программирования.</a></li><li><a href="https://wiki.haskell.org/Parallelism_vs._Concurrency">Параллелизм vs. Конкурентность.</a></li><li><a href="https://tproger.ru/translations/programming-concepts-concurrency/">Основные принципы программирования: конкурентность</a>.</li></ol>]]></content:encoded>
    </item>
  </channel>
</rss>