Datenbankzugriffsschicht ohne mit Singletons um sich zu schmeißen?



  • dot schrieb:

    Du musst nun sämtlichen Code anfassen der den "Singleton" verwendet und den "Singleton" rausfactoren und durch ne Referenz ersetzen. Da der "Singleton" ja so einfach von überall aus erreichbar ist ist das vermutlich sehr viel Code da du dir beim Schreiben des Codes mit "Singleton" nicht viele Gedanken darüber gemacht hast was, wann, wie, wo wirklich Zugriff auf welche Schnittstelle braucht (99.99% aller "Singletons" werden ja von vornherein von faulen Programmierern verwendet um sich genau keine Gedanken machen zu müssen). Dein Code ist also an allen Ecken und Enden übersäht mit Zugriffen auf den "Singleton" und das so gewachsene Design vermutlich an einigen Stellen gar nicht wirklich für eine ordentlichen Lösung über Dependency Injection geeignet. D.h. den Singleton loszuwerden bedeutet ein komplettes redesign großer Teile des Systems. Wenn du es stattdessen einfach von vornherein so gebaut hättest dass Objekte die Objekte benötigen diese über entsprechende Referenzen explizit kennen wäre das einzige was du nun tun müsstest einfach eine zweite Datenbankverbindung zu instanzieren, den entsprechenden Objekten das andere Datenbankverbindungsobjekt zu reichen und das wars.

    Ehrlich gesagt weiß ich nicht wieso das besser sein sollte. Woher weißt du jetzt welches Objekt welche Datenbankverbindung bekommen soll und wieviel Connections du schon hast? Wahrscheinlich brauchst du ein Singleton, das mitzählt. Die Connection sollte man aber innerhalb von Transaktionen rumreichen und nicht überall das Singleton verwenden.



  • aaaaaaaaaüö schrieb:

    Woher weißt du jetzt welches Objekt welche Datenbankverbindung bekommen soll und wieviel Connections du schon hast?

    Wenn du das nicht weißt ist doch sowieso alles sinnlos?

    aaaaaaaaaüö schrieb:

    Wahrscheinlich brauchst du ein Singleton, das mitzählt.

    wofür?

    aaaaaaaaaüö schrieb:

    Die Connection sollte man aber innerhalb von Transaktionen rumreichen und nicht überall das Singleton verwenden.

    Wenn du das tust dann hast du das Problem natürlich nichtmehr. Das ist aber eben genau nicht wie 99.99% aller "Singletons" da draußen verwendet werden...



  • dot schrieb:

    aaaaaaaaaüö schrieb:

    Woher weißt du jetzt welches Objekt welche Datenbankverbindung bekommen soll und wieviel Connections du schon hast?

    Wenn du das nicht weißt ist doch sowieso alles sinnlos?

    aaaaaaaaaüö schrieb:

    Wahrscheinlich brauchst du ein Singleton, das mitzählt.

    wofür?

    Ich geh mal davon aus, dass man mit mehreren Threads arbeitet und nicht jeder Thread für immer eine Connection offen halten kann, also die Anzahl der Connections begrenzt ist, sonst ist es relativ simpel. Dann kannst du wirklich alle Connections beim Programmstart verteilen und rumreichen.



  • Und wo genau profitiert man in diesem Szenario von Singleton? Und wer sagt dass alle Connections überhaupt zur selben Datenbank laufen?



  • Wenn du 100 Threads hast und nur 10 Connections, kannst du immer 10 Threads die gleiche Connection geben und die anderen 9 dann warten lassen solange ein Thread die Connection verwendet. Oder du hast ein Singleton, dass die 10 Connections verwaltet und eine an den Thread gibt der gerade eine braucht. Dann müssen die Threads erst warten wenn alle Connections verwendet werden und nicht wenn einer zufällig gerade die gleiche braucht.



  • Ja, aber das hat doch absolut nichts mit dem Singleton Pattern zu tun!? Die entsprechende Funktionalität würd ich hinter einem DatabaseConnection Objekt kapseln das ich einfach weiterreiche an wen auch immer es braucht. Ich seh jedenfalls wirklich nicht wo genau man da jetzt den Singleton Pattern brauchen sollte!?



  • Na, du kannst natürlich immer statt eines Singletons ein einziges Objekt erzeugen und das dann überall rumreichen. Wenn du dann noch ein paar mehr solcher Objekte hast, hast du überall x Parameter mehr in deinen Methoden und Konstruktoren, da würde ich dann doch irgendwann ein Singleton nehmen. Man muss ja nicht für alle theoretischen Fälle ein Design vorsehen. Mehrere Datenbanken wird wahrscheinlich nicht mal 0.1% aller Anwendungen brauchen.



  • aaaaaaaaaüö schrieb:

    Wenn du dann noch ein paar mehr solcher Objekte hast, hast du überall x Parameter mehr in deinen Methoden und Konstruktoren [...]

    Meiner Erfahrung nach ist das nicht so schlimm. Wenn es viele sind ist das nur ein Zeichen dass am Design grundsätzlich was nicht stimmt.

    aaaaaaaaaüö schrieb:

    Man muss ja nicht für alle theoretischen Fälle ein Design vorsehen. Mehrere Datenbanken wird wahrscheinlich nicht mal 0.1% aller Anwendungen brauchen.

    Gut. Aber ich seh keinen Grund diese 0.1% auszuschließen wenn mir das keinen Vorteil bringt!? Design und Implementierung werden durch ein Singleton jedenfalls sicherlich nicht einfacher. Das Singleton bringt nämlich einige nichttriviale Konsequenzen mit sich. Z.B. Initialisierungsreihenfolge, Multithreading (getInstance() gegen Race Condition absichern), Unit-Testing (globaler statischer Zustand), ...



  • Wie groß sind eigentlich die Teams in denen du programmierst? Wie stellst du sicher, das jeder die "einzelnen" Objekte übergibt und nicht selber falsch erstellt?



  • aaaaaaaaaüö schrieb:

    Wie groß sind eigentlich die Teams in denen du programmierst?

    Ich hab bisher noch nie wirklich in größeren Teams gearbeitet, maximal 4 Leute.

    aaaaaaaaaüö schrieb:

    Wie stellst du sicher, das jeder die "einzelnen" Objekte übergibt und nicht selber falsch erstellt?

    Das System zwingt einen doch schon dazu!? Ohne ein Objekt zu übergeben lassen sich die andren Objekte garnicht instanzieren. Ich seh da kein Problem, aber du wirst mir sicher gleich sagen dass mir einfach die Erfahrung fehlt worauf ich natürlich nichts entgegnen kann. Die potentielle Unfähigkeit meiner Teamkollegen ist für mich jedenfalls kein Argument für ein Singleton und ich wüsste nicht was passieren müsste dass sich daran was ändert.



  • Ist auch etwas seltsam steigende Komplexität (mehrere Objekte die rumgereicht werden müssen), als Argument für Singletons/globale Variablen anzuführen.

    Mal ganz abgesehen davon, dass man mehrere Objekte zu einem zusammenfassen kann, wenn sie öfters zusammen gebraucht werden. Soll angeblich manchmal ganz gut funktionieren.



  • dot schrieb:

    aaaaaaaaaüö schrieb:

    Wie stellst du sicher, das jeder die "einzelnen" Objekte übergibt und nicht selber falsch erstellt?

    Das System zwingt einen doch schon dazu!? Ohne ein Objekt zu übergeben lassen sich die andren Objekte garnicht instanzieren.

    Mal ein Pseudocode wie du dir das vorstellst.

    main
    {
      DatabaseConnection db;
      foo(db);
    }
    
    foo( DatabaseConnection db )
    {
       Query(db) q;
       q...
    }
    
    class Query( DatabaseConnection db )
    {
    ...
    }
    

    Was hinder Teammember 46 daran dein Programm so zu erweitern und 2 DatabaseConnections anzulegen?

    main
    {
      DatabaseConnection db;
      foo(db);
    
      bar();
    }
    
    bar()
    {
       DatabaseConnection db;
       foo(db);
    }
    
    foo( DatabaseConnection db )
    {
       Query(db) q;
       q...
    }
    
    class Query( DatabaseConnection db )
    {
    ...
    }
    

    Und dann kommen sie zu dir und behaupten deine DatabaseConnection hat einen Bug und speichert manchmal nicht richtig in der DB.

    Wann würdet ihr dann überhaupt Singletons verwenden? Garnie?



  • aaaaaaaaaüö schrieb:

    Was hinder Teammember 46 daran dein Programm so zu erweitern und 2 DatabaseConnections anzulegen?

    Nichts!?

    aaaaaaaaaüö schrieb:

    Und dann kommen sie zu dir und behaupten deine DatabaseConnection hat einen Bug und speichert manchmal nicht richtig in der DB.

    Mit derart unfähigen Programmierern musste ich bisher zum Glück noch nicht arbeiten. Und selbst wenn rechtfertigt das nicht den Einsatz eines Singleton.

    aaaaaaaaaüö schrieb:

    Wann würdet ihr dann überhaupt Singletons verwenden? Garnie?

    Exakt, zumindest nicht für einen globalen Zustand. Dafür ist und war Singleton nie gedacht (falls dir aufgefallen ist hab ich immer von "Singleton" gesprochen, die "" waren durchaus Absicht). Die Gründe hab ich ja schon genannt. Wenn du noch mehr Gründe wissen willst schau einfach mal hier oder hier 😉



  • aaaaaaaaaüö schrieb:

    Was hinder Teammember 46 daran dein Programm so zu erweitern und 2 DatabaseConnections anzulegen?

    Nichts. Und das ist normalerweise absolut ok.
    Was hindert den Programmierer daran, eine zweite Datei zu öffnen?
    Klar darf man nicht zweimal zugleich in die selbe Datei schreiben.
    Das war aber nie ein Problem.

    Falls Du meinst, das Prog dürfe immer nur mit einer Datenbank reden, kannste das mit einem Singleton festmachen. Aber es kann auch sein, daß sich das Team davon eher genervt fühlt, als gut aufgehoben. Würdest Du selber den Schutz brauchen oder wollen? Falls ja, dann mach halt nen Singleton draus.



  • dot schrieb:

    aaaaaaaaaüö schrieb:

    Wann würdet ihr dann überhaupt Singletons verwenden? Garnie?

    Exakt, zumindest nicht für einen globalen Zustand. Dafür ist und war Singleton nie gedacht (falls dir aufgefallen ist hab ich immer von "Singleton" gesprochen, die "" waren durchaus Absicht).

    Die Frage bleibt. Wann würdet ihr dann überhaupt Singletons verwenden? Bis jetzt war ein Singleton für dich für garnichts gedacht.



  • Korrekt. Potentielle Anwendungsfälle für ein Singleton sind extrem selten und man kann drüber diskutieren inwiefern der Pattern überhaupt den Grundfesten der OOP widerspricht. Ich hab schon viele Singletons gesehen und jeder einzige davon war ein Designfehler. Singleton wird eben ständig als bunte Verpackung für eine globale Variable verwendet. Das ist aber nicht wofür Singleton gedacht ist und nur weil man die globale Variable nichtmehr direkt als solche erkennt ist sie noch lange nicht verschwunden. Die Tatsache dass ein globaler Zugriffspunkt existiert ist eine Konseqzenz aber nicht der Sinn des Singleton Pattern.



  • volkard schrieb:

    aaaaaaaaaüö schrieb:

    Was hinder Teammember 46 daran dein Programm so zu erweitern und 2 DatabaseConnections anzulegen?

    Nichts. Und das ist normalerweise absolut ok.
    Was hindert den Programmierer daran, eine zweite Datei zu öffnen?
    Klar darf man nicht zweimal zugleich in die selbe Datei schreiben.
    Das war aber nie ein Problem.

    Verwendest du private und protected oder programmierst du wie in Python in C++?



  • dot schrieb:

    Korrekt. Es gibt extrem wenige Anwendungen für Singleton und man kann drüber diskutieren inwiefern der Pattern überhaupt den Grundfesten der OOP widerspricht. Ich hab schon viele Singletons gesehen und jeder einzige davon war ein Designfehler. Singleton wird eben ständig als bunte Verpackung für eine globale Variable verwendet. Das ist aber nicht wofür Singleton gedacht ist und nur weil man die globale Variable nichtmehr direkt als solche erkennt ist sie noch lange nicht verschwunden. Die Tatsache dass ein globaler Zugriffspunkt existiert ist eine Konseqzenz aber nicht der Sinn des Singleton Pattern.

    Wie kannst du behaupten, du weißt wofür Singletons gedacht sind, wenn du behauptest, dass sie für nichts gedacht sind?



  • Ich verwende eigentlich ausschließlich private und public, protected nur recht selten und wenn dann auf keinen Fall für Datenmember.



  • aaaaaaaaaüö schrieb:

    Wie kannst du behaupten, du weißt wofür Singletons gedacht sind, wenn du behauptest, dass sie für nichts gedacht sind?

    Ich habe nicht behauptet dass Singletons für nichts gedacht sind, nur dass potentielle Anwendungsfälle für ein Singleton extrem selten sind. Woher ich weiß wofür Singletons gedacht sind? Ganz einfach:

    Design Patterns, S. 127 schrieb:

    Use the Singleton pattern when

    • There must be exactly one instance of a class [...]
    • [...]

    Mit dem Singleton Pattern drückst du aus dass es eine inhärente Eigenschaft des Typs ist dass es nur eine einzige Instanz geben darf. Genau das sicherzustellen ist der Zweck des Singleton Pattern (hence the name). Und das ist etwas grundlegend Anderes als "ich brauch nur eine Instanz". Und mit globalen Variablen hats noch weniger was zu tun.

    Das Problem ist nicht das Singleton Pattern an sich sondern die Tatsache dass es praktisch überall, verhältnismäßig viel zu oft und dabei ständig falsch verwendet wird. Nämlich als "Ersatz" für eine globale Variable.


Anmelden zum Antworten