14 Min. Lesezeit

Modellierungsmetriken für UML-Diagramme

UML-Quantitäts-Metriken

Quantitäts-Metriken sind Zählungen der im UML-Modell enthaltenen Diagramm- und Modelltypen. Die Modelltypen werden weiter unterteilt in Zählungen von Entitäten und Zählungen von Beziehungen.

Die 9 UML-Diagramm-Typen sind:

Anzahl der…

  • Anwendungsfall-Diagramme
  • Aktivitätsdiagramme
  • Klassendiagramme
  • Sequenzdiagramme
  • Interaktionsdiagramme
  • Zustandsdiagramme
  • Komponentendiagramme
  • Verteilungsdiagramme
  • Entwurfsdiagramme

Die 17 Entitätstypen sind:

Anzahl der…

  • Sub-Systeme
  • Anwendungsfälle
  • Aktoren
  • Komponenten
  • Schnittstellen
  • Klassen
  • Basis-/Superklassen
  • Methoden
  • Parameter
  • Attribute
  • Aktivitäten
  • Objekte
  • Staaten
  • Regeln
  • Stereotypen
  • Design-Entitäten
  • Design-Entitäten referenziert

Die 10 Beziehungstypen sind:

Anzahl der…

  • Verwendungen
  • Assoziationen
  • Verallgemeinerungen
  • Interaktionen
  • Klassenhierarchiestufen
  • Methodenaufrufe
  • Aktivitätsflüsse
  • Zustandsübergänge
  • Testfälle
  • Design Beziehungen

Diese Größen bzw. Elementanzahlen wurden aufgrund ihres Bezugs zu den Zielen des objektorientierten Systementwurfs nach der Ziel-Frage-Metrik-Methode von Basili und Rombach ausgewählt.

UML-Komplexitäts-Metriken

Komplexitäts-Metriken sind Berechnungen zur Ermittlung ausgewählter Komplexitäten. Komplexität ist hier definiert als das Verhältnis von Entitäten zu Beziehungen. Die Größe einer Menge wird durch die Anzahl der Elemente in dieser Menge bestimmt. Die Komplexität einer Menge ist eine Frage der Anzahl der Beziehungen zwischen den Elementen dieser Menge. Je mehr Verbindungen oder Abhängigkeiten es im Verhältnis zur Anzahl der Elemente gibt, desto größer ist die Komplexität. Die Komplexität einer einzelnen Entität wird durch die Anzahl der Unterentitäten im Verhältnis zur Anzahl der Beziehungen zwischen diesen Unterentitäten bestimmt. Die Gesamtkomplexität des Designs kann einfach wie folgt angegeben werden:

uml_design_complexity_metrics

Vor diesem Hintergrund wurden die folgenden Komplexitätstypen für UML-Modelle definiert.

Komplexität der Objektinteraktion

object_interaction_complexity

Je mehr Interaktionen zwischen Objekten und je mehr Assoziationen zwischen Klassen vorhanden sind, desto höher ist die Komplexität. Auf diese Weise wird sowohl die abstrakte Ebene der Klasse als auch die physikalische Ebene der Objekte berücksichtigt. Dieses Maß ist eine inverse Kopplungsmetrik. Es basiert auf der empirischen Erkenntnis, dass Systeme mit vielen Abhängigkeiten zwischen ihren Teilen schwer zu warten sind.

Komplexität der Klassenhierarchie

class_hierachical_complexity

Je mehr Hierarchieebenen es in den Klassenhierarchien gibt, desto abhängiger sind die Klassen der unteren Ebene von den Klassen der höheren Ebene. Tiefe Vererbung wurde oft dafür kritisiert, dass sie zu erhöhter Komplexität führt. Diese Metrik entspricht der Tiefe der Baummetrik von Chidamer und Kemerer. Sie basiert auf empirischen Belegen, dass objektorientierte Systeme mit tiefen Vererbungsbäumen (z. B. > 3) fehleranfälliger sind als andere.

Komplexität der Klassendaten

class_data_complexity

Je mehr Datenattribute eine Klasse hat, desto höher ist ihre Komplexität. Dies entspricht der Klassenattribut-Metrik in den Mood-Metriken. Das Design-Ziel ist es, viele Klassen mit jeweils wenigen Datenattributen zu haben, im Gegensatz zu wenigen Klassen mit jeweils vielen Attributen. Dieses Ziel basiert auf der Annahme, dass es einfacher ist, kleinere Datensätze zu testen und zu pflegen.

Komplexität der Klassenfunktionen

class_funktional_complexity

Je mehr Methoden, d. h. Funktionen, eine Klasse hat, desto höher ist ihre Komplexität, wobei davon ausgegangen wird, dass jede Klasse mindestens zwei implizite Funktionen – einen Konstruktor und einen Destruktor – hat. Dies entspricht der Number of Methods-Metrik von Chidamer und Kemerer. Das Entwurfsziel ist es, viele Klassen mit einer minimalen Anzahl von Funktionen zu haben, im Gegensatz zu wenigen Klassen mit vielen Methoden. Dieses Ziel basiert auf der Annahme, dass es einfacher ist, ein System zu warten und zu testen, das in viele kleine Teile der Funktionalität unterteilt ist.

Komplexität des Objektzustands

object_state_complexity

Objekte sind Instanzen einer Klasse. Objekte haben Zustände. Je mehr sie haben, desto komplexer sind sie. Eine einfache Klasse ist ein Singleton mit einem Objekt, das einen statischen Zustand hat. Eine komplexe Klasse ist eine Klasse mit mehreren Objekten, von denen jedes mehrere mögliche Zustände hat. Weder die CK- noch die MOOD-Metriken berücksichtigen die Zustandskomplexität, obwohl sie zusammen mit der zyklomatischen Komplexität der Methoden ein Haupttreiber des Testaufwands ist. Das Design-Ziel ist es, viele Klassen zu haben, jede mit einer minimalen Anzahl von Funktionen, im Gegensatz zu möglichst wenigen Objektzuständen, aber das wird durch die Anwendung bestimmt. Wenn ein Objekt wie z. B. ein Konto viele Zustände hat, z. B. eröffnet, ausgeglichen, überzogen, gesperrt, geschlossen usw., müssen sie alle erstellt und getestet werden.

Komplexität der Zustandsübergänge

state_transition_complexity

Die Verbindungslinien eines Zustandsdiagramms stellen die Übergänge von einem Zustand in einen anderen dar. Ein gegebener Zustand kann eine beliebige Anzahl von Nachfolgezuständen haben. Je mehr es sind, desto höher ist die Komplexität des Zustandsübergangsgraphen. Wie beim McCabe-Maß für zyklomatische Komplexität messen wir hier eigentlich das Verhältnis von Kanten zu Knoten in einem Graphen. Nur sind hier die Knoten keine Anweisungen, sondern Zustände, und die Kanten sind keine Verzweigungen, sondern Transitionen. Das Entwurfsziel ist es, möglichst wenige Transitionen zu haben, da jeder Zustandsübergang mindestens einmal getestet werden muss und das die Testkosten in die Höhe treibt.

Aktivitäts-Kontrollfluss Komplexität

activity_control_flow_complexity

Die Verbindungslinien eines Aktivitätsdiagramms stellen den Kontrollfluss von einer Aktivität zur anderen dar. Sie können bedingte oder nicht bedingte Abläufe sein. Bedingte Flüsse erhöhen die Komplexität des modellierten Prozesses. Eine Aktivität kann eine beliebige Anzahl von Folgeaktivitäten haben. Je mehr es sind und je mehr bedingte es gibt, desto höher ist die Komplexität des Prozesses.

Komplexität des Anwendungsfalls

use_case_complexity

Anwendungsfälle, wie sie von Ivar Jacobson geprägt wurden, sind Instanzen der Systemnutzung. Ein Benutzer oder Systemakteur ruft einen Anwendungsfall auf. Dies ist ein Fall von Nutzung. Die Beziehungen zwischen Use Cases können unterschiedliche Bedeutungen haben. Sie können Verwendung oder Erweiterung oder Einschließen oder Erben bedeuten. Je mehr Beziehungen es gibt, desto höher ist die Komplexität der Verwendung. Das Ziel des Designs ist es, die Komplexität zu reduzieren, indem die Anzahl der Abhängigkeiten zwischen Anwendungsfällen eingeschränkt wird. Andererseits, wenn die Anwendung sie benötigt, dann müssen sie einbezogen werden. Andernfalls wird die Komplexität nur auf eine andere Schicht abgeschoben.

Komplexität der Akteur-Interaktion

actor_interaction_complexity

Systemakteure lösen die Anwendungsfälle aus. Jeder einzelne Akteur kann einen oder mehrere Anwendungsfälle auslösen. Je mehr Anwendungsfälle es pro Akteur gibt, desto komplexer ist die Beziehung zwischen Akteuren und dem System. Aus der Sicht eines Akteurs ist ein System komplex, wenn er sich mit vielen Anwendungsfällen auseinandersetzen muss. Je mehr Anwendungsfälle es pro Akteur gibt, desto höher ist die Komplexität. Ein System, das nur einen Anwendungsfall pro Akteur hat, ist einfach, weil es entsprechend den Akteuren partitioniert ist. Das Ziel des Designs ist es, die Anzahl der Anwendungsfälle pro Akteur zu begrenzen. Natürlich steigt durch mehr Akteure die Größe des Systems in Use-Case-Punkten.

Gesamtkomplexität der Konstruktion

overall_design_complexity

Die Gesamtkomplexität des Designs wird als das Verhältnis zwischen der Summe aller Design-Entitäten und der Summe aller Design-Beziehungen berechnet.

Ein Entwurf, bei dem jede Entität nur wenige Beziehungen hat, kann als weniger komplex angesehen werden als ein Systementwurf, bei dem die Anzahl der Beziehungen pro Entität hoch ist. Dies spiegelt die Komplexität als das Verhältnis der Anzahl von Beziehungen zwischen Elementen einer Menge und der Anzahl von Elementen in einer Menge wider. Je mehr Elemente es gibt, desto größer ist die Menge. Je mehr Beziehungen vorhanden sind, desto höher ist die Komplexität der Menge. Das Konstruktionsziel besteht darin, die Anzahl der Beziehungen zwischen den Konstruktionsobjekten zu minimieren.

UML-Qualitäts-Metriken

Die Metriken zur Entwurfsqualität sind Berechnungen zur Ermittlung ausgewählter Qualitäten. Qualität wird hier definiert als das Verhältnis des Zustands, in dem sich das Modell befindet, zu dem Zustand, in dem es sich befinden sollte. Die Qualitätsmessung setzt einen Standard für das UML-Modell voraus. Der Ist-Zustand des Modells wird dann mit diesem Standard verglichen. Je näher das Modell an diesem Standard ist, desto höher ist seine Qualität. Im Deutschen lässt sich die Gesamtentwurfsqualität einfach durch das Verhältnis ausdrücken:

uml_design_quality_metrics

Die obere Grenze der Metrik ist 1. Wenn der IST-Wert den SOLL-Wert überschreitet, wurde das Qualitätsziel übertroffen. Ein Quotientenkoeffizient von 0,5 zeigt eine mittlere Qualität an. Es ist zu bedenken, dass Qualität relativ ist. Für sich genommen bedeutet der Quotient vielleicht nicht so viel. Im Vergleich mit dem Quotienten, der von einer anderen Konstruktion auf genau dieselbe Weise abgeleitet wurde, zeigt er jedoch an, dass die eine Konstruktion eine bessere oder schlechtere Qualität hat als die andere, zumindest in Bezug auf das gemessene Qualitätsmerkmal. Da es keine absolute Qualitätsskala gibt, kann die Qualität eines Systementwurfs nur in Relation zu der Qualität eines anderen beurteilt werden. Für die Beurteilung der Qualität eines UML-Modells wurden die folgenden Qualitätsmerkmale ausgewählt.

Grad der Klassenkopplung

Die Klassenkopplung ist der Kehrwert der Interaktionskomplexität. Sie wird durch die Gleichung berechnet:

degree_of_class_coupling

Je mehr Interaktionen und Assoziationen es zwischen Objekten und Klassen gibt, desto größer ist die Abhängigkeit dieser Objekte und Klassen voneinander. Diese gegenseitige Abhängigkeit wird als Kopplung bezeichnet. Klassen mit einer hohen Kopplung haben einen größeren Wirkungsbereich. Wenn sie geändert werden, ist die Wahrscheinlichkeit größer, dass auch die anderen Klassen davon betroffen sind. Ziel des Designs ist es, möglichst wenige Abhängigkeiten zu haben, d.h. die Kopplung sollte gering sein. Dieses Qualitätsmerkmal beruht auf der empirischen Erkenntnis, dass eine hohe Kopplung mit einer größeren Auswirkungsdomäne, mit einer höheren Fehlerrate und mit einem höheren Wartungsaufwand verbunden ist.

Grad der Klassenkohäsion

Die Klassenkohäsion wird anhand der Anzahl der Datenattribute in einer Klasse im Verhältnis zur Anzahl der Klassenmethoden gemessen. Sie wird durch die Gleichung berechnet:

degree_of_class_cohesion

Der Begriff der Kohäsion bezeichnet den Grad der Zusammengehörigkeit der Funktionen eines Moduls. Funktionen gehören zusammen, wenn sie die gleichen Daten verarbeiten. Dies kann man als Datenkopplung bezeichnen. Je weniger Daten also von den gleichen Funktionen verwendet werden, desto besser. Klassen mit einer hohen Kohäsion haben viele Methoden und wenige Attribute. Klassen mit vielen Attributen und wenigen Methoden haben eine geringere Kohäsion. Das Designziel ist, möglichst wenige gemeinsame Attribute für gleiche Methoden zu haben. Diesem Qualitätsmerkmal liegt die Hypothese zugrunde, dass eine hohe Kohäsion mit einer hohen Wartbarkeit verbunden ist. Diese Hypothese ist nie wirklich bewiesen worden.

Grad der Modularität

Modularität ist ein Maß für die Dekomposition. Sie drückt den Grad aus, in dem ein großes System in viele kleine Teile zerlegt wurde. Die Theorie besagt, dass es einfacher ist, mit kleineren Code-Einheiten umzugehen. Die Modularität von Klassen wird durch die Anzahl der Attribute und Methoden bestimmt, die eine Klasse hat. Sie wird durch die Gleichung ausgedrückt:

degree_of_modularity

Es gibt eine vorherrschende Überzeugung, die durch zahlreiche Feldversuche untergraben wird, dass viele kleinere Code-Einheiten leichter zu ändern sind als wenige größere. Das alte römische Prinzip des “divide et imperum” gilt auch für Software. Es ist nicht bewiesen, dass kleinere Module notwendigerweise fehlerfreier sind. Daher basiert die Rechtfertigung für Modularität auf der Einfachheit der Änderung. Bei der Messung von Code kann die Modularität bestimmt werden, indem die tatsächliche Größe der Codeeinheiten in Anweisungen mit einer vordefinierten Maximalgröße verglichen wird. In einem objektorientierten Design sind die elementaren Einheiten die Methoden. Die Anzahl der Methoden pro Klasse sollte eine definierte Grenze nicht überschreiten. Zur Messung der Modularität der UML empfiehlt es sich hier, die Gesamtzahl der Methoden mit der minimalen Anzahl von Methoden pro Klasse multipliziert mit der Gesamtzahl der Klassen zu vergleichen. Das Designziel ist hier, so wenig Methoden wie möglich pro Klasse zu haben, um den Designer zu ermutigen, mehr und kleinere Klassen zu erstellen.

Grad der Portabilität

Die Portabilität auf der Entwurfsebene ist ein Maß für die Leichtigkeit, mit der die Architektur in eine andere Umgebung portiert werden kann. Sie wird von der Art und Weise beeinflusst, wie das Design verpackt ist. Viele kleine Pakete lassen sich leichter portieren als wenige große. Deshalb ist es wichtig, die Größe der Pakete so klein wie möglich zu halten. Die Paketgröße ist eine Frage der Anzahl der Klassen pro Paket. Gleichzeitig sollten Pakete nur wenige Abhängigkeiten zu ihrer Umgebung haben. Je weniger Schnittstellen jedes Paket hat, desto besser. Die Portabilität eines Systems wird durch die Gleichung ausgedrückt:

degree_of_portability

Die Begründung für dieses Qualitätsmerkmal geht in die gleiche Richtung wie die der Modularität. Die Anzahl der Klassen pro Paket sollte eine bestimmte Grenze nicht überschreiten, und ein Paket sollte auch nicht mehr als eine bestimmte Anzahl von Schnittstellen mit seiner Umgebung haben, da Schnittstellen ein Paket mit seiner Umgebung verbinden. Das Designziel ist es, Pakete mit einer minimalen Anzahl von Klassen und Schnittstellen zu erstellen.

Grad der Wiederverwendbarkeit

Wiederverwendbarkeit ist ein Maß für die Leichtigkeit, mit der Code- oder Design-Einheiten aus ihrer ursprünglichen Umgebung herausgenommen und in eine andere Umgebung verpflanzt werden können. Das bedeutet, dass es ein Minimum an Abhängigkeiten zwischen Designeinheiten geben sollte. Abhängigkeiten werden in der UML als Generalisierungen, Assoziationen und Interaktionen ausgedrückt. Daher lautet die Gleichung zum Messen des Grads der Abhängigkeit:

degree_of_reuseability

Je mehr Generalisierungen, Assoziationen und Interaktionen es gibt, desto schwieriger ist es, einzelne Klassen und Methoden aus der aktuellen Architektur herauszunehmen und in einer anderen wiederzuverwenden. Wie bei Pflanzen, wenn ihre Wurzeln mit den Wurzeln benachbarter Pflanzen verwickelt sind, ist es schwierig, sie zu verpflanzen. Die verschlungenen Wurzeln müssen durchtrennt werden. Das gilt auch für Software. Der Grad der Abhängigkeit sollte so gering wie möglich sein. Vererbung und Interaktion mit anderen Klassen erhöht den Grad der Abhängigkeit und senkt den Grad der Wiederverwendbarkeit. Das Designziel ist hier, so wenig Abhängigkeiten wie möglich zu haben.

Grad der Testbarkeit

Die Testbarkeit ist ein Maß für den Aufwand, der zum Testen eines Systems erforderlich ist, im Verhältnis zur Größe des Systems. Je weniger Aufwand erforderlich ist, desto höher ist der Grad der Testbarkeit. Der Testaufwand wird durch die Anzahl der zu testenden Testfälle sowie durch die Breite der Schnittstellen bestimmt, wobei diese Breite durch die Anzahl der Parameter pro Schnittstelle ausgedrückt wird. Die Gleichung zur Berechnung der Testbarkeit lautet:

degree_of_testability

Die Anzahl der benötigten Testfälle errechnet sich aus der Anzahl der möglichen Pfade durch die Systemarchitektur. Um eine Schnittstelle zu testen, müssen die Parameter dieser Schnittstelle auf verschiedene Kombinationen eingestellt werden. Je mehr Parameter sie enthält, desto mehr Kombinationen müssen getestet werden. Die Praxiserfahrung hat gezeigt, dass es einfacher ist, mehrere schmale Schnittstellen, d. h. Schnittstellen mit wenigen Parametern, zu testen als einige breite Schnittstellen, d. h. Schnittstellen mit vielen Parametern. Somit beeinflusst nicht nur die Anzahl der Testfälle, sondern auch die Breite der Schnittstellen den Testaufwand. Das Entwurfsziel ist hier, eine Architektur zu entwerfen, die mit möglichst geringem Aufwand getestet werden kann. Dies kann durch die Minimierung der möglichen Pfade durch das System und durch die Modularisierung der Schnittstellen erreicht werden.

Grad der Konformität

Konformität ist ein Maß für das Ausmaß, in dem Designregeln eingehalten werden. Jedes Softwareprojekt sollte eine Konvention für die Benennung von Entitäten haben. Es sollte vorgeschriebene Namen für Datenattribute und Schnittstellen sowie für Klassen und Methoden geben. Es liegt in der Verantwortung der Projektleitung, dafür zu sorgen, dass diese Namenskonventionen zur Verfügung gestellt werden. Es liegt in der Verantwortung der Qualitätssicherung, dafür zu sorgen, dass sie eingehalten werden. Die Gleichung für die Konformität ist sehr einfach:

degree_of_conformity

Unverständliche Namen sind das größte Hindernis für das Verständnis von Code. Egal wie gut der Code strukturiert ist, er bleibt unverständlich, solange der Codeinhalt durch unzureichende Daten- und Prozedurnamen unscharf ist. Die in den UML-Diagrammen vergebenen Namen werden in den Code übernommen. Sie sollten daher mit großer Sorgfalt ausgewählt werden und einer strengen Namenskonvention entsprechen. Ziel ist es, die Designer dazu zu bringen, sinnvolle, standardisierte Namen in ihrer Designdokumentation zu verwenden.

Grad der Konsistenz

Konsistenz im Entwurf impliziert, dass die Entwurfsdokumente miteinander übereinstimmen. Man sollte nicht auf eine Klasse oder Methode in einem Sequenzdiagramm verweisen, die nicht auch in einem Klassendiagramm enthalten ist. Dies wäre inkonsistent. Das Gleiche gilt für die Methoden in den Aktivitätsdiagrammen. Sie sollten mit den Methoden in den Sequenz- und Klassendiagrammen übereinstimmen. Die Parameter, die in den Sequenzdiagrammen übergeben werden, sollten auch die Parameter sein, die den Methoden in den Klassendiagrammen zugeordnet sind. Die Klassendiagramme sind also die Basisdiagramme. Alle anderen Diagramme sollten mit ihnen übereinstimmen. Wenn nicht, liegt ein Konsistenzproblem vor. Die Gleichung zur Berechnung der Konsistenz lautet:

degree_of_consistency

Wenn wir den Grad der Konsistenz messen, stoßen wir auf eine der größten Schwächen der Designsprache UML. Sie ist in sich selbst inkonsistent. Das liegt daran, dass sie aus vielen verschiedenen Entwurfsdiagrammtypen zusammengeklebt wurde, die alle ihren eigenen Ursprung haben. Zustandsdiagramme, Aktivitätsdiagramme und Kollaborationsdiagramme gab es schon lange bevor die UML geboren wurde. Sie wurden aus dem strukturierten Entwurf übernommen. Die Grundlage des objektorientierten Designs ist das Klassendiagramm von Grady Booch. Use-Case- und Sequenzdiagramme wurden später von Ivar Jacobson hinzugefügt. Es gab also nie ein einheitliches Design der UML-Sprache. Der Designer hat die Möglichkeit, die verschiedenen Diagrammtypen völlig unabhängig voneinander zu erstellen. Wenn das UML-Design-Tool dies nicht überprüft, führt dies zu inkonsistenter Benennung. Das Designziel ist hier, die Designer zu zwingen, einen gemeinsamen Namensraum für alle Diagramme zu verwenden und sicherzustellen, dass die referenzierten Methoden, Parameter und Attribute in den Klassendiagrammen definiert sind.

Grad der Vollständigkeit

Die Vollständigkeit eines Entwurfs könnte bedeuten, dass alle im Anforderungsdokument angegebenen Anforderungen und Anwendungsfälle durch die Entwurfsdokumentation abgedeckt sind. Um dies zu überprüfen, wäre eine Verknüpfung mit dem Anforderungs-Repository erforderlich und es müsste sichergestellt werden, dass im Design die gleichen Namen für die gleichen Entitäten verwendet werden wie im Anforderungstext. Leider ist der Stand der Informationstechnologie von diesem Ideal weit entfernt. Kaum ein IT-Projekt hat einen gemeinsamen Namensraum für alle seine Dokumente, geschweige denn ein gemeinsames Repository. Deshalb wird hier nur die formale Vollständigkeit gemessen, d. h., dass alle geforderten Diagramme auch vorhanden sind. Der Grad der Vollständigkeit ist eine einfache Relation von fertigen zu benötigten Dokumenten.

degree_of_completeness

Das Ziel des Entwurfs ist hier, sicherzustellen, dass alle für das Projekt erforderlichen UML-Diagrammtypen tatsächlich vorhanden sind. Wie bei allen UML-Projekten, die dieser Autor jemals getestet hat, wird das Design nie abgeschlossen. Der Druck, mit der Codierung zu beginnen, ist zu groß und sobald mit der Codierung begonnen wird, wird das Design obsolet.

Grad der Übereinstimmung

Die ultimative Qualität eines Systementwurfs ist, dass er die Anforderungen erfüllt. Nicht alles, was gemessen wird, ist wichtig und vieles von dem, was wichtig ist, ist nicht messbar. Das trifft hier sicherlich zu. Ob die Anforderungen des Anwenders wirklich erfüllt werden, lässt sich nur feststellen, indem das Endprodukt gegen die Anforderungen getestet wird. Dabei kann man höchstens die Akteure und Anwendungsfälle im Entwurf mit denen in den Anforderungen vergleichen. Jede funktionale Anforderung sollte im Anforderungsdokument einem Anwendungsfall zugeordnet sein. Wenn dies der Fall ist, sollten die Anwendungsfälle im Anforderungsdokument alle funktionalen Anforderungen abdecken. Wenn die Anzahl der Use Cases im Entwurf mit der Anzahl der Use Cases in den Anforderungen übereinstimmt, können wir den Entwurf als konform mit den Anforderungen betrachten, zumindest formal. Dies kann durch den Koeffizienten ausgedrückt werden:

degree_of_compliance

Wenn mehr Anwendungsfälle entworfen wurden, als erforderlich waren, zeigt dies nur, dass die Lösung größer ist als das Problem. Wenn weniger Anwendungsfälle entworfen werden, dann ist der Entwurf offensichtlich nicht konform. Das Entwurfsziel ist hier, ein System zu entwerfen, das alle Anforderungen abdeckt, zumindest auf der Ebene der Anwendungsfälle.

UML-Entwurfsgrößen-Metriken

Die Konstruktionsgrößenmetriken sind berechnete Werte zur Darstellung der Größe eines Systems. Gemessen wird hier natürlich nicht das System selbst, sondern ein Modell des Systems. Das System selbst wird erst messbar, wenn es fertig ist. Man braucht Größenmaße in einem frühen Stadium, um den Aufwand für die Produktion und den Test eines Systems vorherzusagen. Diese Größenmaße können aus den Anforderungen durch Analyse der Anforderungstexte oder zur Entwurfszeit durch Analyse der Entwurfsdiagramme abgeleitet werden. Beide Messungen können natürlich nur so gut sein wie die Anforderungen und/oder das Design, das gemessen wird. Da der Entwurf detaillierter ist und mit größerer Wahrscheinlichkeit vollständig ist, führt die Messung der Entwurfsgröße zu einer zuverlässigeren Schätzung. Das Design ist jedoch erst viel später vollständig als die Anforderungen. Das bedeutet, dass die ursprüngliche Kostenschätzung auf den Anforderungen basieren muss. Wenn die designbasierte Schätzung die ursprüngliche übersteigt, ist es notwendig, Funktionalität zu streichen, d. h. weniger wichtige Anwendungsfälle und Objekte wegzulassen. Weicht die designbasierte Schätzung signifikant von der ursprünglichen ab, ist es notwendig, das Projekt zu stoppen und die vorgeschlagene Zeit und die Kosten neu zu verhandeln. In jedem Fall sollte das Projekt neu kalkuliert werden, wenn der Entwurf fertig ist.

Es gibt verschiedene Methoden zur Schätzung von Software-Projektkosten. Jede basiert auf einer anderen Größenmetrik. Bei der Schätzung eines Projekts sollte man immer mit mindestens drei verschiedenen Methoden schätzen. Aus diesem Grund werden fünf Größenmaße genommen, um dem Schätzer eine Auswahl zu geben. Die fünf verwendeten Größenmaße sind:

  • Daten-Punkte
  • Funktions-Punkte
  • Objekt-Punkte
  • Use-Case-Points
  • Test-Fälle

Daten-Punkte

Data-Points ist ein Größenmaß, das ursprünglich von Sneed im Jahr 1990 veröffentlicht wurde. Es soll die Größe eines Systems allein auf der Basis seines Datenmodells, aber unter Einbeziehung der Benutzerschnittstellen messen. Es ist ein Produkt der Softwareentwicklung der 4. Generation, bei der die Anwendungen um das bestehende Datenmodell herum aufgebaut werden. Das Datenmodell in UML wird in den Klassendiagrammen ausgedrückt. Die Benutzerschnittstellen können in den Use-Case-Diagrammen identifiziert werden. Dies führt zu der folgenden Berechnung von Datenpunkten:

data_points

Funktions-Punkte

Function-Points ist ein Größenmaß, das ursprünglich 1979 von Albrecht bei IBM eingeführt wurde. Es soll die Größe eines Systems auf der Grundlage seiner Eingänge und Ausgänge zusammen mit seinen Datendateien und Schnittstellen messen. Eingaben werden von 3 bis 6, Ausgaben von 4 bis 7, Dateien von 7 bis 15 und Systemschnittstellen von 5 bis 10 gewichtet. Diese Methode der Systemdimensionierung basiert auf der strukturierten Systemanalyse- und Entwurfstechnik. Sie hat sich im Laufe der Jahre weiterentwickelt, aber das grundlegende Zählschema ist unverändert geblieben. Es war nie für objektorientierte Systeme gedacht, kann aber angepasst werden. In einem UML-Entwurf sind die Klassen den logischen Dateien am nächsten. Den Benutzereingaben und -ausgaben am nächsten sind die Interaktionen zwischen Akteuren und Anwendungsfällen. Die Schnittstellen zwischen den Klassen können als Systemschnittstellen interpretiert werden. Mit dieser groben Annäherung kommen wir zu folgender Berechnung von Funktionspunkten:

function_points

Objekt-Punkte

Object-Points wurden 1996 von Sneed speziell für die Messung der Größe von objektorientierten Systemen entwickelt. Die Idee war, ein Größenmaß zu finden, das sich leicht aus einem Objektentwurf ableiten lässt. Als solches passt es perfekt zum UML-Design. Objektpunkte sind offensichtlich das beste Größenmaß für ein Objektmodell. Klassen wiegen 4 Punkte, Methoden wiegen 3 Punkte, Schnittstellen wiegen 2 Punkte und Attribute/Parameter wiegen einen Punkt. Auf diese Weise werden Objekt-Punkte berechnet als:

object_points

UseCase-Points

UC-Points wurden 1993 von einem schwedischen Studenten, der bei Ericsson arbeitete, namens G. Karner eingeführt. Die Idee dabei war, die Größe eines Softwaresystems anhand der Anzahl der Akteure sowie der Anzahl und Komplexität der Anwendungsfälle abzuschätzen. Sowohl Akteure als auch Anwendungsfälle wurden in drei Stufen eingeteilt – einfach, mittel und schwierig. Die Akteure wurden auf einer Skala von 1 bis 3 bewertet, die Anwendungsfälle nun auf einer Skala von 5 bis 15. Beide werden miteinander multipliziert, um die unbereinigten Use-Case-Punkte zu erhalten. Diese Methode eignet sich auch zum Messen der Größe eines UML-Entwurfs, sofern die Anwendungsfälle und Akteure alle spezifiziert sind. Hier werden die Medianwerte zur Klassifizierung aller Akteure und Anwendungsfälle verwendet, aber um die Anzahl der Interaktionen zwischen Akteuren und Anwendungsfällen erweitert.

usecase_points

Testfälle

Testfälle wurden erstmals 1978 von Sneed als Größenmaßstab zur Abschätzung des Testaufwands für das Siemens Integrated Transport System – ITS verwendet. Die Motivation dahinter war, den Modultest auf der Basis von Testfällen zu berechnen. Ein Testfall wurde dabei als Äquivalent zu einem Pfad durch das Testobjekt definiert. Viel später wurde die Methode wiederbelebt, um die Kosten für den Test von Systemen abzuschätzen. Beim Testen von Systemen ist ein Testfall äquivalent zu einem Pfad durch das System. Er beginnt an der Interaktion zwischen einem Akteur und dem System und folgt entweder einem Pfad durch die Aktivitätsdiagramme oder durchläuft die Sequenzdiagramme über Interaktionen zwischen den Klassen. Für jeden Pfad durch die Interaktionsdiagramme sowie für jeden in den Zustandsdiagrammen spezifizierten Objektzustand sollte es einen Testfall geben. Die Anzahl der Testfälle ergibt sich also aus den Use-Case-Interaktionen mal der Anzahl der Klasseninteraktionen mal der Anzahl der Objektzustände. Sie errechnet sich wie folgt:

test_cases

Automatisierte Analyse von UML-Entwürfen mit UMLAudit

Zur Messung von UML-Entwürfen wurde das Tool UMLAudit entwickelt. UMLAudit ist ein Mitglied des SoftAudit-Toolsets für die automatisierte Qualitätssicherung. Dieses Tool-Set enthält auch Analysetools für englische und deutsche Anforderungstexte sowie für alle führenden Programmiersprachen, die gängigsten Datenbankschemasprachen und mehrere Sprachen zur Definition von Benutzer- und Systemschnittstellen. UMLAudit enthält einen XML-Parser, der die vom UML-Modellierungstool erzeugten XML-Dateien zur Darstellung der Diagramme parst. Dabei werden die Diagramm- und Modellinstanztypen, -namen und -beziehungen als Attribute aufgenommen, die anhand ihrer Modelltypen und -namen leicht erkannt werden können. Das Messobjekt ist das XML-Schema des UML-2-Modells mit seinen Modelltypen, wie von der OMG spezifiziert.

Der erste Schritt von UMLAudit besteht darin, die Entwurfstypen und Namen aus den XML-Dateien zu sammeln und in Tabellen zu speichern. Der zweite Schritt besteht darin, die Tabellen durchzugehen und sie zu zählen. Im dritten Schritt werden die Namen anhand der Vorlagen für Namenskonventionen überprüft. Der letzte Schritt besteht darin, die referenzielle Konsistenz zu prüfen, indem die referenzierten Entitäten mit den definierten Entitäten verglichen werden. Als Ergebnis werden zwei Ausgaben erzeugt:

  • einen UML-Mängelbericht und
  • einen UML-Metrikenbericht.

Der UML-Mängelbericht ist ein nach Diagrammen geordnetes Protokoll von Regelverletzungen und Unstimmigkeiten. Zurzeit gibt es nur zwei Arten von Mängeln:

  • Inkonsistente Referenzen und
  • Regelverstöße benennen.

Wenn ein Diagramm, z. B. ein Zustands-, Aktivitäts- oder Sequenzdiagramm, auf eine Klasse, eine Methode oder einen Parameter verweist, die bzw. der nicht im Klassendiagramm definiert ist, wird eine inkonsistente Referenz gemeldet. Wenn der Name einer Entität von den Benennungsregeln für diesen Entitätstyp abweicht, wird eine Benennungsverletzung gemeldet. Diese Mängel werden aufsummiert und mit der Anzahl der Modelltypen und Typnamen verglichen, um die Entwurfskonformität zu ermitteln.

Der UML-Metrikenbericht listet die Mengen-, Komplexitäts- und Qualitätsmetriken auf Datei- und Systemebene auf. Die Mengenmetriken sind weiter unterteilt in Diagrammmengen, Strukturmengen, Beziehungsmengen und Größenmetriken.

Fazit

Ein Softwaresystem nach seinem Design zu beurteilen, ist wie die Beurteilung eines Buches nach seinem Inhaltsverzeichnis. Wenn das Inhaltsverzeichnis sehr feinkörnig ist, können Sie die Struktur und den Aufbau des Buchs beurteilen und Annahmen über den Inhalt treffen. Das Gleiche gilt für UML. Wenn der UML-Entwurf bis auf eine detaillierte Ebene feinkörnig ist, ist es möglich, eine Beurteilung vorzunehmen und die Kosten auf der Grundlage des Entwurfs zu schätzen. Wenn es nur grobkörnig ist, wird die Bewertung des Systems oberflächlich und die Schätzung unzuverlässig sein. Das Messen von Größe, Komplexität und Qualität von irgendetwas kann nur so genau sein wie die Sache, die man misst. UML ist nur ein Modell und Modelle spiegeln nicht unbedingt die Realität wider. Tatsächlich tun sie das nur selten. UML-Modelle sind in der Praxis oft unvollständig und inkonsistent, was es schwierig macht, einen Test auf ihnen aufzubauen. Dies bleibt das größte Hindernis für modellbasiertes Testen.

Unittest

Der Unittest ist für mich die essentiellste aller Teststufen. Auf sie schaue ich auch zuerst, wenn ich ein neues Beratungsprojekt starte. Warum? Hier...

Weiterlesen

Testen eines Geoportals

Der Testprozess Motivation Viele Behörden und Unternehmen, die mit raumbezogenen Informationen arbeiten, bauen heute Geoportale als wesentlichen...

Weiterlesen

1 Min. Lesezeit

Digitalisierung – Deal with it!

Die Digitalisierung wird nicht kommen – sie ist schon längst da! Und sie wird auch nicht mehr weggehen. Aussitzen und Kopf in den Sand stecken ist...

Weiterlesen