Je weniger Code desto besser?

Pippen123

Cadet 4th Year
Registriert
Okt. 2008
Beiträge
113
Ich fange gerade an, Programmieren zu lernen, und zwar mit Swift Playgrounds. Da habe ich eine Frage: Ist der Code besser, der das Gleiche mit weniger Befehlszeilen ausführt, als ein Code der dafür mehr Befehle braucht? Ich habe mir nämlich angewöhnt, meine Programmierlösungen zu den Aufgaben danach zu bewerten, ob ich mehr oder weniger Zeilen brauche als die Lösung. Brauche ich weniger, dann freue ich mich und sehe mich sogar als besser als der Löser, brauche ich mehr, dann habe ich einen Fehler gemacht. Mein naiver Hingergedanke ist: jeder Befehl kostet Zeit und Ressourcen, d.h. je weniger desto besser.

Ich frage mich, ob meine Gedanken verallgemeinerbar sind.
 
Dein Hintergedanke ist nicht korrekt.
1. Codezeilen haben keine fixen Laufzeiten. Befehle haben Laufzeiten. Ein Code mit 5 Zeilen kann schneller laufen als ein einteiliger Code.
2. Selbst wenn wenig Code mindestens genauso schnell ist, ist wenig Code nicht automatisch besser. Schleifen oder If Blöcke lassen sich oft mit 1-2 Zeilen Code schreiben - auf Kosten der les- und entsprechend der wartbarkeit.

Es gibt meistens Code Konventionen. Die geben vor, was "guter" Code ist. Der Rest ist erfahrung und GruppenArbeit
 
  • Gefällt mir
Reaktionen: [ChAoZ], henpara, Skysnake und 6 andere
Ich würde verallgemeinert sagen Nein, kürzerer Code ist nicht zwangsläufig besser.

Je nachdem was du vor hast, kommt es auch auf Nachvollziehbar-/Verständlichkeit, Wartbarkeit, Erweiterbarkeit, etc. an.
 
  • Gefällt mir
Reaktionen: pizza4ever, Ranayna, GTrash81 und eine weitere Person
das kann man nicht verallgemeinern...
es gab auch schon Wetbewerbe, so viel "Funktion" wie möglich in eine Zeile zu packen.
"guter" Code zeichnet sich durch andere Dinge aus als Länge oder "Kürze".

und was der Compiler daraus macht, das ist heute eh schon "fast Zauberei" ;)
 
  • Gefällt mir
Reaktionen: Skysnake und GTrash81
Nein. Lines of code und anzahl der Buchstaben sind keine Messmethode für qualität

Pippen123 schrieb:
jeder Befehl kostet Zeit und Ressourcen, d.h. je weniger desto besser.
an sich richtig, aber wenn du nun über n elemente iterierst, was beeinflusst dann die performance?

mal ein beispiel. ich habe hier mal Mergesort und Swapsort Python implementationen gesucht.

welcher code ist schneller bei identischer anzahl Elemente?
Merge Soirt:
Python:
def mergeSort(arr):
    if len(arr) > 1:
 
         # Finding the mid of the array
        mid = len(arr)//2
 
        # Dividing the array elements
        L = arr[:mid]
 
        # into 2 halves
        R = arr[mid:]
 
        # Sorting the first half
        mergeSort(L)
 
        # Sorting the second half
        mergeSort(R)
 
        i = j = k = 0
 
        # Copy data to temp arrays L[] and R[]
        while i < len(L) and j < len(R):
            if L[i] < R[j]:
                arr[k] = L[i]
                i += 1
            else:
                arr[k] = R[j]
                j += 1
            k += 1
 
        # Checking if any element was left
        while i < len(L):
            arr[k] = L[i]
            i += 1
            k += 1
 
        while j < len(R):
            arr[k] = R[j]
            j += 1
            k += 1
##Source: https://www.geeksforgeeks.org/merge-sort/

Swap Sort:
Python:
def swap_sort(sortme):
    index = 0
    while index < len(sortme) - 1:
        new_index = sum(x < sortme[index] for x in sortme)
        if index == new_index:
            index += 1
        else:
            sortme[index], sortme[new_index] = sortme[new_index], sortme[index]

Beide lösen das selbe Problem. einer davon braucht immer n^2 schritte, einer n*log(n) im worst, und n Schritte im best case.


Lesestoff:
https://de.wikipedia.org/wiki/Laufzeit_(Informatik)
https://de.wikipedia.org/wiki/Sortierverfahren
https://www.inf-schule.de/algorithm...ren/laufzeitverhalten/systematischebestimmung
 
Zuletzt bearbeitet:
  • Gefällt mir
Reaktionen: Arc Angeling
Ich würde auch 'nein' sagen

Lieber im Klartext lesbarer und kommentierter Code, der dasselbe macht wie eine Zeile super kompakter Code, wo du dir erstmal 'ne Minute lang den Kopf kratzt bis du schnallst was der macht.

Ansonsten - effizienter Code und kompakter Code sind zwei komplett verschiedene Sachen.
Wenn du eine riesige Abfrage in einer Schleife bastelst weil du nicht ein paar Zeilen Code schreiben wolltest um die Abfrage vor zu sortieren, dann hast du vielleicht Zeilen gewonnen, aber massiv Performance verloren.
 
  • Gefällt mir
Reaktionen: [ChAoZ], Skysnake und BeBur
Grundsätzlich ja: Je weniger Code, desto besser.
 
  • Gefällt mir
Reaktionen: Micke
Das ist in erster Linie eine Glaubenssache.

Ich würde daran kein Gedanken verschwenden. Kommt Routine, kommt die Lösung von selbst.


____
Ich tendiere auch grundsätzlich zu ja. Aber ist wiegesagt reine Glaubenssache. Prioritär sind sowieso andere Dinge wie einwandfreie Funktion, Lesbarkeit, Wartbarkeit. Auch diese Sachen werden sich mit der Zeit von selbst ergeben.
 
  • Gefällt mir
Reaktionen: TomH22
Wenn du in Maschinensprache programmieren würdest, würde ich dir zustimmen. Wobei es vermutlich auch da Ausnahmen gibt.

Die Frage ist ja: was bedeutet für dich "besser"? Schneller?

Wenn es um Geschwindigkeit geht: in höheren Programmiersprachen ist die Laufzeit der Befehle ja nicht identisch, nicht jeder Befehl braucht gleich lange. Mächtige Befehle und Funktionen, die viele Schritte auf einmal ausführen, dauern oft länger als ein längerer, aber für deinen Zweck optimierter Code, weil sie einen gewissen overhead mitbringen können. Dann kommt dazu, das nicht nur CPU Zeit für die Geschwindigkeit ausschlaggebend ist, sondern z.B. auch I/O Zugriffe... Wenn du mehr Code brauchst um langsame I/O Zugriffe zu minimieren/optimieren kann dein gesamter Code schneller werden...

Schau dir mal die verschiedenen Sortieralgorythmen an die es so gibt... die sind alle sehr unterschiedlich und je nach Daten ist der eine oder andere schneller, unabhängig von der Codelänge.
 
Die reine Quantität von Codezeilen ist an sich noch kein Qualitätskriterium, denn viele Programmiersprachen würden es dir erlauben, ALLES in eine Zeile zu schreiben ;)

Bis zu einem gewissen Grad gilt weniger Code enthält auch weniger Fehler. Aber wenn der voll mit Schwarzmagie ist, kann den irgendwann auch keiner mehr außer dir lesen.

Daher würde ich empfehlen, das "weniger" nicht im quantitativen Sinne zu verstehen, sondern im Sinne der Komplexität: Je weniger komplex deine Lösung ist, desto besser im Sinne von so wenig komplex wie möglich, aber so komplex wie nötig.
 
  • Gefällt mir
Reaktionen: henpara, Ephesus, TPZ und 2 andere
Korben2206 schrieb:
Wenn du in Maschinensprache programmieren würdest, würde ich dir zustimmen. Wobei es vermutlich auch da Ausnahmen gibt.
Mit der Verfügbarkeit von einigen dutzend Generationen CPUs für verschiedenen Architekturen, sind die Ausnahmen die Regel :)

LoC ist keine sinnvolle Metrik!
 
  • Gefällt mir
Reaktionen: mental.dIseASe und madmax2010
Mir erscheint es logisch, dass weniger Code besser ist als viel Code, vorausgesetzt man macht deswegen nicht wo anders Kompromisse:
  • Code ist schneller verstehbar
  • Code ist schneller geschrieben
 
  • Gefällt mir
Reaktionen: Seby007
Guter Code ist (unter anderem) gut verständlich. Das hat rein gar nichts mit lang oder kurz zu tun, schlechter Code kann zu kurz sein oder er kann zu lang sein. Das simpelste was man falsch machen kann ist, kurze Variablennamen zu vergeben.
Guter Code der nichts aufregendes macht ist auch von Laien gut lesbar:
Ruby:
customers.each do |customer|
  customer_age = calculate_age(customer)
  if customer_age >= 18
    birthday_greeting_mode = :naughty
  else
    birthday_greeting_mode = :underage
  end
  send_birthday_greeting(customer, birthday_greeting_mode)
end
Das ist übrigens syntaktisch korrekter (Ruby) Code. [Disclaimer: Und so wie es da steht natürlich auch nicht super geil z.B. eine 'magic number' kommt vor und es ist auch kein idiomatischer ruby code durch das if-else konstrukt]
 
Korben2206 schrieb:
Wenn du in Maschinensprache programmieren würdest, würde ich dir zustimmen. Wobei es vermutlich auch da Ausnahmen gibt.
Nochmal genauer drüber nachgedacht, das sollte bei allen Architekturen nicht zutreffen.

Möglichst kurzer Assembler enthält für jeden Funktionsaufruf eine Sprung zur Adresse der Funktion und danach einen Sprung zurück um jedes bisschen Redundanz zu vermeiden. Bei kleineren Funktionen ist es jedoch in der Regel für die Performance sinnvoller, eben jene Sprünge einzusparen und die Befehle der Funktion direkt einzusetzen.
Es kann vorkommen, dass bei optimiertem Assembler die Befehle einen einzelnen Funktion zigfach Redundant vorkommen.

Bei Hochsprachen ist das zurecht verpöhnt, die Compiler machen sowas aber bei erster Gelegenheit, solang man denen nicht explizit mitgiebt, dass man möglichst kompakten Code haben will.
 
Zuletzt bearbeitet:
  • Gefällt mir
Reaktionen: Arc Angeling und GTrash81
Da gibt es sogar ein hübsches reales Beispiel: Quake Fast Inverse Square Root.
Mal ein Link:
https://betterexplained.com/articles/understanding-quakes-fast-inverse-square-root/

Der Punkt ist, dass zumindest damals, gewisse Rechenoperationen extrem teuer waren,
die aber Programme bestimmte Funktionen ermöglichten.
Bei dem Spiel Quake hat man dann diese Form des Inverse Square Root verwendet,
die zwar etwas länger, aber um mehrere Ebenen schneller ist.

"Herausgefunden hat das jemand anderes und man ist darüber gestolpert, hat es
ausprobiert und für perfekt empfunden."
 
Guter Code ist in erster Linie gut wartbar. Indirekt kann das auch etwas mit der Länge zu tun haben, ja. Doppelter Code ist beispielsweise meist kein gutes Zeichen. Kürze ist bei gutem Code aber eher ein Nebenprodukt.

Aber Code, dessen Autor primär die Kürze als Qualitätskriterium auserkoren hat, wird eher selten guter Code sein :D

Jetzt mal davon abgehen, dass die Länge des Codes nicht besonders viel über die Geschwindigkeit aussagen muss. Noch nicht mal bei Maschinencode, weil auch hier unter Umständen verschiedene Instruktionen auch unterschiedliche Zeiten benötigen.
 
Zuletzt bearbeitet:
Naja, so schwarzweiß ist es halt alles nicht.

Ja, wenn ich mit einer Codezeile erledigen kann, wo ich sonst das 10+fache gebraucht hätte, das ist schon mal gar nicht so schlecht.
Naßtrocken - also DRY, WET und "moist" Code --- wurde ja schon erwähnt.

Die Kunst ist halt zu entscheiden, was wann und wo. Nicht zu vernachlässigen ist auch der Kosten-Nutzen-Faktor.

Ein Script was exakt einmal laufen soll? Da investiere ich nicht einen Monat, um aus zwei Zeilen eine zu machen.

Es nützt mir auch nichts, "optimierten" Code zu haben, wo ich morgen draufguck und nicht verstehe was ich überhaupt wollte oder warum das funktioniert.

Vernünftiger Code ist modular - was aufbläst -- objektorierentiert -- was auch aufbläst --- erweiterbar -- was nicht minder aufbläst --- und performant, was "meistens" reduziert.

Persönlich denke ich braucht man auch ein vernünftiges Paradigma für seine konkrete Anwendung. Eine Möglichkeit ist zB ein "Flußmodell" wo wenn da was hängenbleibt, weil Schleife, weil nicht-konstant-viele Daten zur Laufzeit gehalten werden müssen, sonstwas -- zu fragen ist ob das gebraucht wird. Das kann man zB für Filter machen, wenn ich einen Input per f(x) auf einen Output reduzieren muß.
In anderen Situationen profitiert man dagegen von einem Poolmodell. Alles auf einen Haufen klatschen und Ressourcen werden gemeinsam genutzt. Oder was weiß ich, irgendeine Vorstellung halt davon wie meine Anwendung arbeiten soll -- dazu muß ich mich nämlich damit auseinandersetzen und merke DURCH diese Auseinandersetzung: hey scheiße ich hab was vergessen, das geht so nicht.

Optimierung kommt dann später. Wobei ich schon denke, daß man bei grundlegenden Dingen das von Anfang an mitnehmen kann. Ich habe Mengen die ich bearbeiten muß? Dann nehm ich kein Array, denn die sind statisch, sondern ich nehme Listen. Oder ich habe Zeichenfolgen die ich manipulieren muß? Dasselbe: Strings sind statisch, aber ich kann durchaus Abstraktionen verwenden, entweder solche von der Umgebung bereitgestellte oder halt selber implementierte, wenn das nötig wird. Ich will für jedes X eine Menge Y haben? Dann kann ich ne Schleife bauen und kann den Haufen sammeln und geschlossen ausgeben, oder ich kann (sinngemäß) "yield return" sagen und in jedem Durchlauf das oder die Ergebnisse FÜR den Durchlauf zurückgeben, vergessen und weitermachen.

Promises. Viel interessanter als eine Codezeile weniger sind Promilles, die buchstäblich erst zur Laufzeit aufgelöst werden. Da hab ich (fast) keinen Ressourcenbedarf, solange ich nichts machen muß. Erst wenn ich wirklich aktiv irgendwo zugreife, DANN werden die Ressourcen belegt.

Multithreading folgt fast automatisch und macht meinen Code nochmal komplexer und unüberschaubarer.


Also ja. Relevante Dinge so kurz und knapp abbilden wie es praktikabel ist, Komplexität kommt fast zwangsläufig hinten dran. Eine "aktive Komponente" (was mein Tool leisten soll) die weniger als 10% des gesamten Codes ausmacht ist nicht besonders unüblich (Prüfung Input, Prüfung Output, Rumreichen von Ressourcen, Einsammeln und Behandeln von Ausnahmen (wo möglich) kommt alles noch oben drauf.

Aber insgesamt betrachtet hat man am Ende des Tages mit "weniger Code" nicht immer, aber oft genug einfach nur weniger gut durchdachten bzw etwas genauer betrachtet unvollständigeren Code, der eben nicht die möglichen Gegebenheiten berücksichtigt bzw. berücksichtigen kann.


Lesestoff: EICAR. Das ist Assemblercode der in wenigen Zeichen verdammt viel tut.
 
  • Gefällt mir
Reaktionen: madmax2010
Pippen123 schrieb:
Brauche ich weniger, dann freue ich mich und sehe mich sogar als besser als der Löser, brauche ich mehr, dann habe ich einen Fehler gemacht.
Du solltest danach gehen, welche Lösung Dir verständlicher, lesbarer, „elaganter“ vorkommt. Im Laufe der Zeit bekommt man als Programmierer ein Gespür für „guten“ vs. schlechten Code, besonders wenn man sich auch Code anderer Leute anschaut. Die Tücke ist, dass die eben genannten Kriterien sich manchmal widersprechen. So ist die beste Lösung nicht automatisch die, die am intuitivsten zu verstehen ist. Beispiel:
Du hast irgendwo ein if statement wo
„if not a and not b then…“ steht. Gemäß den de-morganschen Regeln ist das identisch mit „if not (a or b)“. Letzteres ist kompakter und „eleganter“, für einen Anfänger ist aber die erste Variante unter Umständen leichter zu verstehen.

Letztendlich ist das aber auch von der Zielgruppe abhängig. Leute mit fundiertem Wissen in theoretischer Informatik finden Dinge elagant und gut lesbar, die für jemanden der als Quereinsteiger zur Programmierung gekommen ist, nur unverständliches Kauderwelsch sind.

Pippen123 schrieb:
Mein naiver Hingergedanke ist: jeder Befehl kostet Zeit und Ressourcen, d.h. je weniger desto besser.
Teilweise ist das richtig, aber wenn man einen hochoptimierenden Compiler hat, kann es sein, das er den „umständlicheren“ Code selber optimiert. Es gibt natürlich simple, nicht optimierende Interpreter (z.B. bei manchen Scriptsprachen) wo selbst ein konstanter Ausdruck wie „5+3“ „wörtlich“ in Code umgesetzt wird. Im Falle Swift kannst du getrost von einem optimierenden Compiler ausgehen. Ich selber schreibe, der Lesbarkeit wegen, z.B. in C/C++ gelegentlich bewusst den „ausführlicheren“ Code hin, weil ich weiß, das der Compiler es eh optimiert.
Also z.B. if (p!=NULL) anstatt if (p).

In der Praxis ist nur ein kleiner Teil des Programmcodes für die Laufzeit des Programms verantwortlich. Üblicherweise sind das die sogenannten „Leaf Functions“ , d.h. die Funktionen ganz unten in der Aufrufhierarchie, die keine anderen Funktionen mehr aufrufen. Hier kann es Sinn machen, diese bis zum letzten Taktzyklus zu optimieren, ggf. auch auf Kosten der Lesbarkeit.


BeBur schrieb:
Das simpelste was man falsch machen kann ist, kurze Variablennamen zu vergeben.
Ja, aber auch hier sollte man mit Bedacht vorgehen.
Beispiel: Es ist seit seeligen Fortran Zeiten üblich Laufvariablen von for Schleifen i oder k zu nennen. Zumindest bei eher kurzen Schleifen finde ich dann lange, sprechende Namen wie „ArrayIndex“ unnötig, im Gegenteil, der Code wird oft sogar schwerer lesbar, weil in Summe länger.
 
  • Gefällt mir
Reaktionen: RalphS
Zurück
Oben