With a history stretching back more than a decade, the IGB project has very deep roots, and represents many years of coding effort. As the project has matured and gained traction in the community, the engineering effort behind the project has become increasingly sophisticated and professionalized. In recent years, there has been a major effort on the part of the IGB development team to adopt widely recognized software industry best practices in all phases of our software development life cycle. One particular area we have been focusing on is adopting a modular service based architecture using the OSGi (open service gateway initiative) standard.
Why use a modular services-based architecture?
Less complexity, more understandable code
Refactoring IGB into self-contained "modules" of independent functionality reduces IGB's complexity and makes it easier to maintain and modify when new needs arise. Why does reduced complexity help? It helps in many ways, but one of the most obvious and important is that it reduces the amount of information a developer must keep in mind when reading or modifying a section of the code. Instead of working on the entire application all at once, a developer can focus on a single module, confident that any changes he or she makes will affect only that one module, provided the module interface stays the same. By enforcing a modular design - and restricting the points of contact between modules - we can build a more complex, powerful application for users while also gaining flexibility to adapt to change. This view of IGB as a system of cooperating modules with clear boundaries builds on the familiar concept of separation of concerns in object oriented programming. Rather than apply this principle at the class or package level, we apply it at the module-level, where modules are "bundles" of code responsible for clear tasks within the IGB application. By working with modules, we can more effectively manage our code base.
OSGi framework orchestrates module and object life cycles
IGB runs within an OSGi framework, a system and protocol for assembling and running applications composed of independent modules. When users launch IGB, they are really launching an OSGi "run-time," which then loads individual IGB modules - called "bundles" - into the run-time environment and instantiates objects as needed to satisfy module's dependencies on each other. To make methods available to other modules, a module developer inserts annotations that signal to the run-time that the method should be provided as an optional service to other modules in the IGB system. Only methods that are explicitly annotated as exportable are exposed to external modules. Moreover, developers rarely have to explicitly create or destroy many of the key objects in the IGB application. The OSGi run-time handles all of that.
Modularity and IGB Apps - a plug-able API for community contributors
The efforts we have made and continue to make to modularize the IGB code base have the incredibly beneficial side effect of leading to a software system which is already pluggable/extensible in a huge variety of ways. The reason why a plugin API is the natural organic output of this refactoring effort is obvious. Each time we find existing functionality in code which is being isolated into a module we must evolve our APIs to allow for extensibility to accommodate. If for example, we find some code which is adding a menu option into the main IGB toolbar, we must then create mechanisms in the plugin API to allow for the addition of menus to this toolbar (e.g. the addition of an interface to implement). These mechanisms are then available to all future module developers to leverage when writing their own extensions to IGB.
IGB module overview
The IGB project contains more than 50 modules. These include:
- Library Modules - modules that contribute "utility" classes for consumption by other modules (e.g. guava, apache commons)
- API Modules - modules that only contain service interfaces, abstract classes, data model, or similar content. (e.g. the igb-services-api module)
- Implementation Modules - modules that implement instances of the interfaces/abstract classes contained in API modules. Their implementations typically will take the form of a registered OSGi service, requiring none of the internal content of a qbundle to be exposed.
- Blended Modules - Small modules which may both define API content and publish implementation content within the same module. We do not consider this improper in most cases as long as the package exports are ensuring a proper separation of concerns and not exposing internals. As a rule, only expose API, utility classes, and data model.
The modularization effort of our project in ongoing, so there are some known violations within our own codebase of the best practices described above, but these will be resolved as our work continues.
- Core Modules - Modules considered to be critical to the core IGB application
- Plugins - Modules providing content which expands the functionality of the core IGB application. Although many plugins are not required, we choose to enable many plugins by default (e.g. weblinks, bookmarks). The line between default plugins packaged with IGB and IGB's core modules can be fuzzy since many of the functions provided by the default plugins are very important to our application. This classification system may evolve to eliminate this category.
Important IGB modules for external developers
- igb-services-api -API module containing most of what would be needed by any external contributor. This is the primary API jar of the project.
- igb-swing-ext - Library module which may be needed by contributors interested in leveraging some of the swing components used elsewhere throughout the codebase.
- common - Library module which has many useful utilities used frequently in our internal modules.
- genometry - Blended module containing much of the data model used in the project. As of this writing, the genometry module needs more work and will in the future be reworked into additional modules, but there is a high likelihood developers contributing significant functionality to the project will need to depend on this module.
- genoviz-sdk - Library module containing many custom components built on by IGB for visualization. Developers working on custom visualizations may have a need to depend on this module. Unlike the above, the Genoviz SDK is managed in a separate repository and has an independent release cycle. See: https://bitbucket.org/lorainelab/genoviz-sdk