<?xml version="1.0" encoding="UTF-8"?><rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>Software Archive - dahlen.org</title>
	<atom:link href="https://www.dahlen.org/tag/software/feed/" rel="self" type="application/rss+xml" />
	<link>https://www.dahlen.org/tag/software/</link>
	<description>Private Webseite der Familie Dahlen</description>
	<lastBuildDate>Mon, 04 Apr 2022 09:09:31 +0000</lastBuildDate>
	<language>de</language>
	<sy:updatePeriod>
	hourly	</sy:updatePeriod>
	<sy:updateFrequency>
	1	</sy:updateFrequency>
	<generator>https://wordpress.org/?v=6.8.3</generator>
	<item>
		<title>Abhängigkeiten vermeiden mit der Java Service Provider Spezifikation</title>
		<link>https://www.dahlen.org/2009/08/14/abhangigkeiten-vermeiden-mit-der-java-service-provider-spezifikation/</link>
					<comments>https://www.dahlen.org/2009/08/14/abhangigkeiten-vermeiden-mit-der-java-service-provider-spezifikation/#comments</comments>
		
		<dc:creator><![CDATA[christoph]]></dc:creator>
		<pubDate>Fri, 14 Aug 2009 11:52:03 +0000</pubDate>
				<category><![CDATA[Informatik]]></category>
		<category><![CDATA[Java]]></category>
		<category><![CDATA[Software]]></category>
		<guid isPermaLink="false">https://www.dahlen.org/?p=197</guid>

					<description><![CDATA[<p>Durch ein aktuelles Projekt der Cassini Consulting konnte ich mich endlich Mal tiefer mit einem grundsätzlichen Problem beschäftigen: der losen Kopplung eines Service Provider Interfaces (SPI) oder grundsätzlich eines API und seiner Implementierungen in Form von Plugins. Das Erstaunliche daran (überlagert von Themen wie Dependency Injection und Spring): Es gibt bereits seit dem JDK 1.3 [&#8230;]</p>
<p>Der Beitrag <a href="https://www.dahlen.org/2009/08/14/abhangigkeiten-vermeiden-mit-der-java-service-provider-spezifikation/">Abhängigkeiten vermeiden mit der Java Service Provider Spezifikation</a> erschien zuerst auf <a href="https://www.dahlen.org">dahlen.org</a>.</p>
]]></description>
										<content:encoded><![CDATA[<p>Durch ein aktuelles Projekt der <a href="http://www.cassini.de/">Cassini Consulting</a> konnte ich mich endlich Mal tiefer mit einem grundsätzlichen Problem beschäftigen: der losen Kopplung eines Service Provider Interfaces (SPI) oder grundsätzlich eines <abbr title="Application Programmers Interface">API</abbr> und seiner Implementierungen in Form von <q>Plugins</q>. Das Erstaunliche daran (überlagert von Themen wie <a href="http://de.wikipedia.org/wiki/Dependency_Injection">Dependency Injection</a> und <a href="http://www.springsource.com/">Spring</a>): Es gibt bereits seit dem <abbr title="Java Development Kit">JDK</abbr> 1.3 eine sehr einfache Lösung für dieses Problem und sie funktioniert auch <q>ab Werk</q>: Die <em>Java Service Provider Spezifikation</em>.<br />
<span id="more-197"></span><br />
Die Problemstellung lässt sich am besten in Form eines Beispiels erläutern. Die Projektleitung kommt auf die irsinnige Idee, ein <q>Quoter</q>-Interface als Teil einer API zu definieren, über welches Texte in Anführungszeichen gefasst werden können. Etwa so:</p>
<pre><code>package demo.api;

public interface IQuoter {
        String quote(String s);
}
</code></pre>
<p>Dazu steuern die Entwickler eine Implementierung für den deutschen Sprachraum bei, welcher tief- und hochgestellte Anführungszeichen verwendet (über Unicode):</p>
<pre><code>package demo.impl;

public class GermanQuoter implements IQuoter {
        public String quote(String s) {
                return '\u201E' + s + '\u201D';
        }
}
</code></pre>
<p>Die Frage ist nun, wie kann man diese Implementierung verwenden,</p>
<ul>
<li>ohne sie direkt in der Applikation zu importieren und</li>
<li>ohne sie direkt in der API zu referenzieren?</li>
</ul>
<p>Die Lösung ist interessanterweise bereits seit dem JDK 1.3 Teil der Java Standard Edition (SE), auch wenn sie zwischen den Versionen einige Male den Platz gewechselt hat. Mit Java&#160;6 scheint sie nun aber ihren endgültigen Platz gefunden zu haben als  java.util.ServiceLoader.</p>
<p>Dafür muß die Implementierung als eigenes <abbr title="Java ARchive">JAR</abbr> ausgeliefert werden, denn folgende Punkte sind Voraussetzung für die Nutzung des ServiceLoader:</p>
<ol>
<li>im JAR muß ein Verzeichnis <em>META-INF/services</em> vorhanden sein</li>
<li>in diesem Verzeichnis muß für jede API Klasse (Interface oder abstrakte Klasse) eine Datei gleichen Namens liegen</li>
<li>in jeder dieser Dateien muß der vollqualifizierte Namen der Implementations-Klasse vermerkt sein</li>
</ol>
<p>Für unser Beispiel bedeutet das also, daß der Inhalt des Implementierungs-JAR wie folgt aussieht:<br />
<code>demo.impl.GermanQuoter<br />
META-INF/services/demo.api.IQuoter</code></p>
<p>Und die einzige Zeile in der Datei demo.api.IQuoter liest sich wie folgt:<br />
<code>demo.impl.GermanQuoter</code></p>
<p>Wie kommt nun unsere Applikation, welche die API und das Implementierungs-JAR im Klassenpfad hat an die Implementierung? Nun, über Aufruf der entsprechenden <q>Service Locator</q>, welche sich je nach JDK an verschiedenen Stellen finden:</p>
<ul>
<li>im JDK 1.3 als sun.misc.Service</li>
<li>im JDK 1.4 &#8211; 1.5 als javax.imageio.spi.ServiceRegistry(!)</li>
<li>seit dem JDK 1.6 endlich an richtiger Stelle als <a href="http://java.sun.com/javase/6/docs/api/java/util/ServiceLoader.html#load%28java.lang.Class%29">java.util.ServiceLoader</a></li>
</ul>
<p>Also schreiben wir uns für das JDK 1.6 eine kleine, generische Utility-Klasse, welche eine oder alle Implementierungen für eine API-Artefakt liefern kann:</p>
<pre><code>package demo.util;

import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.ServiceLoader;

public final class GenericServiceLocator {

    private GenericServiceLocator() {
    }

    public static &lt;T> T locate(final Class&lt;T> clazz) {
        final List services = locateAll(clazz);
        return services.isEmpty() ? (T) null : services.get(0);
    }

    public static &lt;T> List&lt;T> locateAll(final Class&lt;T> clazz) {

        final Iterator&lt;T> iterator = ServiceLoader.load(clazz).iterator();
        final List&lt;T> services = new ArrayList&lt;T>();

        while(iterator.hasNext()) {
            try {
                services.add(iterator.next());
            } catch (Error e) {
                e.printStackTrace(System.err);
            }
        }

        return services;

    }
}
</code></pre>
<p>Und so sieht dann der Aufruf aus unserer Beispiel-Applikation aus:</p>
<pre><code>package demo;

import demo.api.IQuoter;
import demo.util.GenericServiceLocator;

public class App {
    public static void main( String[] args ) {
        System.out.println(
                GenericServiceLocator
                    .locate(IQuoter.class)
                    .quote("Quote Me")
        );
    }
}
</code></pre>
<p>Das ist alles. Befinden sich API, Implementierung und Applikation im Klassenpfad, kann der Test über den Aufruf von<br />
<code>java -cp demo-api.jar;demo-impl.jar;demo-app.jar demo.App</code><br />
erfolgen. Das Ergebnis sollte auf Unicode-Terminals ein <tt>&#8222;Quote Me&#8221;</tt> sein. Auf der Windows&nbsp;XP Console ist es übrigens <tt>äQuote Meö</tt> &#8230;</p>
<p>Zum Ausprobieren ist das <a href="https://www.dahlen.org/wp-content/uploads/2009/08/spi-demo.zip">Beispiel-Projekt</a> als <a href="http://maven.apache.org/">Maven2</a> Multi-Module beigefügt, die Verwendung in eigenen Projekten ist &#8211; selbstverständlich &#8211; gestattet.</p>
<p>Der Beitrag <a href="https://www.dahlen.org/2009/08/14/abhangigkeiten-vermeiden-mit-der-java-service-provider-spezifikation/">Abhängigkeiten vermeiden mit der Java Service Provider Spezifikation</a> erschien zuerst auf <a href="https://www.dahlen.org">dahlen.org</a>.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://www.dahlen.org/2009/08/14/abhangigkeiten-vermeiden-mit-der-java-service-provider-spezifikation/feed/</wfw:commentRss>
			<slash:comments>1</slash:comments>
		
		
			</item>
		<item>
		<title>Qualitätsmetriken des OOD</title>
		<link>https://www.dahlen.org/2009/07/28/qualitaetsmetriken-des-ood/</link>
					<comments>https://www.dahlen.org/2009/07/28/qualitaetsmetriken-des-ood/#respond</comments>
		
		<dc:creator><![CDATA[christoph]]></dc:creator>
		<pubDate>Tue, 28 Jul 2009 09:53:03 +0000</pubDate>
				<category><![CDATA[Informatik]]></category>
		<category><![CDATA[Metriken]]></category>
		<category><![CDATA[OOD]]></category>
		<category><![CDATA[Qualität]]></category>
		<category><![CDATA[Software]]></category>
		<guid isPermaLink="false">https://www.dahlen.org/?p=119</guid>

					<description><![CDATA[<p>Aktuell unterstütze ich für meinen Arbeitgeber, die Cassini Consulting einen IT-Dienstleister bei der Realisierung einer kundenspezifischen Software-Plattform, gebildet aus Mitteln der JEE (Spring, JMS, JPA). Im Zuge dieses Projektes werden auch Analyse-Werkzeugen eingesetzt, welche Aspekte des objekt-orientierten Designs erfassen und (graphisch) aufbereiten. Getreu dem Motto „a fool with a tool is still a fool” ist [&#8230;]</p>
<p>Der Beitrag <a href="https://www.dahlen.org/2009/07/28/qualitaetsmetriken-des-ood/">Qualitätsmetriken des OOD</a> erschien zuerst auf <a href="https://www.dahlen.org">dahlen.org</a>.</p>
]]></description>
										<content:encoded><![CDATA[<p>Aktuell unterstütze ich für meinen Arbeitgeber, die <a href="http://www.cassini.de/">Cassini Consulting</a> einen IT-Dienstleister bei der Realisierung einer kundenspezifischen Software-Plattform, gebildet aus Mitteln der JEE (Spring, <acronym title="Java Messaging Service">JMS</acronym>, <acronym title="Java Persistence API">JPA</acronym>). Im Zuge dieses Projektes werden auch Analyse-Werkzeugen eingesetzt, welche Aspekte des objekt-orientierten Designs erfassen und (graphisch) aufbereiten. Getreu dem Motto „a fool with a tool is still a fool” ist für mich vor allem der theoretische Hintergrund von Bedeutung.<br />
<span id="more-119"></span></p>
<h3>Metriken</h3>
<p>Viele der eingesetzen Werkzeuge (wie <a href="http://www.clarkware.com/software/JDepend.html">JDepend</a>, CAP, <a href="http://www.hello2morrow.com/products/sonarj">SonarJ</a>) verwenden Metriken, die bereits 1994 von Robert Martin als <cite>OO Design Quality Metrics</cite><a href="https://www.dahlen.org/2009/07/28/qualitaetsmetriken-des-ood/#fn1">1</a> definiert wurden. Die maßgeblichen Kennzahlen dabei sind:</p>
<ul>
<li>die Abstraktheit (abstractness, A) einer Kategorie</li>
<li>die Instabilität (instability, I) einer Kategorie</li>
<li>die Distanz (distance, D) einer Kategorie zur Ideallinie, der sog. main sequence</li>
</ul>
<p>Der Begriff „Kategorie” beschreibt in diesem Kontext eine logische Gruppierung innerhalb der Architektur, hierbei könnte es sich z.B. um eine Java Library, ein Java Package oder ein <a href="http://maven.apache.org/">Maven</a> Modul handeln.</p>
<h4>Abstraktheit</h4>
<p>Die Abstraktheit wird nun aus dem Verhältnis von „abstrakten” (N<sub>a</sub>) zur Summe aller Klassen gebildet (abstrakte und „konkrete”, N<sub>c</sub>). Im Java-Kontext schließt die Qualifizierung als „abstrakt” dabei auch Interfaces mit ein. Es gilt:</p>
<p>A = N<sub>a</sub> : (N<sub>a</sub> + N<sub>c</sub>)</p>
<p>Der Wertbereich ist [0,1], kann also als Prozentzahl wiedergegeben werden. 0% bedeutet, das die Kategorie ausschließlich aus konkreten Klassen besteht, 100% bedeutet, daß die Kategorie ausschließlich aus abstrakten Klassen oder Interfaces besteht.</p>
<h4>Instabilität</h4>
<p>Zur Bestimmung der Instabilität verwendet R. Martin die Abhängigkeiten einer Kategorie von anderen Kategorien. Dabei unterscheidet er zwischen eingehenden Abhängigkeiten (afferent couplings, C<sub>a</sub>) und ausgehenden Abhängigkeiten (efferent couplings, C<sub>e</sub>).</p>
<p>Afferent couplings sind also Abhängigkeiten, welche andere Kategorien in die betrachtete Kategorien haben, efferent couplings sind Abhängigkeiten, welche die betrachtete Kategorie in andere Kategorien hat.</p>
<p>Wieder wird das Verhältnis gebildet, es gilt:</p>
<p>I = C<sub>e</sub> : (C<sub>e</sub> + C<sub>a</sub>)</p>
<p>Auch hier kann der Wertebereich [0,1] in Prozent ausgedrückt werden. Je mehr ausgehende Abhängigkeiten eine Kategorie hat, desto höher ist der Grad an Instabilität. I ist also 0 für Kategorien, die keinerlei ausgehende Abhängigkeiten haben und 1 für Kategorien, die ausschließlich ausgehende Abhängigkeiten haben.<br />
<!--netxpage--></p>
<h4>Main Sequence</h4>
<p>Die für eine Kategorie ermittelte Abstraktheit A und Instabilität I lassen sich hervorragend als Achsen eines Graphen verwenden. Jede Kategorie kann dann als Koordinate in das System eingetragen werden. Doch welche Aussage lässt sich aus ihrer Plazierung machen?</p>
<dl>
<dt>A=1, I=0 </dt>
<dd>eine Kategorie, die zu 100% abstrakt ist und keinerlei ausgehende Abhängigkeiten hat, ist eine API. Interfaces und abstrakte Klassen definieren dabei die notwendigen Operationen, welche durch eine konkrete Implementierung zu realisieren sind </dd>
<dt>A=0, I=1 </dt>
<dd>eine Kategorie, die zu 0% abstrakt ist und ausschließlich abgehende Abhängigkeiten hat, ist eine Implementierung. Am Ende der Vererbungskette realisiert sie z.B. eine API </dd>
<dt>A=1, I=1 </dt>
<dd>eine Kategorie, die zu einem hochgradig abstrakt ist und andererseits ausschließlich abgehende Abhängigkeiten hat, stellt keinen erstrebenswerten Zustand dar. Als API ist sie zu instabil, als Implementierung müssten konkrete Klassen vorhanden sein </dd>
<dt>A=0, I=0 </dt>
<dd>Kategorien, welche stabil und konkret sind, haben ihre Berechtigung als geschlossenes, kleines System. Ein klassisches Beispiel dafür ist das typische HelloWorld.java, lässt man die Abhängigkeiten zu den JRE/JEE Bibliotheken außen vor. In größeren Architekturen wird dieser Punkt vermutlich nie erreicht werden. </dd>
</dl>
<figure id="attachment_181" aria-describedby="caption-attachment-181" style="width: 150px" class="wp-caption aligncenter"><a href="https://www.dahlen.org/wp-content/uploads/2009/07/ood-metriken-graph.gif"><img decoding="async" class="ngg-singlepic ngg-left " title="OOD Matriken als Graph" src="https://www.dahlen.org/wp-content/uploads/2009/07/ood-metriken-graph-150x150.gif" alt="Metriken nach R. Martin" width="150" height="150" /></a><figcaption id="caption-attachment-181" class="wp-caption-text">Metriken nach R. Martin</figcaption></figure>
<p>In der Theorie von R. Martin bildet die Strecke zwischen den Extremen von A und I nun die sog. Main Sequence (A + I = 1). Sie beschreibt das Verhältnis zwischen Abstraktheit und Instabilität, welches als ausgewogen (balanced) gilt.</p>
<h4>Distanz</h4>
<p>Die oben beschriebenen Kennzahlen dienen bisher nur der Einordnung einer Kategorie in den Graphen. Zur Bestimmung der „Güte” einer Kategorie empfiehlt R. Martin nun die Berechnung der Distanz (distance) einer Kategorie von der main sequence. Es gilt:</p>
<p>D = |(A + I &#8211; 1) : 2|</p>
<p>oder einfacher (um einen Wert zwischen 0 und 1 zu erhalten):</p>
<p>D = |A + I &#8211; 1|</p>
<p>Ziel des objekt-orientierten Design sollte es nun sein, die Distanz nahe an 0 zu bringen, etwa indem man ausgehende Abhängigkeiten eliminiert und damit die Stabilität erhöht, oder Kategorien in APIs mit hoher Abstraktheit und Implementierungs-Bereiche unterteilt.</p>
<h3>Fazit</h3>
<p>Die oben aufgeführten Metriken können eine Hilfe beim objekt-orientieren Design bzw. der objekt-orientierten Analyse sein. Man sollte sich ihnen aber nicht blind unterwerfen, denn wie immer gilt: Das Ideal im Blick, das Projektziel unter den Fingern.</p>
<p><sup>1</sup> <a name="fn1" href="http://www.objectmentor.com/resources/articles/oodmetrc.pdf">Robert Martin: OO Design Quality Metrics &#8211; An Analysis of Dependencies, 1994</a></p>
<p>Der Beitrag <a href="https://www.dahlen.org/2009/07/28/qualitaetsmetriken-des-ood/">Qualitätsmetriken des OOD</a> erschien zuerst auf <a href="https://www.dahlen.org">dahlen.org</a>.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://www.dahlen.org/2009/07/28/qualitaetsmetriken-des-ood/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
	</channel>
</rss>
