Patterns zum Umgang mit Legacy Code: ServiceLoader

By Gerald Mücke | October 9, 2015

Patterns zum Umgang mit Legacy Code: ServiceLoader

Legacy Code ist Code, der nicht nach aktuellen Massstäben der Software-Entwicklung entwickelt wurde, nicht mehr gewartet wird und häufig nicht oder unzureichend dokumentiert wird. Aber auch externe, proprietäre closed source Libraries genügen häufig diesen Kriterien. Oftmals wird dieser Code jedoch nach wie vor betrieben und muss auch hin und wieder angepasst werden, z.B. um regulatorischen Anforderungen nachzukommen. Legacy Code kommt häufig in der Form eine CLOBs daher. Eine undefinierte Masse an Codezeilen, von der keiner mehr weiss, was er tut. Ein erster Schritt ist es, das System in seine logischen Bestandteile zu zerlegen. Nicht selten werden jedoch Umsysteme über 3rd Party Libraries eingebunden und der Zugriff darauf erfolgt von der Präsentationsschicht durch alle anderen logischen Schichten bis zum Umsystem in einer einzigen Methode. Bevor ein Refactoring einer solchen Methode geschehen kann, muss die Abhängigkeit zum Umsystem entkoppelt um einen Test der bestehenden Methode geschrieben. Ein einfaches Hilfsmittel aus dem Java Toolset zur Entkopplung des Umsystems ist der ServiceLoader. Der ServiceLoader ist ein einfacher Dependency Injection Mechanisms und Teil der Standard Edition, d.h. seit der Version 6 in jedem Java Runtime Environment verfügbar. Um den ServiceLoader zu benutzen, benötigt man drei Elemente:

  1. Eine abstrakte Klasse oder ein Interface, dessen Implementierung austauschbar sein soll
  2. Eine Datei im Verzeichnis META-INF/services, dessen Name der vollqualifizierte Name der abstrakten Klasse oder des Interfaces ist und dessen Inhalt der vollqualifizierte Name der Implementierung ist. Diese Datei wird im Jar des Providers gebraucht, d.h. muss dort liegen, wo auch die Implementierung liegt
  3. Eine Factory Methode, die mithilfe des ServiceLoader eine Instanz der Implementierung der abstrakten Klasse oder des Interfaces liefert.

Um den Legacycode nun so zu modifizieren, dass die 3rd Party Library austauschbar wird sollte wie folgt vorgegangen werden.

  1. Zugriffe auf 3rd Party Library in eine neue Klasse auslagern
  2. Interface der Klasse abstrahieren
    1. Interface in Service Provider Interface (SPI) Modul zusammen mit der Factory Methode auslagern
    2. Abhängigkeit des Legacycodes auf SPI ändern
  3. Klasse mit den 3rd Party Library Zugriffen in ein Provider-Module auslagern, diese enthält die services Datei.
  4. Für den produktiven Einsatz muss das Provider-Module im Classpath vorhanden sein, sodass die entsprechende Implementierung angezogen wird.

Nachdem diese Umstellung erfolgt ist, kann nun ein Test Provider entwickelt werden, der das Verhalten der 3rd Party Library mockt. Damit kann dann der Legacy Code ohne Umsystem mithilfe des Test-Providers getestet und damit auch refactored werden.

comments powered by Disqus