Einbinden von Bibliotheken – Auf der Suche nach dem Königsweg.
Wer viel arbeitet steht auch vor vielen Problemen. Da ich im Moment nur ein Problem habe, schließe ich mal drauf, dass die andere Richtung nicht stimmt. Ich hoffe irgendjemand hat den „Witz“ verstanden. Aber eigentlich auch egal. Mein Ego ist da groß genug. So fangen wir an.
Es wird immer und überall davon berichtet, dass es doch ganz toll ist wenn man Code nicht selbst schreibt, sondern sich auf schon geschriebenen und für gut befundenen Code berufen soll. Klingt erstmal super. Nehmen wir also an, wir bauen eine Applikation, die auf einem anderen Rechner einen Trigger anstößt. Wir sind übrigens grad bei den doofen, aber anschaulichen Beispielen angelangt. Jetzt wollen wir also einen HTTP-Request senden. Dazu nehmen wir das Zend Framework und dort die Zend_Http_Client -Klasse. Übrigens eine sehr gute Implementierung, wie ich finde.
Jetzt haben wir mehrere Möglichkeiten die Bibliothek einzubinden:
- Kompletter Einbau: Wir schmeißen einfach das komplette Zend Framework mit in die Applikation. Vorteil ist, wir haben keine Abhängigkeiten, die wir auflösen müssen. Auch in Zukunft können wir einfach weitere Funktionalitäten der Bibliothek nutzen, ohne weiteren Aufwand zu haben. Nachteil ist: das Ding ist riesig. Das Zend Framework besteht aus hunderten von Dateien, die Größe ist auch nicht zu verachten. Ein Deployment kann somit um einiges länger dauern, denn der Source Code ist wahrscheinlich als external mit im SVN oder ähnliches.
- Partieller Einbau: Wir schnappen uns nur die Klassen, die wir auch tatsächlich brauchen. Vorteil ist, dass wir eine sehr schlanke Lösung haben unsere Applikation wird nicht künstlich aufgeblasen und das Deployment geht ratz-fatz. Nachteil ist, dass wir das Stück Code rauslösen müssen, das wir benötigen und ich glaube, dass dies keinen Spaß macht. Das müssen wir dann auch immer machen, wenn man Funktionalität braucht. Dabei hätte ich auch Angst, dass Plugin1 Teile aus dem ZF 1.10 benutzt und Plugin 2 1.11. Wäre blöd, wenn die Versionen auseinanderlaufen.
- Externe Lagerung: Wir packen die Bibliothek einfach neben die Applikation. Vorteil ist, dass wir den sich doch nie ändernden Source-Code nicht immer mitdeployen brauchen. Die Applikation wird dadurch zwar nicht schlanker, da die Abhängigkeit ja trotzdem existiert, aber es fühlt sich leichtgewichtiger an. Nachteil ist, dass man nicht mehr über einen zusammenhängenden „Klumpen“ Source-Code redet. Es müssen externe Bibliotheken installiert werden und ein einfaches svn co reicht nicht mehr um eine funktionierende Applikation zu haben.
- Phar-Archiv: Gehen wir mal davon aus, dass es nicht die Größe der Bibliothek ist, die uns Probleme macht, sondern die Masse von Dateien. In dem Fall könnte man versuchen das Zend Framework in ein phar-Archiv zu packen und dieses zu deployen. Nachteil von Phar-Archiven ist, dass man nicht mehr wirklich browsen kann. Um ehrlich zu sein, ist das jetzt aber nur eine Vermutung, da ich mit phar und PDT noch nie wirklich gearbeitet habe.
Das waren jetzt die Alternativen, die mir „spontan“ eingefallen sind. Ich tendiere bei den Projekten, die ich so aufsetze zur ersten Lösung. Wie oft deployed man denn? Zwei mal die Woche vielleicht und dann macht es keinen Unterschied, ob es dann dich 10min länger dauert. Dafür hat man alle Vorteile der Bibliothek.
Wir seht ihr das? Welche der Lösungen lacht euch am ehesten an oder habt ihr vielleicht einen Weg, den ich noch nicht gefunden habe?
Guten Morgen,
ideal finde ich die Lösung die Library auszulagern und für alle Anwendungen zu nutzen bei Bedarf. Hier muss allerdings der Admin mitspielen und die Librarys auch updaten und aktuell halten.
Als Variante 2, ganz klar die Library mit der Anwendung deployen, selbst mit meiner kleinen DSL Leitung ist es doch kein Thema mehr die paar MB auf einen Server zu schieben?
Ich benutze auch (fast) immer die erste Version, für mich ist es wirklich kein Problem, dass deployen dann ein wenig länger dauert.
Oft ersteres. Bei dem Zend Framework kann man aber auch sehr gut nur einzelne Pakete herausnehmen, die Abhängigkeiten sind alle sehr gut dokumentiert und das zusammensuchen ist fix gemacht.
Ich habe mir vor kurzem die gleiche Frage gestellt. Unzufrieden mit Lösung 1 bin ich auf Lösung 3 umgestiegen. Bestärkt hat mich Punkt 3 unter folgendem Link: http://ganoro.blogspot.com/2010/09/five-more-tips-for-speeding-up-eclipse.html. Meistens ist es ja nicht nur das ZF was im lib Verzeichnis liegt. Da kommt noch PHPIDS, der HTMLPurifier die eigen Bibliothek, usw… Dann kann das mit der Build-Zeit ganz schön ausarten.
Also wir nutzen auch nur einen Bruchteil des gesamten Frameworks in den ganzen Projekten. Dennoch haben wir das komplette Framework als External im Repository liegen. Dadurch hat man immer alle Abhängigkeiten erfüllt. Und bei einem Update des Frameworks ändere ich nur das External und verlasse mich darauf, dass die Änderungen im Framework mit Hilfe der Unittests korrekt sind und freue mich, wenn ein Fehler in meinen verwendeten Komponenten behoben wurde. Da ich bereits Fehler im ZF-Ticketsystem gemeldet habe, weiß ich, dass die Entwicklung relativ flott ist. Das reicht für unsere Deploy-Zyklen für das Live-System meist aus.
Ich neige auch zu Variante 1.
Wir deployen mit Phing und dann macht es uns auch nichts aus, ob das 3 min länger dauert oder nicht. Dafür kann man sich aber sicher(er) sein, dass man alles in einem Paket hat und das nachher auch funktioniert. Früher benutzen wir Lösung 3 und hatten damit immer wieder Probleme,
Grüße
Bjoern
Irgendwie kann ich das Deploy-Argument nicht wirklich verstehen. Gerade wenn man Ant oder Phing benutzt sollte es doch ein leichtes sein die Bibliotheken mit auf den Server zu deployen.
Im Developement-Zyklus würde ich immer svn externals verwenden und im Deployment-Prozess mit Symlinks arbeiten damit brauche ich eben nicht immer alle Bibliotheken zu deployen. Will ich eine Bibliotek updaten muss ich eben den Symlink im Build-Prozess aktualisieren und die aktualisierte Bilbiothek entsprechend hochladen. Sehe da keinen signifikanten Nachteil im Gegensatz zu allen anderen Möglichkeiten.
Partieller Einbau: Ich muss immer wieder die Abhängigkeiten manuell selbst auflösen und pflegen. Unnötige Zeit.
Externe Lagerung: Bei einem Update der Bibiothek will ich nicht zwangsläufig alle Anwendungen auf diese Bilbiothek upgraden.
Phar-Archiv: Lösst nicht das Problem der Dateigrößen. Insbesondere auf dem Testing / Staging – System kann das schon nervend sein.
Zum Thema externe Bibliotheken möchte ich ein aktuelles Problem anbringen. Prinzipiell ist es ja schön, wenn man was einbindet, was gut dokumentiert ist und einen guten Programmierstil hat. Bei TCPDF ist dies leider nicht so. Es ist aber wiederum das einzige Tool, dass einem in einem Mehrspaltenlayout auch noch eine, wenn auch extern genutzte (shy-Tags) Silbentrennung hat. Nun versuche ich noch einen Bereich für z. B. ein Bild aus zu sparen. Und plötzlich verschwinden 2 Absätze. Nun ist es ja kein Problem in die Programmierung zu schauen, aber was man da sieht ist grauenvoll. ICh habe Respekt vor den Leuten, die Open Source entwickeln, aber wenn es so ungenügend dokumentiert ist, dann kommt man schon ins grübeln. Sorry war n bisschen off topic aber irgendwo muss man ja Frust ablassen. 😉
Persönlich tendiere ich zu Lösung 3, denn hier kann ich im Gegensatz zu den anderen Lösungen auch mehrere Versionen der Libraries vorhalten und verweise in der Applikation per Symlink auf die gewünschte.
(@Ulf: somit sind die anderen Applikationen vollständig selbständig in der Wahl der Bibliothek)
Wo es nicht möglich ist Symlinks zu setzen ist es meistens auch nicht möglich svn zu nutzen, dann muss man über die anderen Möglichkeiten nachdenken.
Ich tendiere nur im Notfall zu Lösung 2 – es sei denn, die Library stellt entsprechende Tools wie z.B. bei YUI oder jQuery zur Verfügung.
Für mich spricht nichts gegen Lösung 3. Ich lade die Libraries einmal hoch, und alle Projekte (manchmal hat man ja auch mehrere auf einem Webserver) können diese benutzen. Problematisch wird es dann wenn mehrere Projekte jeweils unterschiedliche Versionen der Libraries benötigen, was aber fast nie auftritt außer die Libraries brechen die Rückwärtskompatibilität. Dann würde es Sinn machen, für jedes Projekt ein eigenes Library Verzeichnis zu haben. Aber gegen das dauernde deployen sträubt sich was in mir, auch wenn es eigentlich keinen Grund dazu gibt, GIT kommt mit den paar Tausend Dateien ohne Probleme klar.
Wenn die Library nicht direkt im Projekt enthalten ist ist es auch unmöglich, etwas in der Library zu ändern (Bugs zu fixen). Das treibt einen an, den Bug lieber via Ableiten der Klasse zu beseitigen, was die bessere Lösung ist als in der Library rumzupfuschen.
Der partielle Einbau macht auch nur Sinn wenn man es mit ins Projektrepository steckt, um Platz zu sparen. PHP selbst stört es nicht wenn da noch viele ungenutzte Dateien rumliegen, die werden weder kompiliert noch sonst irgendwie beachtet. Wer noch SVN nutzt wird den Unterschied merken, bei GIT Benutzern werden die unnützen Dateien nicht auffallen.
Mit Phar habe ich auch noch keine Erfahrungen, ich weiß auch nicht ob APC damit gut klarkommt…
Was ist aus PEAR geworden? Das erscheint mir am ehesten dazu geeignet, solche Probleme zu lösen, wenn es denn genutzt würde.
Bei PEAR handelt es sich ja eher um die Art, wie deployed wird, die Abhängigkeiten legt der Entwickler ja selber fest. Andernfalls könnte man ja auch noch die verschiedenen Pakete (rpm, deb, usw.) in Betracht ziehen, da geht es aber auch nur um die Art des Deployments, die genauen Abhängigkeiten muss der Entwickler selber festlegen.
Stimmt. Ich habe nur PEAR in Betracht gezogen, da es plattformunabhängig und auf PHP spezialisiert ist.
Angenommen, man könnte bei seinem Projekt auf PEAR-Pakete zurückgreifen, dann könnte man aus seinem Projekt selbst ein PEAR-Paket erstellen. Das würde den Buildprozess wahrscheinlich vereinfachen und die Wiederverwendbarkeit erhöhen. Wenn man seine direkten Abhängigkeiten kennt, braucht man sich auch nicht mehr um die transitiven Abhängigkeiten zu kümmern, weil sie automatisch durch PEAR aufgelöst werden.
Meine Frage in einem Satz zusammengefasst: Warum wird PEAR nur vereinzelt genutzt?
@Andre: Ich glaube der Hauptgrund, warum man Pear nicht nutzt ist, dass es angestaubt wirkt und die ein echt mieses Marketing haben. Warum man den Installer von denen nicht nutzt? Keine Ahnung. Wahrscheinlich weil es ein zusätzlicher Schritt ist Pakete zu bauen, wenn man doch eben so gut einfach ein SVN auschecken kann. Außerdem ist es wahrscheinlich eher konzipiert um Softwareverteilung zu machen und nicht deployments.
@Andre: Ach ja, wir nutzen den Pear-Installer in der Firma. Rollen damit hausinterne Tools aus.
Im Zusammenspiel mit Phar könnte man auch an einen Deploy-Prozess mit Maven denken und Artefakte erstellen, die man dann z.B. mit Archiva verwalten kann. Aber auch da handelt es sich in der Regel um die Bereitstellung der kompletten Library.
Bezüglich PEAR denke ich auch, dass hier lange falsch bzw. schlecht kommuniziert wurde! Lange Zeit habe ich auch nichts von der Möglichkeit gewusst, eigene Pakete zu verwalten, ohne diese der gesamten Community zur Verfügung zu stellen.
Variante 3 scheint mir die beste. SymLinks bei Bedarf oder eben absolute Pfade verwenden (von Autoloadern per Bezeichnerkonvention halte ich eh nix). Ich sehe ehrlich gesagt auch nicht das Problem, hier mehrere Versionen einer Library zu benutzen. Abzuraten ist bei 3) natürlich davon, stets ein Update der verwendeten Library einzuspielen. Das sollte dann schon vorher für alle abhängigen Applikationen getestet sein. Weiterer positiver Nebeneffekt – auch lokal zur Entwicklung kann man unsäglich große Libraries von der Versionierung ausnehmen.
Übrigens kann man das selbe Prinzip selbstredend auch anwenden, wenn man selbst ein Framework entwickelt. Die Entwicklung kann parallel und eigenständig versioniert vorangetrieben werden, während bestimmte Anwendungen vielleicht noch die ältere stable einbinden.
@nik: zusätzlich kann man auch als Nebeneffekt beobachten, dass der Bedarf an Plattenplatz sinkt, je mehr Applikationen ein Framework benutzen.
Ferner möchte ich hier mal eine Brücke zu Javascript schlagen. Hier bietet sich für die Bereitstellung der JS-Frameworks ein CDN-Server an. Je mehr Applikationen darauf zugreifen, desto sinnvoller, da der Browser das bzw. die Frameworks dann cachen kann und das zu übertragende Datenvolumen sinkt. (Für manch einen Anbieter kann dass doppelt Sinn machen – dann, wenn er dadurch weniger Traffic zu zahlen hat.)