усы2

Стой под стрелой

Поступки и мысли, о которых могу вспомнить не краснея

When in doubt, write a DTD
усы2
tonsky

Хочу поговорить про схемы. Поводов два — во-первых, Cognitect (company behind clojure/core и Datomic) выпустила Transit, протокол сериализации данных, и в нем не предусмотрено out-of-band схемы. Точнее, повод это HackerNews тред, в котором пророчат будущее за протоколами с явной схемой. Во-вторых, мне на глаза попался сборник HTTP API guidelines, и там безапелляционно требуют прикладывать машинно-верифицируемую схему к вашему API (и заметьте, что никак не мотивируют это).

Преимущества иметь схему заранее — быстрый парсинг. Конечно protobuf/thrift парсятся быстрее JSON, как бы ни оптимизировали последний. Подход performance first затуманил взгляд многим тысячам программистов, ведь когда слышишь «зато мы можем кодировать 120Mb/sec», из рассмотрения уходят любые другие факторы. Включая, к сожалению, и вопрос «а наберется ли у нас эти 120 Мб в секунду»?

Все следующие преимущества проходят по разряду спорных или даже маргинальных. Возможность запустить механический валидатор по возвращенному документу это преимущество уровня статической типизации в ЯП — уберегает от самых тривиальных ошибок вроде опечаток (эх, если бы все мои проблемы были такими простыми!), но никогда не поможет отличить смысловые ошибки вроде перепутанных min и max. Плюс, если статическую типизацию хотя бы ясно когда и как запускать, то когда валидировать схему не очень понятно. На каждый пришедший документ? Выборочно? В режиме разработки только? И что делать, когда документ не прошел валидацию? То есть, непонятен банальнейший сценарий использования, последовательность действий. В XML был механизм DTD, например, валялись в документах ссылки на схему, или неработающие, или устаревшие. Чёт не прижилось.

Дальше по нарастающей идут сложности, а не преимущества. Например, как описать вариабельный ответ? Скажем, если в запросе я указываю, какие поля хочу видеть в ответе. Или если ответ это список разнородных ресурсов. Или я хочу выразить «присутствовать должно только одно поле из вот этих трех». Это или усложняет язык описания схемы (и тогда все на нее забьют), или поднимает вопрос «а зачем нам схема, если она даже половину синтаксических ошибок не ловит»?

Есть еще проблема миграции. В какой-то момент по системе будут летать сообщения хорошо если двух, а то и пяти-шести версий (если лень, скажем, 5 Тб базу конвертировать в новый формат). И ладно если это всё внутри, как-то можно с этим справиться (переучиваем сначала приемник, затем передатчик). А внешний клиент, который сидит на схеме X, и вдруг начинает получать сообщения в формате X+1? Да, часть простейших миграций можно предусмотреть, но когда содержимое документа парсится на основании чего-то снаружи, отстающий клиент рано или позжно даже прочитать сообщение не сможет. То есть проблема возникнет не на этапе «я не знаю что мне с этим делать», проблема возникнет еще на этапе чтения бинарного потока, когда никакую логику/эвристику пользовательский код еще не может применить.

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

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


Подкаст
усы2
tonsky
Кто не видел в твиттере, я записался в подкасте, да таком длинном, что растянулся на два выпуска. Текстовая расшифровка также имеется.

http://eax.me/eaxcast-s02e05/
http://eax.me/eaxcast-s02e06/

Улькемп 2014
усы2
tonsky

Четвертый Улькемп (twitter.com/ulcamp, ulcamp.ru) у меня выдался самым удачным. Скорее всего, конечно, компания сложилась, но есть вероятность что и Улькемп становится лучше. Это не самая массовая конференция, зато самая уютная и свободная. Организаторы почти ничего не контролируют, только обеспечивают. А дальше, если приехали правильные люди, они организуются сами, причем так, как никто никогда спланировать и реализовать не сможет. Плюс, в секретном арсенале Улькемпа два зайца.

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

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

Смысл в том, что главная сцена на конференциях традиционно получается жиденькая: у организаторов какие-то свои мотивы, планы, тематика, взгляды на мир, спонсорам в конце концов надо дать доклады, или евангелист какой просочится. Баркемп лишен этих недостатков: если у тебя есть, что сказать, можно приезжать и говорить. Атмосфера располагает: не так интересно сорок минут вещать со сцены в режиме радиостанции, а в конце ответить на пару заданных из вежливости вопросов, как в тесном кружке совместно перемывать косточки рубям и опенсорсу, иногда матом. Бывает, что нетривиальная реплика из зала интереснее всего доклада. Можно собрать немного людей и объяснить им в подробностях, как работает какая-нибудь маленькая, но интересная штучка. Формат большой сцены располагает к глобальности, или хотя бы к претензии на полноту, что обычно скучно. Если есть минимальный кругозор, интересны уже отклонения и особенности, сочные детали, а не то, как обстоят дела в целом.

Хотелось бы, конечно, чтобы все конференции, и Кодефест в первую очередь, куда-то сюда двигались: меньше хождения строем и поверпоинта, больше диверсификации, маленьких кулуаров и объяснений на пальцах (отсутствие проектора — огромный вин, хотя некоторые все-таки умудрялись притаскивать распечатанные на A1 слайды). Может быть, даже попробовать развернуть в Экспоцентре палатки.

Пользуясь случаем, несколько традиционных инсайтов.

Я успокоился по поводу Котлина: было ощущение, что Next Java языки (Kotlin, Xtend, Ceylon, Fantom, Gosu) это что-то хорошее не абсолютно, но в достаточной мере, чтобы обычным, не хипстер-в-жопе разработчикам сидеть на них и никуда не хотеть слазить. Казалось, что уговаривать переходить на Clojure не совсем честно: слишком радикальные вливания требуются, в то время как большую часть бенефитов можно получить на чем-то гораздо более близком к Java, причем все основные pain points у Java снимающем. Оказалось, нет, все хорошо, позиции Clojure непоколебимы, мир Next Java языков живет всеми теми же проблемами, что и сама Java: как генерировать getter-ы, можно ли не писать вот тут скобочки, есть ли поддержка IDE, кто лучше генерирует hashCode, как перегрузить конструкторы или сделать приватные поля, а потом разгребать проблемы вокруг невозможности к ним доступиться. Понятно, что и я сам когда-то над этими проблемами «думал» (даже ««думал»») и, наверное, проводил, хотя бы в уме, сравнительные чарты разных языков, пытаясь ««взвесить»», но блин. Это не имеет никакого отношения ни к задаче, ни к полезному действию, ни к надежности, ни к эксплуатации, ни к удобству, ни к переиспользованию, ни даже к культуре программирования. Это споры ради споров и улучшения в тех местах, которые просто не нужны, совсем. Самое главное, за что я люблю, ценю и так рекламирую Clojure, так это за фокус, возможность сосредоточиться на существенном и выведении нонсенса за рамки картины мира. Спасибо, что живой.

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

    String x = "hello world";
    x.

нажимаешь Ctrl+Space и видишь, из чего этот String устроен. Перед тобой, как на витрине, разложены варианты. Ты знаешь, что тут можно сказать, а что нельзя. Аналогичным образом графические меню приложения и контекстные меню вытеснили терминал: в терминале требовалось тренировать память, а в GUI перед тобой открытая для изучения онтология текущего окна.

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

А закруглимся давайте картинкой из Ульяновска:


Google design?
усы2
tonsky
Почитал http://www.google.com/design/spec/

Всё красиво конечно, и многое продумано (особенно начало многообещающее), но четыре мысли:

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

2. Гугл так и не научился в отступы. Видно, насколько сетка для них важнее здравого смысла. Даже сам сайт сверстан с совершенно рандомным применением whitespace. Все надежды на красивый GMail можно закапывать.

Зацените, например, расстояния до чекбоксов:





Или вот расстояния до иконок внизу (по сетке, но не по логике):



3. Анимации это гиперздорово. Тот, кто придумает как делать все те чумовые эффекты-переходы-анимации ценой не нескольких человеко-лет, а парой взмахов в чем-то типа after effects, может о пенсии не беспокоиться. Особенно если для веба.

4. При нажатии кнопка подскакивает вперед, а не назад?

Reinventing GIT interface
усы2
tonsky
Накидал статью про то как GIT интерфейс должен выглядеть, если по-нормальному (но с сохранением совместимости):

http://tonsky.me/blog/reinventing-git-interface/

без темы
усы2
tonsky
Уважаемый чатик,

а можешь мне подсказать, каков смысл слов usr и local в названии папки /usr/local/?

Спасибо

Где именно закапывать Линукс, или вперед, в светлое будущее
усы2
tonsky

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

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

Исходный Линукс это такая большая интегрированная среда для разработки C-приложений. IDE for C. Если вы пишите на C, то весь Линукс, сама операционная система, это для вас такой рантайм, управление зависимостями, биндинги для C ко всему, тулинг. Понятно почему так получилось, но остальным это даром не нужно, а ведь создает кучу геморроя просто потому что есть и надо как-то считаться.

Итак, вперед, в будущее. Вместо файловой системы, очевидно, нужна база данных. По сути, файловая система это и так БД, только не реляционная, без транзакций, с неудобным программным API и непрозрачная внутрь файлов (sed/awk чтобы поменять значение поля в конфиге? буээ). Также как гонять unbounded потоки байт по TCP малой полезности идея (в 100% случаев нужны сообщения, а не поток), хранить большие бинарные блобы произвольного содержания редко кому нужно. Любое приложение почти всегда работает со структурированными данными, так зачем мучать котенка и каждого разработчика заставлять придумывать сериализатор и парсер конфигов и документов, когда это можно сделать на уровне системы. См. живой пример здесь. Как побочный эффект, целая пачка линуксовых утилит и их сумасшедшие command-line arguments умрут сведутся к набору SQL выражений (ps → select from processes..., ls → select from files..., и т.д.).

Очевидно, современная ОС должна быть network-aware. Начиная от более толкового сетевого протокола (SCTP? ∅mq?), ориентированного на сообщения, а не на поток байт (поверх которого все равно все придумывают сообщения), продолжая более соответствующими современной обстановке буферами (16Kb default TCP write buffer? SRSLY?) и минимальными возможностями роутинга (message broker вполне хорошо бы смотрелся в качестве системного компонента, и востребованность ∅mq это подтверждает), заканчивая cluster awareness. Было бы круто, если бы я мог системными средствами видеть, где, кто и сколько машин вокруг, как-то разумно распределять по ним запросы, следить за их доступностью, броадкастить и общаться между ними. Хорошую работу в этом направлении делают CoreOS и Serf.

Далее, модель процессов. Она построена вокруг предполагаемой интерактивности: stdin, stdout, string arguments, return value, это всё для работы в sh придумано. То что каждый процесс может максимум что вернуть 1 целое число проходит по категории тяжелого детства и деревянных игрушек. Может показаться что это круто и как раз и принесло UNIX модели бешеную популярность, но на деле это заставляет каждый процесс городить парсер на входе и сериализатор на выходе. Реализация интерактивности идет внутрь приложения, хотя она должна быть снаружи, вокруг не интерактивного, а extremely programmable, composable ядра. Программа принимает на вход путь до файла. Зачем? Почему не содержимое файла? Если я хочу состыковать ее с другой программой, мне придется научить их разговаривать через файл. Спрашивать на stdout вопрос, а на stdin ждать ответа (привет, ssh)? Это низ composability, ниже некуда. Ориентированность на использование в sh рождает целую кучу бредовых паттернов (как вернуть из процесса строку, например?), о которых в обычных PL никогда не слышали. Есть целая индустрия command-line arg parsers, считаете это хороший знак? Понятно, что программа на Java не передаст программе на Perl в качестве return value свой объект, но вот json может, и это будет куда лучше хрен-пойми-как-tab-space-and-comma-delimited вывода какой-нибудь утилиты типа ls, который еще и на stdout уйдет. Как это могло бы работать: TermKit и мой пост про смерть терминала.

Можно еще больше расфантазироваться, предложить делать каждый запускаемый процесс network addressable и приделать к нему mailbox (место, куда кто угодно может положить сообщение, а процесс прочитать). Модель украдена у Эрленга, но так ведь не зря — только Эрленгу пока и удается делать массивные кластерные приложения разумным количеством усилий. Почему, собственно, это не легитимизовать на уровне ОС? Интеграция чего угодно с чем угодно внезапно становится тривиальной вещью. Главная тут штука в том, что появляется штатный механизм как пообщаться с процессом, своего рода default API (на самом деле API transport). Сейчас, например, я поднимаю Java-программу и мне не очень понятно как с ней пообщаться. Нужно либо коннектиться к чему-то (message broker), либо поднимать целое HTTP API, что во многих случаях overkill. Подробнее см. Erlang On Xen.

Вообще, раз уж мы придумали себе process manager, неплохо оснастить его чуть более богатым чем spawn набором фич. Базовые возможности supervisord, мониторинг liveness, таймеры, реакция на события, оповещения, торчащий наружу API (самое главное).

Еще одна тривиальная, но жутко полезная вещь — metrics dashboard. Логично, если бы в ОС была встроенная time series database в которую логировалось бы всё происходящее внутри этой же системы и можно было бы прямо зайдя на http://host:17801/ посмотреть на графики. Тут важно чтобы это была не какая-то особенная система сбора метрик, а чтобы она была стандартная системная, включена по умолчанию и покрывала все базовые случаи (CPU, Memory, Limits). См., например, Amazon CloudWatch или Couchbase Dashboard, очень удобно.

С интерактивностью у меня вообще давние счеты. Мне кажется правильным строго забанить ходить по ssh на сервера, потому что куча бед и усилий у людей тратится на то, чтобы сделать себе удобный dev environment на удаленном сервере. Чувак, ты что там забыл, сервером надо управлять с пульта, а не сидеть на нём, настраивая тему в vim-е. Запускать процессы, инспектировать ФС (SELECT) и редактировать конфиги (UPDATE по БД), мониторить метрики можно по сети. Заметьте, что все перечисленные вверху средства network friendly. Плюсом будет огромное количество сэкономленных усилий, когда станет понятно, что sh-like интерактивность большинству программ не очень-то и нужна.

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

Тут еще пора сказать, что надо прикрывать многопользовательность, она никому не нужна в век облаков. У серверов все равно как правило в /home один юзер, да и тот с правами sudo. Раньше был смысл экономить (поставили один Линукс и весь институт на нем сидит), а сейчас есть новые средства, виртуализация, и самое простое и адекватное решение это одна задача — одна машина (или больше :).

Итак, что же мы тут насочиняли?

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

Во-вторых, мне очень нравится, как многие вещи тут объединяются и работают вместе. Скажем, пространство для process inbox может выделяться в той же самой БД, или local fs access ничем не отличается от remote fs access потому что SQL, или network-addressable processes сильно упрощаются при наличии process manager.

В-третьих, совершенно справедливо можно заметить, что это скорее обычные devops-практики, чем что-то кардинально новое. Многое из этого можно достичь сегодня в user-level. Верно, но. Главное достоинство концепта (если он когда-либо реализуется) в том, что это будет у каждого, по умолчанию и об этом не надо будет задумываться. Сейчас можно повторить, скажем, сбор метрик, но это надо уметь. А много ли ума надо, чтобы, скажем, записать строку в файл? Нисколько, это просто есть и работает. Так же и тут, если оно просто будет, всегда и by default, и просто будет работать, это кардинальнейшим образом упростит создание приложений. Современных, работающих в кластере, принимающих нетривиальные согласованные решения.

В-четвертых, очень приятно убирать лишнее. В этой концепции девелоперские машины, конечно, остаются сложными и интерактивными швейцарскими ножами, но от продакшна требуется быть минимальным — несколько core services да возможность запустить процесс, всё. Меня давно нервировал тот факт, что для того чтобы запустить 1 java-процесс который собственно и является продакшн-приложением нужно поставить линукс с 20K файлов и 5K каких-то других левых процессов.

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


Дизайн в школе
усы2
tonsky

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

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

Сегодняшнему школьнику, если показать айФон, он скажет «о, клево», и пойдет СМС-ки на нём строчить. Если в будущем ему придется проектировать смартфон, он скорее всего будет копировать то, что видел, без понимания «почему». Я, например, за свою жизнь, может быть, всего пять книг по дизайну прочитал (и ни одной про эстетику и визуальную сторону, всё про проектирование), но я когда на айФон смотрю, я уже чуть ли не рентгеном вижу, как и почему он устроен так, а не иначе. И эти знания, их легко передать, им легко научить, там никакого матана, это простые вещи, потому что они про человека и для человека, они чуть ли не интуитивно схватываются — с плохих примеров, с хороших, с анализа удобств и недостатков.

Даже сегодня, у профессиональных дизайнеров, делающих доклады на конференциях, часто можно наблюдать развитие мысли в направлении: увидел какую-то особенность в продукте Эппла/Гугла/Фейсбука → сделал вывод → сделал доклад. Хотя по-нормальному все продукты Эппла/Гугла/Нокии естественно вытекают из тех же самых принципов, которые в голове у любого дизайнера уже должны сидеть. Для меня, например, развитие компьютерных интерфейсов сейчас — это череда постоянных «а, ну наконец-то и до этого догадались». Потому что это минимальный общий базис, а не прорыв или инновации.

Другой пример, работающий в подтверждение концепции — недавняя статья про то, как в пресловутом Эппле дизайн внутри устроен. Вкратце, это не дизайнеры у них особенные, а все, начиная от топ-менеджмента и кончая последними программистами разделают общую направленность на гладкий опыт конечного пользователя. Как они этого добились отдельный вопрос, а вот результаты такой концентрации design awareness все прекрасно видели. Представляете, если каждый будет хотя бы знать, что такое и зачем дизайн, то не только в Эппле, а в любой компании дизайнер приходит к программисту, или к начальнику своему и говорит «вот так будет круто сделать», а они ему вместо «ты тут работы на полгода принес, иди ле**м, не до тебя сейчас» говорят «да, очень круто, пойду согласую ресурсы под это со своим менеджером». Ну или хотя бы поймут, о чем это он и почему это важно. Да даже и не дизайнер к программисту, а кассир к управляющему сыроварного завода или водитель маршрутки №15 к директору депо.

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


DataScript и сервер
усы2
tonsky

В понедельник я выступил на Hangout с рассказом про DataScript, и одним из частых вопросов остается вопрос про ленивую подгрузку данных. Я написал в Readme, что у Датаскрипта нет и не планируется никакой истории про синхронизацию с сервером, ленивость, localStorage, и так далее. Причина — потому что я не знаю как удовлетворить всех, поэтому вынес это за рамки. Тем не менее, пусть не внутри Датаскрипта, а снаружи, но вопрос остается.

У меня сейчас такое понимание вариантов использования. Данные, которыми оперирует web-приложение, могут быть большими или маленькими, частными (personal for user) или публичными, требующими real-time sync (server push) или нет.

Первый случай, когда данных мало, мы загружаем их при загрузке страницы одним вызовом API «дай мне всё про эту страницу». Это такие применения как github issues, доска trello. Это то, про что я говорил на hangout, логика работы интерфейса и view model уходят из server-side api cовсем и сосредоточены теперь в js. Это очень простой случай и от DataScript тут требуется только разве что batch import быстрый (думаю, сделаю).

Кстати, тут можно поиграться, если данных средне, скажем. У проекта, например, 10000 issues и они занимают, сериализованные, 5 мегабайт, скажем. Можно грузить их кусками по 128, запихивать в DataScript по мере загрузки, а интерфейс никак не тюнить, просто дать ему перерендериться на каждый такой «запих». Получится, что ты быстро открываешь пустую страницу и у тебя на глазах в ней появляется все больше и больше issues, счетчик total issues крутится, paginator толстеет, и так далее. Наглядно и красиво, короче, и позволит скрыть некоторую тормознутость подсасывания. И писать ничего специально не надо, потому что, как мы знаем, в React рендер это f(Store)→Dom, чистая функция, мы просто инкрементально увеличиваем Store.

Опционально, можно сделать server sync через transaction reports формат. Тогда, скажем, такая вещь как многопользовательская игра будет тривиальной — каждый участник загружает себе начальное состояние, шлет на сервер свои транзакции и получает все чужие. В итоге все видят одно и то же. Прелесть в том, что это можно сделать переиспользуемым компонентом, не зная ничего о специфике игры. Это может и не игра быть, а софт для совместного редактирования чего-то, Trello скажем. Важно, чтобы клиент имел открытый двухсторонний канал с сервером (веб-сокет), а на сервере стоял fan-out по всем подключенным сейчас клиентам.

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

С другой стороны, конечно, «а что считать данными». Потому что можно было бы взять IMDb и положить его целиком в датомик. Датомик сегменты закачать на s3. Далее DataScript получает с сервера (или с того же s3) только URL на root index node и браузером уже ходит в s3 за сегментами.

Получается в точности модель Datomic, только peer in-browser, а transactor это server-side api, которое отдает current index root, novelty и пушит real-time изменения (если такая степень динамизма нужна, для IMDb не нужна, скажем — каждая страница может работать на слепке БД в момент её, страницы, загрузки).

Это всё очень интересно, это будет ощущаться как «вся база у меня в руках», а сегменты будут прозрачно докачиваться и кешироваться где-то за занавеской. Но это вот уже нереальное количество работы, так что я пока не буду подписываться даже на то, что это когда-нибудь возможно будет. Это реально сделать весь Датомик, только пир в джаваскрипте должен работать. На такое даже Рич Хики пока не готов.

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

Это можно свести к первому случаю (оперируем письмами только за последние 3 дня, например, iOS Mail так делает).

Можно свести к случаю второму — для каждого юзера иметь свою Datomic DB, корневым индексом и сегментами которой оперирует in-browser peer. В принципе вариант работает, если данные действительно персональные и их никто больше не видит (письма — да, форум уже нет, любой collaboration софт тоже нет, так что скорее почти всегда нет).

Тут наверное остается только решение о ленивой подгрузке. Из-за особенностей модели данных, у Датаскрипта нету никакого куска, который бы мог быть обозначен «ленивым» и подгрузиться по необходимости с сервера. Датомы слишком маленькие — проще загрузить датом, чем делать его ленивым. Entity не очень удобны — ленивый entity можно сделать, но он тоже слишком маленький (конечное число атрибутов), и интереснее скорее ленивые коллекции entity, чем один конкретный. Плюс, ленивые entity это сразу проблема N+1 select, от которой пытались уйти. Короче, на уровне Датаскрипта сделать ленивость правильно и универсально — это делать через сегменты, а это непросто.

Остается ручная ленивость. Запоминать, что загрузили, а что еще нет, запоминать докуда догрузили. Эту информацию можно прям атрибутами в БД хранить. Концептуально не очень правильно (есть данные или нет это не особенность БД, это особенность способа к ней доступиться; откат по истории будет абсурдно удалять подгруженные позже данные; возможны дыры в консистентости), но в приницпе терпимо. Не удобно, да, но это всегда было неудобно. Датаскрипт в этом случае не помогает, но и не мешает вроде.

Более того, хоть я и привык так делать, смирился, мне кажется что все равно с Датаскриптом получается лучше среднего. Если мы делаем статус ленивости атрибутом entity, скажем, есть у нас [188 :label/title "label:social"] и [188 :loaded :no], потом понимаем что нам этот label нужен (пользователь щелкнул), меняем в БД статус на [:db/add 188 :loaded :loading] и пуляем AJAX-запрос. Первый важный момент, это что именно этот атрибут статуса подхватится нашим рендером и он нарисует прогрессбар. Второй, что когда придет AJAX-запрос, нам нужно сделать ровно одну, простейшую, вещь: запихнуть пришедшие данные в БД и поменять статус на [:db/add 188 :loaded :yes]. Рендрер, во-первых, грохнет прогрессбар, а во-вторых нарисует то что пришло, потому что он на ту же базу подписан, блин. Если пользователь за это время что-то нащелкал там, перешел в другой таб, ничего страшного, ничего не отрисуется, зато потом, когда он вернется в наш label, он уже подгруженные данные увидит. Если он вышел, потом вернулся, а запрос все еще грузится, он опять прогресс бар увидит, потому что статус всё еще :loading. Космос же?

Короче, естественным образом, DataScript ориентирован на первый случай: данных мало/умеренно, они помещаются в браузер. Я надеюсь (программа максимум), что даже это уже изменит привычки веб-разработчиков. Согласитесь, большинству приложений не нужно иметь дело со стотысячными базами в браузере. Обычно то, на что смотрит пользователь, умеренных объемов, и это именно тот случай, developer experience которого можно сильно улучшить. Быстрая загрузка всей базы на старте + real-time updates через двухсторонний web socket и получится, что real-time веб-интерфейсы, collaboration tools, многопользовательские игры тривиально писать. Моделируешь схему данных, пишешь рендер и логику, остальное покрыто generic компонентами, сервер-сайд тупой.

Живой пример: загрузить 100 issues через API github занимает 50 kB (gzipped) и 600–800 мс. Загрузить 10 issues, как они делают это сейчас, в text/html, занимает 6.3 KB и 300 мс (упирается, естественно, в latency). Естественно, первый response гораздо лучше кешируертся, потому что у него нету всей этой вариабельности в URL а-ля direction=desc&page=1&sort=created&state=open. Плюс user experience лучше — мы не шлем server-side запрос на каждый клик в интерфейсе. В проекте уровня Om issues всего ~200 за всё время существования. В Trello-доске вряд ли будет больше 100 карточек. Это все реальные приложения и прекрасные use cases для DataScript, bigdata в браузер пока не пришла, а вот interaction очень сложный и есть что улучшать.


Поковырял Datomic
усы2
tonsky
Всё, что вы хотели знать, но боялись спросить:

http://tonsky.me/blog/unofficial-guide-to-datomic-internals/

без темы
усы2
tonsky
Продолжаю пописывать на английском если что

http://tonsky.me/blog/datomic-as-protocol/
Метки:

Вопрос по информационной безопасности
усы2
tonsky
Если я закрываю входную дверь на два оборота ключа вместо одного, защищаю ли я квартиру лучше?

DataScript
усы2
tonsky
В общем, я тут портировал Datomic на ClojureScript.

Зачем это нужно, подробно описано вот тут: tonsky.me/blog/decomposing-web-app-development/ (почитайте, там много хорошего).

Сама библиотека здесь: github.com/tonsky/datascript

Enjoy!

UPD: переименовал DatomicScript в DataScript, чтобы никто случайно не спутал и не начал запускать коммерческий Datomic в браузере.

без темы
усы2
tonsky
А вот еще вопрос. Когда речь заходит о client-side web apps, всегда приводят GMail, чуть ли не как имя нарицательное, как пример сложного интерфейса. Типа, а на этом вашем Vaadin вы бы GMail написали? На jQuery бы написали? На ClojureScript Dart написали бы? То-то же, сидите тихо и компиляйте GWT. Проверенная технология.

Короче, вопрос вот в чем: а чего там такого сложного-то? Самый крутой эффект, кажется, который есть во всем GMail — это перетаскивание писем в папочку. Всё остальное обычная верстка (весьма корявая, кстати) + довольно простая логика, без переходов, без анимаций. Очень прямолинейно структурированная.

То есть, я понимаю, как Google в такую ситуацию попал, и не может ей facelift сделать хотя бы до уровня G+, не разломав там всё к чертям и не скатившись в полное переписывание. И все-таки, если с нуля делать и не тремя этажами индусов, а нормальными frontend-разработчиками, неужели это сложно? Чего я не понимаю?

Om, React и все-все-все
усы2
tonsky

React.js — это библиотека, недавно перевернувшая JavaScript-мир с ног на голову одной простой идеей: давайте оперировать не настоящими DOM-елементами, а JavaScript-классами, их изображающими. Синхронизацию этого симулякра с настоящим браузером отдадим библиотеке.

Оказалось, что если не трогать DOM, работать с объектами настолько дешево, что можно их даже не хранить, а всегда дергать функцию state → pseudo-dom, генерирующую каждый раз новый псевдо-дом. Это первое достижение React-а, сделать двухстороннюю синхронизацию данные-интерфейс односторонней. Мы всегда пишем, как из данных получить UI, и никогда не пишем, как один UI перевести в другой UI. На всякий случай еще раз: подход «а вот по этой кнопке скроем панельку» был хорош до определенного предела, пока сайт был в основном статический, с немного меняющимися частями. Сейчас же то, что рисуется в браузере при загрузке, и то, что там будет через 2 минуты, может не иметь ничего общего вообще. Поэтому подход «дайвайте опишем, как эволюционирует наш DOM» работает не очень из-за комбинаторного взрыва — слишком много способов, как он может эволюционировать.

Второе достижение React-а в том, что они реализовали концепцию «всё свое ношу с собой», придав компонентам адекватную стандартизованную структуру. Грубо говоря, в момент создания компонент сам себе нужные ресурсы выделяет и сохраняет в собственный стейт (таймеры, сокеты, листенеры), а в момент удаления — прибирает. Звучит банально, но здесь важен факт, что это есть. Ситуация аналогична проблеме неймспейсов — яйца выеденного не стоит, но в JS их забыли и каждый разработчик вынужден пускаться в собственную езду на лыжах по кирпичам. DOM-листенеры тоже, кстати, крепятся к компоненту, но уже самим react-ом. Это опять же важно для highly dynamic интерфейсов — руками за всеми ресурсами следить и замаешься, и не уследишь.

Получаем, что react-овские компоненты это такие маленькие самостоятельные кирпичики, которые действительно можно складывать в стену и они сами будут работать, не захламляя приложение в неожиданных местах типа регистрации в top-level listener или создаваемых, но никем не удаляемых setInterval.

В общем, я примерно всю революцию уже описал. Можно делать самодостаточные, переиспользуемые компоненты (у них честное воткнул-и-готово), очень простой и мощный data binding (произвольная js-функция state→dom, и не надо выкручиваться в ограничениях template bindinds, и вообще html с шаблоном не нужен), быстрая синхронизация с DOM. React.js маленький-легковесный и это, в целом, opinionless библиотека, которую можно совмещать с чем угодно. Используется Фейсбуком и Инстаграмом, куча баек про то, как интерфейс, переписанный на React, избавляется от проблем со скоростью отрисовки. Но главное, что с ростом количества динамических частей на странице код не начинает катиться в говно экспоненциально. В целом, прорыв уровня jQuery.

Теперь Om. Om — это ClojureScript-биндинг к React-у от David Nolen, главного коммитера ClojureScript, и первая вещь, которую надо про него понять — это не биндинг. Да, он использует React, оборачивает его в cljs интерфейсы, но на самом деле под этой (достаточно выгодной) этикеткой продает свои, совсем другие идеи.

Первая, и очень хорошая — зачем нам рендериться на любое изменение стейта, давайте рендериться один раз на requestAnimationFrame. Мы получим те же 60 fps и еще меньшую площадь соприкосновения с DOM, чем в React. За счет этого, например, он обогнал голый React в ToDoMVC перфтесте.

Вторая — это управление состоянием всего приложения. Если React в этом смысле был достаточно нейтрален (ну, ты, это, давай там сам как-нибудь сам), то у Om насчет состояния вполне четкие планы. Дэвид постаралася сохранить переиспользуемость компонентов и добавить несколько бонусов сверху. Если коротко, то состояние всех компонентов в Om — один большой atom, персистентная структура, а все компоненты получают view в эту структуру на то место, которое относится непосредственно к ним. Т.е. они получают такой handle (в терминах om — cursor), через который они могут читать кусочек этого большого дерева и писать в него. Если компоненту нужны подкомпоненты, можно создать под-курсор из своего курсора, например.

Эта простая идея дает два бенефита:

Возможность показывать в разных местах страницы одно и то же значение буквально. То есть, например, слева у нас таблица сотрудников (компонент table), и в колонке «пол» у них или Man, или Woman. А справа у нас text input для редактирования списка полов, и мы в нем меням Man на Male и в таблице все автоматом синхронизируется. Потому что оба компонента работают с курсором на одно и то же место в атоме. Из-за особенностей реализации text inputs в React можно даже сделать так, чтобы значение в таблице менялось по мере набора букв в text input.

Второй бенефит — это возможность работать с состоянием всего приложения как с чем-то цельным. Это персистентная структура, значит можно хранить историю состояний всего на 100 (например) версий назад, каждое состояние иммутабельное и все они разделяют кусочки, которые не изменялись. Элементарно прикручивается undo, причем на любую версию: ты просто говоришь om-у (а он react-у): давай сейчас вот это состояние рисуй, и react сам вычисляет оптимальный способ его нарисовать из текущего dom: где что удалить/добавить/подвинуть, чтобы получить целевое. Палитру History в фотошопе видели? Короче, бонус в том, что управление состоянием вынесено за скобки. Можно прикрутить логику синхронизации с сервером, undo, сохранение в localStorage — и всё это будет снаружи и отдельно, а не размазано по GUI-компонентам.

Там не всё идеально — документация мутная, курсоры излишне хитрожопо сделаны и не описаны (точнее, сейчас описаны, но это я доку написал), и вообще оно alpha. Но это уже, наверное, самый востребованный GUI-фреймворк на cljs — я думаю, из-за hype вокруг React + имени создателя. Я не то чтобы рекомендую, я скорее популяризирую хорошие идеи, плюс это еще такой спасательный круг тем, кто полезет в Om разбираться.

Вот здесь можно посмотреть на мои эксперименты: игра «41 носок» вживую, исходники.


30 советов 30-летним от тех, кому за 40
усы2
tonsky
  1. Определись. 30 лет — возраст, когда пора сказать себе: определись!
  2. Не дай провести себя на мякине. Вообще по возможности обходи стороной мякину.
  3. Старайся уделять больше внимания. Внимание — твой самый ценный ресурс. Уделяй его.
  4. Составь план. Хороший план очень сложно выполнить, но составить — легко.
  5. Ходи на работу. Многие люди потеряли свою работу после того, как перестали ходить на нее.
  6. Спорт — это важно. Старайся чаще думать о нем.
  7. Сфокусируйся. Расфокусируйся. Вообще, потренируй глаза. Ты можешь добиться в жизни большего, если потренируешь глаза.
  8. Старайся рисковать, но в меру. Будь безрассудным, но рассудительным. Ты еще не молод, но уже не стар.
  9. Привыкай к тому, что многие привычки привычно входят в привычку.
  10. Помни, что то, что тебе сейчас кажется важным, может оказаться на самом деле важным, и может не оказаться. Попробуй угадывать, хоть это и бесполезно.
  11. Старайся жить так, будто каждый день твоей жизни — 10957-ой.
  12. Не откладывай развитие. Если кто-то предложит тебе заняться развитием — не отказывай ему сразу. Подумай.
  13. По возможности не разговаривай на улице с незнакомцами.
  14. Используй ноги при ходьбе. Постоянно дыши. Ешь ртом. Это простые вещи, но они могут кардинально изменить твою жизнь.
  15. Найди время и научись пользоваться интернетом. В 21-м веке без интернета никуда, даже если тебе уже 30 лет. Особенно если тебе 30 лет. На 30 лет у многих приходится пик использования интернета. Будет обидно пропустить его.
  16. С возрастом все труднее вспоминать прошлое. Так что расслабься, больше фантазируй.
  17. Старайся меньше полагаться на свою память. Не надейся запомнить вещи, лучше запиши их на бумажке и запомни, куда положил бумажку.
  18. Начни планировать бороду. К 80-ти годам пышная седая борода не вырастет сама, если ты не начнешь закладывать фундамент уже сейчас. Многие 40-летние жалеют о том, что не начали думать об этом в 30 лет.
  19. Помогай людям стать лучше. Совершённое добро всегда возвращается с лихвой. Говори «я преподал вам урок» вместо «извините».
  20. Научись ценить свое время. Научись ценить время близких тебе людей. Чаще напоминай друзьям, сколько времени ты потратил на них впустую.
  21. Почаще спрашивай себя. Если не услышишь ответа — задумайся.
  22. Купи барабан. В 30 лет это звучит глупо, но поверь мне, через 10 лет ты скажешь мне спасибо за этот совет. К сельдерею тоже присмотрись.
  23. Жизнь это ручей. Чем старше ты становишься, тем яснее видишь аналогию. Ее можно перейти на коне, в ней можно помыть ноги или увидеть свое отражение. После дождя в ней лучше клюет, а посторонний мужчина может в нее помочиться.
  24. Избегай идиотских советов. Тебе не нужна чужая мудрость, чтобы заниматься своими глупостями.
  25. Больше внимания уделяй здоровью. Ешь здоровую еду, пей здоровую воду, носи здоровую одежду, общайся со здоровыми людьми.
  26. Перед началом любого дела подумай, будешь ли ты считать его таким же важным через 10 лет? Если да, то можешь не торопиться.
  27. Оптимизируй свое время. Ложись пораньше, вставай попозже. Ты успеешь сделать больше, если будешь спешить.
  28. Обязательно выдели 30 минут в день, чтобы смотреть на ковер. Если ковра нет, стена тоже подойдет. В это время тебя не должны беспокоить.
  29. Главное в жизни — это баланс. Обязательно научись ходить по канату, стоять на руках и сидеть на табурете с одной ножкой.
  30. Не трать время на споры с дураками. Ты можешь узнать неприятную правду о себе.


On Dynamic vs. Static typing
усы2
tonsky

Datomic for small businesses
усы2
tonsky
В связи с Datomic-ом, среди часто рекламируемых его достоинств, почему-то пропускают вот что: это чертовски удобная база для маленьких проектов.

Посудите сами:

У него есть in-memory реализация, что идеально для dev setup и тестов. Подключил jar-ку в lein и всё, у тебя есть полноценная база, на которой можешь пилить свое приложение и об остальном пока не думать. Никакого администрирования.

Деплоймент бесплатной версии проще некуда: кроме jvm ничего не нужно, вообще. Никаких компиляций, пакетов, создания схем, юзеров, тейблспейсов и прав доступа. Представьте, что вы делаете небольшой сайт, ну, блог там, или cms. Данных там смешное количество, а разворачивание и тюнинг mysql на сервере несмешная работа.

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

Работать с Datomic можно нативно из кода, это удобно и нет нужды в ORM.

Клиент Datomic это уже умный in-process cache, т.е. при небольшом датасете (а мы говорим о маленьких проектах) данные будут просто лежать в памяти процесса. Если wordpress делает 30 сетевых запросов на страницу (и дохнет без page или хотя бы query cache), то Datomic в аналогичной ситуации вообще в сеть не пойдет. Для маленького проекта — еще минус одна движущаяся часть.

Естественно, всё это с расчетом на вырост: перестало хватать двух серверов — купили платную версию, поставили нормальный storage (dynamo, riak, sql, whatelse) вместо h2 из бесплатного. Код не меняется при этом.

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

без темы
усы2
tonsky
Такой вопрос:

если мне нужно побыстрее и по-безболезнее сделать сайт,

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

и при этом я хочу всю верстку запилить сам,

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

Что лучше всего для этого взять?

Я смотрел WordPress, у него даже простейшие с виду темы это под капотом куча php-кода, и мне как-то даже от админки его грустно. Т.е. это хорошее решение, видимо, когда нужно просто взять чью-то готовую тему (а лучше купить) и запустить на ней веб-сайт.

P.S. спонсор этого поста — vagrantpress.org, без него я бы повесился.

Get that job at XXX
усы2
tonsky

Тут Саша Алексеев рассуждает про найм, и мне тоже захотелось поделиться опытом.

Во второй половине 2013 года мы провели успешную кампанию по расширению штата Эхо. Успешной она оказалась благодаря следующим принципам:

  1. Убрать кота в мешке
  2. Зацепить
  3. Сократить дистанцию
  4. Отфильтровать

«Кот в мешке» — это любая компания, повесившая объявление на hh.ru/moikrug/куда-там-еще. С точки зрения кандидата совершенно непонятно, куда он попадет. Что там за люди (есть ли там люди?), чем они занимаются, от чего у них горят глаза, насколько всё плохо/хорошо/тоскливо. Эта неизвестность очень мешает. У всех написано «интересная работа, молодой коллектив, печеньки» — это ни о чем, стоп-слова на самом деле. Сайты айтишных контор сами знаете, как выглядят.

В Эхо было несколько сотрудников, пишуших в ЖЖ на рабочие темы, у нас был корпоративный блог, из которого кое-что можно было понять, мы выступали на конференциях в Ульяновске и в Новосибирске, какой-никакой гитхаб с опенсорсом. Благодаря усилиям Льва Валкина и ульяновской команды Эхо была очень заметной в ИТ-тусовке Ульяновска и среди студентов. Мы звали к себе на хакатоны, лекции и скайп-посиделки на около-ФП темы.

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

«Зацепить» это примерно про то же самое — кандидат (потенциальный! Он пока даже не думает о смене работы) должен представлять, а что же такого интересного он будет у вас делать. О том, что надо будет работать, догадываются все — а вот чем именно будет эта работа радовать, надо рассказать обязательно. Вместо «у нас на кухне есть кулер» пишите лучше, что у вас есть: горячие темы (облака, high load, ML), свобода в выборе инструментов, 20% side project, etc. У нас, например, даже тестовое задание «цепляло», его хотелось сделать.

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

По идее, на этом этапе к вам уже хочется. Дело-то сделано. Уже где-то есть N людей, которые хотят к вам и которых хотите вы. Осталось подписать бумаги.

У нас дополнительно встала проблема фильтрации — будучи небольшим стартапом, мы искали людей определенного уровня, способных брать и тащить не отдельные задачи, а целые направления. Поэтому мы сделали обязательным входным условием тестовое задание — это серьезный фильтр, зато оно помогало отсеять людей с attiutude «сначала заплатите, а потом я может быть поработаю». У всех, кто его сделал, проблем с «выдавать результат» позже не возникало. Задание непростое, зато work-related, то есть похоже на то, чем нужно будет заниматься. Короче, оно сработало еще и как фильтр по интересам.

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

Устное собеседование тоже было, но там ничего необычного.

В итоге: большой поток кандидатов по сравнению с предыдущим «пассивным» наймом и отсутствие ложно-позитивных срабатываний (все попавшие в Эхо оправдали ожидания на 100-110%). Благодаря этой схеме был почти полностью сформирован Новосибирский офис и серьезно расширен Ульяновский.

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