
Kevin Erath
Geschäftsführer
Veröffentlicht am
1. Mai 2021

Die bisher gelösten Aufgaben waren alle recht linear. Es gab im Prinzip keine alternativen Pfade. Eine solche Verzweigung wird meist mit Kontrollstrukturen wie einer if
-Anweisung realisiert. Größere Programme kommen ohne diese nicht aus. Wie kann dies also mit Flow-Design umgesetzt werden? Insbesondere, wenn wir das IOSP einhalten wollen und somit in Integrationen keine Logik zulassen.
Als Beispiel für so eine Situation hier ein kleines Flow-Design.

Die Funktionseinheit Parse
hat die Aufgabe eine Zeichenkette zu parsen. Handelt es sich um eine ganze Zahl, so soll diese über die Funktionseinheit PrintNumber
auf dem Bildschirm ausgegeben werden. Ansonsten soll die Zeichenkette selbst über die Funktionseinheit PrintText
auf dem Bildschirm ausgegeben werden. Die dazugehörigen Datenflüsse, die aus Parse
herauskommen, tragen jeweils einen Namen OnString
und OnInt
.
Was aus dem Diagramm zwar nicht direkt hervorgeht, aber aufgrund der sinnvollen Benennung der Ausgänge OnString
sowie OnInit
hergeleitet werden kann, ist, dass es sich in diesem Falle um Alternativen handelt. Möchte man das deutlicher kennzeichnen, so kann das bei Bedarf leicht im Diagramm ergänzt werden, auch wenn die Notation ein solches Oder eigentlich nicht abdeckt.

Wie kann den nun aber ein Diagramm mit einer solchen Verzweigung in Code umgesetzt werden? Die Antwort variiert hier je nach Programmiersprache. In C# kann man hier z.B. auf Events oder Delegates in Kombination mit Lambda-Ausdrücken zurückgreifen. Ersteres findet man auch unter dem Begriff Event-based Components. Die zweite Umsetzungsvariante basiert auf dem Konzept des Continuation Passing Style, vereinfacht auch Continuations genannt.
Werden Event-based Components im großen Stil in der eigenen Anwendung eingesetzt, so wird dafür häufig auf ein Framework zurückgegriffen. Da die Verdrahtung nicht immer leicht nachvollziehbar ist, wird gerne ein Tool zur visuellen Darstellung und Erzeugung dieser Verbindungen verwendet. Ein solches Framework bzw. Tool ist z.B. NoFlo. Dieses orientiert sich am Flow-based Programming, dass sehr starke Ähnlichkeiten zu Flow Design besitzt.
Für einfache Verdrahtungen sind aber weder Framework noch ein visuelles Entwurfswerkzeug notwendig. Diese können in C# dank des Schlüsselwortes event
einfach umgesetzt werden. Hier die Umsetzung für das obige Flow-Design mithilfe von C# und Events.
using System;
internal class Parser
{
public Action<int> OnInt;
public Action<string> OnString;
public void Parse(string text)
{
int value;
if (int.TryParse(text, out value))
{
OnInt(value);
}
else
{
OnString(text);
}
}
}
internal static class Program
{
private static void Main(string[] args)
{
var parser = new Parser();
parser.OnInt += PrintNumber;
parser.OnString += PrintText;
parser.Parse(args[0]);
}
private static void PrintNumber(int number)
{
Console.WriteLine("Number is {0}", number);
}
private static void PrintText(string text)
{
Console.WriteLine("Text is {0}", text);
}
}
Hier ist schön zu sehen, dass in diesem Falle aus der Funktionseinheit Parse
eine ganze Klasse wird. Der Rückgabewert wich nun zwei Events. Die Verdrahtung erfolgt dann über die Registrierung der Methoden bei diesen Events. Gleichzeitig ist aber auch das Problem zu sehen, dass durch die Verdrahtung via Events, besonders bei größeren Projekten, nicht mehr sofort ersichtlich ist, was mit wem zusammenhängt. Aus diesem Grund nutze ich Events nur in bestimmten Situationen, wie z.B. der Entkopplung des UIs.
Meine bevorzugte Lösung für solche Probleme setzt in C# auf Continuations und Lambda-Ausdrücke. Hier die Lösung mit Continuations:
using System;
internal static class Program
{
private static void Main(string[] args)
{
Parse(args[0], PrintNumber, PrintText);
}
private static void Parse(string text, Action<int> onInt, Action<string> onString)
{
int value;
if (int.TryParse(text, out value))
{
onInt(value);
}
else
{
onString(text);
}
}
private static void PrintNumber(int number)
{
Console.WriteLine("Number is {0}", number);
}
private static void PrintText(string text)
{
Console.WriteLine("Text is {0}", text);
}
}
Sicherlich wirkt der Code etwas gewöhnungsbedürftig, vor allem dann, wenn man mit Delegates bzw. Continuations nicht vertraut ist. Aber neben dem knapperen Code ist eben die Verdrahtung und damit die Verzweigung direkt beim Methodenaufruf sichtbar.
Letztendlich kann mit beiden Varianten PoMO und IOSP eingehalten werden.
Anmerkung: Bei diesem Text handelt es sich um einen überarbeiteten Repost eines alten Blog-Artikels aus 2015 von mir.

Hier schreibt
Kevin Erath
Als Mitbegründer und Geschäftsführer von pep.digital verbringe ich zwar nicht mehr jeden Tag ausschließlich damit, coole Lösungen für unsere Kunden zu realisieren. Trotzdem finde ich immer wieder die Zeit, mich auch mal tiefer in die Technik einzutauchen und meine Erkenntnisse hier im Blog zu teilen. Und ehrlich gesagt, das Unternehmen und unsere tollen Mitarbeiter:innen weiterzuentwickeln, macht mir mindestens genauso viel Spaß.
Quellen
Weitere interessante Artikel
Wir möchten hier nicht nur über Neuigkeiten aus dem Unternehmen berichten, sondern auch das Wissen und die Erfahrung unserer Experten teilen.

Mehr Softwarequalität durch Programmieren nach Plan
Wer sich vor dem Kodieren Gedanken zum Aufbau der zu entwickelnden Software macht, der erzeugt eine deutlich höhere Softwarequalität. Dies gilt nicht nur bei der Entwicklung digitaler Produkte, sondern generell.

Kevin Erath
Geschäftsführer

Cargo Cult in der Softwareentwicklung
Die Softwareentwicklung ist voller Best Practices, Muster und Methoden, die darauf abzielen, unsere Arbeit effizienter und unseren Code zuverlässiger zu machen. Oft orientieren wir uns an erfolgreichen Projekten und erfahrenen Entwicklern, um ihre Techniken nachzuahmen und ähnlichen Erfolg zu erzielen. Manchmal konzentrieren wir uns jedoch zu sehr auf das Kopieren dieser Praktiken, ohne die dahinterliegenden Prinzipien vollständig zu verstehen. Dies kann zu dem führen, was als „Cargo Cult“-Programmierung bekannt ist.

Klemens Morbe
Softwareentwickler