C#Clean Code

Römische Zahl konvertieren mit C#

Eine einfache Lösung in C# zur Konvertierung von römischen Zahlen. C# setzen wir auch gerne bei der Umsetzung unserer Kundenprojekte ein.

Römische Zahl mit C# konvertieren
Anne Nygård

Hier ein kleines C#-Programm, das sich an der Kata RomanNumerals orientiert. Es basiert auf dem zweiten Teil der Kata, bei dem es um die Konvertierung von römischen Zahlen in Dezimalzahlen geht.

using System;
using System.Collections.Generic;
using System.Linq;

internal static class Program
{
  private static void Main(string[] args)
  {
    var mapping = new Dictionary<string, int>
    {
      {"I", 1}, {"V", 5}, {"X", 10}, {"L", 50}, {"C", 100},
      { "D", 500}, {"M", 1000}, {"IV", 4}, {"IX", 9},
      { "XL", 40}, {"XC", 90}, {"CD", 400}, {"CM", 900}
    };
    var number = 0;
    var lastChar = "-";
    foreach (var chr in args[0].Select(x => x.ToString()))
    {
      if (mapping.ContainsKey(lastChar + chr))
      {
        number += mapping[lastChar + chr] - mapping[lastChar];
      }
      else
      {
        number += mapping[chr];
      }
      lastChar = chr;
    }
    Console.WriteLine("{0} -> {1}", args[0], number);
  }
}

Sieht das Programm nicht überschaubar aus? Klar, das wollte ich auch so. Mein Ziel war es, eine kurze Lösung zu schreiben. Aber handelt es sich dabei auch um guten Code?

Zumindest laut C#-Tools wie dem ReSharper ist der Code nicht optimal. Weist dieser doch mit einer Warnung darauf hin, dass ich bei der Methode ToString() keine Culture angegeben habe. Ein Programmieranfänger hingegen könnte über den LINQ-Aufruf stolpern, den ich innerhalb der foreach-Schleife zur Konvertierung des Zeichens in eine Zeichenkette nutze. Vielleicht hat er aber auch damit Probleme, dass ich keinen Lookahead eingebaut habe und lieber Zahlen die mit subtraktiver Schreibung angegeben wurde, durch Abziehen des vorherigen Werts korrigiere. Ist die Performance wichtig, dann stört sicherlich, dass ich viel zu viele unnötige Zeichenketten erzeuge (Speicherverbrauch? Garbage Collection?). Geht es um Clean Code, dann verletze ich wohl das SRP (Single Responsibility Prinicple), da die Methode Main() einfach alles macht.

Die meisten werden jetzt vermutlich denken: „So what? Keep it simple, stupid!“. Es handelt sich hier ja nur um eine sehr kleine C#-Konsolenanwendung. Viel schiefgehen kann bei einer so kleinen Anwendung ja nicht und funktionieren tut sie ja auch. Zur Not wird die Anwendung nochmals angepasst und bei Bedarf dann refaktorisiert oder neu geschrieben.

Ja, dem muss ich zustimmen, KISS sollte berücksichtigt werden. Dennoch verpassen wir leider viel zu oft den Zeitpunkt für das Aufräumen, sonst würden Softwareprojekte nicht irgendwann wie Efeu wuchern. Eventuell liegt es auch daran, dass Änderungen irgendwann (oder gar von Anfang an?) nach dem VHIT-Prinzip (vom Hirn ins Terminal) durchgeführt werden. Oder man traut sich nicht, den bestehenden Code aufzuräumen – man könnte ja etwas kaputt machen. Es fehlt in diesem Fall, neben dem Glauben an sich selbst, auch noch an einem Sicherheitsnetz. Man sieht schon, es gibt wirklich viele Gründe, warum ein bestimmter Quellcode so ist, wie er ist. Ich vermute diese Diskussion könnte man noch ziemlich lange fortführen. Einen einheitlichen Standard, was guten oder schlechten Code auszeichnet, gibt es nicht.

Und warum nun die ganze Diskussion? Das Programm ist schließlich fertig! Na ja, eigentlich nicht. Es fehlt z. B. eine Überprüfung, ob auch eine gültige römische Zahl eingegeben wurde. Auch stürzt das Programm ab, wenn gar nichts beim Programmstart übergeben wurde. In so einem Fall könnte man stattdessen auch eine kleine Hilfe für den Anwender anzeigen. Damit sind wir dann auch schon mittendrin im Weiterentwicklungszyklus. Warum ist das wichtig? Weil ich denke, wir sollten genau auf die Weiterentwicklungsfähigkeit (auch Evolvierbarkeit genannt) unserer Softwareprojekte achten.

Anmerkung: Bei diesem Text handelt es sich um einen überarbeiteten Repost eines alten Blog-Artikels aus 2015 von mir.