Wahrscheinlich,
In diesem Übersichtsartikel werden wir versuchen, einige Grundlagen der Eclipse-Architektur als Plattform zum Aufbau integrierter Entwicklungstools zu betrachten und einen ersten Überblick über die Eclipse-Komponenten zu geben, die die Grundlage der Technologie bilden Plattform für den „neuen Konfigurator“ 1C: Enterprise.
Einführung in die Eclipse-Architektur
Schauen wir uns zunächst einige allgemeine Aspekte der Eclipse-Architektur anhand des Beispiels an
Zunächst ist anzumerken, dass sich Eclipse durch eine ziemlich klare Architekturschichtung auszeichnet, mit der Trennung sprachunabhängiger Funktionalität von Funktionalität zur Unterstützung bestimmter Programmiersprachen sowie der Trennung UI-unabhängiger „Kern“-Komponenten von zugehörigen Komponenten mit unterstützender Benutzeroberfläche.
Somit definiert die Eclipse-Plattform eine gemeinsame, sprachunabhängige Infrastruktur und die Java-Entwicklungstools fügen Eclipse eine voll funktionsfähige Java-IDE hinzu. Sowohl die Eclipse-Plattform als auch das JDT bestehen aus mehreren Komponenten, die jeweils entweder zu einem UI-unabhängigen „Kern“ oder einer UI-Schicht gehören (Abbildung 1).
Reis. 1. Eclipse-Plattform und JDT
Lassen Sie uns die Hauptkomponenten der Eclipse-Plattform auflisten:
- Laufzeit – Definiert die Plugin-Infrastruktur. Eclipse zeichnet sich durch eine modulare Architektur aus. Im Wesentlichen ist Eclipse eine Sammlung von „Erweiterungspunkten“ und „Erweiterungen“.
- Arbeitsplatz — Verwaltet ein oder mehrere Projekte. Ein Projekt besteht aus Ordnern und Dateien, die direkt dem Dateisystem zugeordnet sind.
- Standard-Widget-Toolkit (SWT) – Stellt grundlegende Benutzeroberflächenelemente bereit, die in das Betriebssystem integriert sind.
- JGesicht – Bietet eine Reihe von UI-Frameworks, die auf SWT basieren.
- Werkbank – Definiert das Eclipse-UI-Paradigma: Editoren, Ansichten, Perspektiven.
Es muss gesagt werden, dass die Eclipse-Plattform auch viele andere nützliche Komponenten zum Erstellen integrierter Entwicklungstools bietet, einschließlich Debug, Compare, Search und Team. Besonders hervorzuheben ist JFace Text – die Grundlage für die Erstellung „intelligenter Editoren“ von Quellcode. Leider ist im Rahmen dieses Artikels nicht einmal eine oberflächliche Betrachtung dieser Komponenten sowie der UI-Layer-Komponenten möglich, daher beschränken wir uns im weiteren Verlauf dieses Abschnitts auf einen Überblick über die wichtigsten „Kern“-Komponenten von die Eclipse-Plattform und JDT.
Kernlaufzeit
Die Eclipse-Plugin-Infrastruktur basiert auf
Kernarbeitsbereich
Nahezu jede integrierte Entwicklungsumgebung, die auf der Eclipse-Plattform aufbaut, funktioniert mit dem Eclipse-Arbeitsbereich. Es ist der Arbeitsbereich, der normalerweise den Quellcode der in der IDE entwickelten Anwendung enthält. Der Arbeitsbereich ist direkt dem Dateisystem zugeordnet und besteht aus Projekten, die Ordner und Dateien enthalten. Diese Projekte, Ordner und Dateien werden aufgerufen die Ressourcen Arbeitsplatz. Die Workspace-Implementierung in Eclipse dient als Cache gegenüber dem Dateisystem, wodurch die Durchquerung des Ressourcenbaums deutlich beschleunigt werden kann. Darüber hinaus bietet Workspace eine Reihe zusätzlicher Dienste, darunter
Die Core Resources-Komponente (org.eclipse.core.resources-Plugin) ist für die Unterstützung des Arbeitsbereichs und seiner Ressourcen verantwortlich. Insbesondere bietet diese Komponente programmgesteuerten Zugriff auf den Arbeitsbereich im Formular Ressourcenmodelle. Um mit diesem Modell effektiv arbeiten zu können, benötigen Kunden eine einfache Möglichkeit, einen Link zu einer Ressource darzustellen. In diesem Fall wäre es wünschenswert, das Objekt, das den Zustand der Ressource direkt im Modell speichert, vor dem Clientzugriff zu verbergen. Andernfalls könnte es beispielsweise beim Löschen einer Datei dazu kommen, dass der Client weiterhin ein Objekt hält, das sich nicht mehr im Modell befindet, was zu Problemen führen kann. Eclipse löst dieses Problem mit etwas namens Griff Ressource. Handle fungiert als Schlüssel (es kennt nur den Pfad zur Ressource im Arbeitsbereich) und steuert vollständig den Zugriff auf das interne Modellobjekt, das direkt Informationen über den Status der Ressource speichert. Dieses Design ist eine Variation des Musters
Reis. Abbildung 2 zeigt die Handle/Body-Sprache, wie sie auf das Ressourcenmodell angewendet wird. Die IResource-Schnittstelle stellt das Handle einer Ressource dar und ist eine API, im Gegensatz zur Resource-Klasse, die diese Schnittstelle implementiert, und der ResourceInfo-Klasse, die den Hauptteil darstellt, die keine APIs sind. Wir betonen, dass das Handle nur den Pfad zur Ressource relativ zum Arbeitsbereichsstamm kennt und keinen Link zu Ressourceninformationen enthält. Ressourcen-Info-Objekte bilden einen sogenannten „Elementbaum“. Diese Datenstruktur wird vollständig im Speicher materialisiert. Um die Ressourceninformationsinstanz zu finden, die einem Handle entspricht, wird der Elementbaum entsprechend dem in diesem Handle gespeicherten Pfad durchlaufen.
Reis. 2. IResource und ResourceInfo
Wie wir später sehen werden, wird das grundlegende Design des Ressourcenmodells (wir könnten es Handle-basiert nennen) in Eclipse auch für andere Modelle verwendet. Lassen Sie uns zunächst einige der besonderen Eigenschaften dieses Designs auflisten:
- Handle ist ein Wertobjekt. Wertobjekte sind unveränderliche Objekte, deren Gleichheit nicht auf Identität beruht. Solche Objekte können sicher als Schlüssel in Hash-Containern verwendet werden. Mehrere Instanzen von handle können auf dieselbe Ressource verweisen. Um sie zu vergleichen, müssen Sie die Methode equal(Object) verwenden.
- Handle definiert das Verhalten einer Ressource, enthält jedoch keine Informationen über den Status der Ressource (die einzigen Daten, die es speichert, sind der „Schlüssel“, der Pfad zur Ressource).
- Handle kann sich auf eine Ressource beziehen, die nicht existiert (entweder eine Ressource, die noch nicht erstellt wurde, oder eine Ressource, die bereits gelöscht wurde). Die Existenz einer Ressource kann mit der Methode IResource.exists() überprüft werden.
- Einige Vorgänge können ausschließlich auf Basis der im Handle selbst gespeicherten Informationen implementiert werden (sogenannte Nur-Handle-Vorgänge). Beispiele sind IResource.getParent(), getFullPath() usw. Die Ressource muss nicht vorhanden sein, damit ein solcher Vorgang erfolgreich ist. Vorgänge, für deren Erfolg die Existenz einer Ressource erforderlich ist, lösen eine CoreException aus, wenn die Ressource nicht vorhanden ist.
Eclipse bietet einen effizienten Mechanismus zur Benachrichtigung über Änderungen der Arbeitsbereichsressourcen (Abbildung 3). Ressourcen können sich entweder aufgrund von Aktionen ändern, die innerhalb der Eclipse-IDE selbst ausgeführt werden, oder aufgrund der Synchronisierung mit dem Dateisystem. In beiden Fällen erhalten Kunden, die Benachrichtigungen abonnieren, detaillierte Informationen über die Änderungen in Form von „Ressourcendeltas“. Ein Delta beschreibt Änderungen zwischen zwei Zuständen eines Workspace-Ressourcen-(Unter-)Baums und ist selbst ein Baum, dessen Knoten jeweils eine Änderung an einer Ressource beschreiben und auf der nächsten Ebene eine Liste von Deltas enthalten, die Änderungen an untergeordneten Ressourcen beschreiben.
Reis. 3. IResourceChangeEvent und IResourceDelta
Der auf Ressourcendeltas basierende Benachrichtigungsmechanismus weist die folgenden Merkmale auf:
- Eine einzelne Änderung und viele Änderungen werden mit derselben Struktur beschrieben, da das Delta nach dem Prinzip der rekursiven Komposition aufgebaut ist. Abonnentenclients können Ressourcenänderungsbenachrichtigungen mithilfe eines rekursiven Abstiegs durch einen Deltabaum verarbeiten.
- Das Delta enthält vollständige Informationen über Änderungen an der Ressource, einschließlich ihrer Bewegung und/oder Änderungen der damit verbundenen „Marker“ (z. B. werden Kompilierungsfehler als Marker dargestellt).
- Da Ressourcenreferenzen über das Handle erfolgen, kann Delta natürlich auf eine Remote-Ressource verweisen.
Wie wir bald sehen werden, sind die Hauptkomponenten des Designs des Benachrichtigungsmechanismus für Ressourcenmodelländerungen auch für andere Handle-basierte Modelle relevant.
JDT-Kern
Das Eclipse-Workspace-Ressourcenmodell ist ein grundlegendes sprachunabhängiges Modell. Die JDT Core-Komponente (Plugin org.eclipse.jdt.core) stellt eine API zum Navigieren und Analysieren der Arbeitsbereichsstruktur aus Java-Perspektive, dem sogenannten „Java-Modell“ (Java-Modell). Diese API wird anhand von Java-Elementen definiert, im Gegensatz zur zugrunde liegenden Ressourcenmodell-API, die anhand von Ordnern und Dateien definiert wird. Die Hauptschnittstellen des Java-Elementbaums sind in Abb. dargestellt. 4.
Reis. 4. Java-Modellelemente
Das Java-Modell verwendet das gleiche Handle/Body-Idiom wie das Ressourcenmodell (Abbildung 5). IJavaElement ist das Handle und JavaElementInfo spielt die Rolle des Körpers. Die IJavaElement-Schnittstelle definiert ein Protokoll, das allen Java-Elementen gemeinsam ist. Einige seiner Methoden sind nur Handles: getElementName(), getParent() usw. Das JavaElementInfo-Objekt speichert den Status des entsprechenden Elements: seine Struktur und Attribute.
Reis. 5. IJavaElement und JavaElementInfo
Das Java-Modell weist einige Unterschiede in der Implementierung des grundlegenden Handle-/Körperdesigns im Vergleich zum Ressourcenmodell auf. Wie oben erwähnt, ist im Ressourcenmodell der Elementbaum, dessen Knoten Ressourceninformationsobjekte sind, vollständig im Speicher enthalten. Das Java-Modell kann jedoch eine wesentlich größere Anzahl von Elementen aufweisen als der Ressourcenbaum, da es auch die interne Struktur von .java- und .class-Dateien darstellt: Typen, Felder und Methoden.
Um zu vermeiden, dass der gesamte Elementbaum vollständig im Speicher materialisiert wird, verwendet die Java-Modellimplementierung einen LRU-Cache mit Elementinformationen begrenzter Größe, wobei der Schlüssel das Handle IJavaElement ist. Element-Info-Objekte werden bei Bedarf erstellt, während durch den Elementbaum navigiert wird. In diesem Fall werden die am seltensten verwendeten Elemente aus dem Cache entfernt und der Speicherverbrauch des Modells bleibt auf die angegebene Cachegröße begrenzt. Dies ist ein weiterer Vorteil des Handle-basierten Designs, das solche Implementierungsdetails vollständig vor dem Client-Code verbirgt.
Der Mechanismus zur Benachrichtigung über Änderungen an Java-Elementen ähnelt im Allgemeinen dem oben beschriebenen Mechanismus zur Verfolgung von Änderungen an Arbeitsbereichsressourcen. Ein Client, der Änderungen im Java-Modell überwachen möchte, abonniert Benachrichtigungen, die als ElementChangedEvent-Objekt dargestellt werden, das ein IJavaElementDelta enthält (Abbildung 6).
Reis. 6. ElementChangedEvent und IJavaElementDelta
Das Java-Modell enthält keine Informationen zu Methodenkörpern oder Namensauflösung. Für eine detaillierte Analyse von in Java geschriebenem Code stellt JDT Core daher ein zusätzliches (nicht auf Handles basierendes) Modell bereit:
Da Syntaxbäume eine beträchtliche Menge an Speicher beanspruchen können, speichert JDT nur einen AST für den aktiven Editor zwischen. Im Gegensatz zum Java-Modell wird der AST typischerweise als „zwischenliegendes“, „temporäres“ Modell betrachtet, auf dessen Elemente Clients keine Verweise außerhalb des Kontexts des Vorgangs enthalten sollten, der zur Erstellung des AST geführt hat.
Die aufgeführten drei Modelle (Java-Modell, AST, Bindungen) bilden zusammen die Grundlage für den Aufbau „intelligenter Entwicklungstools“ in JDT, einschließlich eines leistungsstarken Java-Editors mit verschiedenen „Helfern“, verschiedenen Aktionen zur Verarbeitung des Quellcodes (einschließlich der Organisation einer Importliste). Namen und Formatierung entsprechend dem benutzerdefinierten Stil), Such- und Refactoring-Tools. Dabei spielt das Java-Modell eine besondere Rolle, da es als Grundlage für eine visuelle Darstellung der Struktur der zu entwickelnden Anwendung dient (z. B. im Package Explorer, Outline, Search, Call Hierarchy usw.). Typhierarchie).
Eclipse-Komponenten, die in 1C:Enterprise Developments Tools verwendet werden
In Abb. Abbildung 7 zeigt die Eclipse-Komponenten, die die Grundlage der Technologieplattform für 1C:Enterprise Development Tools bilden.
Reis. 7. Eclipse als Plattform für 1C:Enterprise Development Tools
Eclipse-Plattform stellt eine grundlegende Infrastruktur bereit. Wir haben uns im vorherigen Abschnitt einige Aspekte dieser Infrastruktur angesehen.
Wie jedes wirklich universelle Werkzeug eignet sich EMF zur Lösung einer Vielzahl von Modellierungsproblemen, einige Modellklassen (z. B. die oben diskutierten handle-basierten Modelle) erfordern jedoch möglicherweise speziellere Modellierungswerkzeuge. Über EMF zu sprechen ist eine undankbare Aufgabe, vor allem im begrenzten Umfang eines Artikels, da dies das Thema eines separaten Buches ist, und zwar eines ziemlich umfangreichen. Beachten wir nur, dass das dem EMF zugrunde liegende hochwertige System von Verallgemeinerungen die Entstehung einer ganzen Reihe von Modellierungsprojekten ermöglichte, die im Top-Level-Projekt enthalten sind
1C:Enterprise Development Tools nutzen aktiv sowohl EMF selbst als auch eine Reihe anderer Eclipse-Modellierungsprojekte. Insbesondere ist Xtext eine der Grundlagen von Entwicklungstools für 1C:Enterprise-Sprachen wie die integrierte Programmiersprache und Abfragesprache. Eine weitere Grundlage für diese Entwicklungstools ist das Eclipse-Handly-Projekt, auf das wir noch näher eingehen werden (von den aufgeführten Eclipse-Komponenten ist es noch die am wenigsten bekannte).
Die grundlegenden Architekturprinzipien von Handle-basierten Modellen, wie etwa dem Handle/Body-Idiom, wurden oben anhand des Ressourcenmodells und des Java-Modells als Beispiele erörtert. Es wurde außerdem darauf hingewiesen, dass sowohl das Ressourcenmodell als auch das Java-Modell wichtige Grundlagen für die Eclipse Java Development Tools (JDT) sind. Und da fast alle *DT-Eclipse-Projekte eine JDT-ähnliche Architektur haben, wäre es keine große Übertreibung zu sagen, dass Handle-basierte Modelle vielen, wenn nicht allen IDEs zugrunde liegen, die auf der Eclipse-Plattform basieren. Beispielsweise verfügt das Eclipse C/C++ Development Tooling (CDT) über ein Handle-basiertes C/C++-Modell, das in der CDT-Architektur dieselbe Rolle spielt wie das Java-Modell im JDT.
Vor Handly bot Eclipse keine speziellen Bibliotheken zum Erstellen von Handle-basierten Sprachmodellen an. Die derzeit existierenden Modelle wurden hauptsächlich durch direkte Anpassung des Java-Modellcodes (auch bekannt als Kopieren/Einfügen) erstellt. in den Fällen, in denen es erlaubt ist Öffentliche Eclipse-Lizenz (EPL). (Offensichtlich ist dies in der Regel kein rechtliches Problem, beispielsweise für Eclipse-Projekte selbst, nicht jedoch für Closed-Source-Produkte.) Zusätzlich zu ihrer inhärenten Zufälligkeit bringt diese Technik bekannte Probleme mit sich: Codeduplizierung, die bei der Anpassung an Fehler entsteht, usw. Schlimmer noch ist, dass die resultierenden Modelle „Dinge für sich“ bleiben und das Potenzial einer Vereinheitlichung nicht nutzen. Die Isolierung gemeinsamer Konzepte und Protokolle für Handle-basierte Sprachmodelle könnte jedoch zur Schaffung wiederverwendbarer Komponenten für die Arbeit mit ihnen führen, ähnlich wie im Fall von EMF.
Es ist nicht so, dass Eclipse diese Probleme nicht verstanden hätte. Damals im Jahr 2005
In gewissem Sinne ist das Handly-Projekt darauf ausgelegt, ungefähr die gleichen Probleme wie EMF zu lösen, jedoch für Handle-basierte Modelle, und zwar hauptsächlich für Sprachmodelle (d. h. die Elemente der Struktur einer Programmiersprache darstellen). Die wichtigsten Ziele, die bei der Gestaltung von Handly gesetzt wurden, sind unten aufgeführt:
- Identifizierung der Hauptabstraktionen des Themenbereichs.
- Reduzierung des Aufwands und Verbesserung der Qualität der Implementierung handle-basierter Sprachmodelle durch Code-Wiederverwendung.
- Bereitstellung einer einheitlichen API auf Metaebene für die resultierenden Modelle, die es ermöglicht, gemeinsame IDE-Komponenten zu erstellen, die mit auf Sprachhandles basierenden Modellen arbeiten.
- Flexibilität und Skalierbarkeit.
- Integration mit Xtext (in einer separaten Ebene).
Um gemeinsame Konzepte und Protokolle hervorzuheben, wurden bestehende Implementierungen von auf Sprachhandles basierenden Modellen analysiert. Die wichtigsten Schnittstellen und grundlegenden Implementierungen von Handly sind in Abb. dargestellt. 8.
Reis. 8. Gemeinsame Schnittstellen und grundlegende Implementierungen von Handly-Elementen
Die IElement-Schnittstelle stellt das Handle eines Elements dar und ist allen Elementen aller Handly-basierten Modelle gemeinsam. Die abstrakte Klasse Element implementiert den verallgemeinerten Handle/Body-Mechanismus (Abb. 9).
Reis. 9. IElement und generische Handle/Body-Implementierung
Darüber hinaus bietet Handly einen allgemeinen Mechanismus zur Benachrichtigung über Änderungen in Modellelementen (Abb. 10). Wie Sie sehen, ähnelt es im Großen und Ganzen den im Ressourcenmodell und im Java-Modell implementierten Benachrichtigungsmechanismen und verwendet IElementDelta, um eine einheitliche Darstellung von Elementänderungsinformationen bereitzustellen.
Reis. 10. Allgemeine Schnittstellen und grundlegende Implementierungen des Handly-Benachrichtigungsmechanismus
Der oben besprochene Handly-Teil (Abb. 9 und 10) kann zur Darstellung nahezu aller griffbasierten Modelle verwendet werden. Zum Gestalten sprachlich Modelle bietet das Projekt zusätzliche Funktionalität – insbesondere gemeinsame Schnittstellen und Basisimplementierungen für Elemente der Quelltextstruktur, die sogenannten Quellelemente (Abb. 8). Die ISourceFile-Schnittstelle stellt eine Quelldatei dar und ISourceConstruct stellt ein Element innerhalb der Quelldatei dar. Die abstrakten Klassen SourceFile und SourceConstruct implementieren verallgemeinerte Mechanismen zur Unterstützung der Arbeit mit Quelldateien und ihren Elementen, beispielsweise die Arbeit mit Textpuffern, die Bindung an die Koordinaten eines Elements im Quelltext und den Abgleich von Modellen mit dem aktuellen Inhalt eines Arbeitskopiepuffers , usw. Die Implementierung dieser Mechanismen stellt normalerweise eine ziemliche Herausforderung dar, und Handly kann den Aufwand für die Entwicklung von Handle-basierten Sprachmodellen durch die Bereitstellung hochwertiger Basisimplementierungen erheblich reduzieren.
Zusätzlich zu den oben aufgeführten Kernmechanismen bietet Handly eine Infrastruktur für Textpuffer und Snapshots, Unterstützung für die Integration mit Quellcode-Editoren (einschließlich der sofort einsatzbereiten Integration mit dem Xtext-Editor) sowie einige gängige UI-Komponenten Arbeiten Sie mit Quellcode-Editoren. Handliche Modelle wie das Outline-Framework. Um seine Fähigkeiten zu veranschaulichen, stellt das Projekt mehrere Beispiele bereit, darunter eine Implementierung des Java-Modells in Handly. (Im Vergleich zur vollständigen Implementierung des Java-Modells in JDT ist dieses Modell aus Gründen der Übersichtlichkeit bewusst etwas vereinfacht.)
Wie bereits erwähnt, lag und liegt ein Hauptaugenmerk beim ersten Design und der anschließenden Entwicklung von Handly auf Skalierbarkeit und Flexibilität.
Prinzipiell skalieren griffbasierte Modelle „by design“ recht gut. Mit der Handle/Body-Idiom können Sie beispielsweise die von einem Modell verbrauchte Speichermenge begrenzen. Aber es gibt auch Nuancen. Beim Testen von Handly auf Skalierbarkeit wurde daher ein Problem bei der Implementierung des Benachrichtigungsmechanismus entdeckt – wenn eine große Anzahl von Elementen geändert wurde, nahm die Erstellung von Deltas zu viel Zeit in Anspruch. Es stellte sich heraus, dass das gleiche Problem im JDT-Java-Modell vorlag, von dem der entsprechende Code einst angepasst wurde. Wir haben den Fehler in Handly behoben und einen ähnlichen Patch für JDT vorbereitet, der dankbar angenommen wurde. Dies ist nur ein Beispiel, bei dem die Einführung von Handly in bestehende Modellimplementierungen potenziell nützlich sein könnte, da in diesem Fall ein solcher Fehler an nur einer Stelle behoben werden könnte.
Um die Implementierung von Handly in bestehende Modellimplementierungen technisch machbar zu machen, muss die Bibliothek über erhebliche Flexibilität verfügen. Das Hauptproblem besteht darin, die Abwärtskompatibilität im gesamten API-Modell aufrechtzuerhalten. Dieses Problem wurde gelöst
Flexibilität hat auch andere Aspekte. Beispielsweise unterliegt Handly nahezu keinen Einschränkungen hinsichtlich der Struktur des Modells und kann zur Modellierung sowohl allgemeiner als auch domänenspezifischer Sprachen verwendet werden. Beim Aufbau der Struktur der Quelldatei schreibt Handly keine bestimmte Form der AST-Darstellung vor und erfordert im Prinzip nicht einmal das Vorhandensein eines AST selbst, wodurch die Kompatibilität mit nahezu jedem Parsing-Mechanismus gewährleistet ist. Schließlich unterstützt Handly die vollständige Integration mit Eclipse Workspace, kann aber dank seiner Integration auch direkt mit Dateisystemen arbeiten
Aktuelle Version
Wie oben erwähnt, ist eines dieser Produkte 1C:Enterprise Development Tools, bei dem Handly von Anfang an verwendet wird, um Elemente der High-Level-Struktur solcher 1C:Enterprise-Sprachen wie die integrierte Programmiersprache und die Abfragesprache zu modellieren . Ein anderes Produkt ist der breiten Öffentlichkeit weniger bekannt. Das
Wir hoffen, dass Handly nach der Veröffentlichung der Version 1.0 mit garantierter API-Stabilität und dem Verlassen des Inkubationsstadiums neue Anwender finden wird. In der Zwischenzeit testet und verbessert das Projekt die API weiter und veröffentlicht zwei „große“ Releases pro Jahr – im Juni (das gleiche Datum wie die gleichzeitige Eclipse-Veröffentlichung) und im Dezember, was einen vorhersehbaren Zeitplan bietet, auf den sich Anwender verlassen können. Wir können auch hinzufügen, dass die „Fehlerrate“ des Projekts auf einem konstant niedrigen Niveau bleibt und Handly seit den ersten Versionen zuverlässig in den Produkten der Early Adopters funktioniert. Um Eclipse weiter zu erkunden, können Sie Handly verwenden
Source: habr.com