Чтение онлайн

ЖАНРЫ

Дефрагментация мозга. Софтостроение изнутри
Шрифт:

В начале 2000-х в ИТ-отрасли разразился кризис лопнувшего пузыря интернет-компаний, продвигать сложные и дорогие инфраструктуры, а коммерческие реализации CORBA стоили порядка тысячи долларов за рабочее место, стало очень трудно. Постепенно из кустов начали выкатывать на сцену рояль веб-сервисов, который из-за проблем с CORBA должен был стать новой платформой интеграции служб и приложений в гетерогенной среде. Концепции быстро придумали многообещающее название СОА. Надо сказать, что рояль не стоял без дела и в кустах: разработка веб-служб и развитие XML велись в конце 1990-х и активно продолжились в 2000-х годах. Поскольку это была технология, хотя и весьма базового уровня, но относительно простая, дешёвая и открытая не только на уровне спецификаций, но и в виде множества

реализаций.

Говоря о базовом уровне технологии, я имею в виду не столько отсутствие сравнимой с CORBA функциональности и номенклатуры служб и средств [80] , сколько необходимость программистам самим надстраивать над этим базисом многое из того, что было даже в самом минимальном варианте CORBA.

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

В CORBA сессии поддерживались средой без дополнительных усилий. Если в частных случаях возникали вопросы нагрузки на поддержку соединений при большом количестве клиентов, они решались так же просто, как и в среде СУБД: приложение самостоятельно отсоединялось от сервера, выполнив пакет необходимых запросов. При желании нетрудно было также организовать и принудительное отсоединение по истечении заданного периода пассивности. Но для корпоративной службы, напомню, речь идёт обычно о десятках и сотнях активных сессий, поддержка которых в большинстве случаев укладывается в ресурсы серверов.

Неприятным следствием отсутствия сессий стала невозможность поддержки транзакций при работе с веб-службами. Для решения проблемы в рамках ООП необходим шаблон «Единица работы» ( unit of work ), суть которого в передаче веб-службе сразу всего упорядоченного множества объектов, подлежащих сохранению в управляемой сервером транзакции.

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

Давайте сравним близкий к реальному псевдокод на сторонах клиента в рамках CORBA с псевдокодом в среде веб-служб. При поддержке сессии все достаточно прозрачно и не нуждается в комментариях.

Псевдокод транзакции в среде CORBA

CosTransactions.Current current = CosTransactions.CurrentHelper.Narrow(

orb.ResolveInitialReferences("TransactionCurrent"));

current.Begin;

try

{

store1.Remove(product, quantity);

store2.Append(product, quantity);

current.Commit;

}

catch (Exception e)

{

current.Rollback;

ShowError("Ошибка выполнения операции: " + e.toString);

}

В среде веб-служб в программе-клиенте приходится надстраивать абстракции DTO [81] . А в серверном приложении, где используются соединения, например, с СУБД или монитором транзакций, необходимо фактически дублировать предыдущий код с раскруткой объекта – единицы работы (unit of work) в реальную транзакцию.

Псевдокод транзакции в среде веб-служб

StoreServiceClient storeServiceClient = new StoreServiceClient(url);

StoreOperationDTO operation1 = storeServiceClient.CreateOperation(store1.Id);

operation1.Type = StoreOperations.Remove;

operation1.ProductId = product.Id;

operation1.Quantity = quantity;

StoreOperationDTO operation2 = storeServiceClient.CreateOperation(store2.Id);

operation2.Type = StoreOperations.Append;

operation2.ProductId = product.Id;

operation2.Quantity = quantity;

UnitOfWork uow = new UnitOfWork;

uof.RegisterDirty(operation1);

uof.RegisterDirty(operation2);

try

{

storeServiceClient.ProcessOperations(uow);

}

catch (Exception e)

{

ShowError("Ошибка

выполнения операции: " + e.toString);

}

Вторым «упрощением» стал переход от понятных прикладному программисту деклараций интерфейсов объектов и служб на языке IDL [82] к WSDL [83] – описаниям, ориентированным, прежде всего, на обработку компьютером. Сравним декларации складской службы, возвращающей по запросу текущее количество товарных позиций.

Декларация службы в CORBA IDL

module StockServices

{

typedef float CurrentQuantity;

struct QuantityRequest

{

string stockSymbol;

};

interface StockInventoryService

{

CurrentQuantity getCurrent(in QuantityRequest request);

};

};

Декларация службы в WSDL

<?xml version ="1.0" encoding ="utf-8"?>

<definitions name ="StockInventoryService"

xmlns: sqs ="http://mycompany.com/stockinventoryservice.wsdl"

xmlns: sqsxsd ="http://mycompany.com/stockinventoryservice.xsd"

xmlns: soap ="http://schemas.xmlsoap.org/wsdl/soap/"

xmlns: wsdl ="http://schemas.xmlsoap.org/wsdl/"

xmlns: xsd ="http://www.w3.org/2000/10/XMLSchema">

<wsdl: types>

<xsd: element name ="CurrentQuantity">

<xsd: complexType>

<xsd: all>

<xsd: element name ="stockSymbol" type ="string"/>

</xsd: all>

</xsd: complexType>

</xsd: element>

<xsd: element name ="CurrentQuantity">

<xsd: complexType>

<xsd: all>

<xsd: element name ="quantity" type ="float"/>

</xsd: all>

</xsd: complexType>

</xsd: element>

</wsdl: types>

<xsd: element name ="CurrentQuantity">

<xsd: complexType>

<xsd: all>

<xsd: element name ="quantity" type ="float"/>

</xsd: all>

</xsd: complexType>

</xsd: element>

</wsdl: types>

<wsdl: message name ="getCurrentInput">

<wsdl: part name ="body" element ="sqsxsd: CurrentQuantity"/>

</wsdl: message>

<wsdl: message name ="getCurrentOutput">

<wsdl: part name ="body" element ="sqsxsd: CurrentQuantity"/>

</wsdl: message>

<wsdl: portType name ="StockInventoryServicePortType">

<wsdl: operation name ="getCurrent">

<wsdl: input message ="sqs: getCurrentInput"/>

<wsdl: output message ="sqs: getCurrentOutput"/>

</wsdl: operation>

</wsdl: portType>

<wsdl: binding name ="StockInventoryServiceSoapBinding"

type ="sqs: StockInventoryServicePortType">

<soap: binding style ="document" transport ="http://schemas.xmlsoap.org/soap/http"/>

<wsdl: operation name ="getCurrent">

<soap: operation soapAction ="http://mycompany.com/getCurrent"/>

<wsdl: input>

<soap: body use ="literal"/>

</wsdl: input>

<wsdl: output>

<soap: body use ="literal"/>

</wsdl: output>

</wsdl: operation>

</wsdl: binding>

Поделиться с друзьями: