Всем привет. Эта история началась 10 лет назад, когда разработчики сайтов только начали использовать XmlHttpRequest, длилась все эти годы и наконец подошла к завершению. XmlHttpRequest мы использовали немного не так, как его используют все, и теперь хотим поделиться многолетним опытом работы и её результатами. Тема большая, очень многое будет недосказано, но я не могу заранее предположить все вопросы и ответить на них в одной статье. Только на нижеприведённый текст ушло больше недели, возможно лучше и быстрее будет отвечать в комментариях на вопросы, если конечно статью опубликуют. В нашем скромном коллективе меня выбрали писателем этой статьи, я долго отказывался, но в итоге пришлось согласиться, никто больше не хочет. Меня можно сказать заставили.
Как всё начиналось
Изначально никакой проект нами вообще не задумывался. Это были ещё те времена, когда одним из наболевших вопросов при разработке сайтов, был вопрос, включен ли у пользователя javascript и как быть если выключен. Холивары были не только на форумах и в комментариях к статьям, но и в коллективах разработчиков. Тогда у нас и родилась идея написать свой велосипед в виде фреймворка, с помощью которого можно было бы делать одностраничные сайты, которые бы индексировали поисковые системы. Получившийся фреймворк несколько раз модифицировался и в итоге стал первым компонентом Матрицы.
В то время мы удалённо работали на одну московскую фирму, наша задача была создавать, поддерживать и постоянно расширять сеть сайтов для неё, а фреймворком мы занимались в свободное от работы время. Сеть сайтов быстро разрасталась, поддерживать их стало неудобно и мы предложили заказчику разработать систему управления всеми сайтами из одной админки. Нам дали добро на разработку и у нас появилась основа второго компонента Матрицы.
Позже мы объединили несколько небольших проектов в один, а ярлыки вынесли в меню, в виде панели задач, тогда и родилась идея проекта, чем мы и стали заниматься в свободное время. Но мы столкнулись с проблемой прав доступа, которую не могли решить, и забросили проект на несколько лет.
Почему "Матрица"
Представьте на минуточку, что мобильное приложение, либо компьютерная программа — это книга. И вот пользуясь приложением, вы эту книгу листаете от одной странице к другой. Когда запущено несколько приложений, открыто несколько книг. Перед глазами одна, остальные лежат в стороне. Как только вы переключаетесь между приложениями, одну книгу вы откладываете в сторону, а на её месте появляется другая. Операционные системы хранят все книги открытыми, на случай если та или иная вам понадобится.
А теперь рассмотрим дисплей. Он устроен так, что ему совершенно не важно какую из книг показывать и на какой странице она открыта. Дисплей лишь отображает книгу, открытую на определённой странице, не зная какая страница была открыта до этого и какая будет открыта дальше. Он просто констатирует факт, что в данный момент картинка выглядит именно так, не вникая в подробности того, как эта картинка была сгенерирована. Именно по такому принципу и работает Матрица. Она не хранит книги открытыми, переключаясь между ними, она сохраняет информацию о том, какие книги и на каких страницах открыты. И когда нужно переключиться между приложениями, она лишь имитирует смену одной книгу на другую, оперируя одной рабочей областью. Визуальных различий между нативными приложениями и приложениями Матрицы нет, во всяком случае пользователи, не обладающие навыками программирования и не знающие как работают приложения — разницы точно не заметят.
Благодаря этому, Матрица может хранить якобы запущенными десятки приложений, не расходуя при этом вычислительные ресурсы устройства. И хоть это всего лишь имитация, она выполняется идеально и визуально не отличить, хранилось ли приложение свёрнутым или было восстановлено и отображено нужное состояние требуемого приложения. А так как дисплей это всего лишь матрица в защитном корпусе, мы решили что это вполне подходящее название для проекта, даже прикольное.
Виды терминалов
Терминалом может выступать любое устройство с дисплеем, сенсорным или с устройством ввода информации, браузером на борту, подключением к интернету, и питанием. Это компьютеры, смартфоны, магазинные терминалы, да хоть часы, если в них есть Firefox.
О приложениях и реактивном PHP
Возможно называть описываемый в статье стиль программирования реактивным неправильно, но отчасти это верно, так как программирование происходит асинхронными потоками, а это является одним из определений реактивного программирования.
Хранить состояния приложений оказалось непросто. Обычно реактивные приложения это программирование клиентских скриптов реагировать на события и отражать изменения, при необходимости обращаясь к серверу за данными или для отправки данных на сервер, а весь контроль за поведением приложения осуществляется самим клиентом. Но нашей задачей стояло научить сервер знать о каждом малейшем изменении на клиенте, чтобы иметь возможность отслеживать каждое действие, запоминать его и восстанавливать по требованию. И мы стали использовать связку подходов, совместив клиент-серверное программирование с реактивным, научив PHP "уметь" javascript.
Пришлось полностью уйти от ссылок, заменив переходы по ссылкам генерацией событий. Для этого мы разработали небольшую библиотеку на javascript и серверную функцию event(), принимающую десяток параметров в виде массива. Это стало полноценной заменой тегу <a> и его атрибуту href="" при программировании интерфейсов, только данный инструмент получился намного мощнее по функциональности. Практически всё, что написано на языке PHP, уже является наработками для приложений Матрицы. Нужно лишь подключить javascript файл в html документ, а в код реализацию функции event(), но в Матрице оба этих действия делаются автоматически, поэтому любой ваш PHP код умеет быть реактивным, можно сказать прямо из коробки, нужно лишь подправить ссылки и PHP сайты превращаются в приложения. И теперь, для изменения состояния приложения, вместо переходов по ссылкам, пишется <tagname onevent="<?php echo event($param); ?>">, где onevent — это onclick, onsubmit, onchange, onblur, onfocus, onmouseover, onmouseout и т.д. А функция event() уже сама программирует клиентскую часть за вас. Таким образом у PHP появляются свои "глаза" и "руки" на клиенте, PHP знает всё, что там происходит. В результате мы получаем реактивное, событийное приложение, работающее по похожему принципу, что и при программировании приложений полностью клиентскими скриптами. Только программируем клиент не вручную, а перекладываем часть этой работы на сервер, облегчая себе задачу и позволяя серверу знать, что происходит с приложением.
Можно провести некую аналогию с промисами, только тут не клиент, а сервер обещает, что он всё изменит когда нибудь в будущем, если оно наступит. Там и сям поменяет одно, туда вставит другое, сюда третье, а ещё и запомнит это состояние у себя, чтобы если произойдёт переход в другое приложение, а потом обратно, восстановить ту же самую ситуацию в точности. Уровень сложности интерфейса прямопропорционален экономии трафика и зависит уже от разработчиков. Можно реализовать как точечно изменяющийся интерфейс, так и просто менять готовые страницы имеющегося проекта, практически его не модифицируя. Что касается уровня сложности написания таких приложений, то собрать качественный интерфейс сможет даже школьник. Всё настолько просто, нужно лишь отбросить все стереотипы и взглянуть на программирование под другим углом. Даже если бы было сложно разобраться в способе программирования, программистов сложность ещё никогда не останавливала. К тому же если сравнивать браузерные веб-сервисы и мобильные приложения, то в большинстве случаев мобильные приложения намного примитивнее устроены, так как рабочая область мобильных устройств небольшая, просто негде всю эту сложность отрисовывать, приложения разбиты на фрагменты с простой функциональностью, а строить такие приложения под Матрицу вообще плёвое дело.
Принцип работы Матрицы
Регистрационный сервер на схеме не указан, это отдельный сервер, который при регистрации пользователя в системе соединяется с сервером S2, передавая ему данные. Сервер S2 обращается к серверу S1, создавая на нём хостинг-аккаунт и записывает туда пару файлов, идентифицирующих аккаунт, после чего возвращает на регистрационный сервер данные для входа в систему.
-
Пользователь инициирует любое событие на клиенте, заранее сгенерированное функцией event() и отданное на клиент в прошлый раз или при первом входе. Клиентская часть формирует и выполняет асинхронный запрос на сервер S1.
-
Сервер S1 принимает запрос и отправляет часть запроса на обработку серверу S2, который производит вычисления, формирует некоторые данные, необходимые для корректной работы приложений и функции event(). Сервера S1 и S2 находятся в локальной сети и данная процедура происходит мгновенно. Это сделано для того, чтобы вынести ответственного за безопасность пользовательского аккаунта за пределы сервера S1. Сервер S2 не принимает ни какие пользовательские данные, чем бы они ни были, а передаёт лишь те, которые отвечают за работу приложения как интерфейса.
-
Сервер S2 отдаёт сгенерированные данные обратно серверу S1, и на основании полученных инструкций, на сервере S1 формируется php скрипт для исполнения. Тут и происходит вся магия. Скрипт указанного контроллера приложения подключается уже в вычислительный процесс, в котором ещё до его подключения уже были выполнены необходимые действия, подключены необходимые классы и функции, и уничтожено всё лишнее, ведь по сути скрипту передаётся полное управление сервером. Даже просканировав сервер и все переменные окружения, приложение поймёт, что здесь ничего нет и не было, кроме всего необходимого для исполнения контроллера приложения.
a,b) Если приложение требует подключение к внешнему источнику С1 (API), за данными, или для передачи данных туда, скрипт выполняет эти действия.
с) Ответ приходит на клиент и изменяет его до требуемого приложением состояния, как в соответствии с указанными ранее инструкциями, так и может получить дополнительные корректировочные указания с сервера.
d,e) Иногда требуются дополнительные кросcдоменные асинхронные запросы или исполнение js сценариев, подгрузка графики и прочих внешних элементов. d,e) уже не попадают в учёт изменений состояния приложений, любые изменения на клиенте, не проходящие через сервер S2 никак не контролируются, не регистрируются и не сохраняются.
Это всё касается общего принципа работы. Теперь о том, как работают сами приложения.
Для того чтобы создавать приложения, необходимо быть зарегистрированным в системе. Приложения создаются через встроенное по умолчанию приложение «IDE». IDE конечно сильно громкое название, поле для кода без подсветки синтаксиса, дизайн деревенский, года так 2009, если не 2008-го, для нас он не имел ни какого значения, так как проект мы вообще не планировали запускать или кому-то показывать, это всегда был лишь прототип, наш тренировочный полигон. Просто цель была не удобный редактор кода написать, а реализовать задуманную идею, решая более сложные задачи, при этом не отвлекаясь на сопутствующие мелочи.
Код любого создаваемого приложения делится на составляющие. Три типа контроллеров, модели, html шаблоны, javascript, css, графика, службы и инсталлятор.
Скрипт, который должен отработать по указанному URL, разработчиками приложений не начинается и не заканчивается, что происходит до выполняемого сценария приложению знать не надо, но важно отметить, что сценарий приложения нельзя останавливать функциями exit(), die() или ошибками работы скрипта. Это всё ломает корректную работу приложения, чем пользователь будет огорчён, поэтому первым двум функциям нужен любой альтернативный алгоритм, а фатальные ошибки элегантно вырезаются из вычислительного процесса, это вообще элементарно, но потребует внимания при написании участков, которые могут дать сбой.
Данные из форм записываются на сервер S2. После публикации приложения оно сразу же появляется в каталоге. Категоризацией к сожалению тоже не занимались, это недоделка… При создании приложений категория присваивается, но выводятся все одним списком. Выглядит это примерно так.
После нажатия на кнопку «Установить» сервер S2 создаёт изолированное от других приложений пространство на сервере S1 и записывает туда файлы устанавливаемого приложения. С правами доступа и была основная проблема, мы только в этом году нашли решение, почему и решили продолжить работу над проектом. Если одно приложение может атаковать другое хоть одним способом, такие приложения никто не будет писать и пользоваться ими тоже никто не будет. На сервере ни у одного приложения железно нет возможности что-то узнать о другом. А вот с клиентом пришлось попотеть. При запуске некого приложения, оно регистрируется сервером S2 как активное. При попытке обратиться на URL другого приложения, текущее приложение деактивируется и становится нерабочим, после чего происходит процедура активации запрошенного приложения. Оба приложения будут неактивными до тех пор, пока не произойдёт перезагрузка браузера, очищающая скрипты текущего приложения. Необходимо лишь гарантированно произвести редирект и принудительную перезагрузку документа, после чего активированное приложение запускается как единственное существующее.
Цель статьи
Самый главный вопрос этого обзора, есть ли смысл в таком проекте и стоит ли продолжать заниматься им или нет. Работа над проектом отнимает много времени, заниматься им в полную силу мало кто хочет, всем некогда, у всех семьи и обязательства. Я один всё это просто не тяну, слишком большой объём работ разных направлений. Так что основная цель этой статьи — узнать есть ли смысл в запуске и если есть, найти партнёров, заинтересованных в этом помочь.
Вот список всех проблем и недоделок:
Проблема 1:
Ключевая проблема касается терминала "смартфон". Пользоваться приложениями Матрицы со смартфона через браузер нам кажется будет неудобно. Возможно лучше сделать приложение с аналогичной функциональностью, которое будет открывать нужный URL и разворачиваться на весь экран. Например, на основе хромиума, по типу Яндекс браузера. В общем мы далеки от мобильной разработки, эта область для нас тёмный лес.
Версия для ПК особого значения для нас не имеет, мы вообще не видим в ней людской потребности, на наш взгляд проект может иметь смысл только в мобильных устройствах. Но работоспособность версии для ПК обязательна в целях удобства разработчиков, так как писать код на мобильном устройстве крайне неудобно. Но есть и другие проблемы со смартфонами. В частности визуальное устройство интерфейса управления. Матрица, имитируя мобильную операционную систему должна обладать аналогичной функциональностью, а это экран ярлыков приложений, экран списка запущенных и свёрнутых приложений, хранящих своё состояние, каталог приложений и возможно настройки. Повторять кнопки телефона выглядит как-то нелепо, хоть вверху меню расположи, хоть внизу. К тому же это меню отнимает кусок области экрана. А кнопка "назад" вообще неуместна, так как повторяет функциональность родной кнопки "назад" устройства. Мы считаем что быть может лучше сделать выдвижное меню слева, скрытое или в виде тонкой полоски на всю высоту. Выдвинув это меню, пользователь увидит список запущенных приложений, в том числе и пункты "установленные приложения", "каталог приложений" и "настройки" в самом верху, и отсортированные по дате последнего использования запущенные приложения. То есть мы хотим чтобы Матрица была доступна на всех мобильных устройствах, но со схемой интерфейса управления так и не определились. Ну посмотрите на скриншоты, разве это нормально выглядит? Ну правый вариант ещё более менее можно попробовать реализовать, заменив кнопку назад на иконку настроек. Что касается уведомлений, то их проще отдавать в систему отображения уведомлений самого телефона, чтобы ещё этим место не отнимать.
В любом случае мы хотим решить следующую задачу. Раньше, в сети по сути главенствовали сайты, но потом появились мобильные телефоны и часть повседневных задач стали решаться с помощью мобильных приложений. Теперь пользователи мобильных устройств используют преимущественно те сервисы, которые есть в маркетах мобильных устройств. То есть если одни и те же услуги предоставляют двадцать компаний, а мобильные приложения создали только пять из этих компаний, в большинстве случаев мобильный рынок ограничивается услугами этих пяти компаний. Не все компании могут позволить себе нанять разработчиков приложения, это дорого, сложно, требует поддержки, постоянных обновлений, можно сказать, что бизнесу к отделу веб разработчиков требуется ещё и отдел разработчиков мобильных приложений. Проект Матрица позволит тому же штату веб разработчиков создать и мобильное приложение, расширяя пользователям мобильных устройств выбор поставщиков услуг, а поставщики услуг избегают затрат на разработчиков нативных мобильных приложений, при этом получая возможность предоставлять услуги пользователям мобильных устройств. Именно это направление мы видим самым перспективным, так как мы, создав однажды приложение под мобильные устройства, избавляем от этого множество сфер услуг, нуждающихся в мобильном приложении. Поэтому сами остро нуждаемся в помощи по проектированию и разработке мобильного приложения "Матрица".
Проблема 2:
Организация сервера S1 это не менее важная проблема. На данный момент регистрация устроена так, что после регистрации на экране написан код файлов .htaccess и index.php. Этот код мы копируем в соответствующие файлы на локальный сервер, таким образом запуская новый аккаунт. Но для пользователей не владеющих навыками программирования это не подходит. Для них необходимо регистрировать
Проблема 3:
Организация сервера S2 процедура не сложная, всё что нужно, это организовать достаточную вычислительную мощность, чтобы проект не упал. Сервера S1, S1 и регистрационный сервер обязательно должны находиться в одной локальной сети, чтобы внешний доступ к был только к регистрационному серверу и серверу S1, а эти сервера уже локально соединялись с сервером S2, недоступному для обращения к нему больше никому извне. Мы хотим позиционировать Матрицу как очень безопасную ОС, используя которую, пользователям не нужно будет переживать о том, что какое-либо приложение причинит ущерб, украдёт данные, или сервер управляющий их аккаунтами будет скомпрометирован. Вся схема работы Матрицы спроектирована так только для того, чтобы устроить из сервера S2 просто бункер, потому что взлом этого сервера равносилен взлому всех пользователей системы, что разумеется неприемлемо.
Проблема 4:
Документация по программированию не готова тоже. Я даже не знаю как её писать, мне и так всё понятно. Описать одну PHP функцию и привести примеры не сложно. Сложно передать как нужно мыслить, создавая интерфейс. Мы такой стиль программирования используем давно и всё происходит интуитивно. Сервер S2 делает за приложение половину того, что все пишут из проекта в проект, сначала это может несколько сбить с толку.
Проблема 5:
Правильное совмещение версий терминалов и переключение между ними, тоже ещё тот вопрос. Так как создание приложений возможно только путём добавления кода через формы приложения "IDE", то нужна возможность создавать приложения под мобильные устройства с компьютера. При чём компьютерная версия должна подразумевать возможность имитировать планшеты и смартфоны, для просмотра этих версий в браузере в том виде, в котором они будут отображаться на устройствах. С другой стороны, мобильные приложения сами определяют планшет это или смартфон, может и не стоит так заморачиваться, но пока вопрос открыт, можно же помочь разработчикам в этом, автоматически подстраивая версию под устройство.
Проблема 6:
Авторизация в приложения и авторизационные токены тоже важный вопрос, на эту тему мы только размышляли. Так как Матрица является инородной для любого устройства, несложно обеспечить функциональность, при которой авторизация в приложениях не будет привязана к конкретному устройству. Установив с одного устройства несколько приложений и авторизовавшись в них, пользователь может зайти в свой аккаунт с другого устройства и не только сразу видеть список установленных приложений, хранящих своё последнее состояние, но и быть авторизованным в них. Во всяком случае устройство системы безопасности это позволяет реализовать.
Резюмируя
Итого мы имеем проблему с дизайном интерфейса и самим приложением мобильного терминала, с вычислительными мощностями и их настройкой, документацией по разработке приложений и с алгоритмом реализации аутентификации в приложениях с различных устройств, остальное, не считая пары мелочей, готово и прекрасно работает. Вот по этим направлениям мы ищем партнёров, сами мы этот проект если и запустим, то очень не скоро.
Возможно статье не место на Хабрахабре, так как проект не запущен, но где ещё найти партнёров, чтобы вместе запустить проект — мы не знаем. Запостить этот текст на форумах, которые просматривает по 100 человек в неделю, результата скорее всего не даст. Пусть лучше эту статью заминусуют и пусть у нас ничего не чего не получится с запуском, чем не попробовать этого сделать вообще. В конце концов мы ничего не теряем. Если это окажется ненужным, мы хотя бы бросим заниматься тем, что зря отнимает наше время.
Дописывать статью можно бесконечно, дополнить есть много чем, но если постоянно это делать, так я не скоро опубликую этот текст. Если не вдаваться в детали механизмов, в целом суть проделанной нами работы должна быть понятна. Извиняюсь за опечатки и оговорки, если таковые имеются. Будем рады любой помощи, советам, критике, и вопросам, на которые вы бы хотели получить ответы.
Автор: RomanBolgov