Ankündigung

Einklappen
Keine Ankündigung bisher.

Code Clean

Einklappen
X
  • Filter
  • Zeit
  • Anzeigen
Alles löschen
neue Beiträge

  • Code Clean

    Hallo Zusammen,
    ich habe auf der folgenden Seite(http://www.sebastianviereck.de/regel...de-clean-code/) folgendes gefunden und hätte dazu Fragen.

    Thema: Nebeneffekte vermeiden

    Wenn Funktionen verprechen eine Aufgabe zu erfüllen, aber auch eine verborgene Funktion ausführen, führt das oft zu Bugs. Das können z.B. das Ändern von Klassenvariablen/globalen Variablen sein. Dies führt zu schwer findbaren Fehlern, die vom zeitlichen Aufruf der Funktion abhängig sind und schwer reproduzierbar sind.
    PHP-Code:
    function checkPassword($userName$password){
    if(
    isAuthorized($userName$password))
    {
    // führt zu Nebeneffekten
    session.start();
    return 
    true;
    }
    else
    {
    return 
    false;
    }

    1. Seht ihr das genauso?
    2. Wie könnte man das anders lösen?
    3. Was ist besser, verschachtelte Methoden (wie in dem oberen Beispiel) oder die Methoden nacheinander aufrufen?


  • #2
    Globale Variablen zu verwenden ist an sich schon ein Fehler.

    Und was soll eine "verborgene" Funktion sein?

    Kommentar


    • #3
      Ich vermute mal das es in dem Beispiel das session_start() ist.
      Wahrscheinlich ist damit gemeint, dass man andere Methoden in der ausgeführten Methode ausführt.

      Kommentar


      • #4
        Zitat von yugox Beitrag anzeigen
        Wahrscheinlich ist damit gemeint, dass man andere Methoden in der ausgeführten Methode ausführt.
        Was aber der Regelfall ist. Die Alternative wäre ein Gottobjekt mit Funktionen, die zigtausende Zeilen lang sind.

        Kommentar


        • #5
          Ich glaube hier geht es in Richtung pure functions. Hier ein netter Artikel für Zwischendurch: Functional Programming in PHP

          Kommentar


          • #6
            Was aber der Regelfall ist. Die Alternative wäre ein Gottobjekt mit Funktionen, die zigtausende Zeilen lang sind.
            Das sehe ich genauso, hätte aber sein können das es Clean Code technisch nicht der beste Weg ist. Deswegen hatte ich mich ja an euch gewandt und wollte mal eure Meinung dazu hören

            Kommentar


            • #7
              Zitat von yugox Beitrag anzeigen
              Das sehe ich genauso, hätte aber sein können das es Clean Code technisch nicht der beste Weg ist. Deswegen hatte ich mich ja an euch gewandt und wollte mal eure Meinung dazu hören
              So wie ich das interpretiere wird hier bemängelt, dass die oben genannte Funktion "checkPassword" (deren Implementierung sowieso irreführend ist) den Nebeneffekt hat, dass die Session gestartet wird. D.h. die Funktion "checkPassword" führt zu Nebeneffekten die für den Aufrufenden nicht direkt ersichtlich sind und zu unerwünschten Fehlern führen können. Die Funktion checkPassword sollte eigentlich nur prüfen ob das Kennwort gültig ist:

              PHP-Code:
              function checkPassword(string $inputUser $user){
                 return 
              myFunkyHash($input) === $user->password;

              Dabei sollte "myFunkyHash" natürlich ebenfalls "pure" sein.

              Kommentar


              • #8
                Zitat von lottikarotti Beitrag anzeigen
                Dabei sollte "myFunkyHash" natürlich ebenfalls "pure" sein.
                Sinnvoller wäre eine Funktion verifyHash() statt einen generierten Hash mit === zu vergleichen. Den wenn man sicherheitstechnisch auf dem neuesten Stand ist, wäre die Funktion myFunkyHash() nicht pure.

                Kommentar


                • #9
                  Ich denke das mit "verborgener Funktion" nicht Funktion im Sinne von PHP-Funktion gemeint ist, sondern im Sinne von "eine Funktion erfüllend", d.h. eigentlich ein Seiteneffekt, so wie lotti geschrieben hat.

                  Ob man myFunkyHash() oder hash_verify() verwendet ist aus Sicht der Seiteneffekte egal. Wieso sollte myFunkyHash() nicht pure sein? (Vorausgesetzt sie tut nur das was sie sagt - einen Hash zurückliefern.)

                  Zu den Fragen:
                  1. OOP lässt sich nicht ohne Nebeneffekte machen, jede Veränderung an einer Objektvariablen ist ein Seiteneffekt. Wichtig ist, dass das möglichst explizit ist. Mit klaren Namen und klarer Trennung von Zuständigkeiten sollte das aber kein großes Problem sein. Wer keine Nebeneffekte will muss funktional programmieren.
                  2. Im konkreten Fall sieht man zu wenig Code dafür, ich wüsste nicht wofür man da eine Session starten müsste. Würde die Methode aber z.B. login() heißen, würde man schon eher eine Session dahinter vermuten als hinter checkPassword()
                  3. Ich wüsste nicht wie das eine oder das andere dabei helfen kann. Das Zentrale ist: Der Aufrufer muss wissen was passiert wenn eine Funktion aufgerufen wird. Das kann man entweder erreichen indem man Seiteneffekte explizit macht oder indem man den "problematischen Code" (z.B. Session erzeugen) den Aufrufer selbst erledigen lässt.

                  Kommentar


                  • #10
                    Zitat von hellbringer Beitrag anzeigen
                    Sinnvoller wäre eine Funktion verifyHash() statt einen generierten Hash mit === zu vergleichen. Den wenn man sicherheitstechnisch auf dem neuesten Stand ist, wäre die Funktion myFunkyHash() nicht pure.
                    Da stimme ich dir natürlich zu, das Beispiel war einfach nur schlecht gewählt und zielte aber primär darauf ab, dass der Seiteneffekt ("Session starten") dort einfach nicht reingehört. In diesem konkreten Fall kann man auch direkt password_verify nutzen.

                    Zitat von Tropi Beitrag anzeigen
                    Ob man myFunkyHash() oder hash_verify() verwendet ist aus Sicht der Seiteneffekte egal. Wieso sollte myFunkyHash() nicht pure sein? (Vorausgesetzt sie tut nur das was sie sagt - einen Hash zurückliefern.)
                    Die Funktion password_hash liefert bei gleichem Input immer einen anderen Output -> impure. Bei password_verify ist das offensichtlich nicht der Fall.

                    Zitat von Tropi Beitrag anzeigen
                    OOP lässt sich nicht ohne Nebeneffekte machen, jede Veränderung an einer Objektvariablen ist ein Seiteneffekt. Wichtig ist, dass das möglichst explizit ist. Mit klaren Namen und klarer Trennung von Zuständigkeiten sollte das aber kein großes Problem sein. Wer keine Nebeneffekte will muss funktional programmieren.
                    Oder mit Persistent Data Structures / Immutable objects arbeiten.

                    Kommentar


                    • #11
                      Zitat von Tropi Beitrag anzeigen
                      Wieso sollte myFunkyHash() nicht pure sein? (Vorausgesetzt sie tut nur das was sie sagt - einen Hash zurückliefern.)
                      password_hash() ist auch nicht pure:
                      PHP-Code:
                      echo password_hash('mein_passwort'PASSWORD_DEFAULT) . PHP_EOL;
                      // $2y$10$i3SuXCYHCFwBvIE39EYAluSJFs4gPLqU97iB90AW1xNQjfhWtcGBm

                      echo password_hash('mein_passwort'PASSWORD_DEFAULT) . PHP_EOL;
                      // $2y$10$0v1mTORXhYIbQl34u3YQiuDvUy5dNpfDknRhfDGP4VtAACsIidVRK

                      echo password_hash('mein_passwort'PASSWORD_DEFAULT) . PHP_EOL;
                      // $2y$10$OQqDiukvEc28bYxxOLfy3ecn5H8kuMzBP33P0QOeZTmLpn4xRA4Pi

                      echo password_hash('mein_passwort'PASSWORD_DEFAULT) . PHP_EOL;
                      // $2y$10$AfgN5kt5SMs4cZoIuMpuGeEWYZudd/0MaYqg3jLxOfCrqTdRqGpwy 
                      http://php.net/manual/en/function.password-hash.php

                      Kommentar


                      • #12
                        Zitat von lottikarotti
                        Die Funktion password_hash liefert bei gleichem Input immer einen anderen Output -> impure. Bei password_verify ist das offensichtlich nicht der Fall.
                        Ich glaub wir reden leicht aneinander vorbei. Von password_hash() habe ich ja gar nicht gesprochen, ich sagte myFunkyHash() kann durchaus pure sein. md5() ist es auch. password_hash() generiert halt zusätzlich zum Hashen noch Salts und ist damit nicht pure.

                        Zitat von hellbringer Beitrag anzeigen
                        password_hash() ist auch nicht pure:
                        Ja, aber das wird in der Dokumentation ja auch explizit dargestellt. Das ist genau die Fallunterscheidung die ich oben erwähnt habe: Entweder du bist der bewusst, dass password_hash() nicht immer das selbe Ergebnis liefert, oder du generierst im Aufrufer selbst die Salts, dann liefert dir password_hash() auch immer das selbe Ergebnis.

                        Kommentar


                        • #13
                          Zitat von yugox Beitrag anzeigen
                          Das sehe ich genauso, hätte aber sein können das es Clean Code technisch nicht der beste Weg ist. Deswegen hatte ich mich ja an euch gewandt und wollte mal eure Meinung dazu hören
                          Moment...

                          Was ist denn ein Seiteneffekt?

                          In der Funktionalen Programmierung ist jede Funktion "deterministisch". Heisst, dass sie zu gegebenen Parametern immer das gleiche Ergebnis zurückliefert. Das ist theoretisch sogar mit einer Random-Funktion kompatibel, wenn man dieser einen Seed-Wert mitgeben kann. Generell ist eine Funktion wie random, die einen Zufälligen Wert zurückgibt, aber eben eine perfekt seiteneffekt-behaftete, also nicht-deterministische Funktion. Versteckte Funktionen sind kein Problem, solange sie deterministisch sind. Eine Session ist nicht deterministisch.

                          OOP kann sehr wohl deterministisch sein - ist es aber, wie Tropi schon angemerkt hat in der Regel nicht. Deswegen gibt es im Moment auch um Sprachen, die FP erzwingen, einen gewissen Hype, denn sie beseitigen eine ganze Fehlerkategorie. Seiteneffekte sind das, was bei der Softwareentwicklung der wohl am schwerten zu beherrschbare Faktor ist. Ohne Seiteneffekte tut ein Code normal genau das, was man beim drüberlesen glaubt zu verstehen. Und er ermöglicht frustfreie Nebenläufigkeit (Threading).

                          Ohne Seiteneffekte gibt es aber nicht, sonst würden Programme keinen Sinn machen. Irgendwas soll ein Programm ja berechnen/verändern/tun. Also sind tatsächlich nur (große) Teile eines FP-Programms tatsächlich seiteneffektfrei.

                          Wenn der Author der verlinkten Seite des ersten Beitrags also von "möglichst Nebeneffekte vermeiden" schreibt, dann meint er, dass Nebeneffekte bei OOP möglichst als Abhängigkeit an ein Objekt übergeben werden sollten und ihrerseits von einem möglichst eng geschnürten Objekt umfasst sein sollten.

                          Hier ist der Seiteneffekt in der Funktion "versteckt":

                          PHP-Code:
                          fn rollAge() = "Mein Alter ist {rand(25, 45)}" 
                          Hier wird er als Parameter übergeben:

                          PHP-Code:
                          fn rollAge(fn rand) = "Mein Alter ist {rand()}" 
                          Der Unterschied ist, dass man von außen sehen kann, mit was rollAge arbeitet. Eine versteckte deterministische Funktion ist hingegen völlig unproblematisch:

                          PHP-Code:
                          fn rollAge(fn rand) = uppercase("Mein Alter ist {rand()}"
                          password_hash ist nicht-deterministisch. password_verify hingegen schon...
                          Standards - Best Practices - AwesomePHP - Guideline für WebApps

                          Kommentar

                          Lädt...
                          X