Design-Herausforderungen Entkopplung, Wartbarkeit und Flexibilität meistern

Plug-in-Design für Eclipse

Matthias Kempka

Die Eclipse-Plattform basiert bekanntlich auf Java. Das macht es einfach, Programmierer für Eclipse-Erweiterungen zu finden. Über die Programmiersprache hinaus kennt Eclipse jedoch Designkonzepte, die Plug-in-Autoren berücksichtigen sollten, wenn ihr Produkt sich reibungslos in die Plattform integrieren soll.

Java-Programmierer kennen Eclipse vor allem als integrierte Entwicklungsumgebung. Bereits in der Standardausführung gilt sie als eine der besten verfügbaren Java-IDEs. Viele Erweiterungen machen Eclipse als Werkzeug, zunehmend aber auch als Plattform für eigene Entwicklungen beliebt. Die Plattform dient Universitäten als Basis für Forschungswerkzeuge, Open-Source-Programmierern als Spielwiese zur Selbstverwirklichung und Versicherungen und Automobilherstellern als strategische Investition.

Die Programmiersprache der Eclipse-Plattform ist Java. So ist es verständlich, dass ein Java-Programmierer, der fortan Eclipse-Plug-ins schreibt, sich nun für einen Eclipse-Programmierer hält. Mit Grundkenntnissen über Abhängigkeiten von Plug-ins tut er das so, wie er zuvor Java-Programme geschrieben hat.

Den wesentlichen Unterschied zwischen normalen Java-Programmen und Eclipse-Plug-ins erkennt der neu gebackene Eclipse-Programmierer in der anderen Art der Installation. Statt Installations- und Klassenpfade selbst zu definieren, kopiert er seine Plug-ins in das plugins-Verzeichnis von Eclipse. Nachforschungen fördern den Update-Mechanismus zutage. Dieser installiert Plug-ins automatisch von einer speziell gestalteten Webseite und lästiges Kopieren von Hand wird überflüssig.

Je nach Grad der Abhängigkeit seines Plug-ins von anderen Plug-ins kann der Java-Programmierer seinen Programmierstil lange Zeit beibehalten. Irgendwann jedoch möchte er seinen Code in die Plattform integrieren, vielleicht möchte er seine Aktionen an verschiedenen Stellen in der Benutzeroberfläche sichtbar machen. Hier macht er erste Bekanntschaft mit der Erweiterung bestehender Extension Points. Während das Projekt wächst, möchten auch andere Programmierer im selben Projekt seine Klassen verwenden. Eine kleine Bibliothek wächst heran, die ihr eigenes Java-Paket bekommt, auf die alle Programmierer zugreifen können.

Bald ist es vorteilhaft, wenn auch Programmierer außerhalb des Projekts auf die Bibliothek zugreifen können. Dabei erscheint es niemandem richtig, von einem Plug-in abzuhängen, von dem nur ein Bruchteil der Funktionalität wiederverwendet wird. Der erfahrene Java-Programmierer gliedert die Bibliothek als eigenes Java-Projekt aus, das als Jar-Datei eingebunden werden kann. Damit kann sie gleichzeitig von herkömmlichen Java-Projekten und von Eclipse-Plug-ins verwendet werden.

Sobald die Bibliothek nützlich wird, wollen andere Eclipse-Programmierer sie aber nicht mehr als Jar in ihrer Plug-ins einbinden, sondern als Eclipse-Plug-in referenzieren. Der Java-Programmierer sieht vor allem den Mehraufwand, seine Bibliothek künftig für zwei Plattformen zu warten. Die Eclipse-Programmierer sind unzufrieden mit der reinen Java-Bibliothek, die ihr gewohntes Plug-in-Konzept durchbricht. Keiner akzeptiert die Gründe des anderen als relevant und bald entfacht sich um das Thema eine zumeist hitzige Diskussion mit dem einzigen Ergebnis der Unzufriedenheit aller Beteiligten.

Es sind Designentscheidungen, über die Entwickler hier streiten, ohne sich notwendigerweise dessen bewusst zu sein. Für den Java-Programmierer, der nur mit einem Bein in der Welt von Eclipse steht, steht fest, dass er sich nicht auf nur diese Plattform festlegen will. Für die Eclipse-Programmierer hingegen ist klar, dass eine reine Java-Bibliothek, obwohl sie eingebunden werden kann, dennoch ein Fremdkörper bleibt.

Vom Java-Jar zum Eclipse-Bundle

Die Programmiersprache der Eclipse-Plattform ist Java. Die Programmeinheit der Eclipse-Plattform ist ein Plug-in, seit Eclipse 3.0 in der Form von OSGI Bundles. Java selbst kennt diese Bundles nicht. Einige Bundle-Eigenschaften erlauben Eclipse-Entwicklern ein Design, das mit reinem Java nicht zu bewerkstelligen ist. Für die klare Definition einer öffentlichen Schnittstelle, Abhängigkeiten und Versionierung gibt das Bundle-Konzept Antworten auf Probleme, die in reinen Java-Programmen oft allenfalls mit Konventionen zu bewerkstelligen sind.

Die Plattform selbst besteht aus der Laufzeitumgebung und Bundles. Bundles wiederum bestehen aus Paketen, Klassen und einer Beschreibung über den Inhalt derselben. Mit dieser Beschreibung ist es der Plattform möglich, Informationen über den Inhalt eines Bundles zu erhalten, ohne die Klassen zu laden und auszuführen. So kann beispielsweise entschieden werden, ob und zu welchem Zeitpunkt ein Bundle überhaupt geladen werden muss. Ein Bundle, das lediglich eine Aktion in der Toolbar anzeigt, wird erst geladen, wenn der Benutzer die Aktion ausführt.

Ein Bundle kann Abhängigkeiten zu anderen Bundles definieren. Die Abhängigkeiten entsprechen in etwa dem Klassenpfad normaler Java-Programme. Ein Bundle kann nur auf diejenigen Klassen zugreifen, die in den öffentlichen Schnittstellen seiner Abhängigkeiten enthalten sind.

Die öffentliche Schnittstelle ist in der Beschreibung eines Bundles enthalten. Sie definiert die Pakete, auf die andere Bundles zugreifen dürfen. Im Standardfall können abhängige Bundles selbst solche Klassen nicht benutzen, die wegen des Java-Schlüsselwortes „public“ über die Paketgrenze hinaus sichtbar sind. Erst wenn das Paket einer Klasse in der öffentlichen Schnittstelle des Bundles enthalten ist, ist sie über die Bundle-Grenzen hinaus sichtbar. Dies erlaubt eine klare Trennung in interne und öffentliche Pakete. Interne Pakete sind nur für das Bundle selbst von Interesse und bleiben vor Klienten versteckt. Öffentliche Pakete sind eine stabile Schnittstelle nach außen, die die Funktionalität des Bundles definiert. Damit definiert ein Bundle eine neue Form von Modul, das in reinem Java nicht bekannt ist.

Häufig liegen in öffentlichen Paketen lediglich Interfaces, deren Implementierungen in internen Paketen versteckt sind. Instanzen solcher Klassenmodelle holt man üblicherweise an einem zentralen Einstiegspunkt. GUI-Elemente lassen sich beispielsweise über PlatformUI.getWorkbench() erreichen, Verzeichnisse und Dateien des Workspace über ResourcesPlugin.getWorkspace().

Mithilfe von Extension Points kann ein Bundle Stellen definieren, die von anderen Bundles erweitert werden können. So definiert das Bundle org.eclipse.ui beispielsweise den Extension Point org.eclipse.ui.actionSet, über den GUI-Elemente in das Menü und die Toolbar eingebracht werden können. Erweiterungen müssen dazu lediglich einen Label-Text, ein Icon und die Klasse angeben, die bei Anwahl durch den Benutzer ausgeführt werden soll.

Die Extension Points und deren Extensions werden in XML beschrieben. Der Editor nutzt ein XML-Schema zum Extension Point, um die Einhaltung formaler Kriterien zu überprüfen. Die gute Editor-Unterstützung macht es verlockend, das Bearbeiten von Extensions zu beenden, sobald die formalen Kriterien erfüllt sind und einfaches Ausprobieren das gewünschte Resultat erbringt. So kommt es, dass viele Eclipse-Entwickler auf das Lesen der begleitenden Dokumentation verzichten. Die Dokumentation von org.eclipse.ui.actionSet beispielsweise warnt davor, das Flag zur globalen Sichtbarkeit zu setzen. Es hat zur Folge, dass ein Toolbar-Eintrag unabhängig von seiner Nützlichkeit in jeder Perspektive zu sehen ist. Für einen einzelnen Button mag die globale Sichtbarkeit erträglich sein, auch wenn dessen Aktion nur in einem Bruchteil der möglichen Fälle Sinn ergibt. Selten ist aber nur ein Bundle installiert, und wenn viele Buttons global sichtbar sind, beeinträchtigt dies die Benutzbarkeit deutlich, da die Benutzeroberfläche unnötig überladen ist.

Eclipse bietet reichhaltige Ressourcen an, dazu aber auch die Möglichkeit, sie schonend zu benutzen. Für den sparsamen Umgang mit Ressourcen ist es durchaus wünschenswert, weithin genutzte Bibliotheken unabhängig von ihrer sonstigen Nutzung auch als OSGI-Bundles zu verpacken. Klassen eines Bundles werden nur einmal geladen, und die Klassen einer Bibliothek können von vielen abhängigen Plug-ins gemeinsam genutzt werden. Das ist auch für Bibliotheksgrößen von nur einem Megabyte von Interesse, wenn man sich folgenden Sachverhalt verdeutlicht: Die Sun Java Virtual Machine stellt unabhängig von der Heap-Größe standardmäßig nur 64 MB Speicher für geladene Klassen zur Verfügung. Klassen werden in den PermGen-Speicher geladen, dessen Konfiguration nicht standardisiert ist, d.h. nicht vom Eclipse-Binary vorgenommen werden kann. Eine mittelgroße Eclipse-Installation enthält etwa 100 Plug-ins. Sind diese vollständig geladen, darf jedes Plug-in nicht mehr als 640 kB Code mitbringen, wenn dem Benutzer die Notwendigkeit der Speicherkonfiguration erspart bleiben soll. Eine Laufzeitumgebung erreicht viel schneller diese kritische Speichergrenze, wenn jedes Plug-in alle benötigten Bibliotheken aufs Neue als Jar-Dateien einbindet, die dann jedes Mal neu geladen werden.

Bereits bei der Eclipse-Version 3.2 stießen größere Installationen an diese Speichergrenze, was die Nutzer oft vor unlösbare Probleme stellte. Für Eclipse 3.3 beschäftigt sich das Orbit-Projekt damit, die Apache-Bibliotheken als Eclipse-Bundles zu verpacken.

Rücksicht auf den Ressourcenverbrauch ist innerhalb der Eclipse-Plattform nicht mit großem Aufwand verbunden. Die Plattform stellt genügend Möglichkeiten zur Verfügung, Ressourcen nur dann zu belegen, wenn sie benötigt werden. Zumeist sind es lediglich Kenntnisse der Umgebung und einfache Design-Entscheidungen, die über diese Art der Qualität entscheiden.

Fazit

Es wird deutlich, dass Java-Kenntnisse für Eclipse-Entwicklung erforderlich sind, dafür aber nicht ausreichen. Die Eclipse-Plattform bietet Schnittstellenkonzepte, die sich im Bundle-Design auswirken können und sollen. Die Eclipse-Projekte wie z.B. JDT oder CDT durchzieht ein Design-Konzept, das sich als abwärtskompatibel, wartbar und dennoch flexibel genug für Änderungen bewährt hat. Eclipse-Entwickler sind angehalten, diese Konzepte in ihren eigenen Entwicklungen zu verwenden. Einerseits erhalten sie so Konsistenz und erleichtern zukünftiges Verstehen ihres Codes. Andererseits folgen sie damit einem Design, das auf die Möglichkeiten der Plattform zugeschnitten ist und gezeigt hat, dass es die großen Designherausforderungen Entkopplung, Wartbarkeit und Flexibilität auch in Umgebungen mit mehreren hundert teilnehmenden Bundles meistert.

Der folgende XML-Code aus der plugin.xml 
legt nicht global sichtbare Extension 
zu org.eclipse.ui.actionSets an. Diese 
wird mit einer Erweiterung zu
org.eclipse.ui.perspectiveExtension
zur Debug-Perspektive hinzugefügt.
-----------------------------------------------------------

Die in Eclipse enthaltene Dokumentation beschreibt Konzepte der Plattform und enthält API-Dokumentationen für alle Eclipse-Projekte (Abschnitt „Platform Plug-in Developer Guide“). Bundle-Autoren sollten sich mit den Abschnitten „Platform Plug-in Developer Guide“ und „Plug-in Development Environment Guide“ vertraut machen. Darüber hinaus gibt es mehrere empfehlenswerte Bücher, unter anderem auch von den Eclipse-Autoren selbst, die Hilfestellung bei den Alltagsproblemen in der Eclipse-Entwicklung geben:

  • Eric Clayberg, Dan Rubel: Eclipse: Building Commercial-Quality Plug-ins
  • Jeff McAffer, Jean-Michel Lemieux: Eclipse Rich Client Platform: Designing, Coding, and Packaging Java Applications
  • Erich Gamma, Kent Beck: Contributing to Eclipse: Principles, Patterns, and Plugins
Dipl.-Inform. Matthias Kempka (mkempka at innoopract.com) arbeitet zusammen mit Kent Beck an Werkzeugen, die Eclipse-Plug-ins auf ihre Design-Qualität überprüfen. Auf deren Grundlage führt er Quality Assessments bei Firmen durch, um bei der Verbesserung bestehender Plattformen zu helfen.
Geschrieben von
Matthias Kempka
Kommentare

Schreibe einen Kommentar

Deine E-Mail-Adresse wird nicht veröffentlicht.