Дефрагментация мозга. Софтостроение изнутри
Шрифт:
Новоиспечённый инженер после пяти лет обучения, имеющий базовые знания Java, XML и UML, после своего прихода на предприятие и перед началом работы был привлечён в понедельник к чтению публичного отчёта по J2EE v1.4 на 228 страницах.
На шести первых страницах этого отчёта значились ссылки на EJB, JSP, JMS, JMX, JCA, JAAS, JAXP, JDBC, JNDI. Эта новая версия J2EE и веб-служб предполагала знание концепций SOAP, SAAJ, JAX-RPC и JAXR. Каждый из этих акронимов имеет соответствующую специ фикацию.
Спецификация EJB 2.1 – это документ PDF на 640 страницах, который будет прочтён во вторник. Среда будет посвящена чтению документации по сервлетам Servlet 2.4
После месяца интенсивных чтений наш инженер наконец готов начать продуктивную работу. .
Я добавил бы, что указанные в статье оценки как временных рамок, так и продуктивности работы излишне оптимистичны. Но вернёмся к CORBA.
Из небольшого списка известных в тот период открытых реализаций (Orba-cus, MICO, Robin) нами в продукте использовался omniORB. В комплекте к третьей версии выпуска 2000 года шла единственная реализованная служба именования (COS naming services) и библиотека синхронизации потоков – минимум, чтобы просто запустить разработку «с нуля». Впрочем, небольшой команде стартапа этого вполне хватило.
В начале 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>