Forum: PC-Programmierung C: Problem in Teilprobleme untergliedern und einzeln testen. Wie lernen?


von Gerd (Gast)


Lesenswert?

Hi

Wie ihr sicherlich aus meinen anderen Threads bereits herauslesen könnt, 
bin ich in Sachen Programmieren noch energetischer Anfänger.

Ich möchte gerne von meiner jetzigen Mentalität wegkommen, ein 
Programmierproblem direkt vom Kopf in Zeilen Code umzuwandeln, und dann 
über Try&Error einen funktionierenden Code zu entwickeln. Ich möchte 
stattdessen gerne das Problem in Teilprobleme unterteilen, und dann 
strategisch diese Teilprobleme lösen, die dann letztendlich das 
Gesamtproblem lösen.

Ich mache mir entsprechend gerade darüber Gedanken, wie man am 
geschicktesten ein gegebenes Problem (gegebene Aufgabe) in Teilprobleme 
(Teilaufgaben) untergliedert, und diese dann einzeln löst. Das 
eigentliche (Programmier)Problem ist dabei erstmal zweitrangig, genau so 
wie die optimale/effiziente Implementierung (ob nun ein Zeiger verwendet 
wurde, oder ein Struct, oder eine for-Schleifer oder eine while-Schleife 
etc.).

Gibt es diesbezüglich eine Art best practices (auch wie tiefgründig die 
Teilprobleme getestet werden sollten), die ihr empfehlen könnt?

Wie lernt man, sich in diese Art von Problemunterteilung 
hineinzuversetzen?

Danke und Gruß,

von Sven B. (scummos)


Lesenswert?

Einfach machen. Kontinuierlich darüber nachdenken, ob einem was besseres 
einfällt, als das was man in der Vergangenheit gemacht hat. Falls ja, 
ändern, und evaluieren ob es jetzt tatsächlich besser ist.

Die Fähigkeit, am Anfang gleich eine gute Struktur zu raten kommt dann 
mit der Zeit dazu. Ist mE reine Erfahrungssache aus der Praxis und lässt 
sich nicht spezifisch lernen.

von Lerninstructor (Gast)


Lesenswert?

Gerd schrieb:
> Wie lernt man, sich in diese Art von Problemunterteilung
> hineinzuversetzen?

learning by doing.

von Programmierer (Gast)


Lesenswert?

Gerd schrieb:
> Wie lernt man, sich in diese Art von Problemunterteilung
> hineinzuversetzen?

Das allerwichtigste hast Du schon gelernt, nämlich den richtigen 
"Mindset", die eigene Retrospektive. Das ist das Fundament.

Es ist nicht ganz einfach das Dickicht von Techniken, Methoden und 
Mode-Erscheinungen (ja, in der Softwareentwicklung gibt es auch Mode) 
zur Software-Entwicklung zu durchdringen.

Einige Einstiegspunkte zur Thematik:

    https://de.wikipedia.org/wiki/Kategorie:Vorgehensmodell_(Software)

und:

    https://de.wikipedia.org/wiki/Kategorie:Programmierparadigma


Ganz konkret möchte ich Dir den Tipp geben, bevor Du loslegst etwas zu 
Programmieren, einfach ein paar Notizen, völlig formlos, auf eine Seite 
Papier zu schreiben, wie Du das konkrete Problem lösen willst. Das 
können irgendwelche "Kästchen" sein, die mit Pfeilen in Beziehung 
gesetzt werden, oder auch nur eine Liste von was Du in welcher 
Reihenfolge lösen willst.
Es geht nicht darum, irgendwelche UML-Diagramme oder so zu malen, sonder 
nur darum, die eigenen Gedanken zu sortieren und einen "Master-Plan" zu 
haben, bevor Du los programmierst.

Als "Über-Konzept" möchte ich Dir einen Zyklus aus "Vorwärts gehen" und 
"Aufräumen" beim Programmieren vorschlagen, der ständig wiederholt wird. 
D.h. es gibt beim Programmieren die Phase "Erschaffen", in der schreibst 
Du neuen Code und gehst nach Vorne, und es gibt die Phase "Aufräumen", 
in der machst Du das was Du neu geschrieben hast, wieder "schön". Also 
immer abwechselnd "Vorwärts" und "Aufräumen".

Viel Erfolg!

von Programmierer (Gast)


Lesenswert?

Ach, und such Dir jemanden oder mehrere, mit denen Du Dich austauschen 
kannst. So lernt ihr voneinander. Das ist recht effektiv. Gerade beim 
Programmieren ist es ein großer Fehler, alleine im Kämmerchen zu sitzen.

von A. S. (Gast)


Lesenswert?

Zum "drauflos programmieren": das ist wie Schreibmaschine schreiben oder 
Klavierspielen.

Als Anfänger bist Du mit Papier und Bleistift immer schneller.
Mit entsprechender Übung wäre es dumm, den Roman oder die Komposition 
oder Konzepte nicht gleich in die Tastatur zu hacken, wenn man etwas 
ausprobieren will. Und für Brainstorming oder Mindmaps halt was anderes 
zu nehmen
Solange man den Scheiß vom Anfang auch in die Tonne kloppt, wenn man es 
besser versteht.

Der Vorteil von Papier und Bleistift ist dann nur noch, dass man es in 
jedem Fall nochmal ins reine schreiben muss.

Ansonsten: whatever floats your boat.

von Theor (Gast)


Lesenswert?

Im Grunde ist das eine alltägliche Fähigkeit, die man im Laufe der 
ersten 10 Jahre des Lebens ausbildet.

Erst die Schuhe anziehen oder die Hosen? Erstmal duschen, dann in 
Pfützen springen und dann zu Oma zum Kaffee? Oder doch lieber 
andersherum?
Erst die Brote oder erst die Bücher einpacken? Die Brote noch einpacken, 
so das keine Fettflecken entstehen? Erst Mathe machen und dann Deutsch 
und zwischendurch (Interrupt) von Mutter zum Essen gerufen werden.

Dann irgendwann mal der zweite Umzug. Erst die Schränke ausräumen, bevor 
man sie zerlegt. Das Werkzeug ganz am Schluss. Dann kehren und den Besen 
noch mitnehmen. Etcpp.
Das tägliche Leben besteht aus Planung (und ein Gutteil Improvisation).

Man schaut sich die Stadt an in der man lebt. Es gibt Mülltonnen an 
bestimmten Orten und an anderen nicht. Sonntags ist alles zu. Dienstags 
ist Markt. Feuerwehr ist immer bereit. An bestimmten Stellen gibt es 
Halteverbote. Anderswo einen Park. Der Müll wird in meiner Strasse am 
Freitag alle 2 Wochen geholt und beim Kumpel zwei Strassen weiter am 
Mittwoch. Erst die Strassendecke aufstemmen und dann die Rohre darunter 
wechseln und vorher noch die Anwohner wg. Stromunterbrechung 
benachrichtigen. Warum ist das so? Hast Du dazu Thesen entwickelt?

Es ist nun die Frage, was genau beim Programmieren dabei anders ist. 
Eigentlich sind es nur die Subjekte (Daten) und die "Werkzeuge" 
(Anweisungen, Ausdrücke, Funktion, Algorithmen). Sie haben und bilden 
wie eine Wohnung, eine Stadt, das Leben eine Struktur, bestimmte 
Abhängigkeiten oder eben keine. Denk Dir, Du baust eine neue Stadt und 
organisierst sie.

Genau so macht man das.

von foobar (Gast)


Lesenswert?

Häufig hilft es, das Problem über die nötigen Datenstrukturen anzugehen. 
Welche Daten gehören auf welchem Layer zusammen, welche Hilfsstrukturen 
brauche ich, um die Daten zu organisieren und die gewünschten 
Manipulationen durchzuführen.  (Tipp: Redundanz so weit wie Möglich 
vermeiden.)  Daraus folgt dann auch eine Einteilung des Programms in 
bestimmte Unterprobleme.

von foobar (Gast)


Lesenswert?

Ach so, wie andere schon schrieben: üben, üben, üben.  Programmieren ist 
ein Handwerk (ja, im direkten Sinne, wie Schreiner, Schmied, Steinmetz, 
Koch, etc), bei dem man sich im Laufe von Jahren immer weiter 
verbessert.  Das lernt man nicht über Nacht.  Eine gute Quelle, neue 
Herangehensweisen/Methoden/Algorithmen/Strukturen/Kniffe kennen zu 
lernen, ist es, fremden Code zu analysieren/studieren[1].  So sammelt 
sich im Laufe der Zeit ein immer größeres Repertoir an, mit dem man 
arbeiten kann.


[1] Dazu gehört auch das Suchen von Bugs in fremden Code - bringt einem 
eine Menge!

von Mohandes H. (Firma: مهندس) (mohandes)


Lesenswert?

Als ich damals anfing zu programmieren (Pascal und Fortran) habe ich die 
Ergebnisse, auch die der Subroutinen, in einfache Textdateien 
geschrieben. Und dann verglichen: was-steht-da, und was soll-da-stehen? 
Das läßt sich auf jede Sprache übertragen.

von F. F. (foldi)


Lesenswert?

Gerd schrieb:
> Ich möchte gerne von meiner jetzigen Mentalität wegkommen, ein
> Programmierproblem direkt vom Kopf in Zeilen Code umzuwandeln, und dann
> über Try&Error einen funktionierenden Code zu entwickeln.

PAP= Programmablaufplan. Da kann man die Struktur mit festlegen.
Aber ehrlicherweise mache ich das auch nicht.
Was ich immer noch mache, weil ich das mit dem Debugging noch nicht 
wusste/konnte, ist das Led Debugging.
An verschiedenen Stellen im Programm den Blinkcode eingefügt und 
geschaut, ob das Programm dort hin kommt.
Im Anfang habe ich die Geschwindigkeit von so einem Controller völlig 
unterschätzt. Da lagen bei mir eigentlich die meisten Fehler.

: Bearbeitet durch User
von Egon D. (Gast)


Lesenswert?

Gerd schrieb:

> Ich möchte gerne von meiner jetzigen Mentalität
> wegkommen, ein Programmierproblem direkt vom Kopf
> in Zeilen Code umzuwandeln, und dann über Try&Error
> einen funktionierenden Code zu entwickeln.

Schrittweise vorgehen: Ehe man ein Problem LÖSEN
kann, sollte man es erstmal klar FORMULIEREN.
Dafür ist es i.d.R. hilfreich, die vorläufigen
Formulierungsversuche NIEDERZUSCHREIBEN und
schrittweise zu verbessern.

Es kann hilfreich sein, dabei auf eine gewisse
Vollständigkeit zu achten :)

Dabei auf Überraschungen gefasst sein: Es kann sein,
dass man ursprünglich vorhatte, eine OCR-Software
zu entwickeln, mitten drin aber feststellt, dass
das eigentliche Problem gar nicht die Erkennung der
Einzelzeichen ist, sondern die LAYOUTANALYSE.


> Ich möchte stattdessen gerne das Problem in
> Teilprobleme unterteilen, und dann strategisch
> diese Teilprobleme lösen, die dann letztendlich
> das Gesamtproblem lösen.

Ob und wie gut das funktioniert, hängt entscheidend
vom Innovationsgrad ab. Für hinreichend neuartige
Dinge führt dieser Ansatz zielsicher in die Sackgasse.

Das heißt nicht, dass man nicht zerlegen soll. Es
heißt nur, dass man bereit sein sollte, die
Zerlegung ungefähr zwanzig Mal zu ändern, weil sie
noch nicht funktioniert.
Die richtige Struktur ist ein wesentliches Entwicklungs-
ergebnis -- keine Voraussetzung!


> Ich mache mir entsprechend gerade darüber Gedanken,
> wie man am geschicktesten ein gegebenes Problem
> (gegebene Aufgabe) in Teilprobleme (Teilaufgaben)
> untergliedert, und diese dann einzeln löst.

Anfängerfehler.

Projektarbeit ist nach meiner bitteren Erfahrung für
den sorgfältigen, akribischen Techniker ein Alptraum:
Er neigt dazu, die Dinge, die schlecht funktionieren,
so zu verbessern, dass sie gut funktionieren. Das ist
aber bei Projektarbeit ein kapitaler Fehler: Es ist
viel wichtiger, erstmal die Dinge ÜBERHAUPT IRGENDWIE
zum Funktionieren zu bringen, die dringend erforderlich
sind, aber bisher von allen übersehen wurden.

Soll heißen: "am geschicktesten" ist der Garant für
einen Reinfall. Wähle erstmal irgendeine Zerlegung,
die Dir halbwegs sinnvoll scheint, und verbessere
diese schrittweise. Mache nichts ohne guten Grund,
d.h. formuliere immer den Mangel und die gewählte
Abhilfe. "Macht man nicht", "ist nicht professionell"
sind keine guten Gründe!


> Das eigentliche (Programmier)Problem ist dabei erstmal
> zweitrangig, genau so wie die optimale/effiziente
> Implementierung (ob nun ein Zeiger verwendet wurde,
> oder ein Struct, oder eine for-Schleifer oder eine
> while-Schleife etc.).

Trenne möglichst das Bearbeiten realer Probleme vom
Erlernen und Erkunden der Programmiersprache. Ein
Musikschüler plagt sich zusätzlich zu den Sonatinen
und Divertimenti, die er üben darf, auch noch mit
Tonleitern, Dreiklängen, Doppelgriffen und zahllosen
weiteren technischen Übungen herum. Das lässt sich
nicht vermeiden.

von sid (Gast)


Lesenswert?

Zunächst macht es Sinn sich damit abzufinden,
dass programmieren IMMER ein iterativer Prozess ist..
man löst das eine Problem, einem fällt beim zweiten auf,
dass man beim ersten was vergessen hat oder besser machen könnte
und man geht wieder einen Schritt zurück.

Nun kann man sich direkt einen logicflow basteln und sich daran halten,
ooder (was mir selbst der natürlichere Weg ist)

man geht direkt ins Eingemachte und bastelt wie ne Flipperkugel...
Sven B. schrieb:
> Einfach machen.

Lerninstructor schrieb:
> learning by doing.
ist schon ziemlich genau der Weg...

man schreibt alles in die main()
und schwupp läuft hello world ;)

irgendwann wird's voll und man merkt, das etwas da weg muss,
also gliedert man es aus,
und gliedert mehr und klassifiziert ausgegliedertes was irgendwie 
zusammengehört;
erstellt zwischendurch Platzhalter
(bool checkVal(int x){return true;})
bis man sich dazu was hat einfallen lassen,
so bleibt der Code fast zu jeder Zeit lauffähig, und man kann
einzelne Aspekte (mMn) "einfacher" debuggen.
ohne sich direkt über das grosse Ganze im Klaren zu sein.
Platzhalter sind dafür super...

Und ja das heisst, dass man sehr viel hin und her springen muss im 
Zweifel
(Flipperkugel eben),
aber eben auch, dass man sich dem grossen Ganzen in kleinen Schritten 
nähern kann (und ich denke so ist Dein Ziel, wenn ich Dich richtig 
verstanden hab)

Im Idealfall (ich bin fast immer zu faul) macht man ausreichend Notizen 
(kommentare oder extern)
Ansonsten kann es sein, dass man in nem Monat draufguckt und sich nur 
wundert (oder schlimmer: ärgert)

Ich ärger mich viel über meine hobby kritzeleien..
Zusammengespuckter Code der zwar läuft aber eben nahezu unwartbar ist.
Manchmal so schlimm, dass es mir nach nem Jahr einfacher scheint von 
Vorne zu beginnen als irgendwas mitzunehmen ;)

Also mach lieber mehr Notizen als ich :D
Am Ende das Gedöns noch aufgeräumt und ggf hübsch gemacht
und schon hast Du ein ziemlich ordentliches Projekt.

'sid

von Noch eine Meinung (Gast)


Lesenswert?

> Manchmal so schlimm, dass es mir nach nem Jahr einfacher scheint von
> Vorne zu beginnen als irgendwas mitzunehmen ;)

Manchmal? Immer!

Wir sollten uns damit abfinden. Die agile Entwicklung mit ihrem 
continuous delivery funktioniert nicht. Nach 2-3 Jahren ist die Software 
in einem Zustand, wo wegwerfen und neu schreiben schneller geht.

Ich schlage ein 2-Phasen-Modell vor. Wir planen von vorn herein ein: 2 
Jahre kloppen wir Features rein. Bringen jede Woche neue Releases 
heraus. Dann werfen wir den Programmcode weg, arbeiten eine neue 
Struktur aus. Einige Monate lang gibt es keine neuen Features.

Wir ändern unsere Einstellung zum Wert des Programmcodes.

Der Wert des Codes ist die Arbeit, die wir einsparen, wenn wir ihn 
weiter verwenden. Wenn neu schreiben schneller geht, hat der Code einen 
negativen Wert. Das Wertvolle sind die Notizen.

von Elfeins111!!!enbeinturmbewohner (Gast)


Lesenswert?

Bewährte Programmuster, Algorithmen und Datenstrukturen ansehen 
verstehen und verinnerlichen.
Selber welche umsetzen. Mehrere davon umsetzen und Vor- & Nachteile 
bewerten.

Viele, möglicht gut gemachte, Programmquelltexte lesen und verstehen.
Weniger gute auch lesen und verstehen, besonders warum sie nicht gut 
sind.

von Sven B. (scummos)


Lesenswert?

Noch eine Meinung schrieb:
> Nach 2-3 Jahren ist die Software
> in einem Zustand, wo wegwerfen und neu schreiben schneller geht.

Das ist doch Quatsch. Schau dir mal erfolgreiche Projekte wie KDE an, wo 
der Großteil vom Code eigentlich relativ lesbar ist; im Kern findet man 
da oft noch Dinge von 1999 oder vergleichbarer Zeit.

Der Punkt ist hier, dass alter Code kontinuierlich verbessert wird und 
man nicht super viel Angst haben darf ihn anzufassen. Klar, den alten 
Core-Code anfassen verursacht oft Bugs -- aber die muss man m.E. durch 
ein geeignetes Release-Modell ausgleichen.

von sid (Gast)


Lesenswert?

Noch eine Meinung schrieb:
> Manchmal? Immer!

neee, immer nicht .. glücklicherweise ;)
Manchmal schaffe ich auch bei "ist doch nur für mich jetzt" Zeug 
sinnvolle Kommentare zu hinterlassen.
und manchmal ist der Code so kurz (sag <200kb) dass rekapitulation gut 
funktioniert ;)

Noch eine Meinung schrieb:
> Nach 2-3 Jahren ist die Software
> in einem Zustand, wo wegwerfen und neu schreiben schneller geht.
Das kann man zum Glück so auch nicht verallgemeinern ;)

Noch eine Meinung schrieb:
> Ich schlage ein 2-Phasen-Modell vor. Wir planen von vorn herein ein: 2
> Jahre kloppen wir Features rein. Bringen jede Woche neue Releases
> heraus.

Hübsche Idee, funktiniert leider nicht wenn der Code eine 
"Auftragsarbeit" für single-shot Kunden ist.
Fertig bei Abgabe und ggf ein bugfix max zwei sonst bleibt's bei 
"einmaliger Kunde"

Noch eine Meinung schrieb:
> Wir ändern unsere Einstellung zum Wert des Programmcodes.
>
> Der Wert des Codes ist die Arbeit, die wir einsparen, wenn wir ihn
> weiter verwenden. Wenn neu schreiben schneller geht, hat der Code einen
> negativen Wert. Das Wertvolle sind die Notizen.
Schöner Ansatz
so läuft's ja eh schon
wenn man den Code zwar geschrieben hab, er einem aber nichtmehr gehört
(in dem Fall ist aber die zweite Neuschrift mindestens günstiger als die 
Urschrift, da man sich kaum gegen Erinnerungen schützen kann und sich so 
auch mal selber 'kopiert')

Aber Du hast Recht.. der Wert einer Codebibliothek die man sich selber 
aufbaut ist nur so hoch wie die Zeitersparnis die man sich damit 
verschaffen kann.
Das gilt auch für Code der zwar dem Grunde nach schlecht ist,
solange er einen aber auf gute Ideen bringen kann.
(liegt im Ordner Inspirationsbeschleuniger ;))

'sid

von Chris (Gast)


Lesenswert?

"Dieser Weg kann wie folgt charakterisiert werden: Ein Problem, eine 
Aufgabenstellung sei möglichst präzise beschrieben. Auf dieser Grundlage 
wird ein Modell entwickelt, welches mit quantitativen und qualitativen 
Methoden eine formale Beschreibung der wesentlichen Objekte sowie deren 
Attribute und Relationen darstellt. Dieses Modell ist Grundlage für die 
Problemlösung mit algorithmischen und damit einem Computer übertragbaren 
Methoden."

https://www.springer.com/de/book/9783519002116

Das Modell ist immer der Schlüssel zum Algorithmus, der das Problem 
löst.

Viel Erfolg!

von Robert (Gast)


Lesenswert?

Ich empfehle die Lektüre von

http://thinking-forth.sourceforge.net/

Es geht darin zwar nicht um C, viele Methoden sind jedoch übertragbar.

von Udo K. (Gast)


Lesenswert?

Wenn ich ein Programm schreiben, dann stelle ich mir folgende Fragen:

- Was sind die Eingangsdaten, und wie lese ich die ein?
- Wie soll die Ausgabe ausschauen?
- Wie schaut die interne Datenstruktur aus?
- Wie wird die interne Datenstruktur verarbeitet und
  durch den angewandten Algorithmus geändert?

Bei den Datenstrukturen hat mir der Sedgewick "Algorithm in C"
gut gefallen.
Das Buch gibt es auch in einer C++ und Java Variante.
Darin sind die grundlegenden Datenstrukturen und Algorithmen
verständlich erklärt.  Es eignet sich auch als Buch für
Learning by doing.

Viel lernen kann man auch, indem man gute Open Source Projekte
anschaut, und versucht, zu verstehen, wie die Probleme dort gelöst
wurden. Das ist aber eher für fortgeschrittene Programmierer.

Als Anfänger versuche einfach mal ein Programm, dass dich
interessiert zu bauen (Spiel, Spass, Technik..).
Interesse ist das wichtigste um weiterzukommen!
Um auf einem Gebiet gut zu werden braucht es aber einige Jahre.
Nicht die Geduld verlieren, sondern einfach dranbleiben.

von Noch eine Meinung (Gast)


Lesenswert?

> Schau dir mal erfolgreiche Projekte wie KDE an

Ein gutes Beispiel.

Das Konzept stammt von 1972. Aus dem Smalltalk. Als Trolltech mit der Qt 
anfing hatten wir bereits 30 Jahre lang Smalltalk-artige Frameworks 
entwickelt und wieder weggeworfen. Diese 20 Jahre alten Komponenten 
basieren auf 1000 Projekten, die wieder eingestampft wurden.

Das verrückte an diesem Beispiel:

Objektorientierte GUI Frameworks sind inzwischen ausgereift. 
Funktionieren einwandfrei. Aber aus irgend welchen Gründen ignorieren 
wir 50 Jahre Erfahrung und fangen mit HTML/JS/CSS neu an.

"Best practices"? In allen anderen Ingenieur-Berufen werden den 
Studenten die bewährten best practices beigebracht. Wenn ein Ingenieur 
ein Auto konstruiert überlegt er gar nicht, wie er ein Auto in 
Teilprobleme zerlegt. Er macht einfach das, was er gelernt hat.

Auf die Programmierung übertragen: KDE ist ausgereift. Das ist besser 
als alles, was wir selbst erfinden können. Ein Programmierer sollte im 
Studium lernen, wie er so ein Framework benutzt. Erst gar nicht 
nachdenken, ob man so etwas auch anders anpacken kann.

Aber das wollen wir doch nicht.

Lieber probieren wir unsere eigenen Ideen aus, fliegen damit auf die 
Schnauze und ärgern uns mit verkorksten Programmcode rum.

von Lolita (Gast)


Lesenswert?

Lerne C++.
Wenn du unbedingt in C proggen mußt:

Programmiere in Bausteinen.

Jedes Teilproblem kommt separat in eine C- Datei.

Globale Variablen werden in dieser dateistatisch angelegt,
sind also nur im Baustein gültig.
Funktionen sind alle dateiprivat, werden als
wie die Variablen statisch angelegt.

Von außen wird nur auf public - Funktionen
zugegriffen, die dann die static - Funktionen aufrufen
Das ist dann dein Interface. So kannst du innerhalb
des Bausteins Änderungen vornehmen, ohne
jedesmal die main neu schreiben zu müssen.

Lasse deine Bausteine durch Konstruktoren
initialisieren, die am anfang der main in einer
Initialize - Funktion aufgerufen werden.

Jeder Baustein muß zur Bereinigung ne Destruktor  Funktion haben,
die dann am Ende Deiner main nacheinander aufgerufen werden.

mfg

von Gerd (Gast)


Lesenswert?

Hi,

vielen Dank für die rege Diskussion und die aufmunternden Worte.

Ich werde mich - auch um meine Programmierkenntnisse zu erweitern - mit 
dem Buch "Introduction to Algorithms von Cormen" einlesen, und die dort 
beschriebenen Probleme in aller Ruhe durcharbeiten. Ich glaube, das 
hilft mir, Probleme von Gedanken auf ein Blatt Papier niederzuschreiben 
und dann anschließend in C zu programmieren.

Ich werde sicherlich bei weiteren Fragen wieder hier auftauchen :)

Danke und Gruß,

von Software (Gast)


Lesenswert?

Ich würde noch gerne folgende Stichworte erwähnen: das Untergliedern 
eines Programms in Komponenten und damit auch zerlegen eines Problems in 
Teilprobleme wird als Softwarearchitektur bezeichnet. Sie hat 
statische (welche Komponenten gibt es?) und dynamische (Ablauf) 
Ansichten.
Für den Entwurf von Software kann man sich auch die Ansprüche an die 
Softwarequalität im Hinterkopf behalten (Änderbarkeit, Benutzbarkeit, 
...). Das sorgt auch schon dafür, dass man zu besser überblickbaren 
Teilfunktionen neigt.

Im Prinzip aber alles in allem gesunder Menschenverstand. Wenn du mal 
rückwirkend etwas ändern musst und merkst dass du dabei Spaghettis 
entheddern musst, kriegst du ein Gefühl wie es besser ginge.

von Gerd (Gast)


Lesenswert?

Software schrieb:
> Ich würde noch gerne folgende Stichworte erwähnen: das Untergliedern
> eines Programms in Komponenten und damit auch zerlegen eines Problems in
> Teilprobleme wird als Softwarearchitektur bezeichnet. Sie hat
> statische (welche Komponenten gibt es?) und dynamische (Ablauf)
> Ansichten.
> Für den Entwurf von Software kann man sich auch die Ansprüche an die
> Softwarequalität im Hinterkopf behalten (Änderbarkeit, Benutzbarkeit,
> ...). Das sorgt auch schon dafür, dass man zu besser überblickbaren
> Teilfunktionen neigt.

Hi Software,
vielen Dank für die Stichwörter. Ich werde danach mal suchen.

Was mich noch interessieren würde, ist, wie man am besten Software 
testet, um sie robust und fehlerfrei zu bekommen?

Lasst uns dazu ein Beispiel nehmen: Meinen selbstgeschriebenen Code 
eines Bubble Sort Algorithmus.

Wie würde man diesen Code auf mögliche Fehler testen? Bis jetzt habe ich 
für meinen "target" alle im Array arr[] vorhandenen Werte getestet, 
sowie Werte auserhalb (z.B. target = 11). Ich habe aber z.B. nicht den 
Fall angehandelt, wenn "target" negativ ist, z.B. target = -1. Dann 
funktioniert das Programm nicht mehr so, wie es soll.

Danke und Gruß,
1
#include <stdio.h>
2
#include <stdlib.h>
3
4
int main()
5
{
6
    int arr[] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
7
    int low = 0;
8
    int high = sizeof(arr)/sizeof(arr[0]);
9
    int mid = (low+high)/2;
10
    int target = 10;
11
12
    while(low<=high)
13
    {
14
        if(arr[mid]==target)
15
        {
16
            printf("Target value is %d\n",arr[mid]);
17
            printf("Index is: %d\n",mid);
18
            break;
19
        }
20
        else if(arr[mid]>target)
21
        {
22
            high = mid-1;
23
            mid = (low+high)/2;
24
        }
25
        else
26
        {
27
            low = mid+1;
28
            mid = (low+high)/2;
29
        }
30
        if(low==high)
31
        {
32
            printf("Fail\n");
33
            break;
34
        }
35
    }
36
    return 0;
37
}

von A. S. (Gast)


Lesenswert?

Gerd schrieb:
> Lasst uns dazu ein Beispiel nehmen: Meinen selbstgeschriebenen Code
> eines Bubble Sort Algorithmus.
> Wie würde man diesen Code auf mögliche Fehler testen?

Sorry, aber was hat der Code mit Bubblesort zu tun?

Und nein, Werte zu ändern und neu kompilieren ist kein testen sondern 
maximal entwickeln, debuggen, verzweifeln.

Zum testen muss die Funktionalität als Funktion separiert werden (und 
zuvor verstanden sein).
Dann ruft man die Funktion mit bekannten Datensets auf und prüft (im 
Programm) das Ergebnis. 3 Möglichkeiten der Prüfung (bzw die 
Referenzlösung zu finden):

1 per hand (Taschenrechner, einfache Beispiele, die offensichtlich sind, 
...)

2 bisherige (funktionierende) Implementierung (wenn etwas neu, besser, 
schneller gemacht wird).

3 Erzeugung "auf anderem, einfacherem Weg". Beispiel: um 
Primzahlzerlegung zu testen, kann ich Testzahlen durch Multiplikation 
zufällig erzeugter Lösungsmengen erzeugen.

von Sven B. (scummos)


Lesenswert?

Was ich dir auf jeden Fall aus Erfahrung sagen kann ist, dass 
seitenlange Diskussionen in Internetforen über an den Haren 
herbeigezogene Beispiele fast immer komplett sinnlos sind.

Die fehlende Einordnung des Problems in einen Kontext stachelt jeden 
dazu an, das Problem in seinen eigenen Alltagskontext einzuordnen und 
entsprechend zu betrachten, und entsprechend hast du dann 20 Leute, die 
sich verbissen darüber streiten, ob man die Klasse Auto mit 4 Rädern und 
1 Lenkrad lieber als 2-Zeilen-Perlskript oder als 40kloc Rust-Framework 
mit 3000 Unit-Tests implementiert.

von Toby P. (Gast)


Lesenswert?

Gerd schrieb:
> Gibt es diesbezüglich eine Art best practices (auch wie tiefgründig die
> Teilprobleme getestet werden sollten), die ihr empfehlen könnt?

Es gibt sehr viele "best practice" Ansätze. Welcher dann geeignet ist 
hängt von der eigenen Struktur und der Aufgabe ab.

Ein "kreativer Wirrkopf"  braucht eher strukturelles und ein 
schematischer Fleißarbeiter eher Techniken wie Brainstorm.

>
> Wie lernt man, sich in diese Art von Problemunterteilung
> hineinzuversetzen?

In dem man es macht. Eine Aufgabe stellen, in Funktionen zerlegen, 
grober Pseudocode, dann coden wäre z.B. ein Ansatz.

Viele Techniken entwickeln sich. Entwürfe mach ich z.B. in der Bahn und 
schreib Sie in mein Notizbuch. Damit bin ich beim proggen min. doppelt 
so schnell wie nur vorm Rechner.

von Lolita (Gast)


Lesenswert?

Beschäftige Dich mit C++!
Du kannst damit wie in C proggen, also ohne
Vererbung, aber mit Klassen und mit Templates.

C++ bietet Dir Klassen, die deine Bausteine werden,
und Template (Vorlagen) - Funktionen, die
für alle Typen nur einmal geschrieben werden müssen.

Jeder Baustein kann dann seperat geschrieben, geändert
und getestet werden,
sowie dann in die Bibliothek aufgenommen werden.

In Deinen Programmen werden diese Bausteine dann
aufgerufen und haben dann "keine Fehler" mehr.

Wozu zum Beispiel ne Dateiverwaltung in jedem Programm
neu proggen, wenn man ne getestete als Baugruppe in der
Bibliothek hat?


mfg

von F. F. (foldi)


Lesenswert?

Lolita schrieb:
> Beschäftige Dich mit C++!

Warte, ich hole schon mal Popcorn.

von Gerd (Gast)


Lesenswert?

A. S. schrieb:
> Sorry, aber was hat der Code mit Bubblesort zu tun?
>
> Und nein, Werte zu ändern und neu kompilieren ist kein testen sondern
> maximal entwickeln, debuggen, verzweifeln.

Das hat nichts mit bubble sort zu tun, und sollte auch eigentlich binary 
search heißen. Gut gesehen :)

Danke für deine Rückmeldung. Dann weiß ich schon mal, dass mein Ansatz 
nicht ausreichend ist. Aber genau da muss man dann ansetzen (auch, um 
sich selbst weiterzuentwickeln ;) )

Sven B. schrieb:
> Was ich dir auf jeden Fall aus Erfahrung sagen kann ist, dass
> seitenlange Diskussionen in Internetforen über an den Haren
> herbeigezogene Beispiele fast immer komplett sinnlos sind.

Mag sein. Aber wenn sich 10 Leute melden und am Ende 12 veschiedene 
Meinungen dabei herauskommen, habe ich im Endeffekt 12 mögliche Ansätze 
gewonnen. Wenn einer von den Ansätzen mit mir harmoniert, dann ist alles 
genau richtig gelaufen.

Die Kernessenz meines Anliegens:
Wie entwickle ich Code, der funktioniert UND robust ist. Und wie teste 
ich (ausreichend), um am Ende zu dem Entschluss zu kommen, dass der Code 
funktioniert UND robust ist.
Da muss es doch einen strategischen Ansatz geben, und Erfahrung alleine 
kann nicht ausreichend sein.

Test cases? Unit tests?

Danke und Gruß,

von Gerd (Gast)


Lesenswert?

Lolita schrieb:
> Beschäftige Dich mit C++!

Ich bin in der Hardwareentwicklung und möchte gerne hardwarenah 
programmieren.


Zu einem späteren Zeitpunkt kommt ggf. eine andere Programmiersprache 
als Zusatz in Erwägung :)

Gruß,

von Noch eine Meinung (Gast)


Lesenswert?

> Wie entwickle ich Code, der funktioniert UND robust ist.
> Da muss es doch einen strategischen Ansatz geben

Ja klar. Die Generation James Watt, Thomas Edison, Werner von Siemens... 
hat eine Lösung gefunden. Arbeitsteilung.

Kreative Wirrköpfe entwickeln neue Ideen. Hauptsächlich Rohrkrepierer. 
Ab und zu etwas weltbewegendes. Hartnäckige Ingenieure arbeiten die 
Details aus. Bürokraten überprüfen, ob alle formalen Qualitätskriterien 
eingehalten werden. Prüfingenieure suchen nach unbekannten 
Fehlerquellen. Und der größte Teil der Menschen macht stupide Routine.

Aber das wollen wir doch nicht! In der Softwareentwicklung sammeln sich 
Menschen, die diese Art von Arbeitsteilung nicht mitmachen wollen. 
Softwareentwicklung ist das letzte mittelalterliche Handwerk. Kreative 
Wirrköpfe übernehmen auch die Tätigkeiten, für die es Bürokraten oder 
stupide Fließbandarbeiter bracht.

Wenn wir das Problem lösen, darfst du gar nicht mehr darüber nachdenken, 
wie du ein Problem in Teilprobleme zerlegst. Wie ein Bauingenieur 
bekommst du ein Teilproblem und eine Haufen Vorschriften vorgesetzt. 
Musst das umsetzen, was andere vor dir ausdiskutiert haben.

von Lolita (Gast)


Lesenswert?

Gerd meinte:

> Lolita schrieb:
> Beschäftige Dich mit C++!

> Ich bin in der Hardwareentwicklung und möchte gerne hardwarenah
> programmieren.

Kein Problem! auch mit C++ kannst du Bitfriemelei
machen! Das mach ich ja auch!

Kannst Du C++, hast Du C gleich mit gelernt.
Kannst Du C ist der Sprung auf C++ schwer. ;-((
und wenn du in C++ die Klassen wegläßt, ists wie C.

Ich übe auf dem Pc, da ist der servise mit Debugging u.s.w.
besser.
Und C++ erzieht Dich zu mehr Korrektheit beim programmieren,
weils typsicherer ist. Das kommt Dir dann bei C zu gute!


mfg

Popcorn- Lolita

von Vn N. (wefwef_s)


Lesenswert?

Gerd schrieb:
> Was mich noch interessieren würde, ist, wie man am besten Software
> testet, um sie robust und fehlerfrei zu bekommen?

https://www.amazon.de/Driven-Development-Embedded-Pragmatic-Programmers/dp/193435662X/ref=sr_1_2?__mk_de_DE=%C3%85M%C3%85%C5%BD%C3%95%C3%91&dchild=1&keywords=test+driven+development&qid=1586348799&sr=8-2
https://www.youtube.com/watch?v=1Ca5iRsta2Q

Gerd schrieb:
> Ich bin in der Hardwareentwicklung und möchte gerne hardwarenah
> programmieren.

C++ ist genau so hardwarenahe wie C.

von Sven B. (scummos)


Lesenswert?

Lolita schrieb:
> Kannst Du C++, hast Du C gleich mit gelernt.

Das ist ein Gerücht. Wenn du Desktop-Anwendungen in C++ programmiert 
hast, und dir dann den Linux-Kernel anschaust (der in C geschrieben ist) 
wirst du merken, dass du von der Sprache eigentlich kaum Ahnung hast. 
Denn die Sprache ist ja nicht "um die Bedingung vom if kommen zwei 
Klammern" sondern "wie löse ich $problem typischerweise".

von Lolita (Gast)


Lesenswert?

Sven meinte:

> Wenn du Desktop-Anwendungen in C++ programmiert
> hast, und dir dann den Linux-Kernel anschaust (der in C geschrieben ist)
> wirst du merken, dass du von der Sprache eigentlich kaum Ahnung hast.

nicht schlecht.

Du hast recht, aber mal ein Vergleich:

trotzdem kann ich C. Ich bin denn aber ein kleiner Zeitungsschmierer
und nicht ein Crack wie unsere besten Schriftsteller.

Der Zeitungsschmierer spricht das Selbe Deusch oder English
wie der Schriftsteller, dieser kann sich dann aber besser
ausdrücken. ;--))

Die Freaks, die Linux geschrieben haben sind die Schriftsteller,
ich bin der Zeitungsschmierer, wir beide können C,
trotzdem man eigendlich immer zuende lernt.


mfg

von Lolita (Gast)


Lesenswert?

es ollte naürlich heißen:

..... nimmer zu Ende lernt.

;--P

mfg

von Vn N. (wefwef_s)


Lesenswert?

Sven B. schrieb:
> Lolita schrieb:
>> Kannst Du C++, hast Du C gleich mit gelernt.
>
> Das ist ein Gerücht. Wenn du Desktop-Anwendungen in C++ programmiert
> hast, und dir dann den Linux-Kernel anschaust (der in C geschrieben ist)
> wirst du merken, dass du von der Sprache eigentlich kaum Ahnung hast.

Kannst du das näher erlätern? Warum hat man, wenn man von C++ kommt, 
keine Ahnung von C? Das was du erwähnst (du implizierst es ja selbst) 
ist eher eine Sache von "Desktopanwendung" und "Kernel".

von Heiko L. (zer0)


Lesenswert?

Vn N. schrieb:
> Warum hat man, wenn man von C++ kommt, keine Ahnung von C?

In C hantiert man routinemäßig mit Sprachkonstrukten, für die man in C++ 
nur schiefe Seitenblicke und Kopfschütteln ernten würde.

von Lolita (Gast)


Lesenswert?

Vn,n meinte:

> Kannst du das näher erlätern? Warum hat man, wenn man von C++ kommt,
> keine Ahnung von C? Das was du erwähnst (du implizierst es ja selbst)
> ist eher eine Sache von "Desktopanwendung" und "Kernel".

So hab ich das nicht gemeint.
Man kann auch in C++ nen Kernel, bare Metal, auf nem Mikrorechner
implementieren. Das geht zB. mit der IAR Workbench.
"C" war nur zuerst da, und schon länger im Geschäft.

C und Cpp sind Computersprachen. Mit ihnen kannn man viel machen,
zum Beispiel Märchen erzählen.

So wie es Linus Thorwalds gemacht hat. Ein Märchen
von Freiheit und Zukunft.
Ja. Linus ist einer der Größten Märchenerzähler der Menschheit.

Andere haben seine Märchen wahrgemacht. Sie haben zum Beispiel
mir ein Gehör gegeben.

C++ ist für große Projekte das Ding. Mann kann seine Bausteine 
entwickeln,
testen und dann in seinen Programmen verwenden.
Das kann man natürlich mit C auch, aber C++ "schreit" richtig nach der 
Anewendung der Methode.

Wenn man ne Weile in C++ geproggt hat, merkt man, das der Quelltext
durch die Klassen, die ja auch nur C- Strukturen  sind, die aber 
Funktonen
enthalten können besser lesbar, wartbar und wieder verwendbar sind.

Das geht auch in C , erfordert aber mehr Disziplin, den der Anfäner
noch nicht mitbringt.
Wenn man dies aber einmal gelernt hat, wird man dieses Paradigma
auch in c anwenden.


mfg

von Sven B. (scummos)


Lesenswert?

Vn N. schrieb:
> Kannst du das näher erlätern? Warum hat man, wenn man von C++ kommt,
> keine Ahnung von C? Das was du erwähnst (du implizierst es ja selbst)
> ist eher eine Sache von "Desktopanwendung" und "Kernel".

Weil man Probleme in C++ einfach anders löst als in C, und weil "Ahnung 
von einer Sprache" nicht bedeutet, dass man die Syntax perfekt 
beherrscht, sondern dass man Erfahrung im praktischen Umgang mit der 
Sprache hat. Sprich, praktische Erfahrung darin, wie man typische 
Aufgaben löst.

Und da gibt es in C eben einen Haufen typischer Pattern, die in C++ 
deplaziert sind, und die nie verwendet werden, wie z.B.
 - Fehlerbehandlung und Ressourcenverwaltung mit goto
 - über char-Pointer iterieren um nullterminierte Strings zu handhaben
 - der CONTAINER_OF-Trick, den man auch oft sieht
 - das ganze "negative Integer-Rückgabewerte zur 
Fehlerbehandlung"-Konzept
 - Linked Lists überall
 - das "void* user_data"-Pattern
 - Utility-Funktionen oder Makros, die Algorithmen für spezifische Typen 
implementieren (for_each_foo, etc)
 - etc etc

Natürlich macht nicht jedes C-Programm all diese Dinge oder kein 
C++-Programm irgendeins davon. Es ergibt aber einen völlig anderen 
Programmierstil und auch ein völlig anderes Denkmodell als C++.

Ich finde modernes C++ mit Python noch näher verwandt als mit C.

von Lolita (Gast)


Lesenswert?

Sven meinte:

> Weil man Probleme in C++ einfach anders löst als in C, und weil "Ahnung
> von einer Sprache" nicht bedeutet, dass man die Syntax perfekt
> beherrscht, sondern dass man Erfahrung im praktischen Umgang mit der
> Sprache hat. Sprich, praktische Erfahrung darin, wie man typische
> Aufgaben löst.

Genau. "Märchenerzählen" muß man können.
Ein Gefühl für die Sache haben, dann
kann man auch in Brainfuck coden, ;---))

> Ich finde modernes C++ mit Python noch näher verwandt als mit C.
nicht schlecht.
Darauf wäre ich allein nicht gekommen. ;-O

@Sven, was machst du eigendlich beruflich?


mfg

von A. S. (Gast)


Lesenswert?

Lolita schrieb:
> C++ ist für große Projekte das Ding.
Die Trennung läuft nicht zwischen groß/klein, alt/neu oder 
einfach/komplex. Die Trennung ist zwischen virtuell und konkret oder 
Steuerung und Edv. Eine SW die Dokumente, Daten, Grafikobjekte etc. 
bearbeitet, hat viele abstrakte Operationen, an denen Templates, 
Objekte, Vererbung, Überladung etc. super sind.

Konkrete Objekte, die Räder eines Autos etwa, mit konkreter 
Funktionalität (ABS, ESP) profitieren viel weniger davon, als man 
angesichts der vielen Lehrbeispiele glaubt.

In C++ ist die größte gefahr der Kontrollfluss-Verlust.

Lolita schrieb:
> Wenn man ne Weile in C++ geproggt hat, merkt man, das der Quelltext
> durch die Klassen, die ja auch nur C- Strukturen  sind, die aber
> Funktonen
> enthalten können besser lesbar, wartbar und wieder verwendbar sind.

Das ist eher eine Frage von Erfahrung. Man sollte auch in C Strukturen 
und deren Methoden beisammen halten.

von Sheeva P. (sheevaplug)


Lesenswert?

Lolita schrieb:
> Lerne C++.

Ja, das wäre auch mein Ratschlag. Leider gibt es für kleine Projekte mit 
starken Ressourcenbeschränkungen viele C++-Konstrukte, auf die man 
besser verzichten sollte, als Beispiele seien hier dynamische 
Speicherallokation (inklusive STL), Exceptions, virtuelle Methoden und 
so weiter genannt.

> Wenn du unbedingt in C proggen mußt:
> Programmiere in Bausteinen.
> Jedes Teilproblem kommt separat in eine C- Datei.

Von Elecia White gibt es da ein wunderbares Buch mit dem Titel "Making 
Embedded Systems", das (auch) diese Dinge sehr schön erklärt.

Ansonsten haben hier viele Leute dem TO ihre Ratschläge gegeben, und mit 
Ausnahme von "Noch eine Meinung" waren die meisten auch sinnvoll und 
gut. Allerdings ist mein Eindruck, daß sich mit den jeweiligen 
Ratschlägen nur jeweils bestimmte Kategorien von Problemen lösen lassen, 
während anderere Probleme besser anders angegangen werden. Es ist eben 
ein Unterschied, ob man ein (relativ) überschaubares Programm für einen 
Mikrocontroller, oder eine fette Verarbeitungspipeline auf einem 
verteilten Cluster entwickelt.

Deswegen erscheinen mir die Tipps von "foobar" besonders gut, und zwar 
zunächst auf die zu verarbeitenden Daten und Datenstrukturen zu schauen, 
dadurch ergibt sich sehr häufig schon eine sehr gute Idee, was einzelne 
Programmteile tun müssen und im Umkehrschluß eben auch, in welche Teile 
dieses Programm also letztlich aufgeteilt ist, und wie die dann am Ende 
zusammengesetzt werden sollten.

Und dann heißt es, da bin ich ebenfalls ganz bei "foobar": üben, üben, 
und nochmals üben. Mit der Zeit und der wachsenden Erfahrung kommt dann 
schon eine meistens (nicht immer ;-)) recht gute Einschätzung, wie man 
welches Problem am effizientesten angehen kann. Eine besser 
strukturierte, vulgo: objektorientierte Technik kann dabei oft sehr 
hilfreich sein, sogar, wenn die verwendete Sprache nicht streng oder 
sogar gar nicht objektorientiert ist -- aber da sind wir wieder bei der 
Konzentration auf die Daten und die Datenstrukturen... ;-)

von Sheeva P. (sheevaplug)


Lesenswert?

Egon D. schrieb:
> Schrittweise vorgehen: Ehe man ein Problem LÖSEN
> kann, sollte man es erstmal klar FORMULIEREN.
> Dafür ist es i.d.R. hilfreich, die vorläufigen
> Formulierungsversuche NIEDERZUSCHREIBEN und
> schrittweise zu verbessern.

Das ist die alte Vorgehensweise mit Lasten- und Pflichtenheft, die aber 
nur bei Problemen mit einer eher überschaubaren Komplexität 
funktioniert. Bei jedem größeren Problem wird man damit scheitern, denn 
dabei entwickeln sich während der Implementierungszeit meist neue 
Probleme, die bei der initialen Planung nicht berücksichtigt wurden.

Es gibt Gründe dafür, warum dieser Ansatz heute zunehmend hinterfragt 
und durch andere Ansätze abgelöst oder zumindest ergänzt wird. Der 
Hauptgrund ist wohl, daß sich im Laufe der Jahre und mit zunehmender 
Komplexität der Probleme gezeigt hat, daß die meisen (je nach Quelle 60 
bis 80 %) aller Entwicklungen am Ende gescheitert sind, indem sie die 
Zeit- und / oder Budgetannahmen und -Vorgaben gesprengt haben...

Deswegen haben sich viele mehr oder weniger kluge Menschen Gedanken 
gemacht und neue Entwicklungsmodelle ausgedacht: Agile, XP, SCRUM, und 
so weiter. Und richtig angewendet funktionieren diese Ansätze in der 
Praxis besser als ihr Ruf, auch wenn viele alte Entwickler darüber 
schimpfen -- Widerstand gegen Veränderungen ist ja auch ein menschlicher 
Instinkt... ;-)

von Sheeva P. (sheevaplug)


Lesenswert?

Gerd schrieb:
> Ich werde mich - auch um meine Programmierkenntnisse zu erweitern - mit
> dem Buch "Introduction to Algorithms von Cormen" einlesen, und die dort
> beschriebenen Probleme in aller Ruhe durcharbeiten. Ich glaube, das
> hilft mir, Probleme von Gedanken auf ein Blatt Papier niederzuschreiben
> und dann anschließend in C zu programmieren.

Algorithmen sind sicherlich ein guter Ansatz, aber ich möchte Dir 
dennoch zusätzlich empfehlen, danach ein gutes Buch zum Thema "Design 
Patterns" zu lesen und dann einige Artikel im Netz zum Thema 
"Antipatterns"...

Design Patterns, oder zu deutsch Entwurfsmuster, beschreiben 
grundsätzliche Ansätze, um bestimmte Probleme zu lösen. Viele davon sind 
gut, manche bergen aber Risiken, die man für eine qualifizierte 
Entscheidung kennen muß.

von Gerd (Gast)


Lesenswert?

Sheeva P. schrieb:
> Algorithmen sind sicherlich ein guter Ansatz, aber ich möchte Dir
> dennoch zusätzlich empfehlen, danach ein gutes Buch zum Thema "Design
> Patterns" zu lesen und dann einige Artikel im Netz zum Thema
> "Antipatterns"...

Vielen Dank, Sheeva.

Der Grund, mich zunächst mit Algorithmen zu beschäftigen, ist, dass der 
Code in den meisten Fällen relativ kurz und überschaubar ist, und ich 
"logisch" denken kann - und einfach um das Programmieren zu üben: 
Problem -> Gedanken -> Papir&Bleistift -> Code.
Da wären Design Patterns vielleicht zu viel des Guten (es sei denn, ich 
wiederverwerte die Algorithmen in größere Programme)?

Danach kämen dann Projekte, die komplexer sind. Und danach eine 
objektorientierte Sprache, bis jetzt vorzugsweise C#.

Der Weg ist lang, aber das Interesse ist da :)

von Noch eine Meinung (Gast)


Lesenswert?

Logisches Denken alleine genügt nicht. Willst du die Qualität erreichen, 
die im Maschinenbau üblich ist, braucht es Menschen mit 
unterschiedlichen Fähigkeiten.

Hinter den Design Pattern stecken tausende von Versuchen. Menschen wie 
Du hatten es ausprobiert - einiges hat funktioniert, der größte Teil 
wird unter Erfahrung und Antipattern verbucht. Du brauchst einen 
starrsinnigen Bürokraten, der Anhand von rein formalen Kritärien 
überprüft, ob du ein Antipattern wiederentdeckst. Und einen 
Prüfingenieur, der testet, ob du etwas Unbekanntes übersiehst.

Wir drehen uns seit 50 Jahren im Kreis.

Agile Programmierung - da waren wir vor 50 Jahren schon mal weiter. Das 
Smalltalk war agiler alles, was heute als agil gehypt wird. Die 
Entwicklungsumgebung blieb im Anwendungsprogramm enthalten. Während der 
Arbeit den Klassenbrowser aufrufen. Methode ändern und weiter arbeiten.
https://www.youtube.com/watch?v=9H79_kKzmFs&t=11m40s

Der Grund, warum die Opas die Agile Programmierung ablehnen, ist nicht 
weil sie nicht neues mehr lernen wollen. Der Grund ist, die haben es 
schon mal ausprobiert und erkannt, es funktioniert genau so schlecht wie 
das Wasserfallmodell.

Wir müssen dickere Bretter bohren.

von Sven B. (scummos)


Lesenswert?

Ich würde nicht so viele Bücher lesen sondern einfach mal was machen. 
Die Bücher kannst du später noch lesen. Mit einem Erfahrungsschatz von 
700 geschriebenen Codezeilen ein Buch über Design Patterns zu lesen ist 
Quatsch.

Ich finde auch dass die meisten Design Patterns Ähnlichkeit mit den 
meisten Patenten haben: die sind nicht wahnsinnig clever oder schwer zu 
entdecken. Wenn man das Problem hat, zu dessen Lösung der Pattern taugt, 
kommt man meist selber drauf. Es kann dann instruktiv sein, so ein Buch 
durchzublättern, in welchem man die typischen Muster mal schön 
tabelliert findet, aber mehr irgendwie auch nicht.

: Bearbeitet durch User
von Vn N. (wefwef_s)


Lesenswert?

Heiko L. schrieb:
> Vn N. schrieb:
>> Warum hat man, wenn man von C++ kommt, keine Ahnung von C?
>
> In C hantiert man routinemäßig mit Sprachkonstrukten, für die man in C++
> nur schiefe Seitenblicke und Kopfschütteln ernten würde.

Die da wären?

Sven B. schrieb:
> Und da gibt es in C eben einen Haufen typischer Pattern, die in C++
> deplaziert sind, und die nie verwendet werden, wie z.B.
>  - Fehlerbehandlung und Ressourcenverwaltung mit goto

Ist auch in C deplatziert. Wer macht bitte Fehlerbehandlung mit goto? 
Also außer Bastlern und Leuten, die in den Neunzigern hängengeblieben 
sind. Funktionen und Kontrollstrukturen gibts auch in C, kein Bedarf für 
goto.

Sven B. schrieb:
> über char-Pointer iterieren um nullterminierte Strings zu handhaben

Äh, ja eh. Weil über ein Array iterieren ist ja so kompliziert.

Sven B. schrieb:
> der CONTAINER_OF-Trick, den man auch oft sieht

Achso, C++-Programmierer sollen also nicht fähig sein, ein simpelstes 
Makro zu verstehen?

Sven B. schrieb:
> das ganze "negative Integer-Rückgabewerte zur
> Fehlerbehandlung"-Konzept

Ja, irrsinnig kompliziert zu kapieren. Wie soll ein C++-Entwickler nur 
ein "return -1" verstehen?

Sven B. schrieb:
> Linked Lists überall

Und wo siehst du das Problem?

Sven B. schrieb:
> Ich finde modernes C++ mit Python noch näher verwandt als mit C.

Mich würde ja echt mal deine Qualifikation interessieren.

Lolita schrieb:
> @Sven, was machst du eigendlich beruflich?

Vermutlich Sportlehrer oder so. Also, nix gegen Sportlehrer.

Sheeva P. schrieb:
> Leider gibt es für kleine Projekte mit
> starken Ressourcenbeschränkungen viele C++-Konstrukte, auf die man
> besser verzichten sollte, als Beispiele seien hier dynamische
> Speicherallokation (inklusive STL), Exceptions, virtuelle Methoden und
> so weiter genannt.

Naja, "malloc nicht verwenden" gilt auch in Bare Metal C.

von Sven B. (scummos)


Lesenswert?

Vn N. schrieb:
> Sven B. schrieb:
>> Und da gibt es in C eben einen Haufen typischer Pattern, die in C++
>> deplaziert sind, und die nie verwendet werden, wie z.B.
>>  - Fehlerbehandlung und Ressourcenverwaltung mit goto
>
> Ist auch in C deplatziert. Wer macht bitte Fehlerbehandlung mit goto?
> Also außer Bastlern und Leuten, die in den Neunzigern hängengeblieben
> sind. Funktionen und Kontrollstrukturen gibts auch in C, kein Bedarf für
> goto.

Ich mache mal in ein paar bekannten C-Libs zufällige C-Dateien auf:
libpng: https://github.com/glennrp/libpng/blob/libpng16/png.c 
Fehlerbehandlung mit goto.
openssl: https://github.com/openssl/openssl/blob/master/ssl/bio_ssl.c 
Fehlerbehandlung mit goto.
Linux: 
https://github.com/torvalds/linux/blob/master/kernel/events/core.c 
Fehlerbehandlung mit goto.
libusb: https://github.com/libusb/libusb/blob/master/libusb/core.c 
Fehlerbehandlung mit goto.
Also man sieht, wirklich niemand macht das. Außer Bastlern, natürlich.

> Sven B. schrieb:
>> über char-Pointer iterieren um nullterminierte Strings zu handhaben
>
> Äh, ja eh. Weil über ein Array iterieren ist ja so kompliziert.

Das habe ich nicht gesagt. Ich habe gesagt, es ist in C++ nicht die 
typische Lösung für das Problem.

> Sven B. schrieb:
>> der CONTAINER_OF-Trick, den man auch oft sieht
>
> Achso, C++-Programmierer sollen also nicht fähig sein, ein simpelstes
> Makro zu verstehen?

Es geht nicht darum, dass du nicht in der Lage bist es zu verstehen. Es 
geht drum dass du es nicht kennst. Deshalb musst du a) nachlesen was es 
tut, wenn es dir begegnet, und kommst b) nicht dirket auf die Idee es 
selbst zu benutzen.

> Sven B. schrieb:
>> das ganze "negative Integer-Rückgabewerte zur
>> Fehlerbehandlung"-Konzept
>
> Ja, irrsinnig kompliziert zu kapieren. Wie soll ein C++-Entwickler nur
> ein "return -1" verstehen?

Auch hier: es geht nicht drum, den Code zu verstehen. Es geht drum, den 
Code zu schreiben. Und in C++ macht man das idR anders.

>
> Sven B. schrieb:
>> Linked Lists überall
>
> Und wo siehst du das Problem?

Dass in C++ kaum Linked Lists verwendet werden. Das ist einfach anderer 
Stil.

> Sven B. schrieb:
>> Ich finde modernes C++ mit Python noch näher verwandt als mit C.
>
> Mich würde ja echt mal deine Qualifikation interessieren.

Gut, dass wir hier so eine faktenbasierte, erwachsene Diskussion führen, 
bei der es auf Argumente ankommt!

von Peter D. (peda)


Lesenswert?

Egon D. schrieb:
> Es ist
> viel wichtiger, erstmal die Dinge ÜBERHAUPT IRGENDWIE
> zum Funktionieren zu bringen, die dringend erforderlich
> sind, aber bisher von allen übersehen wurden.

Meine Erfahrung ist, sowas führt regelmäßig in eine Sackgasse. Wenn man 
Code schnell mal eben so hinschludert, hat man viele undurchdringliche 
Copy&Paste Monster. Sobald Änderungen nötig sind, sucht man sich nen 
Wolf, d.h. der Code ist unwartbar. Und bei Fehlern werden dann planlos 
irgendwelche Timeouts hochgesetzt. Die Fehler werden dadurch nur 
seltener, gehen aber nicht weg.

Ich bevorzuge daher die Bottom-Up-Methode, d.h. ich entwickele kleine 
leicht zu durchschauende Module, teste sie und baue dann daraus immer 
größere Module, bis das Programm fertig ist. Der Vorteil ist, man hat ja 
die Testroutinen schon geschrieben, kann also jederzeit an den Modulen 
Änderungen vornehmen und testen. Die Testroutinen also nicht 
wegschmeißen, sondern als Testprojekte aufheben.

Auch hasse ich Codedopplungen wie die Pest. Werden ähnliche Sequenzen 
mehrfach benötigt, dann als Unterfunktion oder Schleife ausführen. So 
muß man Änderungen immer nur an einer einzigen Stelle vornehmen. Im 
Notfall schreibt man solche Sequenzen als Macro, d.h. der Präprozessor 
nimmt dann die Codedopplungen vor. Der ist da nämlich besser als der 
Mensch, d.h. er vergißt keine Stelle zu ändern.

Was man leider oft sieht, sind Batterien von sscanf oder strcmp über den 
ganzen Code verteilt. Ehe man da rauskriegt, welche Kommandos 
unterstützt werden, vergeht ne Ewigkeit. Dopplungen und Schreibfehler 
passieren dann auch gerne.
Ich benutze daher immer nur ein scanf bzw. ein printf, die sich die 
Liste der Kommandos und Antworten aus einem Array holen. So bleibt auch 
die Syntax einheitlich.

Auch sollte man immer daran denken, daß jede Operation Zeit kostet und 
manche richtig viel Zeit. Man sollte daher immer überlegen, wie oft 
etwas wirklich ausgeführt werden muß.
Z.B. ist es äußerst unklug, in einem Timerinterrupt für eine 
Multiplexanzeige, die Zahl immer von neuem in Digits zu zerlegen und 
nach 7-Segment zu wandeln. Das muß man nur einmal tun, wenn der neue 
Meßwert vorliegt. Der Mensch kann eh nur 2..5 Meßwerte je Sekunde 
streßfrei ablesen.

Auch sollte man harwareabhängige IO-Zugriffe in separate Unterfunktionen 
auslagern. Soviel wie mögliche Unterfunktionen sollten harwareunabhängig 
sein.

von Gerd (Gast)


Lesenswert?

Peter D. schrieb:
> Ich bevorzuge daher die Bottom-Up-Methode, d.h. ich entwickele kleine
> leicht zu durchschauende Module, teste sie und baue dann daraus immer
> größere Module, bis das Programm fertig ist. Der Vorteil ist, man hat ja
> die Testroutinen schon geschrieben, kann also jederzeit an den Modulen
> Änderungen vornehmen und testen. Die Testroutinen also nicht
> wegschmeißen, sondern als Testprojekte aufheben.

Hi Peter
ich stimme deinem kompletten Beitrag zu, möchte aber speziell auf den 
zitierten Teil eine Frage stellen:


Genau diese Strategie Bottom-Up möchte ich verinnerlichen und festigen.

Meine Frage zielt aufs Testen aus. Wie testest du die einzelnen Module? 
Wäre das mittels Unit tests oder welche Strategie wendest du da an?


Danke und Gruß,

von Egon D. (Gast)


Lesenswert?

Peter D. schrieb:

> Egon D. schrieb:
>> Es ist viel wichtiger, erstmal die Dinge ÜBERHAUPT
>> IRGENDWIE zum Funktionieren zu bringen, die dringend
>> erforderlich sind, aber bisher von allen übersehen
>> wurden.
>
> Meine Erfahrung ist, sowas führt regelmäßig in eine
> Sackgasse.

Mag sein; vielleicht bin ich die große Ausnahme.

Ich habe auch nur eine persönliche Erfahrung mitgeteilt.
Soweit ich das einschätzen kann, bin ich relativ
akribisch und perfektionistisch. Ich habe es noch nie
erlebt, dass ein Projekt daran gescheitert ist, dass
die Qualität einer KOMPONENTE nicht ausreichend gewesen
wäre -- wohl aber, dass Projekte komplett stecken-
geblieben sind, weil ganze Problemfelder komplett
übersehen wurden.

Das hängt aber stark von den Beteiligten und ihren
persönlichen Stärken und Schwächen ab, das gebe ich
zu.


> Ich bevorzuge daher die Bottom-Up-Methode,

Ich auch.

Mir fiel nur auf, dass der TO davon redet, ein Problem
systematisch in Teilprobleme zu zerlegen und Code zu
schreiben.

Häh?

Fehlt da nicht irgendwas? Ist es inzwischen auch schon
total veraltet, Probleme zu LÖSEN, bevor man die
gefundene Lösung in Form eines Programmes formuliert?

von Gerd (Gast)


Lesenswert?

Egon D. schrieb:
> Mir fiel nur auf, dass der TO davon redet, ein Problem
> systematisch in Teilprobleme zu zerlegen und Code zu
> schreiben.
>
> Häh?
>
> Fehlt da nicht irgendwas? Ist es inzwischen auch schon
> total veraltet, Probleme zu LÖSEN, bevor man die
> gefundene Lösung in Form eines Programmes formuliert?

Ach komm... Da hast du mich total missverstanden.

Wenn du zum allerersten Mal einen Sortieralgorithmus in Code 
niederschreiben sollst, formulierst du das Problem und den Algorithmus 
nicht erstmal in eine Art Pseudocode auf ein Blatt Papier bevor du 
überhaupt anfängst Code niederzuschreiben?

Ist aber auch egal. Ich bezweifle, dass dieser Thread noch wesentlich an 
Qualität zu unterbieten ist. :)

Gruß,

von Frank E. (Firma: Q3) (qualidat)


Lesenswert?

Was auch nicht schaden kann: OOP lernen. Auch wenn C nicht OO ist, man 
lernt trotzdem Denkmodelle und Strategien kennen, die hilfreich sind und 
den Horizont erweitern.

von A. S. (Gast)


Lesenswert?

Peter D. schrieb:
> Egon D. schrieb:
>> Es ist
>> viel wichtiger, erstmal die Dinge ÜBERHAUPT IRGENDWIE
>> zum Funktionieren zu bringen, die dringend erforderlich
>> sind, aber bisher von allen übersehen wurden.
>
> Meine Erfahrung ist, sowas führt regelmäßig in eine Sackgasse. Wenn man
> Code schnell mal eben so hinschludert, hat man viele undurchdringliche
> Copy&Paste Monster. Sobald Änderungen nötig sind, sucht man sich nen
> Wolf, d.h. der Code ist unwartbar. Und bei Fehlern werden dann planlos
> irgendwelche Timeouts hochgesetzt. Die Fehler werden dadurch nur
> seltener, gehen aber nicht weg.

Peter, Du bist sehr erfahren und machst vermutlich viele Dinge die Du in 
der ein oder anderen Form schon kennst.

Der TE ist ein vollkommener Anfänger. Und da ist es m.E. wirklich 
ratsam, auch diesen Weg (laufen, irgendwie) zu verfolgen, um überhaupt 
die Dinge zu verstehen, von denen "die anderen" immer reden.

Das man einen solch einen Code nicht behalten sollte ist klar. So wie 
die ersten Bilder, die ersten Holzarbeiten oder der erste Windvogel 
nicht Basis für die nächsten sein sollten.

von Lotta  . (mercedes)


Lesenswert?

Ein absolut geiler Thread!!

Macht Euch bitte nicht andauernd gegenseitig schlecht.
"Dumme" finden das Board hier nicht und diesen Thread
erst recht nicht! ;--P

@Gerd:

Wenn du schon fortgeschritten bist, solltest Du das Buch
"C im 21. Jahrhundert" von Ben Klemens lesen.
Da sind gute Techniken drinne, die es erlauben auch
mit den Möglichkeiten von C an "Micro Python"( C++ ) ;--P
heranzukommen.
Zum Beispiel die Benutzung von asprintf(), was dann die
ganze "Zeigerei" bei der Stringbearbeitung sehr vermindert.

Ich hätte auch ein Proggy für Dich ( Easycode ), was professionell
aus "C" Nassi-Schneidermann-Diagramme macht und umgekehrt.

Leider bin ich noch in Quarantäne, und wie lang dies dauert weiß
zur Zeit keiner.
Aber, wenn du dich anmeldest, kannst Du mal oben auf  "Lolita"
klicken... ;--P


mfg

von Josef (Gast)


Lesenswert?

Hi,

du liest jetzt den Cormen und beschäftigst dich mit Algorithmen.
Ein guter Anfang.

Dazu passt gut testgetriebene Entwicklung 
https://de.wikipedia.org/wiki/Testgetriebene_Entwicklung.

Dazu kann man jetzt ein Framework benutzen (gTest oder cpputest,
alle C++ Frameworks gehen auch für C)
oder selbst ein kleines Gerüst bauen. Das ist auch eine gute Übung.

Z.B. für einen Sortieralgorithmus kommen die zu sortierenden Daten
in eine externe Datei. Ebenso die Lösungen, also die sortierten Daten.

Deine Testroutinen lesen die Daten, sortieren sie mit deinen 
Sortieralgorithmen und vergleichen das Ergebnis mit den Lösungen.

Vorteil dabei ist
- Testdaten / Lösungen erzeugen ist mehr Benutzersicht
- du musst den Sortieralogrithmus verwenden. Dabei fällt auf ob das 
Interface was taugt oder es total kompliziert und unbenutzbar ist.
etc.

Stichworte für weitere Schritte: Clean Code, Refaktorierung, Design 
Pattern, Architektur, Spezifikation, Kommunikation.

Nur man kann nicht alles gleichzeitig machen und jetzt zu allen Themen 
ein Buch lesen.

Verzettel dich nicht.

von Sheeva P. (sheevaplug)


Lesenswert?

Vn N. schrieb:
> Sven B. schrieb:
>> Und da gibt es in C eben einen Haufen typischer Pattern, die in C++
>> deplaziert sind, und die nie verwendet werden, wie z.B.
>>  - Fehlerbehandlung und Ressourcenverwaltung mit goto
>
> Ist auch in C deplatziert. Wer macht bitte Fehlerbehandlung mit goto?
> Also außer Bastlern und Leuten, die in den Neunzigern hängengeblieben
> sind. Funktionen und Kontrollstrukturen gibts auch in C, kein Bedarf für
> goto.

Das ist... äh... nur die halbe Wahrheit. In vielen Fällen ist es einfach 
sinnvoll, maximal performant und korrekt, zum Beispiel tief 
verschachtelte Kontrollstrukturen im Fehlerfall mit einem goto zu 
verlassen. In hochoptimierten Anwendungsfällen wie Betriebssystemkerneln 
(Linux, SunOS/Solaris) oder Datenbankcores (PostgreSQL) ist das manchmal 
die schnellste und einfachste Möglichkeit, aus einer Fehlersituation 
heraus zu kommen.

Richtig ist allerdings auch, daß goto möglichst sparsam und nur in sehr 
wenigen, begründeten Ausnahmefällen genutzt -- und dann gut dokumentiert 
werden sollte.

> Sheeva P. schrieb:
>> Leider gibt es für kleine Projekte mit
>> starken Ressourcenbeschränkungen viele C++-Konstrukte, auf die man
>> besser verzichten sollte, als Beispiele seien hier dynamische
>> Speicherallokation (inklusive STL), Exceptions, virtuelle Methoden und
>> so weiter genannt.
>
> Naja, "malloc nicht verwenden" gilt auch in Bare Metal C.

Ja, natürlich. Aber zum Beispiel Exceptions, virtuelle Methoden, oder 
eben auch jede Form von dynamischer Speicherallokation können auf den 
ganz kleinen uCs wegen deren beschränkter Ressourcen problematisch sein 
-- und trotzdem hin und wieder die beste Lösung sein...

Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.