img_20161028_123257

Der Ansatz des agilen Projektmanagements lässt sich sehr gut mit Scrum kombinieren. Die Rollen, Meetings und Verantwortungen aus Scrum werden dabei 1 zu 1 übernommen. Allerdings ergänzen wir Scrum mit Werkzeugen aus dem agilen Projektmanagement und nehmen das Project Inception und die Projektbeauftragung hinzu.

Der Scrum-Zyklus verändert sich ein wenig uns sieht wie im folgenden Beispiel aus:

img_20161028_123257

Vision

Der Auftraggeber (z.B. CEO, Marketingchef, externer Kunde) hat eine Produktvision und kommt mit dieser Vision zum Projektteam, um über die Machbarkeit zu diskutieren.

Project Inception

Es wird ein erstes Projektteam gebildet, z.B. aus Scrum Master, Product Owner und einem oder zwei Entwickler mit genügend Wissen für eine erste Analyse der Vision.
Die Vision wird näher betrachtet und das Projektteam fertigt ein Project Inception an. Mit dem Auftraggeber werden Rahmenbedingungen wie die Priorität von Umfang/Qualität/Budget/Zeit bestimmt und eine erste Generierung der Backlog Items geschieht. Je nachdem in wie weit der Kunde in den Prozess mit eingebunden werden kann (und möchte), wird entschieden, ob in dieser Phase bereits eine umfangreiche Aufwandsschätzung zu erfolgen hat. In dem Fall wird bereits frühzeitig das Projektteam erweitert, so dass die Aufwandsschätzung von den Team-Mitgliedern durchgeführt wird, die an dem Projekt auch arbeiten werden.
Sobald die Rahmenbedingungen für das Projekt festgelegt worden sind, erfolgt eine schriftliche Genehmigung des Projekts durch den Auftraggeber. Dies stellt den Startschuss für das Projektteam dar.

Backlog füllen

Die erste Aufgabe wird es sein, das Backlog mit weiteren Backlog Items zu füllen. Das Team wird sich dabei zunächst auf der Ebene von Master Stories bewegen und nur nach und nach die User Stories dazu erstellen.
Das Füllen wird in einem oder mehrere Sprints durchgeführt. Dazu werden vor allem SPIKES angewendet, um eine Analyse der Requirements durchzuführen.

Vorbereitung zu Sprint 1

Im Rahmen des Füllens des Backlogs wird auch der erste Sprint vorbereitet. Dazu werden die User Stories identifiziert, die für den Projektstart erforderlich sind und bereits detaillierter beschrieben und geschätzt. Umso mehr User Stories zur Wahl für Sprint 1 stehen, desto besser. Allerdings sollte auch diese Phase zeitlich begrenzt sein, um nicht zu viel Zeit auf die Planung anzuwenden. Die weitere Planung wird im Laufe der Projektumsetzung parallel zur Entwicklung des Produktes erfolgen.

Der Sprint-Zyklus beginnt

Ab jetzt arbeitet das Scrum-Team wie gewohnt an den User Stories aus dem Product Backlog. In den Estimation Meetings werden nach und nach die noch nicht als User Stories heruntergebrochenen Master Stories besprochen und User Stories generiert sowie geschätzt.

Parallel dazu: die Roadmap

Während das Scrum-Team mit Sprint 1 beginnt, wird der Product Owner die bereits zur Verfügung stehenden Master Stories in die Roadmap und einen Releaseplan übertragen. Beide Pläne werden im Sprint-Zyklus kontinuierlich aktualisiert.

Das Produkt entsteht inkrementell

Das Scrum-Team hat weiterhin das Ziel, am Ende jedes Sprints einen releasbaren Stand des Produktes zu haben. Im Projekt werden neue Releases allerdings anhand des Releaseplans abgebildet, weshalb sich das Release am Sprintende vermutlich auf eine neue testbare Version beschränken wird. Vielleicht hat das Team ein Demosystem für den Auftraggeber aufgesetzt, auf das am Sprint-Ende der jeweils aktuelle Stand eingespielt wird.
Sobald das Projekt abgeschlossen ist, bekommt der Auftraggeber das fertige Produkt ausgeliefert.

Dank vieler Releases in der Zwischenzeit und kontinuierliches Feedback durch den Auftraggeber, wird das Produkt am Ende keine Überraschung für den Auftraggeber sein und ein für Scrum-Team und Auftraggeber zufriedenstellendes Ergebnis darstellen.

Wenn Scrum oder andere Prozesse in einem Unternehmen eingeführt werden, dann ist es sehr hilfreich, wenn die Rollen klar definiert werden. Es muss klar herausgestellt werden, wer für was verantwortlich ist und zu wem jemand gehen muss, um eine(n) Lösung/Antwort/Denkanstoß zu erhalten. In Scrum gibt es im Wesentlichen drei Rollen: Scrum Team (oder auch Scrum Developer genannt), Product Owner und Scrum Master.
Hier eine kurze Auflistung der Aufgaben von Scrum Master und Product Owner, die typischerweise von diesen Rollen übernommen werden.

Product Owner:

  • bereitstellen/vermitteln der Vision
  • vorbereiten des Sprint-Inhaltes
  • Priorisierung der Aufgaben
  • erstellen einer Roadmap
  • Pflege des Backlogs
  • Verantwortlich für das Produkt
  • Inhaltliche Verantwortung
  • Beratung des Kunden
  • Kundenkontakt
  • Übersetzer (von den Anforderungen des Kunden in die Entwicklersprache)
  • erstellt User Stories
  • beschreibt Anforderungen
  • hat Budger-Verantwortung
  • für die Abnahme am Sprint-Ende durch / Produkt-Abnahme
  • holt Kundenfeedback ein

Scrum Master:

  • sorgt dafür, dass Scrum funktioniert
  • setzt sich für die Organisationsentwicklung ein
  • hilft bei der Organisation im Team
  • führt eine kontinuierliche Prozess-Optimierung durch
  • stimmt sich mit anderen Scrum Mastern ab
  • sorgt für die Abstimmung mit anderen Teams
  • pocht auf Regeln und Meetings
  • unterstützt den Product Owner bei Bedarf
  • moderiert Meetings
  • Schutzschildfunktion (schützt das Team vor äußeren Störfaktoren)
  • Bindeglied zum Product Owner
  • das gute Herz des Teams
  • fordert Dokumentation ein und erstellt ggf. Meeting Minutes
  • beseitigt Hindernisse (und deckt sie ggf. auf)
  • beschafft Informationen/Räume/Material

IMG_20141117_103351-300x405

Nachdem der Kurs Agiles Projektmanagement am Beispiel von Scrum bereits 2014 erfolgreich stattgefunden hat, wird es auch in diesem Jahr wieder ein Seminar zum Thema agiles Projektmanagement an der VHS Wiesbaden geben.

Mo. 04.05.2015 – Fr. 08.05.2015 und
Mo. 12.10.2015 – Fr. 16.10.2015 (jeweils von 09:00 bis 16:00 Uhr)

Weitere Informationen zu den beiden Lehrveranstaltungen gibt es unter:

Sie werden in diesem Kurs unter Anderem erfahren, was es mit folgendem Konstrukt auf sich hat:
IMG_20141117_103351

 

 

Beim Verbindungsaufbau zu einem WebService, bin ich über ein Problem gestolpert, dass der Zugriff auf den WebService nicht mehr möglich war. Obwohl bei der Generierung des Services (javax.xml.ws.Service) die URL zur WSDL-Datei angegeben wurde und in dieser Datei die Endpoint-URL definiert war, funktionierte der Aufruf jeweils nur einmal nach dem Deployment im jBoss Application Server. Warum? Keine Ahnung. Zunächst wurde die Verbindung wie folgt aufgebaut:

String plainUrl = "http://mywebserivce:9999/call.php?wsdl";
Url url = new Url(plainUrl);
PrintManagerService service = new PrintManagerService(url);	
soap = service.getPrintManagerPort();

In der lokalen Testumgebung (Windows) funktionierte das einwandfrei. Erst im Produktionssystem (Linux; vermutlich spielt das BS hier keine Rolle) kam es zu folgender Fehlermeldung:


javax.xml.ws.WebServiceException: Could not send Message.
at org.apache.cxf.jaxws.JaxWsClientProxy.invoke(JaxWsClientProxy.java:135)
...
Caused by: java.io.IOException: IOException invoking http://localhost:8080/call.php: HTTP response '404: Not Found'

Der Host wurde offensichtlich von mywebservice:9999 auf localhost:8080 geändert. Im Code konnte ich keine Stelle finden, an dem vom localhost auf Port 8080 die Rede war. Durch Ergänzung von

((BindingProvider)soap).getRequestContext().put(BindingProvider.ENDPOINT_ADDRESS_PROPERTY, plainUrl);

konnte das Problem gelöst werden. Nun wird einmal die URL übergeben und direkt danach der Endpoint ein weiteres Mal gesetzt:

String plainUrl = "http://mywebserivce:9999/call.php?wsdl";
Url url = new Url(plainUrl);
PrintManagerService service = new PrintManagerService(url);	
soap = service.getPrintManagerPort();
((BindingProvider)soap).getRequestContext().put(BindingProvider.ENDPOINT_ADDRESS_PROPERTY, plainUrl);

Das folgende Beispiel zeigt die Verwendung der Plentymarkets SOAP Api Version 110. Die SOAP-Klassen wurden mittels dem in Eclipse eingebauten Tool zur Erstellung von Java-Klassen anhand einer WSDL-Datei generiert.

public class PlentyConnector {
	private Logger logger = Logger.getLogger(PlentyConnector.class);
	private String TOKEN = "";
	private int USERID = -1;
	private PlentySoapApiFunctionContainerServiceStub service = null;

// die weiteren Methoden werden separat gezeigt

}

In der folgenden Methoden wird ein Token geladen, sofern dies noch nicht geschehen ist.

   private void createService(String accountUser, String accountPassword, String portAddress) throws Exception {
		try {
			service = new PlentySoapApiFunctionContainerServiceStub(portAddress);
			if (this.TOKEN.equals("") || USERID == -1) {
                                //request a new token
				GetAuthentificationToken req = new GetAuthentificationToken();
				req.setOLogin(new PlentySoapRequest_GetAuthentificationToken());
				req.getOLogin().setUsername(accountUser);
				req.getOLogin().setUserpass(accountPassword);
				GetAuthentificationTokenResponse resp = service.getAuthentificationToken(req);
				this.TOKEN = resp.get_return().getToken();
				this.USERID = resp.get_return().getUserID();
			}
                        //modify the service and set the userid and token as a header element
			SOAPFactory factory = OMAbstractFactory.getSOAP12Factory();
		    SOAPHeaderBlock header = factory.createSOAPHeaderBlock("verifyingToken", null);
		    OMFactory omFactory = OMAbstractFactory.getOMFactory();
		    OMNode userNameNode = omFactory.createOMElement(new QName("UserID"));
		    ((OMElement) userNameNode).setText(""+USERID);
		    header.addChild(userNameNode);
		    OMNode passwordNode = omFactory.createOMElement(new QName("Token"));
		    ((OMElement) passwordNode).setText(TOKEN);
		    header.addChild(passwordNode);
		    service._getServiceClient().addHeader(header);
			System.out.println("token: " + this.TOKEN + " userid: " + this.USERID);
		}
		catch(Exception e) {
			logger.error("Authentification token not loaded correctly!");
			throw e;
		}
	}

Die nächste Methode zeigt am Beispiel der Serverzeit, wie weitere Aufrufe erfolgen können:

	private void getServerTime() {
		try {
	    	PlentySoapResponse_GetServerTime resp = service.getServerTime(new GetServerTime()).get_return();
	    	System.out.println("Servertime : "+resp.getTimestamp());
	   }   
	   catch(Exception e) {
		   logger.error("Server time not loaded correctly: " + e.getMessage(), e);
	   }
	}

In der nachfolgenden Methode wird ein Aufruf mit ein paar Testdaten durchgeführt, um die Funktionsweise zu veranschaulichen:

	public void executePlentyCall() throws Exception {
		System.out.println("login");
		createService("MyUserName", "MyPassword", "http://my.plenty.installation.de/soap/version110/");
		getServerTime();
}

Die SOAP-Klassen zum Verbindungsaufbau wurden mit Hilfe des axis2-Tools wsdl2java.bat erstellt.