Abhängigkeiten zwischen Libs



  • Hi,

    ich hab eine Applikation und zwei Libs (libA, libB).

    Mein Problem ist nun, dass sowohl die Applikation als auch libB Dinge aus libA benötigt. Ich kann keine statischen Bibliotheken verwenden, da ich unter C# bin und es da nur DLLs gibt. Mein Problem besteht darin, dass es sein kann, dass die Applikation von Version 0.0.1 der libA ausgeht und libB von Version 0.0.2. Wenn die Lib nun in Version 0.0.2 eine Funktion nicht mehr beinhaltet, die in 0.0.1 noch drin war, hab ich ein Problem, weil unter Umständen die Applikation dann abschmiert. Wie könnte ich das Problem lösen? Immer auf Abwärtskompatibilität zu achten ist keine Option, geht es auch anders?



  • Eine gute Lösung gibt es nicht. Das einzige, was mir einfällt und wenigstens halbwegs akzeptabel ist, wäre die beiden Versionen von libA als unterschiedliche Bibliotheken behandeln sie müssten dann aber unterschiedliche Namen haben. Also z.B. libA_1 und libA_2.

    mfg Martin



  • Deine Idee hatte ich auch schon, aber die finde ich, wie du ja auch sagst, nur halbwegs akzeptabel. Gibt es wirklich nichts Schöneres?

    Ich frag mich immer wie andere sowas lösen. Die müssen doch solche Probleme auch haben.



  • abhänger schrieb:

    Immer auf Abwärtskompatibilität zu achten ist keine Option, geht es auch anders?

    Was spricht gegen die Option bei einem breaking Change LibB und die Applikation beide neu auszuliefern? Dann entsteht nie die Situation das LibB und die App unterschiedliche Versionen von LibA brauchen.



  • Sowas sollte auch nie auftreten, wenn LibB ebenfalls Teil der Applikation ist. In so einem Fall ist immer die ganze Applikation neu auszuliefern.

    Wobei ich den Ansatz noch fataler finde, aus mehrfach verwendeten Assemblies eine Klasse oder Methode zu löschen. Nehme man ganz einfach mal an, man hat eine Assembly die in 100 Programmen zum Einsatz kommt. - Nun wird da einfach eine Klasse weggeworfen. - War das dann so klug?



  • abhänger schrieb:

    Wie könnte ich das Problem lösen?

    Ziemlich einfach: In der Applikation Version 0.0.1 verwenden und in libB Version 0.0.2... 😉

    Ich hoffe doch sehr, dass nicht die Applikation sowohl libA als auch libB braucht? In dem Fall liegt da imo rein prinzipiell einiges bei dir im Argen und du solltest das Problem fixen, anstatt die Symptome zu bekämpfen.

    Ansonsten: http://msdn.microsoft.com/en-us/library/windows/desktop/dd408052.aspx



  • dot schrieb:

    Ziemlich einfach: In der Applikation Version 0.0.1 verwenden und in libB Version 0.0.2... 😉

    Dann müsste ich mit meiner Applikation beide Versionen der libA ausliefern. Des stört mich irgendwie.

    dot schrieb:

    Ich hoffe doch sehr, dass nicht die Applikation sowohl libA als auch libB braucht?

    Doch. In libA sind allgemeine Funktionen, die auch andere Applikationen brauchen. In libB sind Funktionen, die wiederum Funktionen aus libA benötigen, aber die an sich nur für zwei bestimmte Applikationen benötigt werden.

    dot schrieb:

    Ansonsten: http://msdn.microsoft.com/en-us/library/windows/desktop/dd408052.aspx

    Schau ich mir mal an, danke.



  • liber schrieb:

    dot schrieb:

    Ich hoffe doch sehr, dass nicht die Applikation sowohl libA als auch libB braucht?

    Doch. In libA sind allgemeine Funktionen, die auch andere Applikationen brauchen. In libB sind Funktionen, die wiederum Funktionen aus libA benötigen, aber die an sich nur für zwei bestimmte Applikationen benötigt werden.

    Ok, das ist schwer kaputt, fix it.



  • dot schrieb:

    Ok, das ist schwer kaputt, fix it.

    Das "Wie" ist die Frage. Wie kann ich die Abhängigkeiten auflösen?



  • "Fix it" heißt in dem Fall: Mach es so, dass libA und die Anwendung die selbe Version von libB brauchen.



  • Man kann auch explizit versionieren.

    Also LibA müsste das in diesem Fall unterstützen.
    Das .NET Framework bietet da möglicherweise Support dafür an - falls es geht schätze ich wird es etwas mit den "strong names" zu tun haben. Hab' mich aber mit dem Thema noch nicht näher befasst, kann sein dass ich da grob daneben liege.

    Was immer geht, mit jeder Programmiersprache: Die Version in den Namespace und Assembly-Namen aufnehmen.
    Also du hast dann "LibA1.dll" mit dem Namespace "LibA1" und "LibA2.dll" mit dem Namespace "LibA2" etc.

    Verschiedene Programmteile können dann leicht verschiedene Versionen von LibA verwenden.

    Probleme kann's dabei nur mit "globalen" Daten geben - also statischen Membern etc.

    Wenn man bei der Entwicklung von LibA aber rücksicht nimmt dass es mehrere verschiedene "Kopien" der "selben" Klassen geben könnte (die dann natürlich auch unabhängige statische Member haben), dann geht das schon.

    Oder der Mittelweg: Wenn es an LibA 'was zu ändern gibt, was zu einer inkompatibilität führen würde, dann wird statt einer Änderung eine neue Klasse gemacht. Oder ein neues Interface. Oder was auch immer. Und die alten Sachen bleiben dann einfach in LibA erhalten, damit ältere Programme oder Programmteile sie verwenden können.
    Ist aber auch nicht ganz einfach, dabei kann man schnell was übersehen. Bzw. es führt durch Abhängigkeiten zwischen den einzelnen Klassen sehr schnell dazu dass man sehr viele Klassen verdoppeln muss, obwohl die "eigentlichen" Änderungen die man machen wollte gar nicht so viele sind.



  • hustbaer schrieb:

    Das .NET Framework bietet da möglicherweise Support dafür an - falls es geht schätze ich wird es etwas mit den "strong names" zu tun haben. Hab' mich aber mit dem Thema noch nicht näher befasst, kann sein dass ich da grob daneben liege.

    Also wie ich die Strong Named Assemblies verstanden habe, sind die dafür da, dass man sicher sein kann, dass niemand anders eine Assembly mit gleichem Namen veröffentlichen und die einem dann "unterjubeln" kann. Die Assembly wird digital signiert und dadurch kann man nur mit dem passenden Private Key die richtige Assembly erstellen.[/quote]

    hustbaer schrieb:

    Was immer geht, mit jeder Programmiersprache: Die Version in den Namespace und Assembly-Namen aufnehmen.
    Also du hast dann "LibA1.dll" mit dem Namespace "LibA1" und "LibA2.dll" mit dem Namespace "LibA2" etc.

    Verschiedene Programmteile können dann leicht verschiedene Versionen von LibA verwenden.

    Ist das so gängige Praxis? Hast du ein Beispiel, wo das so umgesetzt ist? Die Idee an sich finde ich ja nicht schlecht - wurde auch schon öfter vorgeschlagen. Noch besser ist es aber natürlich, wenn es schon jemand erfolgreich umsetzt.

    hustbaer schrieb:

    Probleme kann's dabei nur mit "globalen" Daten geben - also statischen Membern etc.

    Wie meinst du das? Der (die? das?) statische Member ist ja in der Klasse, die wiederum im richtigen Namespace liegt. Und ohne Namespace gibts in C# keine Variablen.

    Abwärtskompatibilität als Lösugn für mein Problem halte ich nicht für geeignet, hab ich aber ja schon in nem vorherigen Post gesagt.

    An der Stelle schon mal vielen Dank für die vielen Anregungen!



  • sharpler schrieb:

    hustbaer schrieb:

    Das .NET Framework bietet da möglicherweise Support dafür an - falls es geht schätze ich wird es etwas mit den "strong names" zu tun haben. Hab' mich aber mit dem Thema noch nicht näher befasst, kann sein dass ich da grob daneben liege.

    Also wie ich die Strong Named Assemblies verstanden habe, sind die dafür da, dass man sicher sein kann, dass niemand anders eine Assembly mit gleichem Namen veröffentlichen und die einem dann "unterjubeln" kann. Die Assembly wird digital signiert und dadurch kann man nur mit dem passenden Private Key die richtige Assembly erstellen.

    Und man kann sie in den GAC installieren. Auch mehrere Versionen parallel.
    Ich dachte dass es dann vielleicht möglich ist dass verschiedene Programmteile verschiedene Versionen "anfordern".
    Wo ich jetzt nochmal drüber nachdenke ... das kann eigentlich gar nicht funktionieren. Denn der Name der Klasse ist ja nach wie vor in allen Versionen "LibA.KlasseX2" - und davon darf es pro AppDomain vermutlich nur eine geben.

    sharpler schrieb:

    hustbaer schrieb:

    Was immer geht, mit jeder Programmiersprache: Die Version in den Namespace und Assembly-Namen aufnehmen.
    Also du hast dann "LibA1.dll" mit dem Namespace "LibA1" und "LibA2.dll" mit dem Namespace "LibA2" etc.

    Verschiedene Programmteile können dann leicht verschiedene Versionen von LibA verwenden.

    Ist das so gängige Praxis?

    Ja. Beispiel kann ich dir aber keins anbieten. Ist aber klar dass es geht - ist ja genau das selbe wie wenn LibA1 und LibA2 zwei komplett unabhängige Libraries wären. Und die kann man ja auch gleichzeitig verwenden.

    sharpler schrieb:

    hustbaer schrieb:

    Probleme kann's dabei nur mit "globalen" Daten geben - also statischen Membern etc.

    Wie meinst du das? Der (die? das?) statische Member ist ja in der Klasse, die wiederum im richtigen Namespace liegt. Und ohne Namespace gibts in C# keine Variablen.

    Es könnte dann problematisch werden, wenn sich die Libaray darauf verlässt dass es diese statischen Member nur 1x gibt.
    Stell dir ne Library vor die genau einen Worker-Thread für irgendwelche Background-Jobs verwendet, damit diese Jobs die Zugriffe auf "ihre" Daten nie synchronisieren müssen.
    Wenns jetzt zwei Versionen von LibA gibt, dann gibt's auf einmal auch zwei Worker-Threads.
    Wenn die Verwendung von LibA1 und LibA2 in voneinander komplett unabhängigen Programmteilen ist, dann wird das eh kein Problem sein.
    Wenn die Background-Tasks die in diesen Programmteilen entstehen aber auf die selben Daten zugreifen, dann könnte es schon ein Problem geben.



  • abhänger schrieb:

    Immer auf Abwärtskompatibilität zu achten ist keine Option, geht es auch anders?

    Naja, das Erhalten von Schnittstellenkompatiblität macht man ja nicht ohne Grund. Du hast nur gerade eines der schweren Probleme von festen Versionsabhängigkeiten entdeckt, dessen Auswirkungen auch für den Entwickler spürbar sind. Der Rest mag für den Entwickler nicht so schlimm sein (d.h. einfach genaue Version x.y.z verlangen), sind aber die Hölle für die Leute, die das von dir entwickelte System mal deployen und sicher administrieren sollen.

    Ein möglicherweise Abhilfe schaffendes Konzept, von anderen hier bereits angesprochen, wird in der Literatur als "Symbol Versioning" bezeichnet. Die NET-Implementierung davon, wenn vorhanden, läuft vielleicht unter einer abweichenden Bezeichnung.

    Das entsprechende Paper findest du hier:
    http://www.usenix.org/publications/library/proceedings/als00/2000papers/papers/full_papers/browndavid/browndavid_html/index.html

    Das ganze bringt, neben der nicht zu vernachlässigenden Komplexitätssteigerung (google "Versioned Symbols – A New Level of Hell"), eine Problematik mit sich, die Hustbär schon ausgeführt hat: die Handhabung von globalem Zustand. Das ist ein Problem, das sich für den allgemeinen Fall nicht lösen lässt. Hier ist Einblick in die beim Schreiben der Librarys getroffenen Annahmen gefordert.

    Meine Meinung: überleg dir nochmal, ob du dir über Schnittstellenkompatiblität nicht doch einmal Gedanken machen willst. Es ist einfach "good engineering practice". Wenn du nach Analyse zum Entschluss gekommen bist, dass Kompatiblität nicht praktikabel ist, ist das ja ok. Es wirkt allerdings nicht so, als hättest du dir überhaupt Gedanken darüber gemacht. Eure Sysadmins werden es dir ebenfalls danken.

    dot schrieb:

    Ich hoffe doch sehr, dass nicht die Applikation sowohl libA als auch libB braucht? In dem Fall liegt da imo rein prinzipiell einiges bei dir im Argen und du solltest das Problem fixen, anstatt die Symptome zu bekämpfen.

    Deine nächsten Beiträge lassen vermuten, dass du schon das richtige meintest, aber trotzdem nochmal zur Klarstellung: das Problem ist nicht, dass das Programm libA und libB (die ihrerseits von libA abhängt) benötigt. Sowas ist absolut gängig. Das Problem liegt darin, dass jeder nur mit spezifischen Versionen der Library kann und das ganze dann noch innerhalb eines Programms existieren soll.



  • harmful schrieb:

    Das Problem liegt darin, dass jeder nur mit spezifischen Versionen der Library kann und das ganze dann noch innerhalb eines Programms existieren soll.

    So lange es nur innerhalb eines Programms ist, die LibA- und LibB-verwendenden Stellen aber nicht untereinander LibA-Daten austauschen müssen, sehe ich kein echtes Problem.


Anmelden zum Antworten