Заметки

Позднее Ctrl + ↑

Control и Poets of the Fall

Я и так уже не устоял перед рыжей чертовкой из трейлера Control, а этим роликом ребята из Remedy и вовсе зашли с непробиваемых козырей.

Послушайте, это просто неприлично круто! Можно как-нибудь перемотать время на конец августа? :-)

23 августа 2019 видеоигры

Парадокс Ферми

Твит

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

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

19 августа 2019 тем временем видеоигры

На, мужик, изоленту

Начитанные друзья иногда спрашивают — мол, какая у тебя любимая книга? Мне, блин, всегда чутка стыдно отвечать на этот вопрос, потому что при всём том огромном выборе, который есть, это «Марсианин» Энди Вейера.

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

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

― Энди Вейер, «Марсианин»

2 августа 2019 книги работа

Observation

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

Это завязка недавней Observation от No Code. Коротко: игра — пушка. Зайдет любителям научной фантастики, особенно классики (Артур Кларк, вот это всё). Из последнего, во что я играл в этом жанре, круче — только SOMA.

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

Музыку к интро, кстати, написал Робин Финк (Nine Inch Nails). Вижуал в момент просмотра непонятен, но когда догоняешь, что именно там показывают — невольно проникаешься.

28 июля 2019 видеоигры

Хороший день

Твит

Дорогой дневник! Сегодня мне заплатили, чтобы я нарисовал думгая, который учит Рапунцель из диснеевской «Запутанной истории» стрельбе из тяжелой штурмовой винтовки. Сегодня был хороший день!

― izra

Обожаю художников. Особенные люди :-)

(а также на рисунке я, обучающий дочку, как рашить зилотами в Starcraft 2)

9 июля 2019 семья видеоигры

Мультиязычность в Vue.js

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

Звучит просто, но на самом деле эта задача рождает довольно много дополнительных проблем, и одна из них — вывод интерфейса. Сначала я по привычке завел на клиенте два массива с фразами на разных языках, но быстро выкинул этот велосипед и прикрутил Vue I18n.

На нижнем уровне это, правда, всё те же два массива с фразами (их нужно задать при инициализации), однако выгода здесь в другом. Этот плагин сам по себе закрывает еще две проблемы с генерацией интерфейса:

  1. Склонение существительных. Нужно, чтобы правильно выводить слово «страница» в статистике по тегам — одна заметка, две заметки, пять заметок и так далее.
  2. Вывод дат. Например, дата под этой заметкой.

Обе задачи, конечно, можно было закрыть на стороне сервера, силами PHP, но я счел это некрасивым решением. Сервер должен возвращать данные, клиент — строить интерфейс. Нечего их смешивать.

25 июня 2019 блог вебдев готово

Draugen

Сравнительно короткая, но по-своему яркая история. Проиграть тут нельзя, особого выбора (кроме вариантов реплик) нет. Но то, как тут всё звучит и выглядит, то, как здорово прописаны персонажи — удивляет и трогает. Даже если угадываешь повороты сюжета до того, как с ними столкнешься.

В целом игра напомнила то ли Firewatch, то ли The Vanishing of Ethan Carter. Сюжет, на мой вкус, мог быть немного длиннее и заметно драматичнее, но мне всё равно чертовски понравилось, как всё закончилось. Эмоции от финала можно выразить — осторожно, спойлервот этой картинкой :-)

10 июня 2019 видеоигры

И приятнее пахнуть

На днях выпустили очередный релиз FirstBIT ERP (наш программный продукт для автоматизации бизнеса в ОАЭ). Вложен вагон труда, всё работает как надо, есть чем гордиться и всё такое. Я, например, кучу сил потратил на то, чтобы сделать полноценный обмен данными с Битрикс24 и порядком рад, что успел этот механизм зафиналить.

Но в душе всё равно немного завидно коллегам из геймдева: наши патчноуты, конечно, тоже интересные, но такого там всё-таки не встретить.

10 июня 2019 видеоигры работа Битрикс

Сикока сикока?

Этот сайт почти полностью написан на PHP. JavaScript на клиенте используется ситуативно — редирект сделать, картинку показать и так далее.

Для личного ресурса ничего сложнее и не нужно, но некоторое время назад мне приспичило слегка освежить свои навыки веб-разработки. В качестве платформы для эксперимента я выбрал Vue.js — популярный, быстрый и не слишком сложный фреймворк.

Я, собственно, к чему это всё пишу. Развернул тут Node.js, Vue CLI, создал первый проект — и чуть не поседел. Триста мегабайт джаваскрипта прямо со старта?! Серьёзно?!

5 июня 2019 блог вебдев Node.js JavaScript

Yomawari: Night Alone

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

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

30 мая 2019 видеоигры

Большая таблица на клиенте

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

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

19 мая 2019

Close to the Sun

Игрожуры и ютуберы соревнуются, кто задорнее обложит «Close to the Sun» в рецензиях, а мне игра неожиданно понравилась. Конечно, это не шедевр, но атмосфера огромного «летучего голландца» передана просто отлично. Происходящее местами напоминает Биошок, но я очень далек от того, чтобы валять в перьях любую историю, которая чем-то похожа на то, что я уже где-то видел.

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

14 мая 2019 видеоигры

Задержки PageLatch

Задержки вида PageIOLatch (я про них сегодня писал) легко встретить в любых системах, в том числе небольших. С задержками PageLatch дела обстоят наоборот — их трудно заметить, пока пользователей меньше нескольких тысяч.

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

Возможных причин две.

Горячее место в индексе

Такой расклад иногда называют хотспотом. Он возникает, когда мы массово пытаемся писать что-то на последнюю страницу индекса; в первую очередь речь идёт об индексе с монотонно возрастающим ключом — например, любые индексы по полям ссылочного типа (начиная с последних версий 8.2, платформа выдает последовательные GUID — это снижает фрагментацию диска и делает ключ индекса монотонно возрастающим).

Что такое «индекс с монотонно возрастающим ключом»? Для платформы 1С это, например, индексы регистров по периоду. Конечно, они растут не вполне монотонно — однако тут скорее важно, что данные мы всегда будем писать в конец. Сюда же относятся индексы по номеру документа и индексы по коду справочника — в обеих случаях мы выдаем некий новый номер, который пишется в конец индекса.

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

Системные страницы tempdb

Когда мы создаём или удаляем таблицу в базе данных, в ней обновляется ряд служебных страниц — IAM (Index Allocation Map), PFS (Page Free Space), GAM (Global Allocation Map), SGAM (Shared Global Allocation Map) и другие.

Почему это важно для tempdb? Для платформы 1С это база, в которой регулярно создается огромное количество таблиц. Служебные страницы при этом обновляются настолько часто, что при этом возникают задержки семейства PageLatch.

Вообще-то MS SQL Server умеет оптимизировать обновления системных страниц для tempdb, благодаря чему это делается реже, но иногда даже этого не достаточно. Особенно если в tempdb создаются таблицы с индексами — а это очень частый кейс для приложений на 1С.

У проблемы есть несколько возможных решений. Первый — если СУБД старше 2016-й, можно отключить смешанные экстенты через флаг трассировки 1118. При этом исчезнет необходимость сразу в двух служебных страницах — GAM и SGAM. Соответственно, ожиданий на их обновлении не будет. Экстент — это восемь страниц данных, т.е. 64 килобайта; если он содержит страницы одной таблицы — это нормированный экстент, если нескольких — смешанный.

Второй подход — разбивать tempdb (с 2016-й версии СУБД она, кстати, по умолчанию разбивается на восемь файлов). Дело в том, что служебные страницы ведутся в разрезе файлов; если их будет несколько — ожидания на обновлениях служебных страниц будут ниже.

Третий вариант — уменьшать количество временных таблиц с целью снизить нагрузку на tempdb. То есть переписывать наиболее частотные запросы так, чтобы они работали приемлемо быстро без временных таблиц.

22 апреля 2019 MS SQL

Задержки PageIOLatch

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

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

В общем, если в системе есть существенные задержки PageIOLatch — их скорее всего можно снизить, используя более быстрые диски, наращивая объём ОЗУ и оптимизируя запросы.

22 апреля 2019 MS SQL

Объектные блокировки

Во-первых, сразу, чтобы не путаться: объектные блокировки платформы никак не связаны с управляемыми блокировками и, тем более, блокировками СУБД. Во-вторых, различают два вида: пессимистические объектные блокировки и оптимистические.

Оба вида неплохо описаны на ИТС; ниже — просто краткая выжимка.

Пессимистические блокировки

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

То есть платформа в данном случае делает своего рода пессимистичную оценку ситуации: мол, раз первый пользователь начал редактировать объект — скорее всего, он его запишет. Раз так, второму пользователю разрешать редактировать нельзя.

Пессимистическую блокировку также можно наложить методом объекта Заблокировать() и снять через метод Разблокировать(). Кроме того, можно воспользоваться методом глобального контекста ЗаблокироватьДанныеДляРедактирования() и методом управляемой формы ЗаблокироватьДанныеФормыДляРедактирования().

Оптимистические блокировки

Сперва немного теории: платформа хранит версии объектов ссылочного типа (справочников, документов и так далее). По сути это просто момент времени, в который объект был изменён последний раз. Когда объект считывается расширением формы или кодом — его версия считывается вместе с ним.

Так вот, в момент записи объекта платформа сверяет ту версию, что была получена при чтении объекта из базы данных и ту, что указана в базе данных в момент записи. Если версии различаются — возникает ошибка «Операция не может быть выполнена из-за несоответствия версии или отсутствия записи базы данных».

Это и есть так называемая «оптимистическая блокировка». Называют её так потому, что платформа тянет с проверкой до последнего — пока не произойдет реальной попытки записи.

Наложить оптимистическую блокировку объекта через код нельзя: версия объекта хранится в поле _Version таблицы данных объекта, заполнением которого занимается СУБД. Напрямую изменить это значение средствами платформы нельзя (можно, впрочем, записать объект — тогда его версия изменится).

22 апреля 2019

Растолстевшие роли

Очень любопытная заметка про неприятности, которые можно нажить командой роли «Снять все права». Нет, никакого криминала, права-то она честно снимает — только вот её вызов может привести к тому, что объект роли на пустом месте сожрёт в несколько раз больше памяти, чем ему реально нужно.

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

Любопытно, как это до сих пор оставалось незамеченным. Скорее всего, из-за количества объектов — у нас сравнительно небольшая конфигурация. То есть проблемные роли потребляли не так много ресурсов, чтобы мы что-то заподозрили.

18 апреля 2019 работа

GRIS

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

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

14 апреля 2019 видеоигры

Простая галочка

Пару недель назад мы добавили в справочник номенклатуры FirstBIT ERP параметр «Inactive». Задача была простой: если товар больше не нужен пользователю — он ставит галочку и тот исчезает отовсюду (из форм выбора, форм подбора остатков на складах и так далее).

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

Параметры выбора

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

Мы принялись искать выход. Проблема в том, что история ввода хранится в системном хранилище и повлиять на неё программно нельзя. Можно разве что полностью удалить — но фактическая очистка истории происходит только при перезапуске клиента (и то через раз). Отключить историю вообще? Напоминает лечение простуды отсечением головы.

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

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

Минуточку!

А ведь как все невинно начиналось, а?

Однако механизм неплохо работает, хотя его недостатки налицо: во-первых, системное хранилище будет постепенно пухнуть по мере появления всё новых и новых сочетаний реальных параметров выбора и нашего, фиктивного. Во-вторых, запись номенклатуры теперь потенциально узкое место: два пользователя не смогут одновременно записать номенклатуры, у которых изменены флаги Inactive (будет блокировка при записи нового значения нашего скрытого параметра выбора в общее хранилище).

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

30 марта 2019 работа

Дата запуска сервера MS SQL

Для чего может пригодиться дата запуска MS SQL Server? Например, мы разбираем задержки в работе СУБД и хотим определить, в течении какого периода времени наполнялась DMV-шка sys.dm_os_wait_stats. Её данные (как и любой другой DMV, впрочем) хранятся в оперативной памяти как раз с момента запуска СУБД.

Дату запуска сервера можно получить из DMV-шки sys.dm_os_sys_info:

SELECT sqlserver_start_time FROM sys.dm_os_sys_info

Есть и другой способ, связанный с tempdb. Эта база данных создаётся при запуске сервера, и дата её создания вполне может считаться датой запуска сервера. Значение можно вытащить из sys.databases:

SELECT create_date FROM sys.databases WHERE name = 'tempdb'

Нюанс: дату запуска сервера как точку начала сбора данных DMV-шек нужно рассматривать с осторожностью. Накопленная статистика могла быть очищена вручную — например, вот так:

DBCC SQLPERF('sys.dm_os_wait_stats', CLEAR)

8 марта 2019 MS SQL

Задержки сервера MS SQL

Каждый раз, когда SQL-запрос может запуститься, но ожидает другого ресурса — он записывает сведения о причине задержки. Доступ к ним можно получить через представление sys.dm_os_wait_stats.

Для анализа представления можно использовать готовые скрипты:

  • Скрипт из статьи Яна Стерка «Открытие скрытых данных для оптимизации производительности приложений», опубликованной в MSDN Magazine ещё в 2008-м году. Выводит список типов задержки, упорядоченный по времени — от самых частотных до наиболее редких.
  • Cкрипт из статьи Пола Рэндала про анализ причин задержек в работе сервера MS SQL (на Хабре, кстати, есть перевод). Фильтрует задержки, которые возникают на сервере всегда и которые обычно можно игнорировать. Кроме того, к каждой задержке добавляется ссылка на страницу, где эта задержка детально описана (например, вот описание CXPACKET).

8 марта 2019 MS SQL

Ранее Ctrl + ↓