flow

Настоящие и фальшивые альтернативы вебу

Наряду с децентрализованными решениями по обмену информацией (тема, которая поднималась в https://justy-tylor.livejournal.com/257216.html), есть и противоположная тенденция - попытки создать решения, ещё больше отрывающие пользователя от своих данных и идентификации, путём создания федераций серверов, которым предлагается всё это передавать.

Причём, авторы этих предложений также используют риторику о децентрализации, но неуклонно сводят решение к замене "неправильной" олигополии интернет-гигантов на "правильную" монополию федерации. Ранее мне казалось, что это ошибка в рассуждениях, люди думают как привыкли. Но сейчас чётко осознал, что такая подмена делается намеренно, будь то очередные метания Тима Бернерса-Ли в виде SOLID или иные самобытные инициативы вроде https://mi3ch.livejournal.com/5043877.html

Основой экономики интернета является реклама. Те же Google и Facebook это формально технологические компании, но почти весь их доход это реклама (более 80% в случае Google, более 95% в случае Facebook). Вторая ниша это подписки и продажа контента (paywall), где основные доходы у онлайн-кинотеатров вроде Netflix, а основной шум и срачи создают отсталые новостные медиа.

Если у пользователя есть возможность получить данные не с "авторизованного сервера", а от соседа на флэшке или через DHT, то экономика меняется. Нет централизованных "просмотров" и "подписчиков". Некуда поставить paywall. Рекламный рынок преобразуется - исчезают самые массовые CPM и CPC механизмы, остаются только CPA и имиджевая реклама "звезда пользуется продукцией нашего бренда". Остаются донаты.

Так что, настоящая децентрализация это хорошо для всех, но не для всего. Однако, её можно совмещать с существующими коммерческими решениями. Если вы сняли видео и хотите донести его до широкой аудитории, то самый действенный вариант это одновременно опубликовать его и в децентрализованных сетях на базе DHT, где доступность будет зависеть от востребованности, и в традиционных сервисах вроде YouTube, где доступность обеспечивается за шанс показать рекламу, но контент могут в любой момент удалить из-за действий злоумышленников или внутренних ошибок копираст-бота. А если ваш заработок зависит от показов и подписчиков, то можете отложить официальную публикацию в децентрализованной сети на пару недель, всё равно получая максимум выгоды из двух миров.

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

В отличие от этого, все предложения по федерациям "серверов персональных данных" и подобному сводятся к встраиванию в старые коммерческие цепочки, появлению странных посредников между вами и существующими сервисами. Они прикрываютя риторикой о "децентрализации", но имеют одну единственную цель - в качестве посредников откусить свой кусок рекламного пирога.
flow

My comment to an entry 'Пора выпускать из пробирки лёд-9? (1/x)' by bacr

Тоже размышлял на эти темы ещё с 2010, когда начал заниматься темой интеграции данных, где необходимость поддержки альтернативных миров/версий естественным образом приводит к требованиям децентрализации. Основные выводы таковы:

1. Для обмена данными наиболее важны не протоколы, а форматы. Желательно бинарные бандлы с документами, где на каждом уровне поддерживаются произвольные бинарные вложения (с дедупликацией в пределах бандла), метаданные и подписи. И не важно, как они пришли — через решения на базе DHT, на флэшке или были скачаны с обычного сайта как "библиотека научных статей такого-то автора". Если контент подходит под критерии интересующего, а подписи под критерии приемлемого, значит данные полезны. API запросов, подписок и публикаций, а также их транспортные протоколы, могут различаться. Например, таким разным узлам как "база знаний компании" и "сервер агрегации обновлений" нужны разные их подмножества, и если разработчики стандарта увлекаются одним из случаев, то стандарт оказывается непригодным для других. Кстати, независимость формата и протоколов успешно работала ещё в фидо, где можно было раздельно выбирать мейлеры (с разным транспортом) и тоссеры. А вот в современных попытках решений на протоколы конкретно залипают.

2. Необходима система идентификации многоверсионных данных. Однако, подходы со случайными айди и синтетическими подобиями файловой системы создают лишний когнитивный мусор. Более того, для многих данных (таких как посты или комментарии в соцсетях) заранее неизвестно, будут ли они перезаписаны новыми (или дописаны альтернативными) версиями. Решение я нашёл в 2017 году, подробнее об этом в https://justy-tylor.livejournal.com/252597.html В частности, таким образом легко разделяются деревья обновлённых/альтернативных версий статей для разных сущностей с одинаковыми именами в вики (или наоборот, продолжается то же дерево, когда меняется основное имя статьи).

3. Начинать следует не с сети, а с локального пользователя. Может он создать у себя заметку о недавно прочитанной научной публикации и прикрепить туда pdf самой публикации через криптохэш (с учётом этой ссылки в локальном content-addressable storage)? Если да — хорошо, это идеально масштабируется до децентрализованной многопользовательской системы (как пример — ранние стадии развития git). Если нет, и требуются некие действия с сетью, либо меняется идентификация документа между локальным и "опубликованным" представлением, то неминуемо повторение сегодняшней веб-помойки.

View the entire thread this comment is a part of

flow

2019 - Компиляторное

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

Фактически, у меня не компилятор "алгоритмов и структур данных", а компилятор произвольных пользовательских требований, где основной проход это requirements gathering. В любой точке исходников, где доступен какой-либо тип, к этому типу могут быть добавлены новые требования, подобно тому как новая бизнес-логика добавляет триггеры в базе данных к существующей старой схеме. Для достижения этого типы и модули должны во время requirement gathering находиться в "многомировой" интерпретации, позволяя ситуации вроде нескольких одноимённых полей в типе, из которых при обращении выбирается нужное для контекста, а не привычный вариант с "заранее выкинуть остальные по ifdef". Если преждевременно создать варианты какого-нибудь типа Entity для нескольких контекстов (натив на сервере, SQL в базе данных, JS на клиенте), то и требования придётся дописывать к каждому из. Кроме того, не все из этих требований будут нужны в выбранном контексте. Например, какие-нибудь хинты по memory layout не являются условными, но применимы только в нативе. Теперь с этим хорошо.

Далее я сделал паузу, чтобы разобраться с другой темой. Синтез конфигураций, упомянутый в https://justy-tylor.livejournal.com/255577.html

Сначала я написал алгоритм с применением необычной many-valued логики, который плющит конфигурации. Затем подобрал удобный способ объявлять правила в мейнстримных языках программирования, не требующий интеграции логических движков. Для правил с простыми фильтрами и множествами - способы редактировать в UI и хранить в базе данных. И даже подход к решению Frame problem. В общем, увлёкся, благо легко и весело.

Но дальше оказалось хитрее. Окей, вот конфигурации в типах, типы наследуются, конфигурации в них плющатся, всё в порядке, ручного описания приоритетов конфигураций не требуется. Однако, программа или модуль при этом получается конфигурацией конфигураций. Даже тип это конфигурация конфигураций в тех случаях, когда язык содержит мощные инструменты кастомизации (как redeclare или constrainedby в Modelica). Есть ли для такой ситуации взаимодействия нескольких иерархий единый правильный способ вывода последовательности для "плющить", покрывающий все интересующие меня кейсы (сразу или с минимальной дополнительной разметкой)? Или потребуется модификация самого алгоритма? Или почти всё автоматически, но иногда с ручными приоритетами? Нарисовал кучу возможных решений, далее предстоит оценить и выбрать что-то работающее. Что, помимо прочего, хорошо повлияет на систему типов и систему модулей в языке.

С такими мыслями сейчас завершаю "компиляторный" 2019. А "танцевальный" и прочие пока продолжаются.
flow

Пользовательские идентификаторы-литералы

Когда-то давно (15 лет назад) я делал наброски языка разметки текстов. С использованием квадратных скобок [] для тэгов и фигурных {} для ссылок на какие-либо термины. Фактически, как в Wikitext для ссылок используется синтаксис [[имя статьи]], так и там {термин} или {имя статьи}. Но проблема, побудившая меня на размышления о решении, была одноразовой (помогал коллегам с восстановлением/переносом интранет-портала), а далее решений и полурешений в этой нише стало достаточно, чтобы к этому не возвращаться.

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

Чаще всего это будет полезно для URL: {https://en.wikipedia.org/}. Другая библиотека может распознавать даты по ISO 8601: {2019-12-17}. Или IPv4 и IPv6: {127.0.0.1}, {::1}. Пути в файловой системе (с автоматическим контролем целостности данных), UUID, что угодно, пока нет противоречий между используемыми библиотеками. Вплоть до тех же {термин} или {имя статьи}, если это уместно.

И кстати, сюда же прекрасно помещаются идентификации по IEC 81346. На эту тему мы много спорили в чатах с ailev, который утверждал о необходимости поддержки IEC 81346 на уровне языка, что, на мой взгляд, превращает любой язык в нишевую самобытную игрушку для инженеров. Однако, использования различных {=J1=HE01} как ещё одного доступного способа идентификации (при использовании библиотеки, распознающей IEC 81346) решает это противоречие, фича для одних не мешает другим.

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

Данное решение не ограничено спецификой моих разработок, оно подойдёт для любого языка, где возможна работа пользовательских библиотек в compile time или (с меньшей надёжностью) используется динамическая типизация. Но в случае "все скобочки уже заняты" будет выглядеть чуть менее элегантно.
flow

Польза из сочетания случайностей

Живя в городах мы привыкли к сквозной нумерации домов, "улица такая-то, дом такой-то". Мы знаем, что с большой вероятностью найдём дом 6 между домами 4 и 8, при этом дом 7 будет на противоположной стороне улицы, а дом 32 где-то вдали, в том же направлении, что от 6 к 8. Это удобно.

Однако, такой подход работает только при сочетании нескольких факторов:
1. Квартальная городская застройка (а не "микрорайонная с пустырями", например).
2. Грамотность пользователя, который должен уметь читать и считать. Начиная с двадцатого века мы воспринимаем это как данность, но так было не всегда. Да и сейчас трудности с распознаванием латиницы или кириллицы могут быть, например, у туриста из Китая.
3. Традиция и практика размещения хорошо читаемых табличек с номерами домов.

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

Мне кажется, что данный пример хорошо показывает работу архитектора информационных систем - нахождение новой пользы в существующей случайной данности. Да и работу инженера/изобретателя вообще.
flow

Merkle tree для идентификации

Криптохэши прекрасно подходят для идентификации статичных данных. Запросили из content-addressable storage (CAS) файлик (точнее blob) по криптохэшу, вот он пришёл, всё можно проверить, ничего нельзя подменить (с поправкой на стойкость криптохэш-функции). Но проверить можно только целиком. А если идентификация не совпала - можно попробовать перекачать, снова целиком, так как неизвестно, какие фрагменты скачаны с ошибками. Для мелких данных ок, для гигабайтных блобов уже нет. Стандартный приём - построить Merkle tree, на нижнем уровне считая криптохэши от фрагментов в N байт, а на каждом следующем криптохэш от списка криптохэшей предыдущего уровня.

Как идентифицировать выбранный алгоритм построения Merkle tree (учитывая разные возможные подходы)? На мой взгляд, удобно задать Merkle tree через криптохэш-функцию и параметр N как максимальный размер и фрагментов данных, и неразрывных фрагментов списков криптохэшей. Например, выбрали SHA-256 и N = 64KiB (2**16) - это фрагменты до 65536 байт данных на нижнем уровне и до 2048 полных криптохэшей SHA-256 на верхних. Тогда получившуюся функцию можно обозначить как SHA-256-P64K (или sha256p64k). При таком подходе идентификация блобов до 64KiB включительно совпадёт с SHA-256, идентификация от 64KiB+1 до 128MiB включительно потребует одного уровня косвенности, и так далее. Обращаемся к CAS, получаем по SHA-256-P64K содержимое файла или карту фрагментов следующего уровня, которые можно параллельно скачивать и проверять, хоть с этого же CAS (с любым приемлемым количеством соединений), хоть с других доверенных источников.

Людей, знакомых с рассматриваемыми технологиями, могла насторожить фраза "идентификация блобов до 64KiB включительно совпадёт с SHA-256". Каждый уровень Merkle tree принято наделять маркером, используемом при вычислении криптохэша на этом уровне. Можно, например, вставить байт 00 перед вычислением криптохэшей от фрагментов данных, байт 01 перед вычислением криптохэшей от фрагментов списков криптохэшей нижнего уровня, и так далее. Без этого идентификация через Merkle tree теряет уникальность, те же байты могут идентифицировать и сами данные, и их "карту", чем могут воспользоваться злоумышленники.

Но я вижу и другое решение. Вместо использования уровня косвенности в качестве префикса при вычислении каждого конкретного криптохэша - использовать это значение в операции xor с последним байтом получаемого криптохэша. В этом случае (для примера с SHA-256-P64K) фрагменты блобов на нижнем уровне будут идентифицироваться по SHA-256, фрагменты списков криптохэшей на следующем - по результату SHA-256 с (hash[31] ^= 1), и так далее с (hash[31] ^= indirection_level). Такая операция возвращает уникальность и обладает тем интересным свойством, что идентификация данных какого-либо уровня и их "карты" расходятся только в последнем байте. Что упрощает отладку и поддержку CAS.

Покрутил я эту модель, прикинул различные сценарии поведения (вплоть до случаев memory error, с учётом прочих метаданных в CAS), и пока выглядит оптимально. Если у вас есть свои соображения - пишите. Чуть позже напишу продолжение об идентификации не-статичных данных.
flow

Забавное


A Talk Near the Future of Python

Содержание: опытный джедай на виду у юных падаванов пишет простейшую VM на Python. Потом лёгким движением руки превращает эту VM в полнофункциональную VM для WebAssembly, которая запускает геймкод скомпилированный из Rust, используя pygame вместо вызовов JS/canvas.

Хорошего пятничного просмотра.
flow

Исследования-дыбр

После некоторого перерыва (включавшего как летние танцы/приключения, так и дела) продолжаю с компилятором. Не секрет (уже мелькало в чатах), что разработка прототипа ведётся на C#. Лет 5 назад я бы сам удивился такому решению, но сейчас .NET это прямо из коробки открытая и кроссплатформенная экосистема, дающая желаемую скорость итераций в exploratory programming.

Параллельно всплыла ещё одна тема - динамический синтез единой конфигурации из разрозненных (и местами противоречивых) требований. Управление правами доступа (к сущностям в базе данных или файлам на диске), описание правил сборки ПО, интеграция каких-либо сервисов или приложений в операционную систему, интеграция плагинов в расширяемый программный продукт - всё это работа с фрагментами требований, авторы которых не могут предсказать содержимого фрагментов из других источников на целевой системе, намерений, с которыми они созданы, а также всего множества ситуаций, возникающих при взаимодействии двух и более фрагментов. Похоже, что мне удалось подобрать представление фактов и алгоритм вывода, работающий с такими фрагментами независимо от предметной области, и дающий интуитивно понятные (а также идеально воспроизводимые на тех же исходных данных) результаты интеграции конфигураций. Ещё в 2011 году, когда мы работали над .15926, vvagr задал мне вопрос, можно ли логикой (а не вставкой extension points и кода на Python) описывать расширения и кастомизацию UI продукта. Я ответил "наверное да, но настоящего решения пока нет, и его поиск может занять очень долгое время" (добавление интерпретатора Prolog или miniKanren создало бы лишь "иллюзию логики", не решая проблему фрагментарных описаний). А сейчас решение есть. Но на 8 лет позже. И хоть и может быть применено в компиляторе (про который в абзаце выше) в какой-то момент, но к разработке ядра компилятора отношения не имеет. В общем, хорошо что случилось, чуть жаль, что только "сейчас", а не "тогда".

Также, продолжил старую тему идентификации криптохэшами, начатую в https://justy-tylor.livejournal.com/252597.html Как по части 4D-идентификации ролей, так и по части идентификации данных для content-addressable storage. Но это заслуживает отдельного поста.
flow

Когда требуется больше времени

В 2013 году я "завершил" интеграционную часть своего исследования в области языков программирования и моделирования. 8 месяцев (при 6 планировавшихся) переосмысления и интеграции знаний, которые десятилетиями накапливались человечеством и годами собирались мной, когда-то как хобби, а затем и целенаправленно. Цель была: вывести набор решений для создания языка программирования следующего поколения и перейти к созданию прототипа.

Предпосылки к успешности данной затеи:
1. Более 30 лет появления новых знаний со времён тех идей, на которых базируется сегодняшнее поколение, а также более полная доступность (благодаря интернету) архивных материалов.
2. Моё желание воспользоваться всем этим опытом прошлого. Как, опять же, показывает история: создатели языков чаще концентрируются на создании "better X with Y", игнорируя большую часть опыта за пределами своей привычной ниши, чем и обуславливается "топтание на месте", а местами и деградация в этой области. Видеть целое это возможность цельно решать существующие проблемы, а не создавать локальные нишевые заплатки.

В чём была ценность лично для меня, помимо научного интереса:
Необходимо было нейтрализовать сложность разработки-сопровождения для других планируемых проектов, включая представляющие коммерческий интерес. Уже тогда я понимал, обилие моментов "долго, дорого, возможны форс-мажоры" снижает шансы каждого из них. Так пусть вместо цепочки лотерей будет одна лотерея - разработка технологии, языка.

И тогда, в 2013, когда необходимая информация была выведена, я приступил к созданию прототипа компилятора. Началось бодро. Но что-то пошло не так. Я обнаружил, что пишу очередной гибридный язык, как Scala, Nemerle или сегодняшние Kotlin и Swift, но с уклоном в расширяемость. И что пишу очередной "компромисный" компилятор, где прибитые гвоздями фичи выглядят логично с точки зрения основного языка, но снижают потенциал развития. В то же время, накопленные за годы знания продолжали работать, приводя к удобным новым решениям, которые прекрасно подходили в виде EDSL-библиотечки на "допишу позже", но противоречили сложившимся дизайнам и коду прототипа уже сейчас.

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

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

Прошлым летом дизайны ещё раз изменились кардинально, но с тех пор скорее дополнялись. Модель компиляции в части совмещения независимых правил и решения противоречий OWA и CWA (open world assumption и closed world assumption) выглядит оптимально. Время действовать.

На этой неделе я начал работать над прототипом нового компилятора. С обновлёнными силами и навыками.

Планировалость одно исследование на 6 месяцев. Получилось другое на 6 лет. 6M6Y. В чём-то как 3D2Y в One Piece.
Luffy_Pays_His_Respects.png
flow

Чтение 2018

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

В прочитанной же публицистике особенно зацепили две книги:

1. Yuval Noah Harari "Homo Deus: A Brief History of Tomorrow" (Юваль Ной Харари "Homo Deus: Краткая история завтрашнего дня"). Футурология - жанр на грани между фантастикой и реальностью, требующий от автора как хорошего понимания "здесь и сейчас", так и достаточного полёта фантазии в вариативности "завтра" (не повторения чего-то вроде "на дискету поместится библиотека"). Так что достойных книг в нём почти нет. Эта - редчайшее приятное исключение, хотя и менее крута, чем "Сумма технологии" Лема.

2. Jordan Ellenberg "How Not to Be Wrong: The Power of Mathematical Thinking" (Джордан Элленберг "Как не ошибаться. Сила математического мышления"). Несмотря на название, книгу с которым в магазине сразу поставят в раздел "популяризация науки", данное произведение не имеет ничего общего с работами клоунов вроде Гладуэлла. Это крепкая прикладная литература, в которой примеры и случаи из реального мира представлены не для удивления читателя, а в качестве моделей для применения математического аппарата, и историй его развития. Книга, способная не только наделить обычного человека знакомством с определёнными разделами математики и логики, но и улучшить связь математика с реальностью.