Re[5]: [Nitra] Почему клинт-сервер?
От: VladD2 Российская Империя www.nemerle.org
Дата: 29.12.17 10:42
Оценка:
Здравствуйте, _Raz_, Вы писали:

_R_>Ну вот ты реально только на первые части фраз внимание обращаешь? Как твой ответ про мою упертость и поддержку ИДЕ в Нитре, связана с "Зачем в Нитре повторять то, что сделано из-за ограничений Electron'а?"


Вот из чего сделан вывод, что сделано "как где-то" или "из-за ограничений Electron-а"?

Предпринимаю последнюю попытку объяснить предпосылки и показать как делается выбор.

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

Какие цели мы имеем?

Цели


1. Многоплатформность и переносимость. Одна из целей Nitra позволить в будущем создавать переносимые решения. На разных платформах имеются разные IDE API которых координально отличаются. Более того у этих IDE отличаются и программные платформы API. Это может быть .Net (для VS и SharpDevelop), Tipe Script/Java Script (для VS Code), Java (для IDEA, Eclipse, NetBeans и еще более 50-и) и нативные API для кучи других IDE.

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

2. Поддержка VS с его 32-битностью. Приоритетной IDE для нас является VS (Microsoft Visual Studio) хотя бы потому, что мы сами ее используем и это основная IDE для .Net-разработки.

У VS есть особенность — она 32-битная. Это значит, что адресное пространство у нас ограничено. В это пространство грузятся интеграции ко всем языкам (включая огромный Разор для C#), а так же плагины вроде ReSharper, которые сами по себе могут отъедать всю память (все адресное пространство) в процессе.

3. Надежность. Nitra — это исходно расширяемая среда. Мы проектируем ее в расчета на то, что когда-нибудь она может быть перенесена на другие платформы. Среди платформ могут быть и небезопасные нативные платформы на основе LLVM или генерации С-кода. Пользовательские расширения могут содержать баги. Застраховаться от вылетов в режиме разработки мы не можем. Но нам нужно как-то защитить код от повреждений в случае некорректной работы пользовательских расширений.

4. Многопоточность. Мы хотим получать преимущества от наличия нескольких процессоров в одной системе. Их число постоянно растет и хотелось бы создать решение, которое будет хорошо масштабироваться. Стало быть мы хотим использовать в IDE-движке и компиляторах многопоточность. При этом наша задача добиться максимального контроля над многопоточной обработкой и при этом не очень пере усложнять код. Использование ручных блокировок, разных async/await-ов хотя и упрощает задачу, но не уберегает от ошибок. Нам же желательно иметь решение, которое было бы сравнимо с однопоточной разработкой по простате, но давало бы нам преимущества многопоточной обработки.

5. Чистота API. Мы хотим добиться максимальной чистоты API нашего движка IDE: четкого отделения движка (по сути являющегося контроллером) от представления, наличия четких мест общения движка с IDE, минимизации API, гарантии того, минимальной связанности движка и внешнего года.

6. Web-интерфейс. Для продвижения языков, да и самой Nitra, нам выгодно реализовать в будущем вариант работы через Web. В идеале мы должны предоставлять простенькую микро-IDE позволяющую человеку не устанавливая ничего на своей машине поиграться с Nitra или любым языком созданным на базе Nitra.

Поиск решения


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

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

Теперь берем каждую из целей и задаемся вопросом реализуем ли она в виде внутри-процессной библиотеки? Уже на вопросе о 32-битном адресном пространстве мы получаем отрицательный ответ. Ряд других целей хотя теоретически и достижимы при реализации в виде внутри-процессной библиотеки, но могут потребовать написания кучи кода для обхода проблем.

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

Даже в 32-битной системе движок Нитры будут иметь собственное адресное пространство не конфликтующее с движками других языков.

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

Работа через Веб сама по себе является клиент-серверным решением, что ложится на выбранный подход 1 в 1.

Остается проверить остальные пункты.

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

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

ЗЫ

Мне кажется, что теперь я разжевал все до мелочей. Все кто способен понять и хочет это сделать, думаю, поняли. Прошу тех кому все еще хочется полезть в бутылку и поспорить просто зачислить меня в клинические идиоты и не посещать данный форум. Я по про прежнему готов отвечать на разумные вопросы. Но очень не хочу повторяться вновь. Это занимает много времени и несет мало пользы.
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Отредактировано 30.12.2017 8:38 VladD2 . Предыдущая версия .
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.