A software system is comprised of parts, which interact through shared
interfaces. Certain qualities of integration, such as loose-coupling, requiring
minimal changes to the software and fine-grained localisation
of dependencies, have impact on the overall software quality. Current
general-purpose languages do not have features that target these integration
qualities at the instance level, hence they lack expressive power to
define integration-specific code. As a result integration requires invasive
code alterations, tightly coupled components that hinder maintainability
and reuse.
In this thesis, we focus on developing language extensions and frameworks,
which offer a declarative way of defining the elements involved
in the instance level software composition. Our motivation is that nonintrusive
means of integration at the granularity of the instance level has
an impact on the maintainability and the extensibility of the software.
We focused on declarativeness since we want to improve how integration
concerns are expressed in the implementation.
We particularly focus on two challenges specific to the instance-level
integration step; the two contributions proposed as a solution to each
of these challenges both present declarative approaches for implementing
specific concerns. These concerns are; 1. selecting objects based on
how they are used in a system and, 2. non-intrusive implementation and
injection of adapters.
The first challenge is the difficulty of selecting objects based on other
criteria than the type system. This is important during integration since,
independent of their type, objects can become relevant to a component
when they participate in specific events. Such events mark the phases
in the life-cycle of objects. The phase in which an object currently is, affects
how it is handled in an application; however phase shifts are often implicit. Selecting objects according to such phase shifts results in scattered
and tangled code. To handle these problems, we introduce a novel
aspect-oriented concept, called instance pointcuts, for maintaining sets
that contain objects with a specified usage history. Specifics are provided
in terms of pointcut-like declarations selecting events in the life-cycle of
objects. Instance pointcuts can be reused, by refining their selection criteria,
e.g., by restricting the scope of an existing instance pointcut; and they
can be composed, e.g., by set operations. These features make instance
pointcuts easy to evolve according to new requirements. The instance
pointcuts approach adds a new dimension to modularity by providing a
fine-grained mechanism and a declarative syntax to create and maintain
phase-specific object sets.
The second challenge we have tackled is establishing common interfaces
between instances while maintaining loose coupling. To this end
we have created an adaptation framework, called zamk, which unites
dependency injection with under-the-hood adaptation logic. Due to limitations
we have identified in the traditional adapter pattern, such as an
increased number of dependencies and implementation challenges due
to dependence on type inheritance, we have created the concept of converters,
which are annotated classes that adhere to a specific structure.
Converter classes do not have to inherit from other classes to implement
the adaptation logic. They are defined by the user and managed by the
zamk runtime; consequently the only dependency that needs to be introduced
during integration is calls to the zamk API. zamk comes with
its own dependency injection mechanism that is used with a designated
domain-specific language called Gluer. The dependency injection logic is
intertwined with the adaptation logic which queries a registry of converters
to perform automated adaptation between two types. We automate
the adaptation process by exploiting the type hierarchies and provide
checks and context-relevant messages for correct integration. As a result
the zamk framework provides a non-intrusive approach for adapting and
binding software, which supports code reuse, software maintainability
and evolution. |