При создании одностраничного приложения или мобильного приложения обычно требуется реализовать веб-API (REST или GraphQL) для соединения внешнего и внутреннего интерфейса. Технически это не очень сложно, но имеет неприятные последствия.
Представьте себе две планеты. Планета «фронтенд» говорит на JavaScript, а планета «бэкэнд» также говорит на JavaScript или любом другом продвинутом языке.
Теперь предположим, что этим планетам необходимо активно сотрудничать, чтобы сформировать единое целое, называемое «приложением».
К сожалению, планеты не могут напрямую общаться друг с другом, используя свой родной язык, и им приходится полагаться на стороннюю программу, называемую «веб-API», которая говорит на менее сложном языке.
Действительно, язык большинства веб-API ограничен комбинацией URL-адресов, нескольких HTTP-глаголов (GET, POST, DELETE и т. д.) и JSON.
Веб-API, использующие GraphQL, являются более продвинутыми, но они все еще далеко отстают от возможностей такого языка программирования, как JavaScript:
- Парадигма программирования бывает процедурной или функциональной (без объектно-ориентированного программирования).
- Поддерживаются только самые основные типы (забудьте о Date, Map, Set и т. д.).
- Отсутствует понятие ссылки (объекты можно передавать только по значению).
- Размещение рудиментарного языка между интерфейсом и сервером добавляет много шаблонов и портит опыт разработки.
Другая проблема заключается в том, что веб-API - это дополнительный уровень, о котором нужно беспокоиться. Он должен быть спроектирован, реализован, протестирован, задокументирован и т. д.
Но хуже всего то, что уровень API обычно вынуждает ухудшать качество кодовой базы. Действительно, довольно сложно сохранить код чистым и связным, когда интерфейс и сервер разделены веб-API.
А теперь представьте, что мы можем избавиться от веб-API. Представьте себе, что интерфейс может напрямую общаться с сервером, используя свой родной язык. Было бы здорово?
Хорошая новость в том, что это возможно сегодня благодаря набору библиотек под названием Layr.
В Layr интерфейс и бэкэнд физически разделены (они работают в разных средах), но логически воссоединены (как если бы они находились в одной среде).
Как это работает?
Бэкэнд состоит из одного или нескольких классов, некоторые из их атрибутов и методов явно доступны во внешнем интерфейсе.
Внешний интерфейс генерирует некоторые прокси-серверы для внутренних классов и может использовать эти прокси, как если бы они были обычными классами JavaScript.
Под капотом Layr полагается на механизм RPC. На первый взгляд это можно рассматривать как нечто вроде CORBA, Java RMI или .NET CWF.
Но Layr кардинально отличается:
- Это не распределенная объектная система. Бэкэнд Layr не имеет состояния, поэтому в стеке нет общих объектов.
- Он не включает в себя шаблонный код, сгенерированный код, файлы конфигурации или артефакты.
- Он использует простой, но мощный протокол сериализации (Deepr), который обеспечивает уникальные функции, такие как цепной вызов, автоматическое пакетирование или частичное выполнение.
- Layr начинает свой путь с JavaScript / TypeScript, но проблема, которую он решает, универсальна, и ее можно перенести на любой объектно-ориентированный язык.
Давайте реализуем классический пример «Counter», чтобы увидеть, как выглядит создание полнофункционального приложения с помощью Layer.
Сначала мы реализуем «модель данных» и «бизнес-логику» в бэкэнде:
// backend.js
import { Component, primaryIdentifier, attribute, method, expose
} from '@layr/component';
import {ComponentHTTPServer} from '@layr/component-http-server';
class Counter extends Component { // We need a primary identifier so a Counter instance // can be transported between the frontend and the backend // while keeping it's identity @expose({get: true, set: true}) @primaryIdentifier() id;
// The counter value is exposed to the frontend @expose({get: true, set: true}) @attribute() value = 0;
// And the "business logic" is exposed as well @expose({call: true}) @method() increment() { this.value++; }
}
// Lastly, we serve the Counter class through an HTTP server
const server = new ComponentHTTPServer(Counter, {port: 3210});
server.start();
Весь этот код только для простого примера «счетчика»? Конечно, это кажется излишним, но на самом деле мы реализовали полноценный бэкэнд с моделью данных, некоторой бизнес-логикой и HTTP-сервером, раскрывающим все это.
Теперь, когда у нас есть бэкэнд, мы можем использовать его из внешнего интерфейса:
// frontend.js
import {ComponentHTTPClient} from '@layr/component-http-client';
(async () => { // We create a client to connect to the backend server const client = new ComponentHTTPClient('http://localhost:3210');
// We get a proxy to the Counter backend class const Counter = await client.getComponent();
// Lastly, we consume the Counter const counter = new Counter(); console.log(counter.value); // => 0 await counter.increment(); console.log(counter.value); // => 1 await counter.increment(); console.log(counter.value); // => 2
})();
Что тут происходит? При вызове метода counter.increment () значение счетчика увеличивается. Обратите внимание, что этот метод не существует во внешнем интерфейсе. Он реализован в серверной части и поэтому выполняется в этой среде. Но с точки зрения внешнего интерфейса фактическая среда выполнения не имеет значения. Тот факт, что метод выполняется удаленно, можно рассматривать как деталь реализации.
Класс Counter во внешнем интерфейсе может быть расширен для реализации функций, специфичных для внешнего интерфейса. Вот пример того, как переопределить метод increment () для отображения сообщения, когда счетчик достигает определенного значения:
class ExtendedCounter extends Counter { async increment() { // We call the `increment()` method in the backend await super.increment();
// We execute some additional code in the frontend if (this.value === 3) console.log('The counter value is 3'); } }
}
Вот как это выглядит, когда фронтенд и бэкэнд воссоединяются.
В чем подвох?
Зачем все создают веб-API, если мы могли бы обойтись без них?
Есть веская причина для реализации веб-API - это когда вы хотите предоставить свой бэкэнд стороннему разработчику. Но давайте будем честными, подавляющее большинство приложений не имеют этого требования. И если окажется, что вам нужен веб-API, его можно добавить позже, продолжая использовать подход «без API» для всех ваших внутренних нужд.
Вывод
Удаление веб-API позволяет намного быстрее создавать полнофункциональное приложение, одновременно повышая качество вашей кодовой базы.
Еще один важный аспект - опыт разработки. Поскольку интерфейс и серверная часть больше не разделены веб-API, вы получаете ощущение, подобное разработке автономного приложения, и это намного веселее.
0 комментариев
Добавить комментарий