Obviously, Ice uses many ideas that can be found in CORBA and earlier distributed computing platforms, such as DCE
[14]. In some areas, Ice is remarkably close to CORBA whereas, in others, the differences are profound and have far-reaching architectural implications. If you have used CORBA in the past, it is important to be aware of these differences.
An Ice object, like a CORBA object, has exactly one most derived main interface. However, an Ice object can provide other interfaces as facets. It is important to notice that all facets of an Ice object share the same object identity, that is, the client sees a single object with multiple interfaces instead of several objects, each with a different interface.
Facets provide great architectural flexibility. In particular, they offer an approach to the versioning problem: it is easy to extend functionality in a server without breaking existing, already deployed clients by simply adding a new facet to an already existing object.
Ice proxies (the equivalent of CORBA object references) are not opaque. Clients can always create a proxy without support from any other system component, as long as they know the type and identity of the object. (For indirect binding, it is
not necessary to be aware of the transport address of the object.)
•
Clients can create proxies without the need to consult an external look-up service, such as a naming service. In effect, the object identity and the object’s name are considered to be one and the same. This eliminates the problems that can arise from having the contents of the naming service go out of sync with reality, and reduces the number of system components that must be functional for clients and servers to work correctly.
Experience over many years with CORBA has shown that, pragmatically, opacity of object references is problematic: not only does it require more complex APIs and run-time support, it also gets in the way of building realistic systems. For that reason, mechanisms such as
corbaloc and
corbaname were added, as well as the (ill-defined)
is_equivalent and
hash operations for reference comparison. All of these mechanisms compromise the opacity of object references, but other parts of the CORBA platform still try to maintain the illusion of opaque references. As a result, the developer gets the worst of both worlds: references are neither fully opaque nor fully transparent—the resulting confusion and complexity are considerable.
The Ice object model assumes that object identities are universally unique (but without imposing this requirement on the application developer). The main advantage of universally unique object identities is that they permit you to migrate servers and to combine the objects in multiple separate servers into a single server without concerns about name collisions: if each Ice object has a unique identity, it is impossible for that identity to clash with the identity of another object in a different domain.
The Ice object model also uses strong object identity: it is possible to determine whether two proxies denote the same object as a local, client-side operation. (With CORBA, you must invoke operations on the remote objects to get reliable identity comparison.) Local identity comparison is far more efficient and crucial for some application domains, such as a distributed transaction service.
CORBA, depending on which specification you choose to read, provides many of the services provided by Ice. For example, CORBA supports asynchronous method invocation and, with the component model, a form of multiple interfaces. However, the problem is that it is typically impossible to find these features in a single implementation. Too many CORBA specifications are either optional or not widely implemented so, as a developer, you are typically faced with having to choose which feature to do without.
The Ice protocol offers bidirectional support, which is a fundamental requirement for allowing callbacks through firewalls. (CORBA specified a bidirectional protocol at one point, but the specification was technically flawed and, to the best of our knowledge, never implemented.) In addition, Ice allows you to use UDP (both unicast and multicast) as well as TCP, so event distribution on reliable (local) networks can be made extremely efficient and light-weight. CORBA provides no support for UDP as a transport.
Another important feature of the Ice protocol is that all messages and data are fully encapsulated on the wire. This allows Ice to implement services such as IceStorm extremely efficiently because, to forward data, no unmarshaling and remarshaling is necessary. Encapsulation is also important for the deployment of protocol bridges, such as Glacier2, because the bridge does not need to be configured with type-specific information.
CORBA is known as a platform that is large and complex. This is largely a result of the way CORBA is standardized: decisions are reached by consensus and majority vote. In practice, this means that, when a new technology is being standardized, the only way to reach agreement is to accommodate the pet features of all interested parties. The result are specifications that are large, complex, and burdened with redundant or useless features. In turn, all this complexity leads to implementations that are large and inefficient. The complexity of the specifications is reflected in the complexity of the CORBA APIs: even experts with years of experience still need to work with a reference manual close at hand, and, due to this complexity, applications are frequently plagued with latent bugs that do not show up until after deployment.
CORBA’s object model adds further to CORBA’s complexity. For example, opaque object references force the specification of a naming service because clients must have some way to access object references. In turn, this requires the developer to learn yet another API, and to configure and deploy yet another service when, as with the Ice object model, no naming service is necessary in the first place.
One of the most infamous areas of complexity in CORBA is the C++ mapping. The CORBA C++ API is arcane in the extreme; in particular, the memory management issues of this mapping are more than what many developers are willing to endure. Yet, the code required to implement the C++ mapping is neither particularly small nor efficient, leading to binaries that are larger and require more memory at run time than they should. If you have used CORBA with C++ in the past, you will appreciate the simplicity, efficiency, and neat integration with STL of the Ice C++ mapping.
In contrast to CORBA, Ice is first and foremost a simple platform. The designers of Ice took great care to pick a feature set that is both sufficient and minimal: you can do everything you want, and you can do it with the smallest and simplest possible API. As you start to use Ice, you will appreciate this simplicity. It makes it easy to learn and understand the platform, and it leads to shorter development time with lower defect counts in deployed applications. At the same time, Ice does not compromise on features: with Ice, you can achieve everything you can achieve with CORBA and do so with less effort, less code, and less complexity. We see this as the most compelling advantage of Ice over any other middleware platform: things are simple, so simple, in fact, that you will be developing industrial-strength distributed applications after only a few days exposure to Ice.