Softwareproduktlinien - Komponenten und Frameworks Christian Kästner (CMU) Sven Apel (Universität Passau) Gunter Saake, Thomas Thüm (Universität Magdeburg) 1
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
Do
mai
n E
ng.
A
pp
licat
ion
En
g.
Feature-Auswahl
Feature-Modell Wiederverwendbare Implementierungs- artefakte
Generator Fertiges Program
3
Wie Variabilität modular implementieren?
Komponenten
4
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)
FinanzbuchhaltungRechnung schreiben
ReportgeneratorRechnung drucken
Webshop
LagerhaltungEinlagern
Entnehmen
GroßhändlerBestellen
KundenverwaltungKunde anlegen
Adresse ändern
Einkäufe
Katalog verwalten
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
Component1
Component2
Component3
Component4
Component5
Component6
Component7
Component8
Component9
Component10
Component11
Component12
Component2
Component6
Component8
Component9
Feature-Auswahl
Feature-Modell
Komponentensammlung
Komponentenauswahl Fertiges Program
Feature-Auswahl als Eingabe
Mapping von Features zu Komponenten
Menge von Komponenten
Entwickler baut fertiges Programm aus Komponenten
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 Granu- larität wiederverwendet
Systematische Wiederverwendung
(Tangram)
12
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 Entwicklungs-aufwand (glue code) im Application Engineering
Keine freie Feature-Auswahl
14
Diskussion: Modularität
15
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?
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
Frameworks
17
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
Rich Client Platform
OSGiSWT
Core Runtime
JFaceHelp
Workbench
Platform
Ant
IDE
Cheat S
heets
Searc
h
Debug
Team
Help
Update
Vie
ws
Reso
urc
es
Conso
le
Editors
Form
s
Text
Editor
s
Com
pare
WTP
J2E
E
Web
SAPinst Workbench
Control I
tem
s
Messa
ges
Res
ourc
epool
Dia
logs
Meta
-Dia
logs
Pre
requ
isite
C.
Com
ponen
t
Table
Scrip
t
JDTB
uild
Debu
g
Edi
t
JU
nit
Refa
ctor
Launch
Weitere Erweiterungen…
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
27
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();} }
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();} }
Taschenrechner als Whitebox-Framework
public class Calculator extends Application { protected String getButtonText() { return "calculate"; } protected String getInititalText() { return "(10 – 3) * 6"; } protected void buttonClicked() { JOptionPane.showMessageDialog(this, "The result of "+getInput()+ " is "+calculate(getInput())); } protected String getApplicationTitle() { return "My Great Calculator"; } public static void main(String[] args) { new Calculator().setVisible(true); }
}
public class Ping extends Application { protected String getButtonText() { return "ping"; } protected String getInititalText() { return "127.0.0.1"; } protected void buttonClicked() { /* … */ } protected String getApplicationTitle() { return "Ping"; } public static void main(String[] args) { new Ping().setVisible(true); }
}
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()); contentPane.setBorder(new BevelBorder(BevelBorder.LOWERED)); JButton button = new JButton(); if (plugin != null) button.setText(plugin.getButtonText()); else 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();}
}
public interface Plugin { String getApplicationTitle(); String getButtonText(); String getInititalText(); void buttonClicked() ; void setApplication(Application app); }
30
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()); contentPane.setBorder(new BevelBorder(BevelBorder.LOWERED)); JButton button = new JButton(); if (plugin != null) button.setText(plugin.getButtonText()); else 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();}
}
Taschenrechner
public class CalcPlugin implements Plugin { private Application application; public void setApplication(Application app) { this.application = app; } public String getButtonText() { return "calculate"; } public String getInititalText() { return "10 / 2 + 6"; } public void buttonClicked() { JOptionPane.showMessageDialog(null, "The result of " + application.getInput() + " is " + calculate(application.getText())); } public String getApplicationTitle() { return "My Great Calculator"; }
}
class CalcStarter { public static void main(String[] args) { new Application(new CalcPlugin()).setVisible(true); }}
31
public interface Plugin { String getApplicationTitle(); String getButtonText(); String getInititalText(); void buttonClicked() ; void setApplication(Application app); }
public class Application extends JFrame implements InputProvider { 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()); contentPane.setBorder(new BevelBorder(BevelBorder.LOWERED)); JButton button = new JButton(); if (plugin != null) button.setText(plugin.getButtonText()); else 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();}
}
Weitere Entkopplung möglich
public class CalcPlugin implements Plugin { private InputProvider application; public void setApplication(InputProvider app) { this.application = app; } public String getButtonText() { return "calculate"; } public String getInititalText() { return "10 / 2 + 6"; } public void buttonClicked() { JOptionPane.showMessageDialog(null, "The result of " + application.getInput() + " is " + calculate(application.getInput())); } public String getApplicationTitle() { return "My Great Calculator"; }
}
public interface Plugin { String getApplicationTitle(); String getButtonText(); String getInititalText(); void buttonClicked() ; void setApplication(InputProvider app); }
class CalcStarter { public static void main(String[] args) { new Application(new CalcPlugin()).setVisible(true); }}
32
public interface InputProvider { String getInput(); }
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)
34
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); } } }
}
Mehrere Plug-ins
35
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;
} }
Frameworks für Produktlinien
Feature-Auswahl
Feature-Modell
Framework + Plugins
Plug-in-Auswahl (und ggf. Startkonfiguration
generieren)
Anwendung = Framework mit
passenden Plugins
Feature-Auswahl als Eingabe
Mapping von Features zu Plug-ins
Do
main
En
g.
Ap
pli
cati
on
En
g.
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
Plug-in für Transaktionsverwaltung oder gewichtete Kanten?
Problem der Querschneidenden Belange
37
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