...

суббота, 26 марта 2016 г.

Минусы Битрикса, или Битрикс глазами программиста

Не пропусти js-ошибку

Разрабатывая и тестируя сайт, зачастую замечаешь не все js-ошибки. Это происходит по ряду причин:
  • отсутствие консоли в некоторых мобильных и планшетных браузерах;
  • открытая консоль мешает при тестировании, перекрывая видимую часть страницы;
  • консоль открывают когда страница уже загрузилась и ошибки, возникающие при загрузке, теряются (Firebug в Firefox, Internet Explorer);
  • при разработке часто отключают логирование ошибок в системах аналитики, чтобы не было лишнего «шума» при анализе ошибок;
  • и прочее.

Для решения проблемы я написал небольшой js-скрипт «show-js-error», который выводит приметное сообщение о js-ошибке при её возникновении в браузере.

На показе сообщений всё не заканчивается, важно зарепортить ошибку. Правильное описание бага — починка половины бага.

Для этого в задаче на исправление бага необходимо указать информацию:

  • описание и тип ошибки;
  • stack trace или имя файла с номером строки;
  • адрес страницы;
  • referrer;
  • ОС и её версия;
  • браузер и его версия;
  • и т.д.

Чтобы каждый раз не тратить время, воспользуемся кнопкой «Copy» для копирования всей информации об ошибке в буфер обмена. Или кнопкой «Send», заведение бага с которой занимает всего один клик.

Правда, для Githubʼа понадобится два клика — клик на кнопку «Send» в сообщении и «Submit new issue» на самом Github'е.
При заведении нового Issue, заголовок и текст сообщения можно пробросить через GET-параметры.
http://ift.tt/1RFWpog

Быстрый старт


Устанавливаем:
npm install show-js-error

Подключаем на свою страницу в <head> перед всеми скриптами:

<link rel="stylesheet" href="./node_modules/show-js-error/dist/show-js-error.css" />
<script src="./node_modules/show-js-error/dist/show-js-error.js"></script>

Также можно показывать ошибки другого типа, например, ошибки с сервера, проброшенные на страницу:

showJSError.show({
    title: 'Server error',
    message: 'My message',
    stack: 'My stack'
});

В итоге:

  • меньше ошибок в проде;
  • «лечим» ошибки при разработке, а не в проде;
  • быстро и четко ставим задачи на починку багов;
  • упрощаем жизнь тестировщикам.

Ссылки:

Комментарии (0)

    Let's block ads! (Why?)

    [Перевод] Var и val в Java?

    Как навести порядок в почтовом ящике с помощью нейронной сети. Часть 1

    image

    В нашем блоге мы много пишем о создании email-рассылок и работе с электронной почтой. Мы уже обсудили сложности борьбы со спамом, будущее email, вопросы защиты почтовой переписки, а также техники работы с email, применяемые руководителями крупных ИТ-компаний. 

    В современном мире люди получают множество писем, и в полный рост встает проблема с их классификацией и упорядочиванием почтового ящика. Инженер из США Андрей Куренков в своем блоге рассказал о том, как решил эту задачу с помощью нейронной сети. Мы решили осветить ход этого проекта и представляем вам первую часть рассказа.

    Код проекта доступен здесь.

    Начало


    Куренков пишет, что один из его любимых мини-проектов, EmailFiler, появился благодаря заданию на курсе «Введение в машинное обучение» в Технологическом Институте Джорджии. Задание состояло в том, чтобы взять какой-либо набор данных, применить к нему ряд контролируемых обучающихся алгоритмов и проанализировать результаты. Суть в том, что по желанию можно было использовать собственные данные. Разработчик так и поступил – экспортировал данные своего gmail для исследования возможностей машинного обучения в решении задачи сортировки электронной почты.

    Куренков пишет, что давно понял, что электронные письма лучше всегда иметь под рукой на случай, если вдруг когда-нибудь понадобится к ним обратиться. С другой стороны, ему всегда хотелось свести количество непрочитанных входящих сообщений к нулю, какой бы безнадежной ни была эта идея. Поэтому много лет назад инженер начал сортировать электронные письма примерно по дюжине папок, и к моменту поступления на курсы машинного обучения, в этих папках накопились тысячи писем.

    Так возникла идея проекта по созданию классификатора, который мог бы предложить единственную категорию для каждого входящего письма – так, чтобы отправлять письмо в соответствующую папку одним нажатием кнопки.

    image

    Категории (папки) и количество писем в каждой из них на момент старта проекта

    В качестве входных данных выступали письма, в число выходных данных попадали категории писем. Сложность заключалась в том, что разработчику хотелось использовать тексты писем и метаданные, но понять, как превратить все это в пригодный для машинного обучения набор данных, было нелегко.

    Любой, кто изучал обработку естественных языков, сразу предложит один простой подход – использование модели Bag of Words (Множество слов). Это один из простейших алгоритмов классификации текстов – найти N общих слов для всех текстов и составить таблицу бинарных признаков для каждого слова (признак равен 1, если заданный текст содержит слово, и 0 – если не содержит).

    Куренков проделал это для группы слов, найденных во всех его письмах, а также для топ-20 отправителей писем (так как в некоторых случаях отправитель строго коррелирует с категорией письма; например, если отправитель –научный руководитель в университете, то категорией будет «Исследования») и для топ-5 доменов, с которых ему присылали письма (поскольку домены типа gatech.edu строго указывают на такие категории как, например, «Обучение»). Так, где-то после часа, потраченного на написание парсера электронной почты, он смог получать данные о своём ящике в формате csv (значения, разделённые запятыми).

    Насколько хорошо все работало? Неплохо, но хотелось большего. Куренков говорит, что тогда увлекался фреймворком для машинного обучения Orange ML на Python, и, как и было положено по заданию, протестировал несколько алгоритмов на своем наборе данных. Выделялись два алгоритма – лучше всего показали себя деревья принятия решений, а хуже всего – нейронные сети:

    image

    Так с небольшим набором данных справились деревья принятия решений

    image

    А так – нейронные сети

    Если внимательно взглянуть на эти графики из OpenOffice Calc, то можно увидеть, что лучший результат деревьев принятия решений на тесте – где-то 72%, а нейронных сетей – жалкие 65%. Ужас! Это, конечно, лучше, чем разложить всё наугад, учитывая, что там 11 категорий, но до отличного результата далеко.

    Почему же результаты оказались такими удручающими? Дело в том, что признаки, полученные для набора данных, оказались весьма примитивны – простой поиск 500 наиболее часто встречающихся в письмах слов даст нам не так уж много полезных индикаторов, но много общеупотребительных конструкций, которые встречаются в английском, например «that» или «is». Инженер понял это и предпринял следующее: полностью убрал из списка слова из трёх и менее букв и написал немного кода, чтобы выбрать наиболее часто встречающиеся слова для каждой категории отдельно; но он все еще не представлял, как улучшить результат.

    Попытка номер два


    Спустя пару лет Куренков решил еще раз попытаться решить задачу — хоть сам проект в университете уже был давно сдан, хотелось улучшить результаты.

    В этот раз инженер решил в качестве одного из основных инструментов применить Keras, потому как он написан на Python и также неплохо ладит с пакетами NumPy, pandas и scikit-learn и поддерживается библиотекой Theano.

    К тому же получилось так, что у Keras есть в лёгком доступе несколько примеров, с которых можно начать работу, включая задачу классификации разнообразных текстов. И вот, что интересно – данный пример использует такие же функции, какие инженер использовал ранее. Он определяет 1000 наиболее часто встречающихся в документах слов, бинарные признаки и обучает нейронную сеть с одним скрытым слоем и dropout-регуляризацией предсказывать категорию заданного текста, основываясь исключительно на этих признаках.

    Итак, первое, что приходит в голову: испробовать этот пример на собственных данных – посмотреть, улучшит ли работу Keras. К счастью, сохранился старый код для парсинга почтового ящика, а у Keras есть удобный класс Tokenizer для получения признаков текста. Поэтому можно легко создать набор данных в таком же формате, как и в примере, и получить новую информацию о текущем количестве электронных писем:

    Using Theano backend.
    Label email count breakdown:
            Personal:440
            Group work:150
            Financial:118
            Academic:1088
            Professional:388
            Group work/SolarJackets:1535
            Personal/Programming:229
            Professional/Research:1066
            Professional/TA:1801
            Sent:513
            Unread:146
            Professional/EPFL:234
            Important:142
            Professional/RISS:173
    Total emails: 8023
    

    Восемь тысяч писем никак не назовёшь большим набором данных, но всё же этого достаточно для того, чтобы немного позаниматься серьёзным машинным обучением. После перевода данных в нужный формат остаётся лишь посмотреть, работает ли обучение нейронной сети на этих данных. Пример с использованием Keras даёт легко сделать следующее:
    7221 train sequences
    802 test sequences
    Building model...
    Train on 6498 samples, validate on 723 samples
    Epoch 1/5
    6498/6498 [==============================] - 2s - loss: 1.3182 - acc: 0.6320 - val_loss: 0.8166 - val_acc: 0.7718
    Epoch 2/5
    6498/6498 [==============================] - 2s - loss: 0.6201 - acc: 0.8316 - val_loss: 0.6598 - val_acc: 0.8285
    Epoch 3/5
    6498/6498 [==============================] - 2s - loss: 0.4102 - acc: 0.8883 - val_loss: 0.6214 - val_acc: 0.8216
    Epoch 4/5
    6498/6498 [==============================] - 2s - loss: 0.2960 - acc: 0.9214 - val_loss: 0.6178 - val_acc: 0.8202
    Epoch 5/5
    6498/6498 [==============================] - 2s - loss: 0.2294 - acc: 0.9372 - val_loss: 0.6031 - val_acc: 0.8326
    802/802 [==============================] - 0s     
    Test score: 0.585222780162
    

    Точность: 0.847880299252

    85% точности! Это намного выше жалких 65% старой нейронной сети. Отлично.

    Но…почему?

    Старый код делал, в общем-то, следующее – определял наиболее часто встречающиеся слова, создавал бинарную матрицу признаков и обучал нейронную сеть с одним скрытым слоем. Может быть, всё из-за нового нейрона «relu», dropout-регуляризации и использования методов оптимизации, отличных от стохастического градиентного спуска? Поскольку признаки, найденные по старым данным, бинарные и представлены в виде матрицы, их очень легко превратить в набор данных для обучения этой нейронной сети. Итак, вот результаты:

    Epoch 1/5
    6546/6546 [==============================] - 1s - loss: 1.8417 - acc: 0.4551 - val_loss: 1.4071 - val_acc: 0.5659
    Epoch 2/5
    6546/6546 [==============================] - 1s - loss: 1.2317 - acc: 0.6150 - val_loss: 1.1837 - val_acc: 0.6291
    Epoch 3/5
    6546/6546 [==============================] - 1s - loss: 1.0417 - acc: 0.6661 - val_loss: 1.1216 - val_acc: 0.6360
    Epoch 4/5
    6546/6546 [==============================] - 1s - loss: 0.9372 - acc: 0.6968 - val_loss: 1.0689 - val_acc: 0.6635
    Epoch 5/5
    6546/6546 [==============================] - 2s - loss: 0.8547 - acc: 0.7215 - val_loss: 1.0564 - val_acc: 0.6690
    808/808 [==============================] - 0s     
    Test score: 1.03195088158
    

    Точность: 0.64603960396

    Итак, старое решение по определению категорий электронных писем было неудачным. Возможно причиной стало сочетание сильных ограничений признаков (вручную определённые топовые отправители, домены и слова из каждой категории) и слишком маленького количества слов.

    Пример, использующий Keras, просто отбирает 1000 наиболее часто встречающихся слов в большую матрицу без дополнительного фильтрования и передает её нейронной сети. Если сильно не ограничивать отбор признаков, из них могут быть выбраны более подходящие, что увеличивает общую точность работы алгоритма.

    Причина или в этом или в наличии ошибок в коде: его изменение с целью сделать процесс отбора признаков менее ограничивающим приводит к повышению точности лишь до 70%. В любом случае, инженер выяснил, что можно было улучшить свой старый результат с использованием современной библиотеки машинного обучения.

    Теперь возникал новый вопрос – можно ли добиться еще более высокой точности?

    Продолжение следует…

    Комментарии (0)

      Let's block ads! (Why?)

      За и против: Когда стоит и не стоит использовать MongoDB

      Разработчик и сотрудник проекта CouldBoost.io Наваз Дандала (Nawaz Dhandala) написал материал о том, почему в некоторых случаях не стоит использовать MongoDB. Мы в «Латере» развиваем биллинг для операторов связи «Гидра» и уже много лет работаем с этой СУБД, поэтому решили представить и свое мнение по данному вопросу.

      Дандала сразу оговаривается, что работал со многими СУБД (как SQL, так и NoSQL) и считает MongoDB отличным инструментом, однако существуют сценарии, в которых его применение нецелесообразно.

      Документоориентированные СУБД такие, как MongoDB, прекрасно справляются с хранением JSON-данных, сгруппированных в «коллекции». В таком формате можно хранить любые JSON-документы и удобно категоризировать и по коллекциям. Содержащийся в MongoDB JSON-документ называется двоичным JSON или BSON и, как любой другой документ этого формата, является неструктурированным. Поэтому, в отличии от традиционных СУБД, в коллекциях можно сохранять любые виды данных, и эта гибкость сочетается с горизонтальной масштабируемостью базы данных. Эта возможность нравится многим разработчикам, однако «не все так однозначно».

      Если MongoDB такая классная, почему ее не используют все и всегда?


      Выбор СУБД зависит в том числе и от того, что за приложение планируется создать. То есть базу данных выбирают не разработчики, а сам продукт, убежден Дандала. Он приводит пример, подтверждающий этот тезис.

      При создании приложения, концепция которого подразумевает работу с документами, MongoDB будет хорошим выбором. К такому типу приложений можно отнести, к примеру, движок блог-платформы, где каждый автор сможет иметь по несколько блогов, и каждый из них будет содержать множество комментариев. База данных для обслуживания такого приложения должна быть легко расширяемой, и здесь MongoDB подойдет как рельзя лучше.

      Однако, необходимо отметить, что у MongoDB нет связей между документами и “коллекциями” (частично это компенсируется Database Reference — ссылками в СУБД, но это не полностью решает проблему). В итоге, возникает ситуация, при которой имеется некий набор данных, который никак не связан с другой информацией в базе, и не существует никакого способа объединить данные из различных документов. В SQL-системах это было бы элементарной задачей.

      Здесь возникает другой вопрос — если в MongoDB нет связей и возможностей по объединению двух таблиц, то зачем ее тогда вообще использовать? Ответ — потому что эта СУБД отлично масштабируется, и по сравнению с традиционными SQL-системами, гораздо быстрее осуществляет чтение и запись.MongoDB прекрасно подходит для приложений, в которых практически не используются данные с зависимостями и необходима масштабируемость базы данных.

      Многие разработчики применяют MongoDB и для хранения связанных данных, реализуя объединения вручную в коде — этого достаточно в сценариях «одноуровневого» объединения или малого количества связей. То есть данный метод далеко не универсален.

      Так какую СУБД выбрать?


      Существует огромное количество различных СУБД, и каждая из них соответствует определённому набору требований, которые разработчики предъявляют к своему приложению:
      • Документоориентированные СУБД (к примеру, MongoDB): Как уже сказано выше, документоориентированные СУБД используются для хранения JSON-документов в “коллекциях” и осуществления запросов по нужным полям. Можно использовать эту базу данных для создания приложений, в которых не будет содержаться слишком большого количества связей. Хорошим примером такого приложения является движок для блог-платформы или хранения каталога продуктов.
      • Графовые СУБД (например Neo4j): Графовая СУБД используется для хранения между субъектами, где узлы являются субъектами, а грани — связями. Например, если разработчики создают социальную сеть, и один пользователь подписывается на другого, то пользователи являются узлами, а их “подписка” — связью. Такие СУБД прекрасно справляются с образованием связей, даже если глубина таких связей более ста уровней. Этот инструмент столь эффективен, что может даже позволяет выявлять мошенничество в сфере электронной коммерции.
      • Кэш (например Redis): Такие СУБД используются, когда требуется крайне быстрый доступ к данным. Если создается приложение для интернет-торговли, в котором есть подгружаемые на каждой страницы категории, то вместо обращения к базе данных при каждом чтении, что крайне затратно, можно хранить данные в кэше. Он позволяет быстро осуществлять операции чтения/записи. Дандала советует применять СУБД, использующие кэш, в качестве оболочки для обработки часто запрашиваемых данных, избавляющей от необходимости совершения частых запросов к самой базе.
      • Поисковые СУБД (например ElasticSearch): В случае необходимости осуществления полнотекстового поиска по базе данных (например поиск продукции в ecommerce-приложении), то хорошей идее будет использование поисковой СУБД вроде ElasticSearch. Эта система способна искать по огромному массиву данных и обладает обширной функциональностью — например, СУБД умеет осуществлять поиск по именованным категориям.
      • Строковые СУБД (например Cassandra): СУБД Cassandra используется для хранения последовательных данных, логов, или огромного объема информации, который может генерироваться автоматически — к примеру, каким-нибудь датчиками. Если разработчики собираются использовать СУБД для записи больших массивов данных и при этом планируется, что будет намного меньше обращений для чтения и данные не будут иметь связи и объединения, тогда Cassandra будет хорошим выбором, уверен Дандала.

      Использование комбинации баз данных


      Существуют и ситуации, в которых может понадобиться использование сразу нескольких различных СУБД.

      Например, если в приложении есть функция поиска, то его можно реализовать с помощью ElasticSearch, а уже для хранения данных без связей лучше подойдет MongoDB. Если речь иет о проекте в сфере «интернета вещей», где огромное количество всевозможных устройств и датчиков генерируют гигантские объёмы данных, вполне разумно будет использовать Cassandra.

      Принцип, при котором используются несколько СУБД для работы в одном приложении, называется “Polyglot Persistence”. В этой статье можно почитать о плюсах и минусах такого подхода.

      Наш опыт


      Наша биллинговая система «Гидра» использует для учета первичных данных и хранения финансовой информации реляционную СУБД. Она идеально подходит для этих целей. Но некоторые модули Гидры, например, RADIUS-сервер, работают под высокой нагрузкой и могут получать тысячи запросов в секунду с жесткими ограничениями на время обработки запроса. Кроме того, в БД нашего автономного RADIUS-сервера данные хранятся в виде набора AVP (attribute/value pair). В таком сценарии реляционная СУБД уже не выглядит лучшим решением, и тут на помощь приходит MongoDB с ее хранилищем документов произвольной структуры, быстрой выдачей ответа и горизонтальной масштабируемостью.

      При эксплуатации более чем на 100 инсталляциях Гидры на протяжении последних 5 лет серьезных проблем с Mongo мы не обнаружили. Но пара нюансов все же есть. Во-первых, после внезапного отключения сервера БД хоть и восстанавливается благодаря журналу, но происходит это медленно. К счастью, необходимость в этом возникает нечасто. Во-вторых, даже при небольшом размере БД редко используемые данные сбрасываются на диск и когда запрос к ним все же приходит, их извлечение занимает много времени. В результате нарушаются ограничения на время выполнения запроса.

      Все это относится к движку MMAPv1, который применяется в Mongo по умолчанию. С другими (WiredTiger и InMemory) мы пока не экспериментировали — проблемы не настолько серьезны.

      Комментарии (0)

        Let's block ads! (Why?)

        пятница, 25 марта 2016 г.

        [Перевод] Самое широкое простое число, записанное римскими цифрами

        [Перевод] Рассыпающийся тигр, затаившийся каньон

        Джефф Лестер работал над созданием визуальных эффектов для игры Far Cry 4. Публикуем перевод материала, в котором Джефф подробно рассказывает, как можно заставить исчезнуть тигра.


        В мире Шангри-Ла из Far Cry 4 многие вещи превращаются в пыль. Например мой приятель Тигра.
        Или, как пошутил Макс Сковилл в своем видео, «из тигра сыплется кокаин». Думаю, лучше не смотреть это видео на работе: лично я не смог удержаться от хохота.

        Я не принимал участия в создании «порошковых» визуальных эффектов, над этим работала команда экспертов: Триша Пенман, Крэг Алгуайр и Джон Ли. В Шангри-Ла очень много спецэффектов, и, нужно сказать, ребята постарались на славу.
        Моей задачей было сделать так, чтобы тело тигра постепенно растворилось в воздухе. Весь процесс длится всего пару секунд, так что можно было особо не заморачиваться.

        Прототип

        Первым делом я набросал прототип в Unity3D, используя ресурсы из библиотеки Modo:

        Я нарисовал черно-белую маску для альфа-канала и обработал ее пороговым методом (по аналогии с корректирующим слоем «Изогелия» в Photoshop). Края альфа-канала слегка размыты: в этой зоне я добавил повторяющуюся огненную текстуру. Не буду вдаваться в подробности, потому что эта техника стара как мир, и в интернете можно найти много обучающих материалов о ее использовании в Unity/UE4. Как оказалось, похожий прием применяется в игре для создания эффекта сгорания плакатов, поэтому я решил его позаимствовать, чтобы не копаться в шейдерах самому.

        Причем здесь каньоны?

        Для детализации карт я использовал инструмент World Machine. В итоге мне пришлось сделать около тридцати черно-белых карт для эффекта рассеивания на разных объектах.

        Рабочий процесс

        В качестве примера возьму модель вортигонта из Half-Life. Я давно собираюсь довести ее до ума, но всё время откладываю на потом, а так от нее будет хоть какая-то польза. Во-первых, для большинства ассетов я сделал грубый набросок черно-белой маски в Modo:

        Затем я экспортировал его в World Machine в виде карты высот и добавил эрозию:

        Готовую карту потока я перенес обратно в Photoshop и наложил ее поверх исходной черно-белой маски, добавив эффект Noise. После быстрой настройки в UE4 вот что получилось:

        Не произведение искусства, но для десяти минут работы очень даже ничего. Прорисовка маски на важных объектах может занять больше времени, но конечный эффект длится всего пару десятков кадров, так что большинство можно оставить как есть.

        Усовершенствование и автоматизация

        По-моему, намного удобнее сгенерировать маску в Houdini, чем рисовать ее вручную.

        • Задать цвет вертексов, с которых должно начинаться рассеивание.
        • Использовать solver для распределения значений вертексов в каждом кадре (или в текстурном пространстве).
        • Разнообразить переход на основе нормалей и гладкости поверхности (как вариант).
        • Заодно можно сделать эрозию или другой аналогичный эффект.

        Впрочем, на такой простой эффект не нужно тратить слишком много времени. Можно попробовать добавить внутрь объектов какой-нибудь объемный эффект (хотя здесь лучше проконсультироваться с графическим программистом).

        Другие примеры

        Я проделал то же самое практически для всех персонажей, за исключением нескольких (ОСТОРОЖНО: СПОЙЛЕР!), включая гигантского босса-орла, которыми, насколько я помню, занимались Нильс Майер и Стив Фабок. Не считая моего приятеля Тигры, вот еще несколько примеров:

        Цепь для колокола

        Если присмотреться, можно заметить, что звенья цепи исчезают одно за другим. Сделать это оказалось непросто: использованный материал не поддерживал 2 UV-канала, а все звенья были развернуты к одному месту в текстуре (что абсолютно логично). К счастью, материал позволял изменить тайлинг маски по UV-координатам по отношению к другим текстурам. Таким образом, мы сделали стек из UV-оболочек звеньев в UV-пространстве:

        Итак, маска рассеивается по мере того, как значение V переходит от нуля к единице. Если бы у нас было 15 звеньев, нам нужно было бы разделить этот процесс на 15 шагов для всех карт (Diffuse, Normal, Roughness), оставив одиночное повторение текстуры маски. За создание ассетов для цепи отвечал Эдвин Чан, и я мог бы попросить его настроить всё вручную в 3ds Max. Но я и так частенько дергал его насчет настройки молитвенных барабанов, и это было бы уже слишком. У колокольной цепи было 3-4 конфигурации, по несколько уровней детализации для разных платформ в каждой. Поэтому я написал MAXScript для упаковки всех UV-координат в допустимый диапазон. Для такого быстрого эффекта я проделал достаточно много работы, но это того стоило.

        Драгоценные камни для лука

        Хоть эти камешки не вышли точь-в-точь, как было задумано, я остался доволен результатом. Излучающий материал не поддерживал параметр Threshold для альфа-канала. Поэтому в меше было 2 слоя: светящийся и несветящийся. Что интересно, исчезает как раз таки несветящийся слой, и по мере его рассеивания на поверхности выступает свечение. Немного запутанно, но результат налицо.

        Комментарии (0)

          Let's block ads! (Why?)

          Таблицы сортировок в СУБД Caché

          Зато какая сортировка!
          (А. С. Пушкин)

          Если бы это была запись для твиттера, то она была бы следующей: «Программисты на Caché ObjectScript! Используйте Cyrillic4 вместо Cyrillic3!». Но тут Хабр, поэтому придётся развернуть мысль – добро пожаловать под кат.

          Всё в Caché хранится в глобалах. Данные, метаданные, классы, программы. Узлы глобала сортируются по значениям индексов (subscript) и сохраняются на диске не в том порядке, в котором их вставили, а в отсортированном — для быстрого поиска:

          USER>set ^a(10)=""
          
          USER>set ^a("фф")=""
           
          USER>set ^a("бб")=""
           
          USER>set ^a(2)=""
           
          USER>zwrite ^a
          ^a(2)=""
          ^a(10)=""
          ^a("бб")=""
          ^a("фф")=""
          

          При сортировке Caché различает числа и строки — 2 рассматривается как число и сортируется перед 10. Команда zwrite и функции $Order и $Query выводят индексы глобала в том порядке, в котором они хранятся на диске: сначала пустая строка, затем отрицательные числа, ноль, положительные числа, затем строки в порядке, определяемом таблицей сортировки (collation).

          В простейшем случае таблица сортировки сопоставляет каждому символу некоторый порядковый номер. Далее таблицу сортировки я буду называть сортировкой.

          Стандартная сортировка в Caché так и называется — Caché standard. Она сопоставляет каждому символу его код в Unicode.

          Сортировка, с которой создаются локальные массивы в текущем процессе, определяется локалью (Портал Управления > Администрирование Системы > Конфигурация > Настройка поддержки национальных языков). Для rusw — русской локали юникодных инсталляций Caché — таблица сортировки по умолчанию — Cyrillic3. Другие возможные сортировки в rusw — Caché standard, Cyrillic1, Cyrillic3, Cyrillic4, Ukrainian1.

          Метод ##class(%Collate).SetLocalName() меняет сортировку для локальных массивов текущего процесса:

          USER>write ##class(%Collate).GetLocalName()
          Cyrillic3
          USER>write ##class(%Collate).SetLocalName("Cache standard")
          1
          USER>write ##class(%Collate).GetLocalName()
          Cache standard
          USER>write ##class(%Collate).SetLocalName("Cyrillic3")
          1
          USER>write ##class(%Collate).GetLocalName()
          Cyrillic3
          

          У каждой сортировки есть парная, в которой числа сортируются как строки. Имя такой парной сортировки получается добавлением " string" к имени оригинальной сортировки:
          USER>write ##class(%Collate).SetLocalName("Cache standard string")
          1
          USER>kill test
           
          USER>set test(10) = "", test(2) = "", test("фф") = "", test("бб") = ""
           
          USER>zwrite test
          test(10)=""
          test(2)=""
          test("бб")=""
          test("фф")=""
           
          USER>write ##class(%Collate).SetLocalName("Cache standard")
          1
          USER>kill test
           
          USER>set test(10) = "", test(2) = "", test("фф") = "", test("бб") = ""
          
          USER>zwrite test
          test(2)=""
          test(10)=""
          test("бб")=""
          test("фф")=""
          

          Caché standard и Cyrillic3


          В Caché standard символы сортируются в порядке их кодов Unicode:
           write ##class(%Library.Collate).SetLocalName("Cache standard"),!
           write ##class(%Library.Collate).GetLocalName(),!
           set letters = "абвгдеёжзийклмнопрстуфхцчщщьыъэюя"
           set letters = letters _ $zconvert(letters,"U")
           kill test
          
           //заполняем test данными
           for i=1:1:$Length(letters) {
               set test($Extract(letters,i)) = ""
           }
           
           //выводим индексы массива test в отсортированном порядке
           set l = "", cnt = 0
           for  {
               set l = $Order(test(l))
               quit:l=""
               write l, " ", $Ascii(l),","
               set cnt = cnt + 1
               write:cnt#8=0 !
           }
          

          USER>do ^testcol
          1
          Cache standard
          Ё 1025,А 1040,Б 1041,В 1042,Г 1043,Д 1044,Е 1045,Ж 1046,
          З 1047,И 1048,Й 1049,К 1050,Л 1051,М 1052,Н 1053,О 1054,
          П 1055,Р 1056,С 1057,Т 1058,У 1059,Ф 1060,Х 1061,Ц 1062,
          Ч 1063,Щ 1065,Ъ 1066,Ы 1067,Ь 1068,Э 1069,Ю 1070,Я 1071,
          а 1072,б 1073,в 1074,г 1075,д 1076,е 1077,ж 1078,з 1079,
          и 1080,й 1081,к 1082,л 1083,м 1084,н 1085,о 1086,п 1087,
          р 1088,с 1089,т 1090,у 1091,ф 1092,х 1093,ц 1094,ч 1095,
          щ 1097,ъ 1098,ы 1099,ь 1100,э 1101,ю 1102,я 1103,ё 1105,
          

          Все буквы на своём месте, кроме букв «ё» и «Ё». Их коды в Unicode выбиваются из общего порядка. Поэтому для русской локали понадобилась своя таблица сортировки — Cyrillic3, в которой буквы идут в том же порядке, как и в русском алфавите:
          
          USER>do ^testcol
          1
          Cyrillic3
          А 1040,Б 1041,В 1042,Г 1043,Д 1044,Е 1045,Ё 1025,Ж 1046,
          З 1047,И 1048,Й 1049,К 1050,Л 1051,М 1052,Н 1053,О 1054,
          П 1055,Р 1056,С 1057,Т 1058,У 1059,Ф 1060,Х 1061,Ц 1062,
          Ч 1063,Щ 1065,Ъ 1066,Ы 1067,Ь 1068,Э 1069,Ю 1070,Я 1071,
          а 1072,б 1073,в 1074,г 1075,д 1076,е 1077,ё 1105,ж 1078,
          з 1079,и 1080,й 1081,к 1082,л 1083,м 1084,н 1085,о 1086,
          п 1087,р 1088,с 1089,т 1090,у 1091,ф 1092,х 1093,ц 1094,
          ч 1095,щ 1097,ъ 1098,ы 1099,ь 1100,э 1101,ю 1102,я 1103,
          

          В Caché ObjectScript есть специальный бинарный оператор ]] — «сортируется после». Он возвращает 1, если в индексе массива левый аргумент будет размещен после правого аргумента, иначе 0:
          USER>write ##class(%Library.Collate).SetLocalName("Cache standard"),!
          1
          USER>write "А" ]] "Ё"
          1
          USER>write ##class(%Library.Collate).SetLocalName("Cyrillic3"),!
          1
          USER>write "А" ]] "Ё"
          0
          

          Глобалы и таблицы сортировок


          Разные глобалы в одной и той же базе данных могут иметь разную сортировку. У каждой базы данных есть настройка — сортировка для новых глобалов. Сразу после инсталляции у всех баз кроме USER сортировка по умолчанию для новых глобалов — Caché standard. Для USER — в зависимости от локали инсталляции. Для rusw — Cyrillic3.

          Создание глобала с сортировкой отличной от сортировки по умолчанию для данной базы:

          USER>kill ^a
          USER>write ##class(%GlobalEdit).Create(,"a",##class(%Collate).DisplayToLogical("Cache standard"))
          

          В списке глобалов в Портале управления (Обозреватель Системы > Глобалы) для каждого глобала показывается его сортировка (четвёртый столбец).

          Нельзя поменять сортировку существующего глобала. Нужно создать глобал с новой сортировкой и скопировать данные из старого глобала командой merge. Массовую конвертацию глобалов из одной сортировки в другую можно сделать методом ##class(SYS.Database).Copy()

          Cyrillic4, Cyrillic3 и умляуты


          В процессе эксплуатации Cyrillic3 выяснилось, что преобразование текстового индекса во внутренний формат происходит дольше, чем в сортировке Caché standard, поэтому вставка и навигация по глобалу (или локальному массиву) с сортировкой Cyrillic3 выполняется медленней. Была создана новая сортировка Cyrillic4, доступная с версии 2014.1. Порядок букв кириллицы в ней такой же, как и в Cyrillic3, но Cyrillic4 заметно быстрее.
          for collation="Cyrillic3","Cyrillic4","Cache standard","Cyrillic1" {
               write ##class(%Library.Collate).SetLocalName(collation),!
               write ##class(%Library.Collate).GetLocalName(),!
               do test(100000)
           }
           quit
          test(C)
           set letters = "абвгдеёжзийклмнопрстуфхцчщщьыъэюя"
           set letters = letters _ $zconvert(letters,"U")
           
           kill test
           write "test insert: "
           // заполняем test данными
           set z1=$zh
           for c=1:1:C {
               for i=1:1:$Length(letters) {
                   set test($Extract(letters,i)_"плюс длинное русское слово" _ $Extract(letters,i)) = ""
               }
           }
           write $zh-z1,!
           
           //перебираем индексы массива test
           write "test $Order: "
           set z1=$zh
           for c=1:1:C {
               set l = ""
               for  {
                   set l = $Order(test(l))
                   quit:l=""
               }
           }
           write $zh-z1,!
          

          USER>do ^testcol
          1
          Cache standard
          test insert: 1.520673
          test $Order: 2.062228
          1
          Cyrillic3
          test insert: 3.541697
          test $Order: 5.938042
          1
          Cyrillic4
          test insert: 1.925205
          test $Order: 2.834399
          

          Cyrillic4 пока не является сортировкой по умолчанию в локали rusw, но, создав свою локаль на базе rusw, можно указать Cyrillic4 сортировкой по умолчанию для локальных массивов. Или указать Cyrillic4 сортировкой по умолчанию для новых глобалов в настройках базы данных.

          Cyrillic3 медленнее Caché standard и Cyrillic4, потому что в её основе лежит алгоритм более общий, чем сортировка двух строк в зависимости от кодов соответствующих символов этих строк.

          В немецком языке при сортировке буква ß должна восприниматься как ss. В Caché так и работает:

          USER>write ##class(%Collate).GetLocalName()
          German3
          USER>set test("Straßer")=1
          USER>set test("Strasser")=1
          USER>set test("Straster")=1
          USER>zwrite test
          test("Strasser")=1
          test("Straßer")=1
          test("Straster")=1
          

          Обратите внимание на порядок строк. А именно, что первые четыре буквы первой строки — «Stras», затем «Straß», затем опять «Stras». Такого порядка нельзя достичь, если каждой букве сопоставлять некоторый код.

          Нам с вами повезло с русским языком — в нём нет умляутов или букв, которые могут сортироваться одинаково, как, например, v и w в финском языке. В русском языке достаточно дать каждой букве номер, и сравнивать строки по номерам букв на соответствующих позициях. За счёт этого и получилось выиграть в скорости в Cyrillic4.

          Таблицы сортировок и SQL


          Не путайте таблицу сортировки в глобалах и сортировку (тоже collation) для столбца в SQL. Вторая сортировка — преобразование, применяемое к значению, перед тем как положить его в индексный глобал или сравнить с другим значением. В Caché SQL сортировка по умолчанию для строк — SQLUPPER. Это преобразование переводит все буквы в верхний регистр, удаляет пробельные символы в конце и добавляет один пробел в начало строки. Три другие SQL сортировки (EXACT, SQLSTRING, TRUNCATE) описаны в документации.

          При некотором умении не сложно создать путаницу, когда разные глобалы в базе данных имеют разную сортировку, а локальные массивы — третью. SQL для внутренних нужд использует базу CACHETEMP, сортировка глобалов которой тоже может отличаться от сортировки по умолчанию текущей локали.

          Основное правило одно — чтобы ORDER BY в запросах SQL возвращал строки в ожидаемом порядке, сортировка глобалов, в которых хранятся данные и индексы таблиц, участвующих в запросе должна быть такой же как сортировка по умолчанию для базы CACHETEMP и сортировка локальных массивов. Подробнее — смотрите абзац в документации «SQL and NLS Collations».

          Создадим тестовый класс:

          Class Habr.test Extends %Persistent
          {
          
          Property Name As %String;
          
          Property Surname As %String;
          
          Index SurInd On Surname;
          
          ClassMethod populate()
          {
              do ..%KillExtent()
              
              set t = ..%New()
              set t.Name = "Павел", t.Surname = "Ёлкин"
              write t.%Save()
              
              set t = ..%New()
              set t.Name = "Пётр", t.Surname = "Иванов"
              write t.%Save()
          
              set t = ..%New()
              set t.Name = "Прохор", t.Surname = "Александров"
              write t.%Save()
          }
          
          }
          

          Внесём данные (можете потом поменять имена на строки из немецкого примера):
          USER>do ##class(Habr.test).populate()
          

          Выполним запрос:

          Результат неожиданный. Главный вопрос — почему не алфавитный порядок имён (Павел, Пётр, Прохор)? Смотрим план запроса:

          Ключевые слова в этом плане — «populates temp-file». Для выполнения запроса оптимизатор SQL решил использовать временную структуру — temp-file — глобал (в некоторых случаях локальный массив), видный только текущему процессу (process-private global). В индексы этого глобала помещаются значения и потом выводятся в отсортированном порядке. Временные глобалы хранятся в базе CACHETEMP, сортировка дла новых глобалов в которой — Caché standard. Но почему «ё» в начале, а не в конце? В индексы временного глобала кладётся значение поля name приведённое к верхнему регистру (SQLUPPERпреобразование по умолчанию для строк), соответственно буква Ё будет идти в самом начале.

          Отменив автоматические преобразование (функция %Exact), получим всё ещё неправильный, но хотя бы ожидаемый порядок — «ё» сортируется после всех букв


          Не будем пока исправлять таблицу сортировки в CACHETEMP — проверим запросы с surname. Ведь на этот столбец есть индекс в глобале ^Habr.TestI. Сортировка этого глобала — Cyrillic3, значит и порядок строк должен быть алфавитный:

          Опять не то. Смотрим план:

          Чтобы вывести фамилии в исходном виде (до преобразования SQLUPPER, которое по умолчанию применяется к элементам индекса SurInd) данных только индекса мало и нужно обращаться к таблице, поэтому оптимизатор SQL решил брать данные сразу из таблицы и сортировать их во временной переменной — так же как и в случае с name.

          Если указать в запросе, что верхний регистр нас устраивает, то порядок будет верный — ведь данные будут браться напрямую из индексного глобала ^Habr.testI:


          План запроса ожидаемый:

          Теперь давайте сделаем, что давно нужно было сделать — изменим сортировку по умолчанию для новых глобалов в базе CACHETEMP на Cyrillic3 (или на Cyrillic4).

          Запросы, использовавшие временные структуры, теперь выводят строки в правильном порядке:


          Выводы


          • Если вас не волнует, в каком порядке отображаются данные с буквой Ё, — используйте таблицу сортировок Caché standard.
          • Если вы используете Cyrillic3, протестируйте своё приложение с таблицей сортировки Cyrillic4. Приложение может стать быстрее.
          • Проверьте, что в базе данных CACHETEMP, рабочей базе данных и в настройках локали стоит одна и та же таблица сортировки.

          Комментарии (0)

            Let's block ads! (Why?)

            LenovoDev запускает Multi-Touch Multi-Hack — хакатон для разработчиков с призовым фондом в 25 000 долларов США

            Есть множество способов взаимодействия с помощью пальцев одной руки. Дай пять. Держу кулачки. «Мирись-мирись» мизинчиками. Протянуть руку помощи. Здороваться с другом ударом кулачков. LenovoDev идёт дальше: мы предлагаем Windows-разработчикам задействовать все десять пальцев на обеих руках и выиграть!


            Мы открываем Multi-Touch Multi-Hack, онлайн-марафон по разработке приложений с помощью нашего комплекта разработчика для многопользовательской мультисенсорной технологии (MUMT). Платформа YOGA Home MUMT, созданная Lenovo, позволяет использовать все десять пальцев при взаимодействии с экраном планшета или сенсорным экраном компьютера и даёт возможность нескольким пользователям работать с устройством одновременно. Денежный призовой фонд марафона составляет 25 000 долларов США, кроме этого множество компьютеров и планшетов Lenovo и различные предложения по продвижению ваших приложений через каналы развития бизнеса и маркетинга Lenovo.
            Чем так интересна технология MUMT?
            Платформы, позволяющие нам работать с устройством наиболее физиологически естественным способом, определяют тенденции развития технологий взаимодействия человека и компьютера. YOGA Home SDK дает возможность людям работать с сенсорными экранами, используя естественные физические движения рук и пальцев. Таким образом, благодаря технологии MUMT уже привычный нам набор жестов — как правило, ограниченный только прикосновением, пролистыванием и перетаскиванием, — дополняется новыми, задействующими все пальцы одной или обеих рук. Поворот, масштабирование, вращение, волнообразные движения, пролистывание всей ладонью, «до-си-до» и даже «лунная походка» — все эти жесты можно применять в работе с устройствами Lenovo. Интерфейс моментально реагирует одновременно на все команды. А ещё экран работает в любой ориентации, поэтому устройством можно управлять под любым углом.

            Для участия в Марафоне вам необходимо до 14 июня 2016 г. разработать приложение под ОС Windows, задействующее жесты 10 пальцев. Приложение должно быть создано в Lenovo YOGA Home. Оно может быть образовательным или развлекательным, и в нём должна быть создана среда для совместного доступа нескольких пользователей. Победитель получит 10 000 долларов США и сможет встретиться со специалистами по развитию бизнеса Lenovo и обсудить возможности продвижения.


            Начните экспериментировать с MUMT прямо сейчас на multitouch.devpost.com. До победы — всего несколько жестов!

            Комментарии (0)

              Let's block ads! (Why?)

              [Перевод] 11 неожиданных особенностей языков программирования

              На свете много языков программирования и каждый из них обладает своими маленькими причудами — странным синтаксисом, необычным функционалом или нестандартными реализациями. Порой это сбивает с толку не только новичков, но и опытных разработчиков. Иногда эти причуды всерьез останавливают от изучения языка или, напротив, становятся известной фишкой.

              Есть очень много подобных вещей в языках программирования, но мы выбрали для вас самые известные из них.

              Пустые строки в Oracle SQL


              Image courtesy Nic Hughes CC BY 2.0

              Oracle считает строки нулевой длины эквивалентными NULL. Это существенное отличие от других БД и ANSI/ISO стандарта SQL, который подразумевает, что пустая строка — ранее известное значение, а NULL — неизвестное, и они не могут быть эквивалентны. Это может принести головную боль при написании кода для нескольких RDBMS или переписывании кода.

              Возникла путаница в далёком 1979 году, когда вышла первая версия SQL, а соответствующий стандарт ещё не был разработан. Впрочем, в Oracle предупреждают, что в ближайшем будущем подобное явление пустой строки может исчезнуть.

              Цитаты:


              «Да, это одна из „прекрасных“ фич Oracle DB» — Lukas Eder
              «Пустая строка эквивалентна NULL не больше, чем числу 0» — Ben Blank
              «ЧТО!? Я так рад, что мы не используем Oracle. Это пугает» — Jeff Davis

              + как универсальный оператор конкатенации в JavaScript


              Image courtesy MicroAssist CC BY-SA 2.0

              Оператор + перегружен в JavaScript, и выполняет роль как математического сложения чисел, так и конкатенации строк. То есть если один из операндов строчный, а другой числовой, то условно вместо 1+1=2 вы получите ‘1’+1=’11’: JavaScript без предупреждения приведет число к строке.

              Причина тому — недостаточный контроль за совместимостью типов. Например, в Python + используется ровно для тех же целей, но у вас ни за что не получится сложить число и символ.

              Цитаты:


              «Проблема в том, что скрытое приведение типов в выражениях непредсказуемо» — Anonymous
              «JavaScript должен выбрасывать исключение в таком случае» — crgwbr
              «+ для конкатенации строк — кошмар» — Matteo Riva

              Модули Perl должны возвращать true



              Image courtesy anthony kelly CC BY 2.0

              Каждый модуль в языке Perl должен возвращать true. Если же этого не происходит, то разработчик рискует сильно подпортить себе карму и столкнуться с ошибкой компиляции.

              Причина этого ясна и понятна, если понимать, что такое модуль в Perl. Программа компиляции, рассматривая подключённые к коду модули, в первую очередь проверяет их выполняемость. Даже если в модуле нет кода инициализации, Perl все еще ожидает получить на выходе True.

              Цитаты:


              «Эта штука всегда оставляет у меня тошнотворное чувство» — Drew Hall
              «Это не имеет практического применения, учитывая непрерывно возникающее раздражение» — Schwern

              Триграфы в C и C++



              Image courtesy REUTERS/Gary Hershorn

              Языки C и C++ поддерживают триграфы — трёхсимвольные обозначения, которые автоматически конвертируются в односимвольные. Так, например, комбинация ??! выдаст вам |. Если вы хотите максимально запутать необразованного врага, решившего прочитать ваш код, используйте вместо квадратных скобок комбинацию ??( и ??).

              Смысл триграфов вовсе не в желании разработчиков языка обфусцировать код, а в том, что когда-то давно многие клавиатуры просто не содержали распространённых ныне символов, например фигурных скобок.

              Цитаты:


              «Google не поможет, если вы ищете что-то по запросу ??!??!» — Isaac
              «Все так ненавидят триграфы, что C99 принес диграфы как альтернативу… еще больше обфускации» — dododge
              «Радость триграфов — делает C нечитаемым с 1977 года» — Martin Beckett

              Чувствительность к регистрам PHP



              Image courtesy Gregg O'Connell CC BY 2.0

              В то время как большинство языков программирования чувствительны к регистру, в PHP названия функций, классов и методов к нему нечувствительны. Но что наиболее сильно поражает разработчиков — то, что имена переменных, констант и свойства классов всё же регистрозависимы.

              Доподлинно неизвестно, откуда повелось такое расхождение, но наиболее вероятный вариант — изначальное желание создателей PHP выделить интерфейс CGI в отдельный полноценный язык программирования.

              Цитаты:


              «Ну, это PHP. Не удивляйтесь» — Grzechooo
              «Вот почему PHP-программисты используют подчеркивания вместо CamelCase, называя свои функции» — paperstreet7
              «Я не имею ни малейшего представления о том, как создавать языки программирования...» — создатель PHP Rasmus Lerdorf
              «Есть ли в PHP что-то, не вызывающее недоумения?» — Lambda Fairy

              Истинный ноль в Ruby



              Image courtesy DaveBleasdale CC BY 2.0

              В Ruby 0 == TRUE. Это неожиданно, расходится с большинством других языков, включая Python и C, где 0 всё-таки FALSE, и часто сбивает с толку новичков в Ruby.

              Причина в том, что в Ruby только boolean false и нулевое значение (nil) вычисляются в FALSE; все остальное имеет значение TRUE. 0 рассматривается как любое другое число.

              Цитаты:


              «Это может быть странным, если бы я не считал это неплохим» — Chris Lutz
              «Вот почему я люблю Ruby. Мне не приходится иметь дело с таким zero-false злом» — Edditoria
              «0==true // аргх, компилятор C в моей голове взорвался!!» — kenny

              Пробелы в Python



              Image courtesy Paul Kitchener CC BY 2.0

              Вместо пунктуации или ключевых слов Python использует отступ для обозначения блока, к которому принадлежит строка кода. Неправильное количество пробелов или смешивание пробелов и табуляции может привести к ошибкам.

              Создатели языка стремились сделать код более читабельным и уменьшить количество нажимаемых клавиш за счет того, что многие редакторы и IDE расставляют отступы автоматически.

              Цитаты:


              «Нет, правда: это то, что мешает мне когда-либо полюбить Python» — wazoox
              «Я обожаю отступы в Python, но есть ньюанс: при копировании и вставке кода из Интернета это часто приводит к необходимости дополнительной очистки» — Greg
              «Если вам нужны навязанные отступы, вы слишком ленивы» — Joris Meys

              Массивы в C подчиняются арифметике указателей



              Image courtesy BlueGum CC BY-ND 2.0

              Кроме того, что можно получить ссылку на элемент массива как a[i], можно получить ее как i[a].

              Причина в том, что массивы в C — указатели на блоки памяти, поэтому a[i]=*(a+i)=*(i+a)=i[a].

              Цитаты:


              «… это бесценно, когда вы участвуете в конкурсе обфускации C...» — Confusion
              «Я не расцениваю это как особенность, это просто взгляд на ядро C. Все для указателей и максимально быстрого получения доступа к памяти. В некотором смысле это красиво» — Michael Neale

              Предопределённые переменные Perl



              Image courtesy Emily Mathews CC BY 2.0

              Если внимательно ознакомиться с описанием языка Perl, можно найти достаточно большое количество предопределённых переменных с, мягко говоря, странными названиями (правда, имеющими достаточно длинный английский эквивалент).

              Они служат для выдачи информации или обеспечения доступа к различным аспектам программы. Так, например, $@ — сообщение об ошибке, $$ — идентификатор процесса, $^V — используемая версия Perl. Новичкам приходится часто заглядывать в документацию.

              Цитаты:


              «Очень раздражает» — MatrixFrog
              «Классная штука для однострочников, кстати» — niXar
              «Я думаю, что худшие из них — $@ и @$. Работают оба, но я до сих пор не знаю, что делает второй...» — Artem Russakovskii
              «Между прочим, есть еще серьезная проблема с этими переменными: они не гуглятся!» — malvim

              Автоматическая вставка точки с запятой в JavaScript



              Image courtesy Nate Angell CC BY 2.0

              JavaScript требует установку точки с запятой в конце каждого законченного выражения. В случае, если этого сделано не было, а после идёт, скажем, пустая строка, JavaScript расценивает это как невнимательность разработчика и самостоятельно вставляет точку с запятой, что иногда помогает, но нередко приводит к ошибкам и неожиданному поведению программы.

              Изначально вставка точки с запятой предназначалась для удобства, чтобы сделать C-подобный синтаксис JavaScript проще для новых разработчиков.

              Цитаты:


              «У вас точно будут проблемы, если вы разрабатываете язык с расчетом на то, что ваши пользователи идиоты» — Rob Van Dam
              «Совет: выясните нужное место для точки с запятой и поставьте ее. Это лучше всего» — Doug Crockford
              «Вставка точки с запятой — одна из злейших частей JavaScript» — fennec

              Автоупаковка в Java и кеширование Integer



              Image courtesy Erich Ferdinand CC BY 2.0

              Java автоматически упаковывает примитивы в объекты, например, int в Integer. В целом ничего страшного, но Integer кешируется, если его значение лежит между -128 и 127. Это может привести к непредвиденным результатам в случае сравнения автоупакованных объектов, так как программа будет присваивать значение TRUE, если оба объекта имеют значение от -128 до 127, и FALSE во всех остальных случаях.

              Autoboxing уменьшает количество кода, а кеширование Integer повышает производительность. Но нужно помнить о подводных камнях.

              Цитаты:


              «Вот результат преждевременной оптимизации» — Joschua
              «Это не распространенная ошибка, но хороший повод использовать нативные типы Java для чисел, логических переменных и так далее» — Ravi Wallau
              «Я так рад, что пишу на C#» — Will

              Автор перевода: Илья Бубнов
              ___

              P. S. Выбрать направление и начать обучаться по одной из технологий, о которых рассказывалось выше, можно на сайте GeekBrains.

              Комментарии (0)

                Let's block ads! (Why?)

                Наш опыт использования фотограмметрии при разработке компьютерной игры (Часть 2)

                [Перевод] Экспериментальная функция отладки .NET Core в Visual Studio Code

                Сегодня мы выпускаем первую, экспериментальную и ознакомительную версию отладчика для набора инструментов ASP.NET Core CLI в составе редактора Visual Studio Code. Вначале я должен упомянуть несколько вещей:
                Этот первый выпуск поддерживает точки останова, пошаговое выполнение, отслеживание переменных и стеки вызовов.

                Однако, .NET Core и функции отладки находятся на ранних этапах разработки, поэтому в VS Code отсутствует ряд возможностей, привычных для пользователей IDE Visual Studio. Вот некоторые особенности редактора:

                • В начале отладки не открывается отдельное окно консоли: все возвращаемые программой данные отображаются в окне Debug Console (Консоль отладки) редактора VS Code. Для использования функции Console.ReadLine в консоли необходимо запустить приложение посредством dotnetrun вне среды VS Code, а затем подключить отладчик.
                • Отсутствие функции Edit & Continue (Редактировать и продолжить): нельзя изменить код и применить изменения в ходе отладки.
                • Нельзя менять значения переменных в ходе отладки.
                • Отсутствуют точки трассировки и условные точки останова.
                • Функция Set Next Statement (Задать следующую инструкцию) не поддерживается

                Мы с нетерпением ждем ваших отзывов, чтобы выбрать наиболее важные для реализации возможности. Подробнее — в конце этой публикации.

                Начало работы


                Вначале необходимо выполнить ряд действий (подробные инструкции приведены на нашей странице GitHub):

                Возможности отладки


                • Точки останова — возможность установки точек останова одним щелчком (или клавишей F9) в редакторе.
                • Контрольные значения — задайте значения, которые необходимо отслеживать.
                • Локальные переменные — автоматическое отображение значений локальных переменных.
                • Стек вызовов — просмотр информации о вызовах методов в стеке.
                • Консоль отладки — содержит все отладочные сообщения (чтобы скрыть или отобразить эту область, нажмите Ctrl+Shift+Y либо Cmd+Shift+Y на компьютере Mac).
                • Текущие значения — наведите курсор на переменную, чтобы узнать ее значение.
                • Во всех областях отображаются связанные значения: когда вы щелкаете запись в стеке вызовов, среда автоматически переходит к соответствующей строке в редакторе, а также обновляет контрольные значения и локальные переменные

                Что еще можно настроить для отладки?


                После установки и настройки расширения вам будут доступны базовые возможности отладки, описанные выше. Но с помощью файла launch.json можно настроить намного больше функций.

                Остановка на точке входа


                Если флажок stopAtEntry установлен, отладчик автоматически остановится на точке входа в приложение. Это позволит выполнять код по шагам, без настройки точек останова.

                Настройка отладки для приложений ASP.NET


                Помимо конфигурации отладки по умолчанию, существует конфигурация .NETCoreLaunch (web), которая предоставляет хорошие начальные возможности отладки приложений ASP.NET. Она содержит дополнительный раздел «launchBrowser», который позволяет открывать веб-браузер на компьютере, используемом для разработки, при запуске каждой отладки. Изначально он настроен на использование заданного по умолчанию браузера, но вы можете выбрать другой, изменив команды в файле. Чтобы начать работу и испытать ASP.NET в деле, скачайте образцы ASP.NET CLI с Github.

                Вот пример настроек файла launch.json для открытия страницы в Opera:

                … 
                "osx": { 
                "command" : "open", 
                "args" : "-a opera ${auto-detect-url}" 
                } 
                … 
                
                

                Изменение открываемого URL-адреса


                Открываемый в браузере URL-адрес также можете изменить. По умолчанию отладчик определяет URL автоматически и переходит по URL-адресу, который прослушивает сервер. Заполнитель ${auto-detect-url} означает команду найти URL-адрес автоматически. Его можно использовать в любом разделе конфигурации. Если при отладке необходимо использовать только определенный URL-адрес, например, http://localhost:5000/api/customers/42, вы можете изменить значение по умолчанию, чтобы не открывать этот адрес вручную.

                Сценарии подключения


                В сценариях подключения интегрируется третий раздел конфигурации. Вам требуется лишь указать имя процесса приложения для отладки. В нашем случае это HelloWorld. Если вы запускаете приложение из командной строки с помощью команды dotnetrun, перед запуском отладчика убедитесь, что выбрана конфигурация .NETCoreAttach.

                Если под одним именем выполняется несколько процессов, можно указать значение параметра processId (идентификатор процесса) вместо processName (имя процесса). Не используйте оба свойства одновременно.



                Скрытые свойства конфигурации


                В настоящее время в конфигурации по умолчанию не отображается три дополнительных свойства. Если вы хотите ознакомиться с ними, не углубляясь в документацию, вот подсказка: введите символы o в launch.json (не забудьте про кавычку в начале), и функция автоматического дополнения отобразит список свойств, содержащих букву «o».

                Эта возможность приходится очень кстати в ходе редактирования, но вам может потребоваться неизменно актуальная документация. Как всегда, окончательная истина представлена в коде. Если вы хотите углубиться в детали, обратите внимание на папку установки — в ней содержится файл package.json. Это главный шаблон любых допустимых конфигураций. Этот простой и понятный файл json позволяет составить очень хорошее представление о конфигурациях, возможных на вашей машине для текущей версии расширения.


                symbolPath
                Параметр «symbolPath» позволяет задать массив путей к символам отладки. Он очень удобен, если символы размещены на центральном сервере или если при разработке используются несколько операционных систем. Символы, сформированные в конкретной операционной системе, можно использовать и в других.

                Ниже приведена допустимая конфигурация пути к символам:

                 “symbolPath”:”[ \”/Volumes/symbols\” , \”/OtherVolume/otherSymbols\” ]”
                
                

                justMyCode
                Если в процессе отладки код выполняется пошагово, то переход в код фреймворка или компонентов, автором которых вы не являетесь, может оказаться излишним. Поэтому мы создали функцию justMyCode. По умолчанию она включена, поскольку такое поведение среды при обычной отладке кажется наиболее удобным. Но если вы хотите отладить код фреймворка или внешних компонентов, установите для нее значение «false».
                “justMyCode”:false  
                
                

                sourceFileMap
                Если нужно указать отладчику на файлы исходного кода для сеанса отладки, задайте таблицу сопоставления с помощью свойства sourceFileMap. Это свойство может содержать любое количество записей. Оно поможет отлаживать именно те файлы исходного кода, которые нужно. Пример конфигурации приведен ниже:
                “sourceFileMap”: { 
                “C:\foo\bar”:”/home/me/foo/bar” 
                } 
                
                

                Отправьте нам отзыв


                Как упоминалось в начале, это наш первый экспериментальный выпуск инструментов отладки, и для их улучшения требуется ваша помощь. Если вы хотите регулярно получать новости о нашей работе и отправлять отзывы о разработке приложений .NET Core в Visual Studio Code, вступайте в группу Visual Studio Code .NET Core Insiders.

                Как всегда, мы будем рады вашим отзывам. Расскажите, что вам понравилось, а что нет, каких функций вам не хватает, какие компоненты рабочего процесса вам подошли или не подошли. С нами можно связаться по электронной почте, путем отправки сообщений о проблемах на нашей странице в Github или через Twitter.

                Об авторе


                Дэниель Майкснер (Daniel Meixner) — технический евангелист корпорации Microsoft в Германии. Твердо верит в идеи кроссплатформенности. Его карьера в разработке программного обеспечения была насыщена событиями (как приятными, так и не очень), и он имеет представление об отрасли со множества точек зрения. До перехода в Microsoft он получил статус MVP в области Visual Studio ALM и ALM Ranger, работал консультантом и архитектором решений ALM в корпоративных средах. Познакомьтесь с блогом Дэниеля, http://ift.tt/1pyFxDu или подпишитесь на него в Twitter.

                Полезные ссылки


                Комментарии (0)

                  Let's block ads! (Why?)

                  Рынок мобильной и веб-разработки уходит в регионы и на Запад

                  Документы по защите персональных данных. Боремся с халявщиками

                  Комплексная инфобезопасность: блиц-обзор линейки Fortinet

                  Привет! Ниже будет ликбез по одной конкретной линейке оборудования, позволяющий понять, что это, зачем нужно (и нужно ли) и какие задачи при этом решаются (общая защита ИКТ-инфраструктуры, реализация блокировок, соответствие ФЗ о ПД).

                  Итак, на сегодняшний день компоненты защиты обычно выглядят как настоящий «зоопарк»:

                  Это потоковый антивирус, файрвол, антиспам и антидидос, а также системы обнаружения вторжений и т. п., стоящие на входе в ваш дата-центр. Фортинет (как и ряд других производителей) объединяет эти устройства в одну железку, плюс пересматривает концепцию защиты в принципе. Они уже 7 лет лидируют по Гартнеру в сегменте UTM (FW + IPS + VPN + Application Control + WebFiltering + Antispam + Antivirus и другие функции).

                  Их идея в том, что периметр находится не на границе с публичным Интернетом. Если раньше защитное железо ставили на выходе, то эти парни считают, что надо ставить устройства ближе к локальной сети — работать с WLAN и в дата-центре прямо между машинами. Естественно, это требует совершенно других потоковых мощностей, но, с другой стороны, даёт и пару огромных плюсов.

                  Решаемые задачи


                  Решения Фортинет — это полный комплекс для защиты сетевой инфраструктуры, встроенный в одну-единственную железку.

                  Вот области применения:
                  — Общая защита сети, внутреннего сегмента и клиентов оператора от сетевых, контентных угроз и угроз прикладного уровня.
                  — Фильтрация запросов в Интернет, в т. ч. для выполнения требований федеральных законов и постановлений правительства по блокировке.
                  — Избавление от «зоопарка» подсистем.
                  — Защита ПД (ФЗ-152) в соответствии с нормами РФ.
                  — Интеграция системы обнаружения и предотвращения направленных атак.
                  — Защита АСУТП.

                  Архитектурные возможности


                  «Ядро» решения представляет собой программно-аппаратный комплекс со множеством сетевых портов. У него есть три типа процессоров: для обработки трафика (сетевые процессоры), управляющие и контент-процессоры. Управляющие процессоры распределяют задачи межу сетевыми и контент-процессорами, балансируют и вообще выполняют системные задачи. У больших железок несколько процессоров, поэтому задачи довольно ровно распараллеливаются. На уровне сетевых процессоров сессия каждый раз тоже распределяется по сетевым сопроцессорам. Все «фишки» типа email-фильтрации, песочницы и прочего лежат на контент-процессорах. Если использовать железку как обычный NGFW, она близка к заявленным синтетическим результатам. Если начать нагружать правилами (в особенности сложными, вроде «не давать сотрудникам разглашать на форуме конфиденциальную информацию»), то контент-процессоры будут предсказуемо жрать мощность.

                  Подход к безопасности системный: все события сети собираются, коррелируются и рассматриваются как цепочка взаимодействий. Например, одна из самых интересных практических задач — запрет торрентов в банках — делается на базе решений Фортинета очень быстро и очень смешно.

                  История такая: у нас был один банк, в котором хитрые пользователи качали торренты. Сначала они использовали свою стандартную прокси-механику, но проблем было несколько. Начиная от необходимости разбирать SSL (что не очень-то реально) и заканчивая тем, что у особо ушлых тот же TCP over DNS никаким прокси не брался. А в банк время от времени приходили письма от американских правообладателей (мол, чего же вы, гады, творите, это был наш фильм).

                  Через год туда поставили UTM и настроили в качестве теста NGFW блокировку торрент-сессий. FortiGate умеет блокировть трафик P2P-клиентов, устанавливая взаимосвязи между поведением пользователей и последующими харкатерными признаками P2P. Вот тут, например, есть про то, как решить этот вопрос для компании раз и навсегда. Кстати, отрабатывается и ещё один традиционный способ обхода прокси и классических решений по контролю пользователей — Translate.Google, лучший анонимайзер.

                  Глубокая интеграция в дата-центр


                  Итак, чтобы обрабатывать весь поток внутри дата-центра, первое, что требуется, это железки с куда более высокой производительностью, чем обычные «стоящие на выходе». Заявленные синтетические характеристики их железа просто огромные. Естественно, тут есть нюанс именно про синтетику (будет ниже), и не один.

                  В целом для инфраструктуры используется распределённый подход к безопасности. На каждый узел (точнее, конечную машину) ставится клиент. Клиенты обрабатывают данные и передают события на основной сервер с UTM, который обрабатывает трафик. Подозрительные объекты с клиентских машин автоматом уходят в песочницу, клиенты сами интегрируются с тем же антиспамом (сами ходят по ссылкам, сами отдают вложения антивирусу и в песочницу и так далее) — в общем, делают всё то, что должны делать в идеале.


                  Типы защиты, дальше мы будем говорить в основном про левый вариант архитектуры

                  Пока главное — Фортинет быстро перемалывает хорошие потоки. Например, UDP «размалывается» на скоростях 52 Гб/с на mid-range вполне штатно, тогда как ближайшие аналоги — это такие же коробочки примерно в тех же ценах, только работающие на 2 Гб/с.

                  Вторая особенность — у этого производителя есть вообще всё для защиты. То есть они закрывают всё и сразу, если вам нужно. Вот их полный набор решений:


                  Всё своё: антивирус, VPN, решение по защите баз данных, свои точки доступа, маршрутизаторы, свитчи

                  У них есть даже свои телефонные шлюзы. Из последнего — очень удачным оказалось то, что у них к их железкам можно прикручивать собственные внешние 3G/LTE экстендеры. Собственно, один файерволл Fortigate может являться контроллером точек доступа, и уже к нему идет модуль внешней антенны, который определяется как обычный интерфейс.

                  Раньше в банках при падении основного канала резервом часто в удалённых регионах был «свисток» одного из операторов — с соответствующими танцами с бубном по интеграции в безопасность или же конкретно проседающим уровнем защиты на время перемены канала (без входной фильтрации, например). А здесь всё в одной коробке, и не надо заморачиваться совместимостью. Это тоже плюс, потому что, например, на маленькие филиалы сейчас все берут Хуавей (где раньше была Циска), а не всё работает точно так, как должно бы (разница реализаций даёт о себе знать).

                  Кому нужно


                  В первую очередь линейку Фортинет смотрят либо компании, на которые регулярно идут атаки, либо различные операторы трафика, например, решения этой группы развёрнуты у Амазона и у LTE-операторов для очистки трафика. Вообще же «зоопарк» внедрений вот такой:

                  Плюс ещё 50 операторов связи от Verizon и T-Mobile до China Telecom и Vodafone.

                  Несмотря на этих «монстров», больше трети продаж Fortinet за 2015 год — это SMB и low-end железо. Малому и среднему бизнесу это тоже интересно за счёт того, что куча разного железа, такого как роутеры, NGFW, WLC и прочее, теперь может быть на одной железке. Имеет смысл брать тем, кто открывает новые филиалы, например.

                  Вот их аналоги по Гартнеру:

                  Отличия «на пальцах» от аналогов в том, что Фортинет даёт в целом высокий стандарт по рынку в плане защиты канала, только лицензируется на устройство и позволяет распределять мощность как угодно. При подключении новых функций у всех этих решений падает производительность, у Фортинета при использовании дополнительных функций поведение более предсказуемое за счёт оптимизации нагрузки аппаратными сопроцессорами.

                  Чем выгодно


                  Фортинет предлагает достаточно выгодные по стоимости решения по сравнению с аналогичным оборудованием других производителей. Для крупного бизнеса главная «точка» сравнения — цена за единицу трафика, для малого и среднего — функциональность. У других вендоров часто такой же набор фич требует очень дорогой железки.

                  Подводные камни


                  Пока не стало совсем радостно, расскажу о том, что нужно знать заранее про особенности этой архитектуры и конкретных решений:
                  • Лицензирование по железкам, то есть вы покупаете мощность (процессоры) и делаете, что хотите. Естественно, возникает желание нагрузить защитный сервер кучей функций — и на момент внедрения он будет всё перемалывать. С ростом трафика и требований производительность будет падать, и нужно будет отключать часть функциональности. Поэтому очень важно протестировать устройство на реальных задачах и взять запас с пониманием своего роста трафика, роста их базы сигнатур и так далее. Известная мне типовая история: сначала админы включают всё и сразу (как в том анекдоте про финскую бензопилу), потом ждут, пока железка всё схавает. И нагружают ещё. Когда пила скажет «хррр», отключают часть функций. Так и живут.
                  • Масштабирование — докупкой новых железок (новых моделей) или строительством кластера из старых. Сразу просчитывайте эти варианты на года три вперёд, чтобы цены не стали сюрпризом. Старая железка никак не апгрейдится, только продаётся, выкидывается или ставится в кластер.
                  • Действующий сертификат ФСТЭК распространяется на устаревшие модели, но ходят слухи о сертификации новой линейки устройств. Здесь же для работающих с ПД вторая засада — обновление базы сигнатур. Сила решения — в постоянном получении данных, поэтому «запломбировать и оставить» не получится, это подходит не всем банкам.
                  • Полные аппаратные байпассы сделаны отдельным решением. Правда, у других вендоров их обычно вообще нет.
                  • Есть разбор SSL по схеме MitM с импортом «родных» сертификатов (с возможностью подписывания трафика) или выставлением самоподписанных на устройстве. После расшифровки проверяется всё то же самое, что и обычно. SSL strip нагружает процессоры, поэтому, несмотря на то, что никаких дополнительных устройств не надо, этот отдельный процесс в ФортиОС будет кушать довольно много ресурсов. Однако можно делать SSL-Offload на внешний дешифратор, если не хочется использовать под эти задачи сам файерволл.
                  • Естественно, не надо забывать, что штатный режим подразумевает отправку подозрительного трафика в их центры анализа, но ни веднор, ни интегратор не имеют права включать эту опцию без прямого согласования с вами, если не хотите делиться своим SSL-содержимым.

                  Резюме


                  Это железо верхнего сегмента, которое окупается за счёт лучшей стоимости владения на больших инфраструктурах. У него предсказуемая производительность (в сравнении с конкурентами), есть широкая поддержка виртуальных инфраструктур (ESXi, Xen, KVM, Hyper-V, а также облачные Azure и AWS), большое количество поддерживаемых гипервизоров, куча разных типов защит. Однако отмечу: при определении бюджета или настройке правил нужны обязательные тесты до внедрения.

                  Ссылки


                  Комментарии (0)

                    Let's block ads! (Why?)

                    [Перевод] REM vs EM – Великий спор

                    Представляю вашему вниманию перевод достаточно большой и объемной статьи по поводу вечного спора, какие же единицы измерения использовать при верстке: em'ы или rem'ы. В каких случаях стоит использовать одни единицы, а в каких другие. Вас ожидает много кода, примеров и их объяснений.

                    Добро пожаловать в мир типографики и относительных единиц измерения =)

                    ************

                    Одним из наиболее эффективных методов типографики в вебе является использование относительных единиц измерения rem и em.

                    Вопрос в том, что использовать? Уже долго длится спор между приверженцами rem'ов и em'ов, которые пытаются доказать, что нужно использовать именно «их» единицы.

                    В этой статье я возьму на себя смелость провести сравнение между rem и em. Вы узнаете что из себя представляют rem, а что em, и как их использовать для построения модульных компонентов.

                    Что такое EM?


                    Википедия говорит нам:
                    em — в типографике относительная единица длины, равная размеру текущего шрифта

                    Это утверждение не имеет смысла в вебе, так как мы не используем размер точки (point-size). Но имеет смысл, если мы заменим размер точки на размер шрифта (font-size).

                    Это значит, что: 1em = 20px в том случае, когда у css-селектора прописано правило font-size: 20px;

                    h1 { font-size: 20px } /* 1em = 20px */
                    p { font-size: 16px } /* 1em = 16px */
                    
                    

                    Единица em может использоваться для того, чтобы задавать размеры шрифтов. По факту, использование относительных величин, например, em, для font-size, является хорошей практикой.

                    h1 { font-size: 2em } /* Что это вообще означает?! */
                    
                    

                    Какой на самом деле font-size у h1?

                    Нам придется взглянуть на родительский элемент, чтобы высчитать размер шрифта у этого h1. Допустим, что родительский элементом является html, и его font-size установлен в 16px.

                    Следуя этому, мы можем увидеть, что высчитанное значение h1 составляет 32px, или 2 * 16px.

                    html { font-size: 16px }
                    h1 { font-size: 2em } /* 16px * 2 = 32px */
                    
                    

                    На самом деле, плохая затея устанавливать font-size для html в пикселях (px), так как тем самым мы переопределяем установки браузера пользователя.

                    Заместо этого вы можете выбрать проценты в качестве значения font-size, или просто не задавайте его в html.

                    Заметка: font-size будет установлен в 100%, если вы сами его не задали.

                    html { font-size: 100% } /* это значит, что по умолчанию размер шрифта будет 16px*/
                    
                    

                    Для большинства пользователей (и браузеров), размер шрифта в 100% будет по умолчанию выдавать 16px до тех пор, пока они его не поменяют в настройках своего браузера. Хотя редко кто подобным занимается.

                    Ладно, что дальше? Вернемся к em.

                    Em также используется, чтобы задать значения для других свойств, в дополнение к font-size. margin и padding являются двумя из тех свойств, которые измеряются в em'ах.

                    Вот где большинство людей путается со значениями em.

                    Рассмотрим следующий код. Каким будет значение margin-bottom для обоих элементов: h1 и p? (Предположим, что font-size у элемента html установлен в 100%)

                    h1 {
                      font-size: 2em; /* 1em = 16px */
                      margin-bottom: 1em; /* 1em = 32px */
                    }
                    
                    p {
                      font-size: 1em; /* 1em = 16px */
                      margin-bottom: 1em; /* 1em = 16px */
                    }
                    
                    

                    Удивлены, что значение margin-bottom, установленное в 1em, разное в обоих случаях?

                    Это явление объясняется тем, что 1em равен размеру шрифта (font-size) своего элемента. Так как font-size у элемента h1 был установлен в 2em, то другие свойства у этого h1 (тот же margin-bottom) уже будут отталкиваться от нового значения font-size. То есть для них 1em будет равен уже 32px.

                    Людей сбивает с толку тот факт, что 1em может принимать различные значения в разных участках кода. Подобное может вас конкретно запутать, если вы только-только начали разбираться с em.

                    Вот такие вот эти em. Что ж, идем далее. Впереди нас ждут rem'ы.

                    Что такое REM?


                    Rem — это корневой em (Root Em). Он создан, чтобы облегчить вычислительные проблемы, с которыми многие иногда сталкиваются.
                    Это единица типографики, равная корневому (базовому) значению font-size. Это значит, что 1rem всегда будет равен значению font-size, которое было определено в html.

                    Рассмотрим тот же самый код, что и выше, только будем использовать уже rem'ы. Как теперь изменится значение margin-bottom?

                    h1 {
                      font-size: 2rem;
                      margin-bottom: 1rem; /* 1rem = 16px */
                    }
                    
                    p {
                      font-size: 1rem;
                      margin-bottom: 1rem; /* 1rem = 16px */
                    }
                    
                    

                    Как видите, 1rem всегда будет принимать значение, равное 16px, и не имеет значения где вы примените его (до тех пор, пока не поменяете font-size у элемента html)
                    Существует зависимость. Это несложно понять.

                    Такие вот rem'ы. Не так сложно понять как они работают, зная как работают em'ы, согласны?

                    Теперь, приступим к самой вкусной части статьи. Итак, rem или em?

                    REM'ы или EM'ы?


                    Это очень спорный вопрос.

                    Некоторые разработчики полностью избегают использование rem, утверждая, что использование этих единиц измерения делают их компоненты менее модульными. Другие разработчики использут их для всего, предпочитая ту простоту, что они предоставляют.

                    Как ни странно, но я все-таки попался в ловушку, используя em'ы и rem'ы в своей работе на разных этапах разработки. Я был в восторге от того, как em'ы помогали мне в создании модульных компонентов, но я терпеть не мог всех тех сложностей, что они привносили в мой код. Мне также нравилось, как при помощи rem'ов все вычисления проходили гораздо проще, но меня бесили те хаки, которые приходилось писать, чтобы сделать мои компоненты модульными.

                    Оказывается, у em и rem существуют как сильные, так и слабые стороны. И их нужно использовать по-разному, в зависимоти от обстоятельств.

                    Как? У меня есть два простых правила:

                    1. Задавай значения в em, если свойства масштабируются относительно font-size;
                    2. Во всех остальных случаях задавай значения в rem.

                    Стало немного проще? Что ж, давайте рассмотрим написание простого компонента (пусть это будет заголовок), используя и em'ы и rem'ы, и вы сами увидите в действии эти два правила.

                    Используем только REM'ы для создания элемента заголовка


                    Скажем, у вас есть элемент заголовка h2, который выглядит вот так:

                    Привет! Я — заголовок!

                    Стили заголовка должны быть подобны нижеуказанным, если вы указываете все в rem:

                    .header {
                      font-size: 1rem;
                      padding: 0.5rem 0.75rem;
                      background: #7F7CFF;
                    }
                    
                    

                    Все идет по плану.

                    Далее, давайте создадим заголовок побольше, ведь на одной странице могут располагаться элементы разных размеров.
                    Когда мы будем это делать, давайте попробуем унаследовать настолько много стилей, насколько это возможно.

                    Разметка нашего второго заголовка будет выглядеть как-то так:

                    <a href="#" class="header header--large">заголовок!</a>
                    
                    

                    CSS будет таким:

                    .header {
                      font-size: 1rem;
                      padding: 0.5rem 0.75rem;
                      background: #7F7CFF;
                    }
                    
                    .header--large {
                      font-size: 2rem;
                    }
                    
                    

                    К сожалению, наш код не стал выглядеть лучше. Можно заметить свободное пространство между краями нашего элемента .header--large и самим текстом заголовка.


                    Не достаточно свободного пространства между краями и текстом нашего большого заголовка

                    Если вы настаиваете на использовании только лишь rem'ов, то единственный способ решить данную проблему — это переопределить padding у .header--large:

                    .header {
                      font-size: 1rem;
                      padding: 0.5rem 0.75rem;
                      background: #7F7CFF;
                    }
                    
                    .header--large {
                      font-size: 2rem;
                      padding: 1rem 1.5rem;
                    }
                    
                    


                    Ну вот, теперь дышать стало посвободнее!

                    Заметили что-нибудь? font-size у элемента .header--large вдвое больше, чем у элемента .header. Вследствие этого, padding у элемента .header--large также вдвое больше, чем у элемента .header.

                    Что произойдет, если у нас будет больше заголовков различных размеров, или если заголовки должны будут меняться в размере? Вы уже понимаете, как указание значений свойств в rem'ах может вызывать дублирование и супер сложный код.

                    Мы можем упростить наш код таким образом, что не придется переопределять padding у элемента .header--large, если не побоимся использовать в совокупности и em'ы и rem'ы.

                    .header {
                      font-size: 1rem;
                      padding: 0.5em 0.75em;
                      background: #7F7CFF;
                    }
                    
                    .header--large {
                      font-size: 2rem;
                    }
                    
                    

                    Как видите, em'ы могут быть невероятно полезны, если у вас имеются свойства, которые нужно масштабировать вместе с размером шрифта элемента. Отсюда и рождается первое правило.

                    Далее, давайте посмотрим, что будет происходить, если вы будете использовать только em'ы в вашем заголовке.

                    Используем только EM'ы для создания элемента заголовка


                    Код реализации заголовка на em'ах не многим отличается от кода на rem'ах, с которым уже познакомились. Все, что нам нужно — это заменить rem'ы на em'ы:
                    .header {
                      font-size: 1em;
                      padding: 0.5em 0.75em;
                      background: #7F7CFF;
                    }
                    
                    .header--large {
                      font-size: 2em;
                    }
                    
                    

                    Оба, .header и .header--large будут выглядеть точно также, как их двойники на rem'ах.

                    То, что нужно?

                    Не-а!

                    Крайне маловероятно, что ваш сайт будет содержать лишь один элемент заголовка и больше ничего. Нужно рассмотреть как он взаимодействует с другими элементами.

                    Как правило, эти элементы идут до или после заголовка, как тут:


                    Заголовки имеют разные связи с другими элементами

                    Разметка для этого блока будет такой:

                    <div class="header header--large">Заголовок</div>
                    <p>Параграф с текстом</p>
                    <p>Параграф с текстом</p>
                    <div class="header">Заголовок</div>
                    <p>Параграф с текстом</p>
                    
                    

                    Мы также добавим margin-right и margin-left для параграфов:

                    p {
                      margin-left: 0.75em;
                      margin-right: 0.75em;
                    }
                    
                    


                    Ой-ёй, padding у первого заголовка не выровнен вместе с текстом параграфа

                    Неееееет! :(

                    padding слева и справа у элемента .header--large слишком большой!

                    Если вы настаиваете на использовании только em'ов, то единственный способ решить данную проблему — это переопределение свойств padding-left и padding-right у .header--large:

                    .header {
                      font-size: 1em;
                      padding: 0.5em 0.75em;
                      /* Прочие стили */
                    }
                    
                    .header--large {
                      font-size: 2em;
                      padding-left: 0.375em;
                      padding-right: 0.375em;
                      margin: 0.75em 0; 
                    }
                    
                    


                    Вот теперь все выглядеит как надо!

                    Заметили что-нибудь? font-size у элемента .header--large вдвое больше, чем у элемента .header. Тем не менее, padding-left и padding-right у элемента .header--large вдвое меньше, чем padding-left и padding-right у элемента .header!

                    Как и в предыдущем случае, мы можем упростить наш код, если согласимся использовать вкупе em'ы и rem'ы. В частности, для padding-left и padding-right мы будем использовать rem'ы, а для padding-top и padding-bottom — em'ы.

                    .header {
                      padding: 0.5em 0.75rem;
                      font-size: 1em;
                      background: #7F7CFF;
                    }
                    
                    .header--large {
                      font-size: 2em;
                    }
                    
                    

                    Как видите, em'ы могут быть невероятно полезны, если у вас имеются свойства, которые нужно масштабировать вместе с размером шрифта элемента. Однако, вы столкнетесь с проблемами, если вам понадобится менять значения свойств относительно корневого (изначального) значения font-size.

                    Стало более понятно, как работают вместе rem и em в одном компоненте, согласны?

                    Теперь, давайте поднимемся на ступеньку выше и посмотрим, как заголовок и параграф взаимодействуют с сеткой.

                    Компоненты на сетке


                    Прежде, чем мы продолжим, давайте объединим наш заголовок и параграфы в единый компонент:

                    <div class="component">
                      <div class="component__header">Заголовок</div>
                      <p>Некий текст внутри параграфа</p>
                    </div>
                    
                    

                    Вот базовые стили для нашего компонента:

                    .component {
                      background: white;
                      border: 2px solid #7F7CFF;
                    }
                    
                    .component__header {
                      font-size: 2em;
                      padding: 0.5em 1.5rem;
                      background: #7F7CFF;
                      margin: 0;
                    }
                    
                    .component p {
                      padding-left: 1.5rem;
                      padding-right: 1.5rem;
                      margin: 1.5rem 0;
                    }
                    
                    

                    Пока все хорошо. Здесь мы видим все, с чем уже познакомились ранее.

                    Идем дальше. Этот компонент может быть где угодно на нашем сайте. Например:

                    1. В контентной части;
                    2. В сайдбаре;
                    3. В любой части нашей сетки;
                    4. ...


                    Вероятные места, где может располагаться наш компонент

                    Заголовок нашего компонента должен становиться меньше по размеру (т.е., уменьшаться его font-size), если компонент будет находиться в узкой части сайта, например, в сайдбаре.


                    Элемент заголовка на сетке

                    Есть вариант как сделать это. Мы можем модифицировать класс нашего компонента. Разметка теперь примет вот такой вид:

                    <div class="component component--small">
                      <!-- Контент нашего компонента -->
                    </div>
                    
                    

                    Ну и стиль:

                    .component--small .component__header {
                      font-size: 1em;
                    }
                    
                    

                    Теперь касательно стилей компонента. Здесь действуют те же самые правила:

                    1. Задавай значения в em, если свойства масштабируются относительно font-size;
                    2. Во всех остальных случаях задавай значения в rem.

                    Как и в случае с элементом заголовка, вы можете определить, для каких свойств неободимо будет задать размеры в em'ах. Это нужно будет сделать для тех свойств, которые непосредственно взаимодействуют с остальными элементами страницы. Существует два пути, чтобы продумать, как лучше выстроить наш компонент:

                    1. Свойства всех внутренних элементов масштабируются вместе со значением font-size компонента;
                    2. Свойства лишь некоторых внутренних элементов масштабируются вместе со значением font-size компонента.

                    Давайте рассмотрим оба случая, пройдем по каждому из путей, и вы поймете, что я имел в виду.

                    Путь первый. Свойства всех внутренних элементов масштабируются вместе со значением font-size компонента


                    Давайте начнем с примера, чтобы увидеть, как выглядит такой компонент:

                    Заметили, как font-size, margin и padding всех элементов внутри компонента изменяются в одно и то же время?

                    Если ваш компонент ведет себя таким же образом при изменении размеров, то вам нужно все размеры указывать в em'ах. То есть код становится таким:

                    .component {
                      background: white;
                      border: 2px solid #7F7CFF;
                    }
                    
                    .component__header {
                      font-size: 2em;
                      padding: 0.5em 0.75em; /* заменили единицы измерения на em */
                      background: #7F7CFF;
                      margin: 0;
                    }
                    
                    .component p {
                      padding-left: 1.5em; /* заменили единицы измерения на em */
                      padding-right: 1.5em; /* заменили единицы измерения на em */
                      margin: 1.5em 0; /* заменили единицы измерения на em */
                    }
                    
                    // Маленький вариант
                    .component--small .component__header {
                      font-size: 1em;
                      padding-left: 1.5em; /* добавили изменяемый padding в em'ах */
                      padding-right: 1.5em; /* добавили изменяемый padding в em'ах */
                    }
                    
                    

                    Затем, чтобы изменения в размерах заработали, необходимо изменить свойство font-size у компонента.

                    .component {
                      // Другие стили
                      @media (min-width: 800px) {
                        font-size: 1.5em;
                      }
                    }
                    
                    

                    Пока все хорошо.

                    Давайте теперь немного усложним наш пример.

                    Представьте, что у вас имеется сетка наподобие этой. Вертикальные и горизонтальные отступы на всех устройствах должны оставаться одинаковыми (с эстетической точки зрени это будет правильно).


                    Одинаковые отступы на сетке вида 2 + 1

                    Разметка для этой сетки такая:

                    <div class="grid">
                      <div class="grid-item"> 
                        <div class="component"> <!-- наш компонент --> </div> 
                      </div>
                    
                      <div class="grid-item">
                        <div class="component component--small"> <!-- A --> </div>
                        <div class="component component--small"> <!-- B --> </div>
                      </div>
                    </div>
                    
                    

                    Я установил промежутки между элементами сетки в 2em, с учетом, что базовый font-size равен 16px. Иными словами, высчитанная ширина каждого промежутка равна 32px.

                    Задача состоит в следующем: разделить маленькие компоненты A и B отступом в 32px. Для начала, мы можем попробовать установить margin-top компоненту B, равное 2em.

                    .component {
                      /* Другие стили */
                      @media (min-width: 800px) {
                        font-size: 1.25em;
                      }
                    }
                    
                    .component + .component {
                      margin-top: 2em;
                    }
                    
                    

                    К сожалению, результат не радует. margin между маленькими компонентами A и B больше, чем ширина вертикального промежутка при видимой области (viewport) более 800px.


                    Пространство между маленькими блоками A и B не такое же, как пространство вертикального промежутка при viewport > 800px

                    Буууу :(

                    Это происходит потому, что font-size компонента равен 1.5em (или 24px), когда видимая область становится более 800px. В тот момент, когда font-size становится 24px, высчитанное значение 2em становится 48px, которое отличается от 32px, которые мы и добивались получить.

                    Рррррр! (╯°□°)╯︵ ┻━┻

                    Какое счастье, что мы можем решить эту проблему, просто заменив единицы измерения на rem. Ведь мы знаем, что ширина промежутков изменяется в зависимости от базового font-size.

                    .component + .component {
                      margin-top: 2rem;
                    }
                    
                    


                    Вертикальный отступ тепер равен горизонтальным!

                    Та-да! Проблема решена :) Вот вам пример на Codepen, можете поиграться с кодом.

                    Заметка: Вам придется использовать Flexbox, чтобы построить такую сетку. Я не буду объяснять, как я ее выстроил, так как это выходит за рамки статьи. Советую почитать эту статью, если хотите узнать больше про Flexbox.

                    Да, кстати, не я придумал эту технику. Chris Coyier написал об этом год назад (он гений!).

                    В любом случае, готовы двигаться дальше? Если да, переходим ко второму случаю. Если нет, не стесняйтесь оставлять комментарии, и я постараюсь объяснить это вам каким-то иным способом.

                    Путь второй. Свойства лишь некоторых внутренних элементов масштабируются вместе со значением font-size компонента.


                    Первый случай несложно объснить. Недостатком, однако, является то, что вам придется придерживаться вашей модульной сетки (Прим. пер.: что это такое, можете почитать тут), вертикальным ритмам (Прим. пер.: что это такое, можете почитать тут) и вы должны быть уверены, что все компоненты имеют одинаковый размер в одно и то же время (особенно, когда вы делаете адаптивные сайты).

                    Иногда требуется изменить небольшой участок компонента, не изменяя размеров всего остального.

                    Например, вам нужно изменить font-size заголовков при большей видимой области (viewport).


                    Только заголовки меняются в размере, когда меняется видимая область

                    Давайте опишем стили данного примера, взяв за основу стили, которые мы описали выше:

                    .component {
                      background: white;
                      border: 2px solid #7F7CFF;
                    }
                    
                    .component__header {
                      font-size: 2em;
                      padding: 0.5em 1.5rem;
                      background: #7F7CFF;
                      margin: 0;
                    }
                    
                    .component p {
                      padding-left: 1.5rem;
                      padding-right: 1.5rem;
                      margin: 1.5rem 0;
                    }
                    
                    .component--small .component__header {
                      font-size: 1em;
                    }
                    
                    

                    Как только меняется font-size у заголовка, на границе видимой области в 1200px, мы можем безопасно использовать rem'ы в качестве единиц измерения каждого свойства (за исключением padding-top и padding-bottom у заголовка)

                    .component {
                      background: white;
                      border: 2px solid #7F7CFF;
                    }
                    
                    .component__header {
                      font-size: 2rem; /* заменяем единицы измерения на rem */
                      padding: 0.5em 1.5rem; /* заменяем единицы измерения на rem */
                      background: #7F7CFF;
                    }
                    
                    .component p {
                      padding-left: 1.5rem; /* заменяем единицы измерения на rem */
                      padding-right: 1.5rem; /* заменяем единицы измерения на rem */
                      margin: 1.5rem 0; /* заменяем единицы измерения на rem */
                    }
                    
                    .component--small .component__header {
                      font-size: 1rem; /* заменяем единицы измерения на rem */
                    }
                    
                    

                    После этого вы можете изменить размер шрифта в заголовке на разных вюьпортах, просто добавив media в них:

                    .component__header {
                      font-size: 2rem;
                      @media (min-width: 1200px) {
                        font-size: 3rem
                      }
                    }
                    
                    .component--small .component__header {
                      font-size: 1rem;
                      @media (min-width: 1200px) {
                        font-size: 1.5rem
                      }
                    }
                    
                    

                    Та-да! Заметили, что когда мы ресайзим окно браузера, меняется только font-size у заголовка? Вот так вот и нужно поступать во втором случае :)

                    Еще один момент


                    Так как рекомендуется использовать лишь несколько размеров типографики, я часто абстрагирую свойство font-size от компонента. Таким образом, я могу быть уверен, что моя типографика останется одинаковой во всех компонентах.
                    h2 { 
                      font-size: 2rem;
                      @media (min-width: 1200px) {
                        font-size: 3rem
                      } 
                    }
                    
                    h3 { 
                      font-size: 1rem; 
                      @media (min-width: 1200px) {
                        font-size: 1.5rem
                      }
                    }
                    
                    .component__header { @extend h2; }
                    .component--small .component__header { @extend h3; }
                    
                    

                    На этом все со вторым случаем. Вот вам пример на Codepen, можете поиграться с кодом.

                    Я уже предвижу ваш вопрос, поэтому сначала отвечу на него: Какой метод вы должны использовать?

                    Я скажу, что все зависит от дизайна.

                    Лично я гораздо чаще пользуюсь вторым, нежели первым, так как предпочитаю абстрагировать типографику в отдельный файл.

                    Подведем итоги


                    Что же использовать, rem или em? Я думаю, что данный вопрос не совсем корректен. И rem и em имеют свои сильные и слабые стороны, и их можно использовать вместе, — это поможет вам в написании простых, модульных компонентов!

                    Теперь касательно вас! Чью сторону вы примите в этом споре? Я бы с радостью почитал в комментариях ниже, что вы думаете по этому поводу:)

                    Комментарии (0)

                      Let's block ads! (Why?)