Uri: Herangehensweise bei Fehlern, wenn man Frameworks verwendet

Hi,

Ich bin noch am studieren und habe eine eher grundsätzliche Frage. Anfangs habe ich meine Sachen mit pures HTML, CSS, und JS gebaut und wenn ich ein Fehler hatte, habe ich mir mein Code so lange angeschaut, bis ich den Fehler gefunden habe.

Ich bau derzeit eine Webapp, die gefühlt aus 99% Framework besteht. Serverseitig habe ich Express js, als View engine Pug, als ORM verwende ich Sequelize und es passiert unter der Oberfläche offenbar, ziemlich viel wovon man nichts mitbekommt. Und wenn irgendwas passiert, was man nicht erwartet, hänge ich einfach und kann nicht mal meinen Code debuggen.

Hier ist der Fehler ziemlich gut dokumentiert.. Ich bin also offenbar nicht der erste, dem das passiert, aber eine Lösung habe ich auch nicht gefunden.

Nun habe ich mich meiner Ansichten nach penibel an die Anleitung gehalten und bekomme einen Fehler geworfen, der mehr oder weniger aus dem nichts kommt.

Wie gehe ich bei solchen Problemen allgemein eigentlich vor?

Gruß Uri

  1. Tach!

    Ich bin noch am studieren und habe eine eher grundsätzliche Frage. Anfangs habe ich meine Sachen mit pures HTML, CSS, und JS gebaut und wenn ich ein Fehler hatte, habe ich mir mein Code so lange angeschaut, bis ich den Fehler gefunden habe.

    Nunja, auch zu der Zeit hast du bereits Komponenten verwendet, auf die du keinen Einfluss hast. Du kannst die Elemente nur so verwenden, wie sie vorgesehen sind. Da gibt es keinen generellen Unterschied. Auch Programmiersprachen sind nur Frameworks - sozusagen.

    Ich bau derzeit eine Webapp, die gefühlt aus 99% Framework besteht. Serverseitig habe ich Express js, als View engine Pug, als ORM verwende ich Sequelize und es passiert unter der Oberfläche offenbar, ziemlich viel wovon man nichts mitbekommt.

    Business as usual.

    Und wenn irgendwas passiert, was man nicht erwartet, hänge ich einfach und kann nicht mal meinen Code debuggen.

    Warum nicht? Das Framework definiert in seiner Dokumentation genauso wie die Programmiersprachen (zuzüglich HTML und CSS in dem Fall), die Schnittstellen, mit denen du arbeiten kannst.

    Der Trick ist, dass man seinen eigenen Code so gestaltet, dass das, was man zu tun gedenkt, möglichst separat läuft, und damit Eingaben und Ausgaben an definierten Punkten übergeben und geprüft werden können. Also Funktionen erstellen und verwenden, so dass im Idealfall die Berührungspunkte mit dem Framework sich auf wenige Zeilen "Daten abholen" und "(Ergebnis-)Daten übergeben" beschränken.

    Hier ist der Fehler ziemlich gut dokumentiert.. Ich bin also offenbar nicht der erste, dem das passiert, aber eine Lösung habe ich auch nicht gefunden.

    Nun habe ich mich meiner Ansichten nach penibel an die Anleitung gehalten und bekomme einen Fehler geworfen, der mehr oder weniger aus dem nichts kommt.

    Sowas passiert. Das kann ein Fehler im Framework sein. Oder an einem falschen Verständnis deinerseits liegen. Meist ist es so, dass man doch etwas nicht ganz so gemacht hat, wie es das Framework vorsieht. Die Wahrscheinlichkeit ist umso höher, je geringer der Busfaktor als auch die Verbreitung des Frameworks ist. Auch in Vanilla-Browsertechniken können Fehler stecken. Da schauen aber mehr Augen auf den Code und mehr Verwender testen und finden Situationen, die die Programmierer so nicht bedacht hatten.

    Wie gehe ich bei solchen Problemen allgemein eigentlich vor?

    Dokumentation lesen. Problem mit dem geringstmöglichen Code nachstellen. Mit Debugging sicherstellen, dass das Problem nicht am eigenen Code liegt. Quelltext des Frameworks lesen, ob da nicht vielleicht ein Hinweis zur Verwendung oder auf einen Fehler zutage tritt.

    Das ist keine verbindlichen Reihenfolge, das waren nur ein paar ungeordnete Gedanken meinerseits, was man tun kann.

    dedlfix.

    1. Hi,

      ok, danke. Werde ein neues projekt erstellen und versuchen das Problem zu reproduzieren ohne das drumherum.

      Mein Problem ist wirklich, dass in dem Fall kein Code habe sondern Befehle in einer vorgegebenen Reihenfolge in die Konsole gebe und dabei Files und Ordner automatisch generiert werden. Das ist mitunter so der Punkt der mich dabei so hilflos wirken lässt.

      z.B "sequelize model:generate --name User --attributes name:string" in die Konsole

      Gruß

      Uri

  2. Hi,

    ein richtiges Framework bildet, wie der Name schon vermuten lässt, einen Rahmen. In diesem Ramen laufen immer wiederkehrende Vorgänge in einer geordneten bzw. durch das FW bestimmten Reihenfolge ab. Wenn es sich um ein Web-FW handelt, beschreiben diese Vorgänge einen Programmablauf der mit dem Request beginnt und mit der Ausgabe der Response endet.

    Kannst Du diesen Rahmen anhand Deines FW nachvollziehen? Wenn ja, solltest Du dafür genau 2 Zeilen finden. Nun setze alles was sich zwischen diesen beiden Zeilen befindet in einen try-{}-Block.

    So werden alle Exceptions aufgefangen und der catch-{}-Block sorgt dafür daß die dazugehörigen Texte mit Content-Type: text/plain unmittelbar im Browser ausgegegen werden.

    So kannst Du bereits auch während der Entwicklung selbst Exceptions werfen um bspw. im Zweifelsfall den Dump einer Datenstruktur im Browser auszugeben. Hierfür lohnt es sich eine spezielle Methode zu haben, nennen wir sie dump & die => dd();

    Statt also ein tail -f aufs Logfile zu setzen rufst Du dd($sruct) und siehst sofort im Browser ob Dein struct erwartungsgemäß bestückt ist. Genauso kannst Du auch einzelne (scalare) Variablen mit einem die $var im Browser ausgeben.

    Da auch im Produktivbetrieb Exceptions fallen können, lässt Du den try-{}-Block so stehen. Du möchtest lediglich danach trachten, daß im Produktivbetrieb nicht allzuviele Informationen rausgehen im Fehlerfall.

    MfG

    1. ein richtiges Framework bildet, wie der Name schon vermuten lässt, einen Rahmen. In diesem Ramen laufen immer wiederkehrende Vorgänge in einer geordneten bzw. durch das FW bestimmten Reihenfolge ab. Wenn es sich um ein Web-FW handelt, beschreiben diese Vorgänge einen Programmablauf der mit dem Request beginnt und mit der Ausgabe der Response endet.

      Gut erklärt 👍

      Kannst Du diesen Rahmen anhand Deines FW nachvollziehen? Wenn ja, solltest Du dafür genau 2 Zeilen finden. Nun setze alles was sich zwischen diesen beiden Zeilen befindet in einen try-{}-Block. So werden alle Exceptions aufgefangen […]

      Jein, der Kontrollfluss in Node.js ist größtenteils asynchron, da funktioniert Fehlerbehandlung mit try/catch nicht. Das folgende Beispiel verdeutlicht das Problem:

      async function raiseException() {
      	throw 'catch me if you can'
      }
      
      try {
      	raiseException()
      } catch (e) {
      	console.log('gotcha')
      }
      
      // --> Uncaught (in promise) catch me if you can
      

      Als Konsequenz daraus haben sich in der asynchronen Programmierung andere Methoden für die Fehlerbehandlung durchgesetzt. Das möchte ich allerdings hier gar nicht vertiefen, weil ich denke, dass Fehlerbehandlung und Debugging zwei verschiedene paar Schuhe sind. Beim Debuggen empfinde ich es eher lästig mir manuell Variablen-Inhalte zu dumpen. Node.js hat hervorragende interaktive Debugger, die uns viel schneller als Ziel bringen können. Für browserseitiges JavaScript gilt das gleiche.

      1. dass Fehlerbehandlung und Debugging zwei verschiedene paar Schuhe sind.

        Ja sicher. Selbst für Fehler gibt es unterschiedliche Ursachen, so wird eine Fehlermeldung bei einem durch den Benutzer verursachten Eingabefehler anders aussehen als eine Solche die sich infolge höherer Gewalt ergibt. Es kommt jedoch darauf an, die Ausgabe so zu konsolidieren daß man nicht haufenweise redundanten Code hat. MfG

      2. hi,

        Node.js hat hervorragende interaktive Debugger, die uns viel schneller als Ziel bringen können. Für browserseitiges JavaScript gilt das gleiche.

        Sieht ziemlich umständlich aus. Wobei ich nach wie vor der Meinung bin, daß Debuggen noch nie eine Frage der Technik/IDE war sondern eine Frage der Herangehensweise. Mir sind auch schon Experten begegnet, denen ihre Debugmethoden sich als völlig untauglich erwiesen haben. Eine weit verbreitete Unsitte besteht darin, Warnungen zu unterdrücken oder ins Log umzuleiten. Da kommt's dann schon vor, daß das error_log größer ist als das access_log.

        Einen dedizierten Debugmodus einzuschalten zu müssen ist grundsätzlich schlecht. Das möchte ich hier aber auch nicht weiter vertiefen weil dieses Thema bei mir Übelkeit und Erbrechen hervorruft.

        MfG

        1. Tach!

          Node.js hat hervorragende interaktive Debugger, die uns viel schneller als Ziel bringen können. Für browserseitiges JavaScript gilt das gleiche.

          Sieht ziemlich umständlich aus.

          Ist es aber nicht. Man richtet das genau einmal ein, was je System meist wenige Handgriffe sind, und danach kann man die eingebauten Möglichkeiten der verwendeten IDE nutzen. Das ist in der Regel ein einfacher Knopfdruck auf den (Run-with-)Debug-Button.

          Einen dedizierten Debugmodus einzuschalten zu müssen ist grundsätzlich schlecht.

          Wenn man die Frage nach der Debug-Strategie mal als geklärt ansieht, ist es immer noch ein deutlicher qualitativer Unterschied, ob man erstmal Debug-Ausgaben einfügt, die man anschließend wieder entfernen muss, oder ob man einfach mal schnell einen Debugger startet und selbst innerhalb der Sitzung auch noch Dinge auswerten kann, für die man die Debug-Ausgabe zu setzen vergessen hat.

          dedlfix.

          1. ob man erstmal Debug-Ausgaben einfügt, die man anschließend wieder entfernen muss, oder ob man einfach mal schnell einen Debugger startet und selbst innerhalb der Sitzung auch noch Dinge auswerten kann, für die man die Debug-Ausgabe zu setzen vergessen hat.

            Noch schneller kommt man zum Ziel wenn man, in einer Entwicklungsumgebung die der Produktivumgebung weitestgehend gleicht, die Fehler sofort sieht. Nur so ist die Wahrscheinlichkeit, eine fehlerfreie Anwendung in die Produktion zu stellen am größten. MfG

            1. Tach!

              Noch schneller kommt man zum Ziel wenn man, in einer Entwicklungsumgebung die der Produktivumgebung weitestgehend gleicht, die Fehler sofort sieht. Nur so ist die Wahrscheinlichkeit, eine fehlerfreie Anwendung in die Produktion zu stellen am größten.

              "Noch schneller" ist hier aber nicht als "die bessere Methode" anzusehen, sondern als ergänzende Maßnahme. Dass man schneller sieht, dass etwas schiefläuft, ist erst der Anfang. Damit ist die Frage nach dem Warum noch lange nicht geklärt. Dafür kommen unter anderem die Debugger ins Spiel.

              Im Falle des OP geht es darum, dass das Fehlverhalten bereits bekannt ist und nun Strategien zur Ursachenermittlung gefragt sind.

              Beim Debuggen geht es hauptsächlich darum, dass man zu den bereits entdeckten Fehlern deren Ursache ermittelt. Es gibt ja nicht nur Fehler, die eine Meldung generieren, sondern auch ungewünschtes Verhalten aufgrund von logischen Fehlern im Programm. Dazu muss man in Variableninhalte schauen, während man schrittweise durch den Code läuft. Sowas kann man nicht sinnvoll lösen, indem man von vornherein seinen Code mit Debug-Ausgabe vollstopft.

              Keine der bisher genannten Maßnahmen kann als allein seeligmachend angesehen werden. Zu einem robusten Programm gehört sowohl Fehlverhalten zu erkennen, was meist Zustände in anderen Systemen betrifft, auf die man nicht direkt Einfluss hat (z.B. Datenbank grad nicht erreichbar), als auch Situationen im eigenen Code zu erkennen, die man nicht bedacht hat, und dazu Strategien zur Ursachenermittlung. Und auch fehlerreduzierende Maßnahmen gehören dazu, wie beispielsweise Test Driven Design.

              dedlfix.

              1. Tach!

                Im Falle des OP geht es darum, dass das Fehlverhalten bereits bekannt ist und nun Strategien zur Ursachenermittlung gefragt sind.

                try/catch und raise error. D.h., daß man auch Warnungen in den Status einer Exception erhebt damit man das gleich mitbekommt. Damit dürfte Auch Dir klar sein, was ich im Sinne von "schneller zum Ziel" meine.

                Beim Debuggen geht es hauptsächlich darum, dass man zu den bereits entdeckten Fehlern deren Ursache ermittelt. Es gibt ja nicht nur Fehler, die eine Meldung generieren, sondern auch ungewünschtes Verhalten aufgrund von logischen Fehlern im Programm. Dazu muss man in Variableninhalte schauen,

                Richtig. Einen Dump erzeugen und ab damit in den Browser. Damit man das gleich (und auch hier wieder: im Sinne von schnell) an Ort und Stelle abklären kann.

                Sowas kann man nicht sinnvoll lösen, indem man von vornherein seinen Code mit Debug-Ausgabe vollstopft.

                Logisch daß man seine Dumps nicht dauerhaft erzeugt sondern nur während der Entwicklung. Ich habe das oft genug erlebt, daß Code im Debugmodus ins Repos gecheckt und sogar deployed wurde. Wenn man da hingegen den ganzen Rahmen in einen try/catch Block setzt, lassen sich solche Peinlichkeiten vemeiden, wenn da jemand seine Debugausgabe stehen lässt wird das nämlich sofort bemerkt. Es gibt nichts Schlimmeres als Debug-Ausgaben ins Logfile zu schicken, i.d.R. haben das diejenigen die sowas machen, spätestens beim Ertönen der Feierabendglocke vergessen und können sich am nächsten Tag an nichts mehr erinnern.

                Keine der bisher genannten Maßnahmen kann als allein seeligmachend angesehen werden.

                Nö. Aber mit try/catch kommt man halt am Weitesten und in Sachen Qualitätssicherung am schnellsten zum Ziel.

                Zu einem robusten Programm gehört sowohl Fehlverhalten zu erkennen, was meist Zustände in anderen Systemen betrifft, auf die man nicht direkt Einfluss hat (z.B. Datenbank grad nicht erreichbar),

                Das ist der klassische Fall für Exceptions. Und das spricht eben auch dafür, sein ganzes FW in einen try/catch Block zu setzen, sowohl während der Entwicklung als auch für den produktiven Betrieb. D.h., daß zum Deploy der Code nicht mehr verändert werden muss.

                als auch Situationen im eigenen Code zu erkennen, die man nicht bedacht hat, und dazu Strategien zur Ursachenermittlung. Und auch fehlerreduzierende Maßnahmen gehören dazu, wie beispielsweise Test Driven Design.

                Wenn man das gesamte Errorhandling über Exceptions abwickelt, ist bei großem Wartungskomfort auch die Qualität gesichert. Es ist dann nur noch eine Frage in welcher Form eine Fehlermeldung ausgegeben werden soll. Liegts am Benutzer wird man dem natürlich nicht eine Meldung in text/plain vor die Nase setzen sondern das Formular mit der fehlerhaften Eingabe in rot.

                Einen Entwickler auf die Zeile zu tracen wo er das API falsch verwendet, ist logischerweise auch kein Fall für den Endanwender. D.h., daß eine falsche Anwendung einer API seitens des Enwicklers sowieso in einem die enden muss damit sowas gar nicht erst rausgeht.

                Und wie gesagt, damit komme ich zurück zu meiner ersten Wortmeldung hierzu. Ein FW stellt einen Rahmen den man auch im Code wiederfindet: In Form von genau 2 Zeilen, nämlich da wo dieser Rahmen beginnt und wo er endet. Alles was an Code erforderlich ist und ggf. hinzukommt, wird nicht etwa neu in diesen Rahmen geschrieben sondern der Rahmen definiert Schnittstellen die das Einbinden von Code klar definieren.

                Spannt man einen try über diesen Rahmen, vermeidet man damit nicht nur redundanten Code bezüglich Fehlerbehandlung sondern schafft auch die Grundlage für einheitliche Verfahren hinsichtlich Qualitätssicherung und Eskalationsprozesse (SMS, Mail an Verteiler, Wallboard usw.). MfG

                1. try/catch und raise error.

                  Wie schon gesagt, kommst du bei Node.js damit nicht weit, weil Node.js hauptsächlich asynchron arbeitet.

                  Beim Debuggen geht es hauptsächlich darum, dass man zu den bereits entdeckten Fehlern deren Ursache ermittelt. Es gibt ja nicht nur Fehler, die eine Meldung generieren, sondern auch ungewünschtes Verhalten aufgrund von logischen Fehlern im Programm. Dazu muss man in Variableninhalte schauen,

                  Richtig. Einen Dump erzeugen und ab damit in den Browser. Damit man das gleich (und auch hier wieder: im Sinne von schnell) an Ort und Stelle abklären kann.

                  Ich glaube du würdest interaktive Debugger lieben, wirklich. Ich verspreche dir, du wirst nie wieder eine Variable per Hand ausgeben wollen, wenn du einmal einen echten Debugger benutzt hast. Gib ihnen einfach mal eine Chance, du hast ja nichts zu verlieren. Du musst dir nichtmal ein zusätzliches Programm installieren, dein Browser hat bereits einen interaktiven Debugger an Board und bei Google gibt es ein einsteigerfreundliches Tutorial.

                  1. try/catch und raise error.

                    Wie schon gesagt, kommst du bei Node.js damit nicht weit, weil Node.js hauptsächlich asynchron arbeitet.

                    Ja schön, aber wo ist denn dann der Sinn eines Framework wenn man die 2 Zeilen nicht benennen kann wo der Rahmen beginnt und wo er endet? Es wäre schön wenn Du das mal ein bishen näher erläutern tätest. Insbesondes den Begriff asynchron in diesem Kontext. MfG

                    1. Tach!

                      try/catch und raise error.

                      Wie schon gesagt, kommst du bei Node.js damit nicht weit, weil Node.js hauptsächlich asynchron arbeitet.

                      Ja schön, aber wo ist denn dann der Sinn eines Framework wenn man die 2 Zeilen nicht benennen kann wo der Rahmen beginnt und wo er endet? Es wäre schön wenn Du das mal ein bishen näher erläutern tätest. Insbesondes den Begriff asynchron in diesem Kontext.

                      Asynchron wie bei XHR. Das Ergebnis einer Operation steht nicht im Anschluss ihres Aufrufs zur Verfügung, sondern erst später. Der Aufrufer gibt außerdem eine Callback-Funktion an, die beim Vorliegen des Ergebnisses ausgeführt wird.

                      Der Rahmen ist weiterhin abgesteckt. Er beginnt bei Express damit, dass eine Funktion aufgerufen wird (die man zuvor registriert hat) und endet an ihrem Ende. Das Ergebnis gibt man zuvor zurück, indem man eine der Methoden des übergebenen response-Objekts aufruft.

                      dedlfix.

                      1. hi,

                        Der Rahmen ist weiterhin abgesteckt. Er beginnt bei Express damit, dass eine Funktion aufgerufen wird (die man zuvor registriert hat) und endet an ihrem Ende. Das Ergebnis gibt man zuvor zurück, indem man eine der Methoden des übergebenen response-Objekts aufruft.

                        Nun das ist bei meinem FW ganz ähnlich. Nur daß ich halt an den URL statt einer Funktionsreferenz eine Klasse binde, aber auch auf diese Art und Weise beliebig viele Methoden definieren kann wobei auch in jeder meiner Methoden ein Request/Response Objekt hineingereicht wird.

                        Warum es da in Express nicht möglich sein soll, ein solches Interface nicht in einen try Block setzen zu können, wird wohl immer Euer Geheimnis bleiben. Daß das FW asynchron arbeitet reicht mir als Erklärung jedenfalls nicht 😉

                        1. Tach!

                          Warum es da in Express nicht möglich sein soll, ein solches Interface nicht in einen try Block setzen zu können, wird wohl immer Euer Geheimnis bleiben. Daß das FW asynchron arbeitet reicht mir als Erklärung jedenfalls nicht 😉

                          Das ist ein generelles Problem bei asynchronem Code, nicht spezifisch für Express.

                          try {
                            setTimeout(function () { 
                              code mit Fehler
                            }, 1000);
                          } catch (e) {
                            console.log(e);
                          }
                          
                          

                          Das sieht aus, als ob der Fehler vom catch gefangen werden kann. Das ist aber nicht der Fall, weil der try-catch-Scope nach dem Aufruf von setTimeout() verlassen wurde. Und er wird auch nicht wieder betreten, wenn die Zeit abgelaufen ist und die Callback-Funktion aufgerufen wird. Der Fehler kann also nicht vom nicht mehr existenten try-catch-Scope gefangen werden. Wenn man den Fehler fangen möchte, muss man einen try-catch-Block in den Callback schreiben. Damit ist er aber auch nicht mehr generell fangbar, sondern nur noch lokal.

                          dedlfix.

                          1. Tach!

                            Warum es da in Express nicht möglich sein soll, ein solches Interface nicht in einen try Block setzen zu können, wird wohl immer Euer Geheimnis bleiben. Daß das FW asynchron arbeitet reicht mir als Erklärung jedenfalls nicht 😉

                            Das ist ein generelles Problem bei asynchronem Code, nicht spezifisch für Express.

                            In Express gibt es ein Request- und ein Responseobjekt in JEDER Methode. Wenn der Code mit der Response fertig ist, geht es daran die Response auszugeben. Und die geht IMMER in Richtung Client, egal ob der Code bis dahin asynchron oder sysnchron durchlaufen wurde. D.h., genau hier hat man die Möglichkeit, das Responseobjekt zu befragen ob es bis dahin Fehler gegeben hat.

                            Der Fehler kann also nicht vom nicht mehr existenten try-catch-Scope gefangen werden. Wenn man den Fehler fangen möchte, muss man einen try-catch-Block in den Callback schreiben.

                            Den try braucht man da wo Fehler auftreten können. Und da ist immer auch das Responseobjekt was mit den dazugehörigen Texten gefüttert werden kann. MfG

                            1. Tach!

                              Warum es da in Express nicht möglich sein soll, ein solches Interface nicht in einen try Block setzen zu können, wird wohl immer Euer Geheimnis bleiben. Daß das FW asynchron arbeitet reicht mir als Erklärung jedenfalls nicht 😉

                              Das ist ein generelles Problem bei asynchronem Code, nicht spezifisch für Express.

                              In Express gibt es ein Request- und ein Responseobjekt in JEDER Methode. Wenn der Code mit der Response fertig ist, geht es daran die Response auszugeben. Und die geht IMMER in Richtung Client, egal ob der Code bis dahin asynchron oder sysnchron durchlaufen wurde. D.h., genau hier hat man die Möglichkeit, das Responseobjekt zu befragen ob es bis dahin Fehler gegeben hat.

                              Ja, natürlich können Fehler auch in asynchronen Programmteilen abgefangen werden, aber nicht mit try/catch. Das war der Punkt deiner Aussage, der nicht stimmte: das try/catch, nicht das Behandeln generell. Der Unterschied ist nicht die prinzipielle Vorgehensweise sondern die konkrete. Die muss für asynchron laufenden Programmteile geeignet sein und kein try-catch-Block.

                              Zwischen "Funktion wird aufgerufen, weil der Router einen Request an sie gibt" und "Response wird abgeliefert" kann durchaus noch der eine oder andere asynchrone Aufruf stecken, beispielsweise Datenbankabfragen, die das Ergebnis asynchron ermitteln und bereitstellen.

                              Der Fehler kann also nicht vom nicht mehr existenten try-catch-Scope gefangen werden. Wenn man den Fehler fangen möchte, muss man einen try-catch-Block in den Callback schreiben.

                              Den try braucht man da wo Fehler auftreten können. Und da ist immer auch das Responseobjekt was mit den dazugehörigen Texten gefüttert werden kann.

                              Nein, das Response-Objekt steht nicht immer zur Verfügung. Ein Service, der benötigte Daten aus einer Datenhaltung holt, muss vom Response-Objekt nichts wissen. Das ist nicht seine Aufgabe, sich um die Response zu kümmern. Der soll nur die Daten holen. Sehr wohl können dabei aber Fehler auftreten. Nur kann er die nicht mit einem throw zurückwerfen, weil aufgrund seiner asynchronen Arbeitweise der Fehler vom Aufrufer nicht mit try/catch gefangen werden kann. Stattdessen bedient man sich eines Mechanismus der Promises, mit denen solche Asynchronitäten heutzutage gern abgehandelt werden. Beim Aufrufen eines Promises übergibt man nicht nur einen Callback für das Ergebnis im Gutfall, sondern auch noch einen weiteren, der im Fehlerfall aufgerufen wird. In diesen beiden Callbacks kann man dann das Response-Objekt auf die eine oder andere Weise befüllen. Also, wenn man im Request-Handler ist, ansonsten ruft man die error-Funktion des Promises auf, um den Fehler an den Aufrufer weiterzugeben.

                              dedlfix.

                              1. Das ist nicht seine Aufgabe, sich um die Response zu kümmern. Der soll nur die Daten holen. Sehr wohl können dabei aber Fehler auftreten.

                                Richtig, anstelle der Daten kann auch ein Fehler geliefert werden. Und was damit gemacht wird, ist dann sehr wohl eine Sache für das Responseobjekt, sei es den Fehlertext nur aufzunehmen. Unter Umständen muss, je nach Fehler, auch eine weitere Ausführung des Programmes verhindert werden weil sie entweder nicht mehr sinnvoll ist oder noch größere Schäden nach sich ziehen würde -- das geht nur per Exception und wie ich grad eben schon schrieb, gibt es dafür auch in Express.js entsprechende Möglichkeiten.

                                Es wäre ja gelacht wenn das nicht so wäre. Das macht eine Diskussion "was alles nicht geht" schon ziemlich fragwürdig.

                                MfG

                                1. Tach!

                                  Das ist nicht seine Aufgabe, sich um die Response zu kümmern. Der soll nur die Daten holen. Sehr wohl können dabei aber Fehler auftreten.

                                  Richtig, anstelle der Daten kann auch ein Fehler geliefert werden. Und was damit gemacht wird, ist dann sehr wohl eine Sache für das Responseobjekt, sei es den Fehlertext nur aufzunehmen.

                                  Nö, nicht zwangsläufig. Es gibt auch Fehler, die man nicht zum Aufrufer durchzureichen gedenkt. Die Beziehung zwischen dem Fehler in diesem Dienst und der Response ist also nicht zwangsläufig gegeben.

                                  Unter Umständen muss, je nach Fehler, auch eine weitere Ausführung des Programmes verhindert werden weil sie entweder nicht mehr sinnvoll ist oder noch größere Schäden nach sich ziehen würde -- das geht nur per Exception und wie ich grad eben schon schrieb, gibt es dafür auch in Express.js entsprechende Möglichkeiten.

                                  Nein, das geht eben nicht per Exception, weil Exceptions in asynchron ablaufenden Teilen nicht gefangen werden können. Das was du nebenan verlinkt hast, ist der Ersatz für Exceptions und try/catch. Das wird auch nicht Exception genannt, um nicht mit den eigentlichen Exceptions verwechselt zu werden. Gängige Begriffe für die Handler bei Promises sind Success- und Failure/Error-Callback.

                                  dedlfix.

                            2. Und siehe da ein catch-all ist auch in Express.js möglich.

                              1. Tach!

                                Und siehe da ein catch-all ist auch in Express.js möglich.

                                Also alles genau so, wie am Anfang der Diskussion bereits gesagt:

                                Nun setze alles was sich zwischen diesen beiden Zeilen befindet in einen try-{}-Block. So werden alle Exceptions aufgefangen […]

                                Jein, der Kontrollfluss in Node.js ist größtenteils asynchron, da funktioniert Fehlerbehandlung mit try/catch nicht. [...]

                                Als Konsequenz daraus haben sich in der asynchronen Programmierung andere Methoden für die Fehlerbehandlung durchgesetzt.

                                dedlfix.

                2. Tach!

                  Beim Debuggen geht es hauptsächlich darum, dass man zu den bereits entdeckten Fehlern deren Ursache ermittelt. Es gibt ja nicht nur Fehler, die eine Meldung generieren, sondern auch ungewünschtes Verhalten aufgrund von logischen Fehlern im Programm. Dazu muss man in Variableninhalte schauen,

                  Richtig. Einen Dump erzeugen und ab damit in den Browser. Damit man das gleich (und auch hier wieder: im Sinne von schnell) an Ort und Stelle abklären kann.

                  Einen Dump zu erzeugen ist ein unnötiger Zwischenschritt, der außerdem nur einen Stand zu einem bestimmten Moment abbilden kann. Damit Schleifendurchläufe zu untersuchen, oder allgemein wie sich Werte im Verlaufe des Codes ändern, ist mit vielen Dumps wesentlich umständlicher, als einen Breakpoint setzen zu können und dann schrittweise weiterzulaufen oder zum nächsten Breakpoint springen zu können und dabei jeweils life und in Farbe die Variableninhalte anschauen zu können. Sogar ändern kann man die Inhalte, um sofort sehen zu können, wie sich die Sache mit einem anderen Wert verhält.

                  Logisch daß man seine Dumps nicht dauerhaft erzeugt sondern nur während der Entwicklung.

                  Warum überhaupt, wenn man mit einem Debugger durch den Code gehen kann? Dumps können eher ihre Eigenschaften ausspielen, wenn man grad nicht mit der Entwicklungsumgebung zugange ist. Beispielsweise, wenn ein Fehler bei einem Anwender auftritt, kann ein Dump Informationen liefern, weil man schlecht auf der Anwendermaschine interaktiv debuggen kann. Nachteilig ist weiterhin, dass es nur ein Stand ist und man nicht unbedingt sieht, wie sich die Dinge entwickelt haben, die zu dem Stand führten.

                  Keine der bisher genannten Maßnahmen kann als allein seeligmachend angesehen werden.

                  Nö. Aber mit try/catch kommt man halt am Weitesten und in Sachen Qualitätssicherung am schnellsten zum Ziel.

                  Oder auch gar nicht, bei asynchronem Code.

                  dedlfix.