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. Eine 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 Hilfmittel aus dem Java Toolset zur Entkopplung des Umsystems ist der ServiceLoader. Der SericeLoader ist ein einfacher Dependency Injection Mechnismus 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 Verzeichnisch 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 mit Hilfe des ServiceLoader eine Instanz der Implementierung der abstrakten Klasse oder des Interfaces liefert.

Um den Legacy Code 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 Legacy Codes 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, so dass die enstprechende Implementierung angezogen wird.

Nach dem 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 mit Hilfe des Test Providers getestet und damit auch refactored werden.

comments powered by Disqus