folgendes ist mir mal kurz real begegnet, habe ich aber dann anders
gemacht bzw.l gar nicht gemacht. Trotzdem - aus rein akedemischen -
Interesse:
Gegeben sein eine Klasse A im Jarfile A_1.jar.
Mit folgender relevanter Signatur:
--------------------------
class A{
public void init();
public int f1();
}
--------------------------
Entscheident ist, dass ich f1() aufrufen möchte aber vorher mit init()
die Klasse initialisieren muss.
Mein Quellcode:
--------------------------
import a.A;
...
A a = new A();
a.init();
...
int result = a.f1()
--------------------------
Nun gibt es eine neue Version dieses jar-Files A_2.jar. In dieser wird
die Initalisierung irgendwie anders gemacht. Jedenfalls nicht mehr
init() explizit aufgerufen. Noch schlimmer, die init() Funktion gibt es
nicht mehr. A sieht jetzt so aus:
--------------------------
class A{
public int f1();
}
--------------------------
Der Compiler beschwert sich zurecht über den a.init() - Aufruf.
Mein Code soll aber auch mit der alten Library A_1.jar laufen.
In C käme jetzt der Präprocessor zu Zuge:
#ifdef VERSION_1
a.init();
#endif
In Python genügt eine einfache if-Anweisung:
if version == VERSION_1:
a.init()
In Java fallen mir nur zwei Lösungen ein:
Parallel zur Bibliothek zwei Versionen meiner eigenen Klasse vorhalten
oder zwei Versionen einer Warpperklasse. Man müsste also immer
zusätzlich zur A-Bibliothek, ein A-Wrapper.jar (a.class) ausliefern.
Fehleranfällig.
Oder man arbeitet mir Reflections und prüft aus das Vorhandensein einer
Funktion init(), die man gegebenfalls über Reflections dann aufruft.
U.U. nicht performant. Bei einer init()-Funktion wird es aber meist gehen.
Geht's auch eleganter?
Es geht noch dreckiger:
try {
a1.init();
} catch (NoSuchMethodError e) {
//do nothing
}
*hust*
Das kompiliert natürlich nur gegen die Version 1 von der Library.
> Es geht noch dreckiger:
Ich bin der letzte der was gegen "Dreck" hat, solange der Dreck
irgendwie "elegant" ist.
> try {
> a1.init();
> } catch (NoSuchMethodError e) {
> //do nothing
> }
>
> *hust*
> Das kompiliert natürlich nur gegen die Version 1 von der Library.
Das ist aber genau das Problem!
Es soll mit beiden Versionen compilieren.
Wäre es eine Option für Dich, den Aufruf selbst zu kapseln, sozusagen eine
Fassade zu erstellen und diese in eine eigene jar zu stellen? Dann kannst
Du für jede Version der lib eine Version der Fassaden erstellen und je
nachdem, welche Version Du willst, bindest Du lib1 und fassade1 oder lib2
und fassade2 ein. Den Rest des Programms benutzt die Schnittstellen Deiner
Fassade und die bleiben gleich.
Raymund
> Noch schlimmer, die init() Funktion gibt es
> nicht mehr. A sieht jetzt so aus:
> --------------------------
> class A{
> public int f1();
> }
> --------------------------
Der wohl üblich Weg bei APIs ist es wohl veraltete Methoden als solche
zu markieren, sie so umzustricken das beim Aufruf und mehr oder weniger
die neue Variante angestossen wird -- aus dem hier geschilderten Grund
-- nicht aus der Klasse zu entfernen.
Denn unabhängig vom Compilerfehler, muss der Aufrufer ja ggf.
andere/neue Methoden benutzen um das zu erreichen, das er vorher mit der
initMethode gemacht hat.
Die Klasse in der Lib müsste also so aussehen.
-----------------------
class A {
/** @deprecated use fz() instead */
@Deprecated
public void init() {
fz();
}
public int f1();
public void fz();
}
-----------------------
Wenn das nicht so ist, wird sie sich als Lib nicht durchsetzen -- eben
aus den von dir genannten Gründen. Wenn ich mich nicht darauf verlassen
kann, das mein bestehender Code auch mit neueren Varianten einer Lib
compiliert, werd ich sie nicht einsetzen.
Ich glaube Sun hat selbst die schlimmsten Sünden aus Java 1.0 bis heute
nicht aus der API geworfen.
bs
> Da kann man sich natürlich fragen welcher 8jährige die Lib programmiert
Leider hast du vor lauter Fragen nichts zum Thema erzählt.
Btw. die init()-Methode war ein aus den Fingern gesogenes Beispiel.
Völlig sinnfrei darüber zu diskutieren.
> Wäre es eine Option für Dich, den Aufruf selbst zu kapseln, sozusagen eine
> Fassade zu erstellen und diese in eine eigene jar zu stellen?
Diese Methode hatte ich selber schon erwähnt, ich nannte sie nur Wrapper
statt Fassade.
Problem dabei ist dass man immer zwei jars zueinander konsitent halten
muss. Klar, Maven kann einem das abnehmen aber wirklich schön ist es
nicht. Deshalb suchte ich nach einer eleganten Möglichkeit.
Es gäbe noch eine dreckige Methode:
Und zwar immer gegen die Variante mit init()-Methode compileren aber
sicherstellen, dass diese Funktion mit der Lib ohne init() nicht
aufgerufen wird. (mit if)
Doch:
> Der wohl üblich Weg bei APIs ist es wohl veraltete Methoden als solche
> zu markieren, sie so umzustricken das beim Aufruf und mehr oder weniger
> die neue Variante angestossen wird -- aus dem hier geschilderten Grund
> -- nicht aus der Klasse zu entfernen.
Soll die Library rückwärtskompatibel sein oder nicht? Wenn ja, dann darf
man public-Methoden nicht einfach so entfernen.
Gruß, Ivan
> Soll die Library rückwärtskompatibel sein oder nicht? Wenn ja, dann darf
> man public-Methoden nicht einfach so entfernen.
Das sind Fragen, mit denen ich mich als Anwender der Lib nicht
beschäftigen brauche. Ich muss mit den Folgen leben indem Fall, dass sie
nicht rückwärtskompatibel ist. Und dazu hast du nichts gesagt, sorry.
Ich weiss ja, es ist im Usenet üblich, auf eine konkrete Frage "wie
mache ich das und das?" erstmal infrage zu stellen, dass man "das und
das" überhaupt machen muss...;-)
Ich habe gesagt was der Weg für eine eine Java-übliche API ist. Denn du
verkennst das Problem: Nicht die offensichtlichen Compilerfehler sind
dein Problem -- die kann ich mit mehr oder weniger vertretbarem Aufwand
beheben -- sondern die subtileren Laufzeitfehler, die eben nicht so
schnell entdeckt und erst recht nicht behoben werden können.
Wenn es denn irgendwelche Tricks gäbe den Compiler auszutricksen, würde
dir das in keinster Weise helfen, sondern eher im Gegenteil den Schaden
noch vergrößern.
Wenn man sich auf Libs aus dubioser Quelle verlassen hat, bleiben einem
3 Wege: Entweder man kontaktiert die Entwickler um eine
abwärtskompatible Version zu erhalten, man liefert alte Programme mit
der alten Lib aus oder -- was ich in einem solchen Falle für den Besten
Weg hielte -- man beisst in den sauren Apfel und trennt sich von der
unzuverlässigen Lib.
Ob der Entwickler, der auf Zuruf mal eben schnell die vorher nicht
bedachte Abwärtskompatibilität schaffen soll das auch umfassend erreicht
ist mindestens fraglich.
Im übrigen ist die sorgfältige Auswahl von zuverlässigen Libs und
Distributoren durchaus ein Thema mit dem sich der Anwender der Lib
beschäftigen muss. Wenn man dies nicht getan hat, muss man eben die
Unzulänglichkeiten des Distributors ausbaden.
Ich halte das Problem aber für sehr konstruiert: Jeder der in der Lage
ist eine Lib zu schreiben, die 1) ausreichend mehrwert bringt um nicht
selbst implementiert zu werden und 2) zuverlässig genug erscheint um
eingesetzt zu werden wird auf Abwärtskompatibilität achten.
Was ist für dich eine Java-übliche API? Java ist doch eine
Programmiersprache und kein Konzept auf das man APIs erstellt. ;)
> Wenn man sich auf Libs aus dubioser Quelle verlassen hat, bleiben einem
> 3 Wege: Entweder man kontaktiert die Entwickler um eine
> abwärtskompatible Version zu erhalten, man liefert alte Programme mit
> der alten Lib aus oder -- was ich in einem solchen Falle für den Besten
> Weg hielte -- man beisst in den sauren Apfel und trennt sich von der
> unzuverlässigen Lib.
Wenn die alte Version nicht mehr gepflegt wird ist das durchaus wahr.
Lieber sein eigenes Projekt umstellen auf eine neue Version oder auf
eine langlebigere Software umsteigen wenn man keinen Aufwand haben will
als eine veraltete Version einzusetzen bei welcher Fehler oder schlimmer
Sicherheitslücken nicht mehr gefixt werden.
> Ich halte das Problem aber für sehr konstruiert: Jeder der in der Lage
> ist eine Lib zu schreiben, die 1) ausreichend mehrwert bringt um nicht
> selbst implementiert zu werden und 2) zuverlässig genug erscheint um
> eingesetzt zu werden wird auf Abwärtskompatibilität achten.
Abwärtskompatibilität bringt aber auch Altlasten mit sich. Es spricht
zum Beispiel ja nichts dagegen eine neue Version inkompatible zu machen,
wenn die alte Version weiterhin gepflegt wird, oder nicht? :)
Ein Produkt als schlecht zu deklarieren, nur weil es nicht
Abwärtskompatible ist halte ich jedenfalls für unsinnig.
--
Mit freundlichen Grüßen,
Christoph Herrmann
>Abwärtskompatibilität bringt aber auch Altlasten mit sich. Es spricht zum
>Beispiel ja nichts dagegen eine neue Version inkompatible zu machen, wenn
>die alte Version weiterhin gepflegt wird, oder nicht? :)
Richtig. Dann hat man aber als Hersteller der Lib seinen "Kunden"
gegenüber die Verpflichtung ihnen die Migration zu erleichtern, und dazu
gehören dann mindestens mal Dokus zu den inkompatiblen Änderungen und wie
man als Anwender der Lib damit umgehen soll. Da TT hier fragt, ist sein
Lib-Hersteller dieser Verpflichtung offenbar nicht nachgekommen.
Daher kann man sehr wohl, wie Ben das tut, auf die Qualität der Lib
schließen und anraten, sich möglichst von ihr zu trennen. Ich meine heute
muss TT vielleicht nur um eine verschwundene Methode herumarbeiten, doch
was brockt ihm der Lib-Hersteller dann als nächstes ein? An seine Kunden
und somit an TT scheint der Hersteller jedenfalls keine Gedanken zu
verschwenden.
cu
Ist das nicht vom Vertrag abhängig? ;) In der Open Source Welt kenne ich
zumindest keine solche Klausel, dass man sich zu so etwas verpflichtet.
Klar sollte man es einem Kunden so einfach wie möglich gestalten, das
bestreite ich ja nicht, was dann ein Handbuch wie du es schreibst für
den Versionswechsel einschließt.
> Daher kann man sehr wohl, wie Ben das tut, auf die Qualität der Lib
> schließen und anraten, sich möglichst von ihr zu trennen. Ich meine
> heute muss TT vielleicht nur um eine verschwundene Methode
> herumarbeiten, doch was brockt ihm der Lib-Hersteller dann als nächstes
> ein? An seine Kunden und somit an TT scheint der Hersteller jedenfalls
> keine Gedanken zu verschwenden.
Wenn ein Lib-Hersteller eine alte Version nicht mehr pflegt und eine
Migration nicht unterstützt, dann ist das für mich auch ein Grund dies
als schlechte Qualität zu beschreiben.
Ich bin aber abgeneigt zu sagen, dass alles was nicht Abwärtskompatible
entwickelt wird gleich schlechte Qualität ist. Solange keine
Notwendigkeit besteht, dass ein Kunde migriert (also Fehler weiterhin
behoben werden) und bei einer Migration geeignete Hilfsmittel zur
Verfügung stehen diese mit geringem Aufwand zu machen sehe ich zumindest
kein Problem darin.
> Abwärtskompatibilität bringt aber auch Altlasten mit sich. Es spricht
> zum Beispiel ja nichts dagegen eine neue Version inkompatible zu machen,
> wenn die alte Version weiterhin gepflegt wird, oder nicht? :)
Das Problem ist, dass alte Versionen eben nicht mehr gepflegt werden
bzw. nach paar Jahren aus der Maintenance fallen.
Bei Projekten, die über mehrere Jahre (also so ab 5-10 Jahre) gepflegt
werden sollen, ist das gar nicht mehr so einfach.
Drum haben wir unseren Core über die Jahre komplett von Drittprodukten
bereinigt (dh. eigene Webserversoftware, eigene Servletengine, eigene
MVC-Tools) und uns auf wenige Features der JVM beschränkt. Wenn externe
Tools benötigt werden, dann sind das Kundenspezifische Ausnahmen.
> Ein Produkt als schlecht zu deklarieren, nur weil es nicht
> Abwärtskompatible ist halte ich jedenfalls für unsinnig.
Sagen wir es mal so: irgendwann hechelt man nicht mehr jedem neuen Wind
hinterher sondern möchte einfach seine Arbeit möglichst stressfrei
erledigen. Und dazu kann man alles gebrauchen, aber nicht mehr sowas :-)
Bernd
--
Unsere Identität entnehmen Sie bitte dem beigefügten Auszug aus
den Personenstandsbüchern. Gegen die Assimilierung in unser
Kollektiv ist nach dem ABGB (§66.4) kein Rechtsmittel zulässig.
Das sehe ich ein. Aber die andere Seite wäre halt Altlasten jahrelang
mitzuschleifen um Abwärtskompatibilität beizubehalten was ebenfalls zu
Problemen führt. Also muss man irgendwo seine Prioritäten legen.
Vielleicht so eine Strategie wie Ubuntu fahren. Die aktuelle Versionen
werden einen festen Zeitraum lang gepflegt und alle Zeit lang gibt es
eine Version, die über einen langem Zeitraum gepflegt wird. Wichtig
finde ich es vor allem im voraus zu wissen, wie lang etwas gepflegt
wird, bevor ich es wirklich einsetze.
> Drum haben wir unseren Core über die Jahre komplett von Drittprodukten
> bereinigt (dh. eigene Webserversoftware, eigene Servletengine, eigene
> MVC-Tools) und uns auf wenige Features der JVM beschränkt. Wenn externe
> Tools benötigt werden, dann sind das Kundenspezifische Ausnahmen.
Jep, aus dem Grunde mache ich mir auch gerne eigene kleine Frameworks.
Weil ich eben gern unabhängig bin und die Dinge so anpasse, wie ich es
haben will (außerdem lernt man dabei mehr, als wenn man ein Produkt nur
nutzt, was mir wichtiger ist derzeit).
> Sagen wir es mal so: irgendwann hechelt man nicht mehr jedem neuen Wind
> hinterher sondern möchte einfach seine Arbeit möglichst stressfrei
> erledigen. Und dazu kann man alles gebrauchen, aber nicht mehr sowas :-)
Wer jedem neuen Wind hinterher rennt, der muss auch flexible sein in
solchen Sachen würde ich sagen. :)
>> Bei Projekten, die über mehrere Jahre (also so ab 5-10 Jahre) gepflegt
>> werden sollen, ist das gar nicht mehr so einfach.
>
> Das sehe ich ein. Aber die andere Seite wäre halt Altlasten jahrelang
> mitzuschleifen um Abwärtskompatibilität beizubehalten was ebenfalls zu
> Problemen führt. Also muss man irgendwo seine Prioritäten legen.
Das hängt immer davon ab, wieviele Projekte davon betroffen sind. Hier
setzen paar Dutzend Grossprojekte auf unser Framework auf und da bin ich
mit Änderungen im Framework sehr knauserig. Wobei es natürlich einfacher
ist, ein eigenes Framework + eigene Applikationen parallel zu pflegen.
> Vielleicht so eine Strategie wie Ubuntu fahren. Die aktuelle Versionen
> werden einen festen Zeitraum lang gepflegt und alle Zeit lang gibt es
> eine Version, die über einen langem Zeitraum gepflegt wird.
So einfach ist das nicht: Du hast zb. 1 Webserver in dessen Kontext
mehrere Servlets laufen die sich alle auf das gleiche Framework stützen.
Ich bin immer wieder erstaunt, was alles so wegknallt wenn man meint,
dass man wirklich alle Anwendungen auf die neue Version migriert hat.
Im Moment machen wir es so, dass wir paar Webserver haben die alle mit
unterschiedlichen Ständen arbeiten und eine Applikation sozusagen
eingefroren wird bis der Kunde sagt "ok, ich bezahle die Migration" (was
kaum einer macht - erhöhter Wartungsaufwand ist optisch erstmal weniger
Geld als die Kosten für eine Migration).
>> Sagen wir es mal so: irgendwann hechelt man nicht mehr jedem neuen Wind
>> hinterher sondern möchte einfach seine Arbeit möglichst stressfrei
>> erledigen. Und dazu kann man alles gebrauchen, aber nicht mehr sowas :-)
>
> Wer jedem neuen Wind hinterher rennt, der muss auch flexible sein in
> solchen Sachen würde ich sagen. :)
So nett hat mir noch niemand gesagt, dass ich ein alter Sack bin *fg*
Sagen wir es mal so: vor paar Jahren hatte ich noch die Ressourcen, bei
jedem Trend dabei zu sein. Aber irgendwann schleppt man einfach soviele
Alt-Projekte hinter sich her, dass einfach eine Konsolidierung
stattfindet und man nur wechselt, wenn man das Gefühl hat damit für die
nächsten 10 Jahre in Ruhe gelassen zu werden.
Und warum benutzen so viele eigentlich noch Winzigweich Fenster
und Winzigweich Büro?
Prinzipiell ist deprecated die bessere Alternative aber eine
Garantie für Version x+5 ist es dennoch nicht. Software soll
sich weiterentwickeln dürfen und sich auch irgendwann mal von
Altlasten befreien können.
Geh mal gedanklich zurück, schreibe unter Java 1.2 ein Swing GUI
und mach dann den Upgrade auf Java 1.4 - viel Spass. Es liegt in
der Eigenverantwortung, sich für oder gegen etwas zu entscheiden.
Nichts ist für die Ewigkeit. Und eine API oder ein Framework
kann nur das heute bedienen - selten aber die Anforderungen, die
morgen entstehen, weil sich völlig neue Möglichkeiten eröffnet
haben. Cest la vice.
Alfred
Darf man fragen wie ihr die gigantischen Entwicklungskosten
wieder reingeholt habt? Etwa durch völlig überteuerte Produkte?
Vielleicht sind aber auch nur deine Beispiele schlecht gewählt.
Zumindest würde ich Web- und/oder Enterprise-Container, die sich
an die Spec halten, ganz sicher nicht neu entwickeln. _Vielleicht_
fällt euch aber auch die Verwendung offener Architekturen und
Standards schwer. Laufen z.B. eure Webanwendungen auch unter Tomcat,
JBoss, BEA, WAS, Glassfish etc. getreu dem Motto: develop once -
deploy anywhere?
> Sagen wir es mal so: irgendwann hechelt man nicht mehr jedem neuen Wind
> hinterher sondern möchte einfach seine Arbeit möglichst stressfrei
> erledigen. Und dazu kann man alles gebrauchen, aber nicht mehr sowas :-)
Das hängt sicher vom Anwendungsrahmen ab, es gibt gute und weniger gute,
sinnvolle und weniger sinnvolle - aber ganz sicher keine perfekten API's
oder Libs oder Frameworks. Und Software ist eigentlich nie wirklich
fertig - immer nur für den Moment oder ein bestimmtes Release.
Alfred
Das dürfte ein ziemlicher Irrglaube sein, es sei denn die Uhren
bleiben stehen.
Alfred
Das muss nicht immer teuer sein. Sich mit Bugs in externer Software
herumzuschlagen, oder mit schwachsinnigen Lizenzen (wenn ich mir nur
vorstelle was uns die Advertising clause kostet) bringt auch kosten.
Zwar hat Homegrown nicht immer die bessere TCO, aber es gibt durchaus viele
Situationen wo das geht. Obwohl es natürlich grade unter Java den Trend zu
third party (oss) libs gibt.
Gruss
Bernd
>Und warum benutzen so viele eigentlich noch Winzigweich Fenster
>und Winzigweich Büro?
Weil Microsoft es versteht hervorragend zu sich selbst kompatibel zu
sein*. Kommt dann noch hinzu, dass man zur Konkurrenz inkompatibel ist,
nennt man das auch Lock-In. Und das ist der Grund, warum MS-Software noch
so sehr im Einsatz ist.
Man kann über Microsoft sagen was man will, aber sie ebnen ihren Kunden
auf jeden Fall den Weg zu den eigenen Produkten, und in diesem Sinne
handeln sie wie der von mir angesprochene verantwortungsvolle
Lib-Hersteller, und daher verdient sich Microsoft eine goldene Nase.
cu
*) Aus Sicht des Endanwenders! Für Entwickler sind die wechselhaften
MS-Bibliotheken eher eine Zumutung, aber der Markt ist zu attraktiv, um an
dieser Stelle den von mir empfohlenen Bibliotheken-Snobismus
durchzuhalten, also heißt es sich durchbeißen. Dagegen gibt es unter Java
zu beinahe jedem Problem gleich ein Dutzend Bibliotheken und damit im
Interesse der eigenen Effizienz genug Raum für Snobismus.
>> Drum haben wir unseren Core über die Jahre komplett von Drittprodukten
>> bereinigt (dh. eigene Webserversoftware, eigene Servletengine, eigene
>> MVC-Tools) und uns auf wenige Features der JVM beschränkt. Wenn externe
>> Tools benötigt werden, dann sind das Kundenspezifische Ausnahmen.
>
> Darf man fragen wie ihr die gigantischen Entwicklungskosten
> wieder reingeholt habt? Etwa durch völlig überteuerte Produkte?
Naja, wenn Du einen Webserver und Servletcontainer mit definierten
Funktionen als "gigantischen Entwicklungsaufwand" bezeichnest...
> Laufen z.B. eure Webanwendungen auch unter Tomcat, JBoss, BEA, WAS,
> Glassfish etc. getreu dem Motto: develop once - deploy anywhere?
Bestimmt. Aber warum sollte jemand sowas wollen? :-)
Bernd
>> Darf man fragen wie ihr die gigantischen Entwicklungskosten
>> wieder reingeholt habt? Etwa durch völlig überteuerte Produkte?
>
> Das muss nicht immer teuer sein. Sich mit Bugs in externer Software
> herumzuschlagen, oder mit schwachsinnigen Lizenzen (wenn ich mir nur
> vorstelle was uns die Advertising clause kostet) bringt auch kosten.
Wenn man nur paar Brocken aus den Engines braucht, ist man recht schnell
fertig mit der Programmierung - vorausgesetzt, man hat die benötigten
Parts mehr oder weniger schon in der Schublade liegen.
Ein Webserver, der rudimentäre Servletfunktionen bringt, ist daher keine
Hexerei. Und wenn man das gleich so Programmiert, wie es dem typischen
Anwendungsfall entspricht, hat man kaum noch Aufwand bei der
Implementierung.
Gerade weil es komplett Homegrown ist und man die Sourcen kennt, ist man
natürlich recht schnell in der Adaption für besondere Einsatzzwecke.