Testen mit EntityManager und Transaktionen

29 August 2017

Immer wieder erlebe ich es, dass in Tests mit EntityManager Transaktionen gestartet und comitted werden. Allerdings gibt es kein Exception-Handling, sodass kein Rollback ausgeführt wird. Schlimmer noch: Die Transaktion wird nicht beendet und andere Tests schlagen ebenfalls fehl.

Um das zu verhindern, verwende ich ein solches Util:

public class TestUtil {
	public static <ENTITY_TYPE> ENTITY_TYPE getEntity(EntityManager entityManager, Class<ENTITY_TYPE> classType, Long id) {
		Query query = entityManager.createQuery("SELECT o FROM " + classType.getSimpleName() + " o");
		return (ENTITY_TYPE) query.getSingleResult();
	}

	public static <ENTITY_TYPE> void persistInTransaction(EntityManager entityManager, ENTITY_TYPE entity) {
		executeInTransaction(entityManager, () -> entityManager.persist(entity));
	}

	public static void executeInTransaction(EntityManager entityManager, TransactionExecutor transactionExecutor) {
		try {
			entityManager.getTransaction().begin();
			transactionExecutor.executeInTransaction();
			entityManager.getTransaction().commit();
		} catch (RuntimeException e) {
			if (entityManager.getTransaction().isActive()) {
				entityManager.getTransaction().rollback();
			}
			throw e;
		}
	}

	@FunctionalInterface
	public interface TransactionExecutor {
		void executeInTransaction();
	}
}

Websphere, Lambda Expression und ArrayIndexOutOfBoundsException

24 Juli 2017

Für das Deployment von Anwendungen lassen sich Python-Skripte verwenden. Im Rahmen eines Projekts haben wir für eine solche Anwendung Java 8 verwendet. Mit Hilfe eines Patches lässt sich das ermöglichen.

Beim Deployment über ein solches Skript haben wir festgestellt, dass sich Lamba Expressions offenbar mit dieser Art Deployment nicht verstehen. Beim Aufruf des Skripts wurde folgende Exception geworfen:

WASX7017E: Exception received while running file "updateApplication.py"; exception information: com.ibm.websphere.management.application.client.AppDeploymentException: com.ibm.websphere.management.application.client.AppDeploymentException:  [Root exception is java.lang.ArrayIndexOutOfBoundsException: Array index out of range: 52264]
java.lang.ArrayIndexOutOfBoundsException: java.lang.ArrayIndexOutOfBoundsException: Array index out of range: 52264

Um das Problem zu beheben, mussten wir die Lambda Expressions entfernen.

Tut es weh? Mach es nochmal (oder hör auf)!

23 Mai 2017

Softwareprojekte werden heutzutage in der Regel so abgewickelt, dass zunächst eine Spezifikation einer Anforderung erstellt wird. Anschließend überlegt sich jemand, wie man diese Anforderung umsetzen kann. Abschließend kommt es zur Umsetzung. Dieses Vorgehen ist in seiner Größe natürlich variabel. Statt nur eine Anforderung werden eventuell auch mehrere gleichzeitig spezifiziert. Es ändert aber nichts am generellen Vorgehen; auch nicht, wenn viele verschiedene Dokumente erstellt werden.

Bei Methoden wie Scrum gibt es dann Zyklen, vor denen eine Spezifikation erstellt wird. Während eines Zykluses findet dann die Implementierung statt. Abschließend gibt es ein Review und eine Retrospektive. Dieses Vorgehen wiederholt sich in Zyklen von zum Beispiel zwei Wochen. Reviews können insofern weh tun, als dass man nach zwei Wochen merkt, dass man in die falsche Richtung entwickelt hat. Es hat aber auch den Vorteil, dass es eben nur zwei Wochen sind.

Wenn man nun alle zwei Wochen eine Anwendung bereitstellt, muss man sich zwangsläufig auch über Migration Gedanken machen. Denn neue Anforderungen bedeuten in der Regel auch Änderungen an der Datenbank oder an Verzeichnissen. Wenn man dann nach zwei Wochen den Testern sagt, dass die Inhalte der Datenbank gelöscht werden, stößt das Vorgehen irgendwann auf seine Grenzen. Das bedeutet dann, dass man sich eine Strategie überlegen muss, wie man Skripte zur Migration organisiert.

Ebenso verhält es sich beim Erstellen eines Releases. Wenn alle zwei Wochen ein Release gebaut wird, kann das eventuell einen großen Teil der Zeit in Anspruch nehmen. Dass dadurch Zeit für die Implementierung von neuen Anforderungen wegfällt, liegt auf der Hand. Auch dafür ist dann eine Strategie zu entwickeln, um zum Beispiel die Erstellung eines Releases zu automatisieren.

Scrum schlägt einen Rahmen vor, wie man aus Projektsicht mit unangenehmen Vorkommnissen umgehen kann: In kleinen Zyklen wiederholen! Das sollte aber nicht nur aus Projektsicht so sein, sondern auf allen Ebenen der Softwareentwicklung.

Wenn es also "weh tut", hilft Routine durch häufiges Wiederholen. Manchmal ist es aber auch sinnvoll, aufzuhören und sich eine Alternative zu überlegen.

Software Engineering - Trennung von Schnittstellen

09 Mai 2017

Mal angenommen es gibt 4 Systeme, die über eine Datei als Schnittstelle miteinander gekoppelt sind. Jedes der 4 Systeme kann schreibend oder lesend darauf zugreifen.

Problematisch sind dabei nicht die verschiedenen Systeme, sondern dass von allen eine Schnittstelle verwendet wird. Wenn also ein System eine Änderung an der Schnittstelle benötigt, sind alle anderen Systeme ebenfalls betroffen. Dass dadurch die Wartbarkeit beinahe bei 0% liegt, macht ein solches Konstrukt die Optimierung von Prozessen fast unmöglich.

Fraglich ist bei einem solchen Konstrukt, ob es überhaupt fachlich Sinn macht. Aus meiner Sicht kann das in der Regel nicht so sein, weil es ja einen Grund hat, warum es verschiedene Systeme sind. Dieser Grund kann dann auch nur fachlich sein, weil die Systeme verschiedene Funktionalitäten implementieren.

Funktionalitäten haben wiederum in der Regel unterschiedliche Anforderungen. Das kann insbesondere auch die Granularität der zu liefernden Daten betreffen. Durch die eine Datei als Schnittstelle muss diese Granularität an das System angepasst werden, das die niedrigste Aggregation der Daten benötigt.

Die Zeit, die vielleicht bei der Implementierung durch nur eine Schnittstelle gespart wurde, geht natürlich spätestens bei einer eventuell nötigen Optimerung verloren. Noch mehr Zeit geht verloren, wenn bis dahin wegen Schnittstellenänderungen alle 4 Systeme angepasst werden müssen.

Natürlich kostet es Zeit, verschiedene Schnittstellen zu implementieren. Wenn man sich die Zeit also nimmt, spart man sich langfristig Zeit und kann bei notwendigen Änderungen schneller reagieren und auf Absprachen zwischen vielen Systemen verzichten.

Software Engineering - Trennung von Informationen basiert auf Fachlichkeit

27 Januar 2017

Unter Meine Datenbank gehört mir schreibt Eberhard Wolff darüber, dass Module nicht ein Datenbankschema teilen sollten. Stattdessen sollte jedes Modul ein eigenes Datenbankschema verwenden. Er begründet das mit dem Konzept des Information Hidings, das nicht nur für Klassen gelte.

Das hört aus meiner Sicht natürlich nicht bei der Datenbank auf, sondern gilt auch auf allen anderen Ebenen. Informationen, die fachlich nichts miteinander zu tun haben, gehören nicht in ein Modul und auch nicht in einen Strukturbaum. Einen solchen Strukturbaum gibt es bei Entitätsklassen. Zwei Strukturbäume ließen sich einfach über bidirektionale Beziehungen verknüpfen. Das sollte unbedingt vermieden werden, weil auch hier die Änderbarkeit leidet. Dass wir Daten in verschiedenen Klassen oder Tabelllen unterbringen, gehört zum Alltag eines Software-Entwicklers.

Diese geschickte Trennung von Informationen gehört zum Software Engineering und basiert immer auf der Fachlichkeit. Das Konzept lässt sich nicht nur auf Klassen anwenden, sondern eben auch auf Module. Meine Erfahrung ist bisher leider, dass sich viele Entwickler mit der Fachlichkeit kaum auseinandersetzen wollen. Diesen Entwicklern Entscheidungen basierend auf der Fachlichkeit zu erläutern ist oft schwierig. Problematisch wird es, wenn diese Entscheidungen ignoriert werden. Umso wichtiger ist es für Software-Entwickler, sich nicht nur mit den neuesten Techniken zu beschäftigen, sondern einen genauen Blick auf die Fachlichtkeit zu werfen. Meine Erfahrung ist nämlich auch, dass man mit Wissen über die Fachlichkeit, Systeme viel einfacher umsetzen kann.


Alte Einträge sind verfügbar im Archiv.