Softwareproduktlinien - Komponenten und Frameworks Christian Kästner (CMU) Sven Apel (Universität Passau) Gunter Saake, Thomas Thüm (Universität Magdeburg) 1
Wiederholung: Konfigurationsmanagement und Präprozessoren Variabilität zur Übersetzungszeit Versionsverwaltungssysteme Nur für wenig Varianten geeignet, dafür etabliert Flexible Kombination von Features nicht möglich Build-Systeme Einfacher Mechanismus mit hoher Flexibilität Entwicklung von Varianten getrennt (keine einzelnen Features) Änderungen auf Dateiebene (eingeschränkte Wiederverwendbarkeit) Präprozessoren Einfaches Muster: markieren und entfernen Standard-Tools, hohe Flexibilität, feine Granularität, Feature-basiert Fehleranfällig, schwer lesbar, scattering/tangling, Wie können Features modular implementiert werden? 2
Wie Variabilität modular implementieren? Domain Eng. Feature-Modell Wiederverwendbare Implementierungsartefakte Application Eng. Feature-Auswahl Generator Fertiges Program 3
4 Komponenten
Komponente Abgeschlossene modulare Implementierungseinheit mit Schnittstelle (black box); bietet einen Dienst an Wird zusammen mit anderen Komponenten auch von anderen Herstellern zusammengesetzt zu Softwaresystemen (Komposition) Einzeln vermarktbar und lauffähig Kontext (z. B. JavaEE, CORBA, COM+/DCOM, OSGi) und Abhängigkeiten (imports, exports) explizit spezifiziert Klein genug für Erzeugung und Wartung in einem Stück, groß genug um sinnvolle Funktion bieten zu können 5
Komponenten vs. Objekte/Klassen Ähnliche Konzepte: Kapselung, Interfaces, Geheimnisprinzip Objekte strukturieren ein Problem Komponenten bieten wiederverwendbare Teilfunktionalität Objekte sind üblicherweise kleiner als Komponenten: Komponenten skalieren Objektorientierung Objekte haben häufig viele Abhängigkeiten zu anderen Objekten; Komponenten haben wenig Abhängigkeiten Interfaces von Objekten sind häufig implementierungsnah; Komponenten abstrahieren mehr 6
Vision: Märkte für Komponenten Komponenten können gekauft und in eigene Produkte integriert werden Best of Breed: Entwickler kann für jedes Teilsystem den besten/billigsten Anbieter auswählen Anbieter können sich auf Kernkompetenz beschränken und diese als Komponente(n) anbieten 7
Komponenten eines Webshops (UML-Notation) Bestellen Großhändler Kunde anlegen Adresse ändern Kundenverwaltung Rechnung drucken Reportgenerator Einkäufe Katalog verwalten Webshop Rechnung schreiben Finanzbuchhaltung Entnehmen Einlagern Lagerhaltung Szenario: Kunde anlegen Einkauf Rechnung schreiben Rechnung drucken 8
Produktlinien aus Komponenten Features werden in verschiedenen Komponenten implementiert z. B. die Komponenten Transaktionsverwaltung, Log/Recovery, Pufferverwaltung, Optimierer Komponenten können ggf. Laufzeitvariabilität enthalten Durch Feature-Auswahl werden Komponenten ausgewählt (mapping) Der Entwickler muss Komponenten verbinden (glue code) 9
Produktlinien aus Komponenten Feature-Modell Mapping von Features zu Komponenten Komponentensammlung Component10 Component6 Component2 Component12 Component5 Component1 Component9 Feature-Auswahl als Eingabe Component3 Component7 Component4 Component8 Component11 Component2 Entwickler baut fertiges Programm aus Komponenten Component6 Component9 Component8 Feature-Auswahl Komponentenauswahl Menge von Komponenten Fertiges Program 11
Wie Komponenten bestimmen? Markt für beliebige Komponenten funktioniert nicht Zu kleine Komponenten hoher Aufwand Zu große Komponenten kaum wiederverwendbar Produktlinien liefern nötige Domänenanalyse Welche Teilfunktionalität wird in welcher Granularität wiederverwendet Systematische Wiederverwendung 12 (Tangram)
Bewertung: Produktlinien aus Komponenten In der Industrie üblich (Beispiel: Heimelektronik mit Koala-Komponenten von Phillips) Produktlinien zum Domain Engineering, zur Organisation der Entwicklung, Systematische (geplante) Wiederverwendung von Komponenten Keine vollständige Automatisierung, hoher Entwicklungsaufwand (glue code) im Application Engineering Keine freie Feature-Auswahl 14
Diskussion: Modularität Komponenten verstecken interne Implementierung Idealerweise kleine Interfaces Feature-Kohäsion aber Grobe Granularität Seitenwechselstrategien, Suchalgorithmen, Locking im B-Baum, oder VARCHAR als Komponente? Farben oder gewichtete Kanten im Graph als Komponenten? Funktionalität ggf. schwer als Komponente zu kapseln Transaktionsverwaltungskomponente? 15
Services Ähnlich zu Komponenten: kapseln Teilfunktionalität (Dienste) i.d.r. verteiltes Szenario Bus-Kommunikation, Web Services, SOAP, REST Produktlinien durch Verbinden von Services, i.d.r. mit Orchestrierung (Workflow-Sprachen wie BPEL) Viele Werkzeuge verfügbar (teils managementgerecht ) 16
17 Frameworks
Frameworks Menge abstrakter und konkreter Klassen Abstrakte Struktur, die für einen bestimmten Zweck angepasst/erweitert werden kann vgl. Template Method Pattern und Strategy Pattern Wiederverwendbare Lösung für eine Problemfamilie in einer Domäne Punkte an denen Erweiterungen vorgesehen sind: hot spots (auch variation points, extension points) Umkehrung der Kontrolle, das Framework bestimmt die Ausführungsreihenfolge Hollywood-Prinzip: Don t call us, we ll call you. 18
Plug-ins Erweiterung eines Frameworks Spezielle Funktionen bei Bedarf hinzufügen Üblicherweise getrennt kompiliert; third-party Beispiele: Email-Programme, Grafikprogramme, Media- Player, Web browser 19
Web Portal Webapplikation- Frameworks wie Struts, die grundlegende Konzepte vorgeben und vorimplementieren Entwickler konzentrieren sich auf Anwendungslogik statt Navigation zwischen Webseiten <?php class WebPage { function getcssfiles(); function getmoduletitle(); function hasaccess(user u); function printpage();?> <?php class ConfigPage extends WebPage { function getcssfiles() { function getmoduletitle() { return Configuration ; function hasaccess(user u) { return user.isadmin(); function printpage() { print <form><div> ;?> 20
Eclipse Eclipse als Framework für IDEs Nur sprachspezifische Erweiterungen (Syntax Highlighting, Compiler) müssen implementiert werden Der gemeinsame Teil (Editoren, Menüs, Projekte, Verzeichnisbaum, Copy & Paste & Undo Operationen, CVS, uvm.) ist durch das Framework vorgegeben Framework aus vielen kleineren Frameworks 21
Eclipse JDT WTP SAPinst Workbench Build Debug Edit JUnit Refactor Launch Platform Ant IDE Cheat Sheets Search Debug Team Help Update Views Resources Console Editors Forms Text Editors Compare J2EE Web Control Items Component Messages Resourcepool Dialogs Weitere Erweiterungen Table Script Meta-Dialogs Prerequisite C. Rich Client Platform Workbench Help JFace Core Runtime OSGi SWT 22
Weitere Framework-Beispiele Frameworks für graphische Benutzeroberflächen, z.b. MacApp, Swing, SWT, MFC Multimedia-Frameworks, z.b. DirectX Instant Messenger-Frameworks, z.b. Miranda, Trillian,... Compiler-Frameworks, z.b. Polyglot, abc, JastAddJ 23
Framework-Implementierung: Mini-Beispiel Familie von Dialogen, bestehend aus Textfeld und Button 90% des Quelltexts sind gleich Main Methode Initialisierung von Fenster, Textfeld und Button Layout Schließen des Fensters 24
Taschenrechner public class Calc extends JFrame { private JTextField textfield; public static void main(string[] args) { new Calc().setVisible(true); public Calc() { init(); protected void init() { JPanel contentpane = new JPanel(new BorderLayout()); contentpane.setborder(new BevelBorder(BevelBorder.LOWERED)); JButton button = new JButton(); button.settext("calculate"); contentpane.add(button, BorderLayout.EAST); textfield = new JTextField(""); textfield.settext("10 / 2 + 6"); textfield.setpreferredsize(new Dimension(200, 20)); contentpane.add(textfield, BorderLayout.WEST); button.addactionlistener(/* code zum berechnen */); this.setcontentpane(contentpane); this.pack(); this.setlocation(100, 100); this.settitle("my Great Calculator"); // code zum schliessen des fensters 25
White-Box Frameworks Erweiterung durch Überschreiben und Hinzufügen von Methoden (vgl. Template Method Pattern) Interna des Framework müssen verstanden werden schwierig zu lernen Flexible Erweiterung Viele Subklassen nötig u.u. unübersichtlich Status direkt verfügbar durch Superklasse Keine Plug-ins, nicht getrennt kompilierbar 26
Taschenrechner als Whitebox-Framework public abstract class Application extends JFrame { protected abstract String getapplicationtitle(); //Abstrakte Methoden protected abstract String getbuttontext(); protected String getinititaltext() {return ""; protected void buttonclicked() { private JTextField textfield; public Application() { init(); protected void init() { JPanel contentpane = new JPanel(new BorderLayout()); contentpane.setborder(new BevelBorder(BevelBorder.LOWERED)); JButton button = new JButton(); button.settext(getbuttontext()); contentpane.add(button, BorderLayout.EAST); textfield = new JTextField(""); textfield.settext(getinititaltext()); textfield.setpreferredsize(new Dimension(200, 20)); contentpane.add(textfield, BorderLayout.WEST); button.addactionlistener(/* buttonclicked(); */); this.setcontentpane(contentpane); this.pack(); this.setlocation(100, 100); this.settitle(getapplicationtitle()); // code zum schliessen des fensters protected String getinput() { return textfield.gettext(); 27
Taschenrechner als Whitebox-Framework public abstract class Application extends JFrame { protected abstract String getapplicationtitle(); //Abstrakte Methoden protected abstract String getbuttontext(); protected String getinititaltext() {return ""; protected void buttonclicked() { private JTextField textfield; public Application() { init(); public class Calculator extends Application { protected void init() { protected String getbuttontext() { return "calculate"; JPanel contentpane = new JPanel(new BorderLayout()); protected String getinititaltext() { return "(10 3) * 6"; contentpane.setborder(new BevelBorder(BevelBorder.LOWERED)); protected void buttonclicked() { JButton button = new JButton(); JOptionPane.showMessageDialog(this, "The result of "+getinput()+ button.settext(getbuttontext()); " is "+calculate(getinput())); contentpane.add(button, BorderLayout.EAST); protected String getapplicationtitle() { return "My Great Calculator"; textfield = new JTextField(""); public static void main(string[] args) { textfield.settext(getinititaltext()); new Calculator().setVisible(true); textfield.setpreferredsize(new Dimension(200, 20)); contentpane.add(textfield, BorderLayout.WEST); button.addactionlistener(/* buttonclicked(); */); public this.setcontentpane(contentpane); class Ping extends Application { this.pack(); protected String getbuttontext() { return "ping"; this.setlocation(100, protected String 100); getinititaltext() { return "127.0.0.1"; this.settitle(getapplicationtitle()); protected void buttonclicked() { /* */ // code zum protected schliessen String des getapplicationtitle() fensters { return "Ping"; public static void main(string[] args) { protected String getinput() new { return Ping().setVisible(true); textfield.gettext(); 28
Black-Box Frameworks Einbinden des anwendungsspezifischen Verhalten durch Komponenten mit speziellem Interface (plug-in) vgl. Strategy Pattern, Observer Pattern Nur das Interface muss verstanden werden einfacher zu lernen, aber aufwendiger zu entwerfen Flexibilität durch bereitgestellte Hot Spots festgelegt, häufig Design Patterns Status nur bekannt wenn durch Interface verfügbar Insgesamt besser wiederverwendbar (?) 29
Taschenrechner public class Application extends JFrame { private JTextField textfield; private Plugin plugin; public Application(Plugin p) { this.plugin=p; p.setapplication(this); init(); protected void init() { JPanel contentpane = new JPanel(new BorderLayout()); public interface Plugin { contentpane.setborder(new BevelBorder(BevelBorder.LOWERED)); String getapplicationtitle(); JButton button = new JButton(); String getbuttontext(); if (plugin!= null) String getinititaltext(); button.settext(plugin.getbuttontext()); void buttonclicked() ; else void setapplication(application app); button.settext("ok"); contentpane.add(button, BorderLayout.EAST); textfield = new JTextField(""); if (plugin!= null) textfield.settext(plugin.getinititaltext()); textfield.setpreferredsize(new Dimension(200, 20)); contentpane.add(textfield, BorderLayout.WEST); if (plugin!= null) button.addactionlistener(/* plugin.buttonclicked(); */); this.setcontentpane(contentpane); public String getinput() { return textfield.gettext(); 30
Taschenrechner public class Application extends JFrame { private JTextField textfield; private Plugin plugin; public Application(Plugin p) { this.plugin=p; p.setapplication(this); init(); protected void init() { JPanel contentpane = new JPanel(new BorderLayout()); public interface Plugin { contentpane.setborder(new BevelBorder(BevelBorder.LOWERED)); String getapplicationtitle(); JButton button = new JButton(); String getbuttontext(); if (plugin!= null) String getinititaltext(); button.settext(plugin.getbuttontext()); void buttonclicked() ; else void setapplication(application app); button.settext("ok"); contentpane.add(button, BorderLayout.EAST); textfield = new JTextField(""); public class CalcPlugin implements Plugin { if (plugin!= null) private Application application; textfield.settext(plugin.getinititaltext()); public void setapplication(application app) { this.application = app; textfield.setpreferredsize(new Dimension(200, public String 20)); getbuttontext() { return "calculate"; contentpane.add(textfield, BorderLayout.WEST); public String getinititaltext() { return "10 / 2 + 6"; if (plugin!= null) public void buttonclicked() { button.addactionlistener(/* JOptionPane.showMessageDialog(null, plugin.buttonclicked(); */); "The result of " this.setcontentpane(contentpane); + application.getinput() + " is " + calculate(application.gettext())); public String getapplicationtitle() { return "My Great Calculator"; public String getinput() { return textfield.gettext(); class CalcStarter { public static void main(string[] args) { new Application(new CalcPlugin()).setVisible(true); 31
public class Application extends JFrame implements InputProvider { private JTextField textfield; private Plugin plugin; public Application(Plugin p) { this.plugin=p; p.setapplication(this); init(); Weitere Entkopplung moeglich public interface InputProvider { String getinput(); protected void init() { JPanel contentpane = new JPanel(new BorderLayout()); public interface Plugin { contentpane.setborder(new BevelBorder(BevelBorder.LOWERED)); String getapplicationtitle(); JButton button = new JButton(); String getbuttontext(); if (plugin!= null) String getinititaltext(); button.settext(plugin.getbuttontext()); void buttonclicked() ; else void setapplication(inputprovider app); button.settext("ok"); contentpane.add(button, BorderLayout.EAST); textfield = new JTextField(""); public class CalcPlugin implements Plugin { if (plugin!= null) private InputProvider application; textfield.settext(plugin.getinititaltext()); public void setapplication(inputprovider app) { this.application = app; textfield.setpreferredsize(new Dimension(200, public String 20)); getbuttontext() { return "calculate"; contentpane.add(textfield, BorderLayout.WEST); public String getinititaltext() { return "10 / 2 + 6"; if (plugin!= null) public void buttonclicked() { button.addactionlistener(/* JOptionPane.showMessageDialog(null, plugin.buttonclicked(); */); "The result of " this.setcontentpane(contentpane); + application.getinput() + " is " + calculate(application.getinput())); public String getapplicationtitle() { return "My Great Calculator"; public String getinput() { return textfield.gettext(); class CalcStarter { public static void main(string[] args) { new Application(new CalcPlugin()).setVisible(true); 32
Plug-ins laden Typisch für viele Frameworks: Plug-in Loader sucht in Verzeichnis nach DLL/Jar/XML Dateien testet ob Datei ein Plug-in implementiert prüft Abhängigkeiten initialisiert Plug-in Häufig zusätzlich GUI für Plugin-Konfiguration Beispiele: Eclipse (plugin-verzeichnis + Jar) Miranda (plugins-verzeichnis + DLL) Alternativ: Plug-ins in Konfigurationsdatei festlegen oder Starter-Programm generieren 33
Beispiel Plugin Loader (benutzt Java Reflection) public class Starter { public static void main(string[] args) { if (args.length!= 1) System.out.println("Plugin name not specified"); else { String pluginname = args[0]; try { Class<?> pluginclass = Class.forName(pluginName); new Application((Plugin) pluginclass.newinstance()).setvisible(true); catch (Exception e) { System.out.println("Cannot load plugin " + pluginname + ", reason: " + e); 34
Mehrere Plug-ins vgl. Observer Pattern Mehrere Plug-ins laden und registrieren Bei Ereignis alle Plug-ins informieren Für unterschiedliche Aufgaben: spezifische Plug-in-Schnittstellen public class Application { private List<Plugin> plugins; public Application(List<Plugin> plugins) { this.plugins=plugins; for (Plugin plugin: plugins) plugin.setapplication(this); public Message processmsg (Message msg) { for (Plugin plugin: plugins) msg = plugin.process(msg);... return msg; 35
Frameworks für Produktlinien Domain Eng. Feature-Modell Mapping von Features zu Plug-ins Framework + Plugins Application Eng. Feature-Auswahl Feature-Auswahl als Eingabe Plug-in-Auswahl (und ggf. Startkonfiguration generieren) Anwendung = Framework mit passenden Plugins 36
Frameworks für Produktlinien Bewertung Vollautomatisierung möglich Modularität Praxiserprobt Erstellungsaufwand und Laufzeit-Overhead für Framework/Architektur Framework-Design erfordert Erfahrung Schwierige Wartung, Evolution Preplanning Problem Grobe Granularität oder riesige Interfaces 37 Plug-in für Transaktionsverwaltung oder gewichtete Kanten? Problem der Querschneidenden Belange
Zusammenfassung Modularisierung von Features mit Komponenten und Frameworks Laufzeitoverhead, grobe Granularität Grenzen bei querschneidenen Belangen und feiner Granularität Modularität erfordert Planung Nicht für alle Produktlinien geeignet (z.b. Graph-Bibliothek, eingebettete Datenbanken) 38
Ausblick Neue Programmierkonzepte Analyse Objekt-Orientierung und deren Grenzen Feature-Orientierung Aspekt-Orientierung 39
Literatur S. Apel, D. Batory, C. Kästner, and G. Saake. Feature-Oriented Software Product Lines - Concepts and Implementation. Springer, 2013. Section 4.3: Frameworks Section 4.4: Components and Services C. Szyperski: Component Software: Beyond Object-Oriented Programming. Addison-Wesley, 1998 [Standardwerk Komponentenorientierte Softwareentwicklung] R. Johnson and B. Foote, Desiging reusable classes, Journal of Object-Oriented Programming, 1(2):22-35, 1988 [OOP Wiederverwendung, insb. Frameworks] L. Bass, P. Clements, R. Kazman, Software Architecture in Practice, Addison-Wesley, 2003 [Architekturgetriebene Produktlinien, typischerweise Frameworks] 40