|
Many libraries that handle interactions with external components - this applies not only to purely message-oriented libraries, but also to remote logging or database access components - assume that they are singletons. This assumption can be seen by the choice of the mechanism that is used for the run-time configuration of the given component - in particular, configuration by system-wide settings, environment variables or a single property file are all consequences of this design choice. A singleton with global configuration strategy is not necessarily a problem in itself, except when it happens to be involved several times in the complete system. It is not uncommon for several distinct components to depend on the same messaging system for their own remote invocation needs. Components which are designed to be singletons are inherently self-conflicting in terms of their configuration. How to set up different timeouts or data window widths in distinct parts of the system if due to a common dependency they all rely on the same environment variable or a single property file?
The problem of being self-conflicting is even more pronounced if a given library expects to be initialized with a single static ``init'' function call, and later operated with a set of global functions. Such a scheme can become very troublesome if the library is not in the first-line dependency list of the final application, but is rather included indirectly by some other component. A possible example might be the chain of dependencies involving the final application, the logging library and a communication library for interaction with remote logging server. Even though the final application does not directly depend on that communication library, its operational state is effectively shared with all other similar instances, which in principle should not be aware of each other. This can imply not only the configuration conflicts, but also multithreading issues.
YAMI4 is composable.
The YAMI4 library does not rely on any global configuration mechanisms and does not operate on any shared state other than the memory allocator - and even that can be eliminated with the YAMI4 core library - and the system space of network port numbers. In addition to be mutually independent, the main run-time YAMI4 objects called agents are relatively inexpensive and it is perfectly acceptable for them to be created and torn down for temporary use. These properties make the YAMI4 very composable in the sense that it can be used independently in many places of the whole application and on different levels of component dependency tree without any risk of creating configuration or state conflicts. In other words, YAMI4 is a component that can be embedded in the final application to provide required services, instead of enforcing a very unnatural approach where the final application is built around some communication framework.