Эта статья призвана помочь тем, кто хочет понять, как работают распределенные объекты.
Распределенные объекты велики, сложны и скучны. Люди, работающие с распределенными объектами, тоже велики, сложны и скучны. Они используют никому непонятные слова, вроде "полиморфный метод", в надежде на то, что вы оставите их в покое и больше не будете приставать. Но все же мы попытаемся обсудить этот сложный вопрос и поговорим кое о чем маленьком, простом и любопытном - о гномах.
ГНОМЕНКЛАТУРА
Гном - это мохнатое маленькое полезное существо. У разных видов гномов разные обязанности. Гном, сообщающий время, например, может сказать вам, который час. Однако вы должны знать, как его спросить. Вопрос "Сколько там натикало?", гном, если он запрограммирован отвечать только на вопрос "Который час?", просто проигнорирует.
Какую задачу выполняет гном, определить не так сложно. Гномы носят с собой визитные карточки с указанием титула. Зная титул гнома, вы можете обратиться к описанию основных заданий, чтобы определить, какие задачи гном с этим титулом может выполнять и как к нему надо обращаться.
Теперь вы должны навести порядок среди гномов. Пусть, например, гном по имени Квик следит за временем. Если попросить Квика передвинуть время на час назад, а затем спросить Квака, другого гнома, сообщающего время, который сейчас час, то вы вряд ли получите верный ответ. Квик и Квак отвечают за различные часы. Если вы попросили Квика перевести время, то тогда лучше всего спрашивать время именно у него.
Иногда гномы находятся в услужении сразу у нескольких человек. Представьте, что семейство гномов с фамилией checkBook ведает балансом корпоративных чековых книжек. Эти гномы знают, как производить такие операции, как writeCheck, makeDeposit и getBalance. Если вы и я работаем в независимых компаниях, то гномы, управляющие чековой книжкой, будут, скорей всего, разными. При работе же в одной компании для расчета баланса чековой книжки предпочтительнее использовать одного и того же гнома, что, кстати, не так просто, как кажется. Предположим, вы и я работаем в разных зданиях. Если гном живет в моем здании, то он не доступен вам. Если гном находится в вашем здании, то он не доступен мне.
Один из способов решения этой проблемы - каждому из нас обзавестись собственным посредником гнома checkBook. Посредник гнома checkBook делает все то же самое, что и гномы checkBook, но менее прямым способом. Посредник, например, не знает, как составить баланс чековой книжки, вместо этого он обращается к настоящему гному checkBook, а тот подсчитывает баланс по его просьбе. Умение посредника гнома checkBook состоит вовсе не в способности работать с чековой книжкой, а в способности общения с гномом checkBook в другом здании.
Правила, лежащие в основе взаимоотношений между посредниками и гномами checkBook, довольно просты - данный посредник гнома checkBook может общаться с одним и только с одним гномом checkBook; установленные отношения между ними уже неизменны.
Несмотря на то что посредник гнома checkBook общается только с одним гномом checkBook, сам гном checkBook может общаться с любым числом посредников. Иными словами, число посредников может быть больше числа гномов. Давайте теперь посмотрим, как эти гномы работают вместе.
Пусть у нас есть гном из семейства checkBook по имени Чокси и два его посредника Фэнси и Фейм. Предположим, мы с вами хотим работать с одной и той же чековой книжкой, но в различных зданиях, а это значит, что нам придется пользоваться услугами Чокси совместно. Но Чокси просто гном checkBook, а гномы checkBook не знают, как общаться на больших расстояниях. Так что, по крайней мере, один из нас вынужден будет остаться не у дел.
Решение состоит в том, чтобы каждый из нас обзавелся посредником гнома checkBook - у вас Фейм, у меня Фэнси. Мы оба даем указания нашим посредникам передать запрос Чокси. Теперь, когда я прошу Фэнси выписать чек writeCheck, Фэнси обращается к Чокси и просит его выполнить writeCheck. Когда вы просите Фейма подсчитать баланс, то он обращается к Чокси и просит его выполнить getBalance. При вычислении баланса Чокси учитывает выписанный мной чек, потому что на деле только он имеет на то право.
Все это хорошо, однако здесь есть одна проблема. Чокси и другие ему подобные хорошо знают свое дело, но они очень наивны при взаимоотношениях с реальным миром. В частности, они не имеют ни малейшего представления о том, как общаться на большом расстоянии, и отвечают только на прямое непосредственное обращение. И если Фэнси и Фейм знают, как общаться на больших расстояниях, то Чокси этого не умеет.
Любая проблема в распределенных системах может быть решена за счет привлечения еще одного гнома. Поэтому пусть Дракс будет гномом-привратником, причем Дракс живет сразу за дверьми Чокси. Привратники знают, как общаться с посредниками и как напрямую обращаться к обычным гномам.
Теперь, когда все гномы собрались вместе, давайте посмотрим, как они работают.
Допустим, я хочу выписать чек и прошу об этом Фэнси. Фэнси упаковывает всю необходимую информацию и отправляет ее Драксу. Дракс вскрывает пакет и просит Чокси выписать чек, передав ему всю информацию, которую я сообщил Фэнси. Чокси считает Дракса достойным собеседником (никаких телефонов!) и поэтому удовлетворяет его просьбу. Он сообщает ответ Драксу, тот в свою очередь упаковывает его и отправляет назад Фейму, и уже Фейм предоставляет его вам.
Я, как пользователь, хочу выписать чек и не хочу знать о посредниках и привратниках, не говоря о дистанционной связи. С моей точки зрения, именно это я и делаю. Обращаюсь к Фэнси с просьбой выписать чек. То, что Фэнси звонит Драксу, Дракс спрашивает Чокси, Чокси отвечает Драксу, а Дракс передает информацию назад Фэнси, меня совершенно не касается.
На самом деле, мне даже незачем знать о существовании посредников вообще. С тем же успехом я могу считать Фэнси обычным гномом из семейства checkBook. А почему бы и нет? Он делает все, что положено делать гномам checkBook. Он может выписывать чеки, вносить денежные суммы и составлять баланс. Что еще мне от него надо?
Чокси - хороший пример удаленного гнома. Тот факт, что он удаленный, дает возможность пользоваться услугами, необходимыми и вам и мне для ведения дел совместно. Однако необходимо иметь в виду, что восприятие зависит от точки зрения смотрящего. На наш взгляд, Чокси - удаленный гном. Но, с точки зрения Чокси, он обычный гном checkBook. Он может и writeCheck, и makeDeposit, и getBalance. Если вы спросите, то он сделает это для вас. Если Дракс его попросит, то он сделает это для Дракса. Ему нет дела.
ПРОИСХОЖДЕНИЕ ГНОМОВ
Мы обошли вниманием один вопрос: откуда берутся гномы?
Гномы рождаются специальным видом гномов - мастерами. Мастеров столь же много, сколь и гномов. Данный вид мастеров знает, как создать данный вид гномов. Например, мастер checkBook создает гномов checkBook, а мастер посредников checkBook создает посредников гномов checkBook.
Все мастера создают гномов по-разному. Как нам узнать, как использовать данный вид мастеров? Так же, как мы узнаем о том, как использовать любого другого гнома. Попросив у него визитку, мы можем найти его титул в описании заданий и выяснить, какие задачи выполняет мастер и как надо сформулировать свою просьбу.
Весьма разумно, что мы просим разных мастеров при создании несхожих гномов. Например, пожелав иметь своего собственного гнома checkBook, я просто прошу мастера checkBook: "Сделай гнома checkBook". Однако если мне нужен посредник гнома checkBook для связи с Чокси, я попрошу мастера по созданию посредников checkBook: "Сделай гнома-посредника checkBook и свяжи его с Чокси".
В ПОИСКАХ НУЖНОГО ГНОМА
Совместное пользование услугами гномов поднимает целый ряд вопросов. Один из них это нахождение нужного вам гнома. Возьмем, например, случай, когда Чокси работает в здании, где много других таких же гномов. Помимо Чокси это и Чаклс, и Чигзл, и Чаффер, и Чантилли, и сотни других. Как я могу узнать, что обращаюсь к Чокси, а не к Чиксу? Если я по ошибке свяжу моего посредника с Чиксом, а вы своего с Чокси, наши денежные дела могут оказаться под угрозой.
Стандартное решение этой проблемы состоит в найме еще одного гнома - гнома каталога. Давайте назовем его Дэрил. Дэрил, как и все другие гномы, имеет визитную карточку, а на ней указан его титул - DirectoryService. Если мы заглянем в описание заданий DirectoryService, то увидим, что Дэрил выполняет две задачи: registerGnomeByName и getGnomeByName.
Деэрил имеет одно отличие по сравнению со всеми другими гномами: если гномов checkBook может быть сотни, то гном каталога всегда один.
Дэрил, единственный гном каталога, поэтому его относительно легко найти, например, с помощью мастера посредников гнома каталогов - уж он-то знает, как создать посредника для Дэрила. Этот мастер знает, что Дэрил уникален, поэтому, когда вы просите его о новом посреднике гнома каталога, он создает посредника автоматически и связывает его с Дэрилом. Вы и я можем иметь разных посредников гномов каталогов, но оба они будут общаться с Дэрилом.
Такое устройство позволяет нам без проблем координировать использование гномов. Все, что от нас требуется, - это дать новому гному имя. Кто первым создал Чокси, тот и регистрирует его в каталоге Дэрила под заранее оговоренным именем, скажем ObjectWatch checkBook. Мы оба спрашиваем Дэрила о гноме, зарегистрированном как ObjectWatch checkBook.
МОЖНО ЛИ ДОВЕРЯТЬ ГНОМАМ?
Выше мы сделали несколько неявных допущений о защищенности системы гномов, а именно:
Если хотя бы одно из этих допущений неверно, то тогда беда. Давайте посмотрим, как можно злоупотребить доверием наших почтенных гномов.
Если какой-нибудь презренный негодяй захочет заменить Чокси на своего пособника, чтобы он переводил деньги на какой-либо другой счет, когда я попрошу поместить денежную сумму на книжку, то он может сделать это разными способами. Например, зарегистрировать гнома-пособника в каталоге Дэрила как ObjectWatch checkBook. Злодей может также заменить мастера checkBook на подставного гнома, чтобы он создавал пособников, а не гномов checkBook, и даже подменить записи в каталоге Дэрила, чтобы тот направлял посредника к своему пособнику, а не к Чокси.
Подменить могут не только Чокси. Система оказывается уязвима, если вместо Дэрила (гнома каталога) или Дракса (гнома-привратника) выступают подставные дубликаты. Даже Фэнси, мой посредник Чокси, не находится в полной безопасности, хотя и живет со мной в одной комнате, где незаметно подменить его гораздо сложней.
Наш гипотетический злодей может также попытаться ввести систему в заблуждение, используя мое доброе имя. Если ему удастся проделать этот трюк, он получит возможность безнаказанно выписывать чеки за мой счет. Кроме того, этот злодей может попытаться атаковать систему при передаче информации, например подслушать данные о чеке и потом шантажировать меня. Не исключено, что он сумеет перехватить информацию о переводе сумм и изменить счет на свой собственный. В результате этот злодей может уничтожить любых гномов, и тогда система окажется недееспособной, а если он не сможет этого сделать, то затопить систему фиктивными запросами ему удастся наверняка.
Как видно, проблема безопасности гномов (в том числе и посредников, гномов-координаторов и т. д.) становится куда более сложным вопросом, когда они находятся в общем пользовании, чем когда они живут все вместе в одной большой темной комнате.
КАК ЗАЩИТИТЬ ГНОМОВ
Вообще говоря, меры по защите гномов не так уж и разнообразны. Все сводится к непосредственной защите гномов и линий связи, во-первых, и к поиску виновных в незаконном использовании гномов, во-вторых.
Чтобы найти виновных следует каждую операцию, выполнение которой может подвергнуть гномов риску, регистрировать. Например, всякий раз, когда кто-либо просит Чокси произвести writeCheck или makeDeposit, соответствующая запись должна быть сделана в журнале.
Вести журнал можно двумя способами. Один из способов научить гномов checkBook, таких как Чокси, или гномов-привратников, таких как Дракс, регистрировать запросы к ним. Преимущество обучения гномов чековой книжки состоит в том, что они лучше знают, какие области подвержены риску.
Если удаленных гномов несколько и каждый из них должен вести журнал, то тогда много проще будет обучить ведению журнала только гнома-привратника вроде Дракса. Так как каждый, кто хочет обратиться к удаленному гному, не сумеет обойти привратника, поручить централизованное ведение журнала можно Драксу и его родственникам.
Если мы поручим эту задачу Драксу, то тогда все запросы к Чокси должны будут регистрироваться до их передачи ему. Кроме того, Драксу надо объяснить, что он должен регистрировать. Но при этом не следует забывать: какой бы механизм не применялся, мы создаем дополнительную область риска.
Альтернативу аудиту представляет принятие привентивных мер. Привентивные меры многообразны, но большинство из них в той или иной степени опираются на применение комбинации открытых и личных ключей, при этом каждый гном имеет такую пару. Например, Чокси имеет открытый и личный ключи. Всякий, кто хочет иметь открытый ключ Чокси, может его получить, но только Чокси знает свой личный ключ.
Открытый и личный ключи связаны алгоритмически. В частности, открытый ключ используется для шифрования информации, в то время как личный ключ - для дешифрования. Зашифровав любую важную информацию перед ее отправкой, вы можете быть спокойны, если даже кто-нибудь ее перехватит, то он ничего в ней не поймет. Знание открытого ключа Чокси здесь не поможет, поскольку он полезен только при шифровании. Зашифрованные данные можно прочитать, только дешифровав их, а для этого злодей должен знать личный ключ.
Так что если вы хотите, чтобы Чокси перевел сумму на чековую книжку, то должны сделать следующее:
- подговить информацию о переводе;
- найти открытый ключ Чокси;
- применить открытый ключ для шифрования номера счета;
- отправить информацию Чокси через Фэнси и Дракса.
Затем Чокси дешифрует номер счета при помощи своего личного ключа.
Создать защищенную систему с помощью пары открытый личный ключ можно и многими другими способами. Однако они слишком многочисленны, чтобы здесь на них останавливаться. (Дополнительную информацию смотрите в разделе FAQ 3.0 on Cryptography по адресу: www.rsa.com/rsalabs/newfaq.)
СНОРОВКА ГНОМОВ
Вопрос, требующий при работе с удаленными гномами особого внимания, - это их сноровка. Описанная инфраструктура для обеспечения удаленной работы с гномами отнюдь не дешева.
Если гном, например, Квик живет в той же комнате, то ответ он даст мгновенно. Так, желая узнать, который час, я просто спрашиваю Квика и тут же получаю ответ.
Обращение же к далекому Чокси сделать что-либо, например, writeCheck, происходит значительно медленнее. Во-первых, я прошу Фэнси выписать чек, Фэнси упаковывает информацию, подходит к телефону и звонит Драксу. Дракс может оказаться занят, и тогда Фэнси должен будет ему перезвонить. Даже если Дракс не занят, он должен будет встать, подойти к телефону, спросить, кто это, и, приняв информацию у Фэнси, попросить Чокси выписать чек (это наиболее быстрая часть операции). Чокси сообщает Драксу результат, Дракс передает информацию назад Фэнси, а Фэнси наконец-то выдает ее мне.
В показатель цена/производительность для удаленных гномов делают вклад две составляющие. Во-первых, это время связи (Фэнси идет к телефону, звонит и т. д.), и оно более или менее фиксировано. Во-вторых, это время выполнения удаленным гномом требуемой работы (в данном случае, выписывание чека), и оно может меняться в широких пределах.
Общее увеличение продолжительности выполнения вследствие удаленности Чокси выражается формулой (W+C)/W, где W - время выполнения работы (выписывания чека), а C - время установления связи (звонка, например). Пусть значения W и C оба равны 10 сек. В этом случае общее увеличение продолжительности выполнения равняется 2, т. е. выполнение задания удаленным гномом занимает в два раза больше времени, чем местным.
В формуле (W+C)/W значение C фиксировано. Что же произойдет, если W будет меняться? Зафиксировав C равным 10 сек, мы получаем для разных значений W:
|
|
|
|
|
|
|
|
|
|
|
|
Например, если W составляет 20 сек, то мы имеем лишь 1,5-кратный рост. Если значение W достаточно велико (в 20 раз превышает значение C), общее увеличение продолжительности работы удаленным образом становится пренебрежимо малым. Значение W можно увеличить двумя способами. Во-первых, попросить Чокси работать как можно медленнее, но вряд ли это будет хорошим решением. Во-вторых, задание, содержащееся в каждом запросе к Чокси, должно быть достаточно объемно.
Давайте, например, усложним задачу Чокси и будем просить его не просто выписать чек, а найти и открыть чековую книжку, выписать чек, закрыть и вернуть чековую книжку на место. Предположим, что выполнение этих заданий занимает следующее время:
getCheckBook = 5
openCheckBook = 3
writeCheck = 10
closeCheckBook = 3
putAwayCheckBook = 5
Дополнительные расходы на передачу по телефону каждого из этих заданий составляют 10 сек, таким образом общая продолжительность их выполнения равна:
(5+10)+(3+10)+(10+10)+(3+10)+(5+10)=76 сек.
С другой стороны, если мы попросим Чокси просто выписать чек (причем Чокси будет знать, что для этого он должен выполнить все перечисленные задания), то общая продолжительность выполнения будет составлять:
(5+3+10+3+5)+10=36 сек.
Разбив задания Чокси на множество мелких задач, мы добились двух отрицательных результатов. Во-первых, весьма расстроили Чокси, так как теперь он вынужден выполнять множество всяких мелких задач вместо одной крупной. Во-вторых, заметно ухудшили общую производительность системы. Чокси, предоставленный самому себе, мог бы выписать чек за 36 сек, мы же удвоили продолжительность этой процедуры более чем в два раза!
Урок прост: мелчить задания всегда плохо, особенно при работе с удаленными гномами.
Удаленные гномы делают обычно свою работу медленнее, чем местные гномы. Однако если продолжительность выполнения задания зависит от местонахождения гнома, то мы можем ускорить его выполнение, поместив гнома туда, где он сделает свою работу наиболее эффективным образом.
Пускай чековая книжка хранится в специальном столе. Всякий раз, выписывая чек, Чокси вынужден идти к этому столу за чековой книжкой. Если стол находится далеко от моей комнаты, то тогда Чокси выгоднее поместить в комнату со столом. В результате задержка на установление связи будет значительно меньше, чем задержка вследствие путешествия Чокси через весь город за книжкой.
КТО ЖЕ ТАКИЕ, ЭТИ ГНОМЫ?
О'кей, думается, пришло время оставить мир гномов и вернуться в мир распределенных объектов. Как говорилось в начале статьи, если вы понимаете принцип работы гномов, то на 95% понимаете, как работают распределенные объекты.
Объект - ничто иное как программный гном. Подобно гномам, объекты делают для вас ту или иную работу. Они имеют тип, и этот тип определяет выполняемую объектом задачу и способ обращения к объекту.
Другое сходство между гномами и объектами состоит в том, что и те и другие могут быть как локальными, так и удаленными. Локальные объекты существуют в нашем процессе, удаленные объекты существуют в некотором другом процессе, причем обычно на другой машине. Подобно удаленным гномам, удаленные объекты могут совместно использоваться многими процессами, и вам и мне совместное применение объектов необходимо по той же причине, что и гномов. Вопросы производительности и безопасности касаются удаленных объектов в той же мере, что и гномов.
Программная система, состоящая из множества взаимосвязанных удаленных объектов, называется распределенной системой объектов. Прилагательное "распределенная" употребляется потому, что объекты распределены по сети.
Архитектура распределенных объектов идеальным образом подходит для целого ряда приложений. Пример небольшой распределенной системы объектов - несколько однотипных систем автоматов в локальной сети, а пример крупной системы - объединение нескольких корпоративных сетей с интерактивными системами управления продажей, покупкой, производством, доставкой, складированием, бухгалтерией и кредитами. Все такие приложения, от мельчайших до крупнейших, работают в соответствии с теми же принципами, что и наши пушистые распределенные гномы.
На рынке распределенных объектов мы имеем три основные конкурирующие технологии: архитектура Группы управления объектами (Object Management Group, OMG) под названием "Общая архитектура брокера объектных запросов" (Common Object Request Broker Architecture, CORBA), система вызова удаленных методов Java (Remote Method Invocation, RMI) и модель распределенных компонентных объектов Microsoft (Distributed Component Object Model, DCOM). Спецификация OMG наиболее разработанная из трех - RMI и DCOM только-только прошли фазу спецификации. (Исчерпывающую информацию о Java RMI можно найти на домашней странице JavaSoft по адресу: www.java.sun.com; а хорошее введение в CORBA и DCOM - в книге Orfali, Harkey и Edwards "The Essential Distributed Object Survival Guide".)
Если не вникать в детали, то различия между этими тремя системами невелики. Все они описывают, как объекты или клиенты в одном процессе осуществляют запросы к объектам в другом процессе. В CORBA Чокси представляет собой кусок кода метода; в Java Чокси может быть частью апплета, выполняемого браузером; в DCOM Чокси - компонент ActiveX. (См. Рисунок о представлении гномов в различных моделях объектов.)
Строго говоря, CORBA представляет собой не продукт, а спецификацию архитектуры: OMG не определяет, как CORBA необходимо реализовывать. Этот продукт может быть создан на базе оборудования окончания канала передачи данных, Kerberos, сокетов, удаленных вызовов процедур и многих других уровней.
Реализации CORBA продают многие компании. Наиболее известные среди них ORBIX компании Iona Technologies, System Object Model компании IBM, Object Broker компании Digital Equipment, PowerBroker компании Expersoft, VisiBroker for C++ компании Visigenic. По крайней мере одну реализацию CORBA поддерживают такие платформы, как Windows 3.x, Windows NT, OS/2, Solaris, SunOS, AIX, UnixWare, SCO Unix, Ultrix, Macintosh, Tandem NonStop Kernel и MVS.
Спецификация CORBA описывает много компонентов. При описании задания для объекта/гнома я использую язык описания интерфейса CORBA (Interface Definition Language). Для определения того, что объект/гном умеет делать, я использую хранилище интерфейсов CORBA (Interface Repository). Для отправки запроса Чокси я обращаюсь к услугам Фэнси и Дракса - все они являются компонентами уровня брокера запросов к объектам (Object Request Broker, ORB). Для нахождения объекта я использую Дэрила, наш сервер имен. Именование - один из многих сервисов CORBA; он представляет собой вспомогательную мини-систему для координации применения удаленных объектов. Среди других сервисов CORBA - Events, Security, Persistence и Transactions.
Одна из важнейших составляющих спецификации CORBA - это протокол Internet Inter-ORB Protocol (IIOP), являющийся частью уровня ORB. Все основные поставщики CORBA заявили о своей поддержке IIOP, благодаря которому объекты или клиенты одного поставщика ORB могут вызывать методы других поставщиков ORB. Это гарантирует совместимость и взаимодействие различных реализаций CORBA.
CORBA поддерживает многие языки, в том числе C, C++, SmallTalk и объектно-ориентированный COBOL.
С технической точки зрения, Java RMI не является брокером запросов к объектам, хотя она и поддерживает многие функции ORB, но отличается от CORBA следующим. Во-первых, по сравнению с CORBA спецификация RMI находится в зачаточном состоянии (примерно на уровне CORBA четырехлетней давности). Кроме того, она поддерживает только один язык программирования Java, причем сам он в сравнении с другими языками находится в младенческом возрасте.
Однако Java RMI имеет один большой плюс: язык Java пользуется сейчас огромной популярностью, и многие компании активно им занимаются. Ввиду полной независимости от платформы исполнимых байт-кодов Java, этот язык рассматривается отраслью, как средство противостояния господству Microsoft.
Что касается DCOM самой Microsoft, то по сути это не распределенная система объектов, потому что DCOM не поддерживает наследование, которое рассматривается как необходимое условие для объектно-ориентированных разработок. На самом деле DCOM представляет собой расширение OLE, позволяющее объектам OLE существовать в удаленных системах.
DCOM не имеет ни широкой поддержки CORBA, ни популярности Java. Это решение одной компании для одного семейства операционных систем. Однако данной компанией является Microsoft, а данным семейством операционных систем - Windows. Что тут еще сказать?
МНОГОЛИКОЕ БУДУЩЕЕ ГНОМОВ
В королевстве распределенных объектов/гномов мы оказались в путах множества стандартов. Что здесь нового? Конечно, при наличии нескольких стандартов мы можем построить мосты между ними. Работы по определению и наведению мостов между Java и CORBA, CORBA и DCOM, DCOM и Java ведутся многими компаниями-членами OMG.
На этом этапе никто не может знать наверняка, во что превратятся его гномы - компоненты ActiveX, апплеты Java или объекты CORBA. Однако мы можем быть уверены, по крайней мере, в одной вещи: Фэнси, Чокси, Дракс и Дэрил отправятся вскоре туда, где до них не был ни один гном.
Роджер Сешнс - президент консалтинговой компании ObjectWatch, специализирующейся на распределенных объектных технологиях. С ним можно связаться по адресу: roger@fc.net.