Open Source

Open Source

Posts 1-10 of 13
  • Francis Pouatcha
    Francis Pouatcha    Premium Member   Group moderator
    The company name is only visible to registered members.
    Spring 2.5 @Service vs. EJB3 @Stateless
    Hallo,

    hat sich jemand beide Technologien (Spring2.5, EJB3) angesehen. Warum sollte man sich für EJB3 (bzw. für Spring2.5) entscheiden?

    - Beide sind schlank genug.
    - Beide lassen sich in IDEs einbetten.
    - Beide bieten einfache Konfiguration über "@PersistenceContext".

    freue mich auf weitere Gemeinsamkeiten bzw. Unterschiede.

    Mit freundlichen Grüssen
  • User photo
    Herbert Fuchs
    (not a XING member)
    Re: Spring 2.5 @Service vs. EJB3 @Stateless
    Hallo Francis,


    bei einem aktuellen Projekt (-> red5) muß ich mich notgedrungen mit Spring befassen.
    Und "schlank" finde ich das überhaupt nicht. Im Gegenteil: sehr fett und schwerfällig.

    Es hat mich erstmal einige Tage gekostet, einen sauberen Build-Prozeß (incl. der
    zahllosen dependencies) hinzubekommen. Saubere Strukturierung sieht anders aus.

    Wenn dann auch noch immer mehr dynamisch configuriert (und zur Laufzeit gebaut)
    anstatt in compiler-prüfbaren Code programmiert wird, dann bekomme ich ein richtig
    mulmiges Gefühl in der Magengrube.

    Auf den ersten Blick sieht das ja alles ganz toll aus: viel flexibler, viel mehr wieder-
    verwendbar. Soweit so gut. Aber das ganze muß ja auch noch administriert werden !
    Wenn das Deployment (bei klassischen Anwendungen, zB. in C/C++, kaum mehr
    als ein paar Files ins target image kopieren, evtl. einmalig ein paar Configfiles anpassen)
    dann zu einem eigenen Projekt wird - auch bei einfachen updates (!) - dann sollte
    man sich wirklich fragen, ob man damit wirklich etwas gekonnt hat. Immer öfter
    verschiebt sich der großteil des Aufwands ledeglich von Entwicklung auf Deployment
    und Administration, nur daß einem hier der Compiler nicht mehr helfen kann, und
    per-instance Tests werden immer aufwendiger (codebase testen reicht dann vorn
    und hinten nicht mehr).

    Im Prinzip find ich's ja gut, wenn für bestimmte Zwecke eigene (sub-)Sprachen
    entwickelt werden, um Tipparbeit zu sparen. Aber dann bitte auch gleich so, daß
    alles auch maschinell validierbar ist und - nicht nur aus Performancegründen, sondern
    eben auch zwecks Robustheit - erstmal Sourcecode rauskommt, der dann durch
    den Compiler geht. DB-Pesistenz wäre zb. ein hervorragendes Beispiel.

    Wo sind die guten alten Build-Configs hin ? Wo die Code-Generatoren ?

    Richtig pervers wirds dann, wenn solche Dinge wie AOP (aka selbstmodifizierender
    Code ;-P) dazu kommen. So macht man die großen Errungenschaften von Java
    (insbesondere strikte Compiler-Prüfungen) einschließlich des "write once - run
    everywhere"-Paradigmum erfolgreich zunichte.


    Gruß
  • Siegfried Göschl
    Siegfried Göschl    Premium Member
    The company name is only visible to registered members.
    Re^2: Spring 2.5 @Service vs. EJB3 @Stateless
    Wo ist da irgendwas schlank - das schaut ganz anders aus, wenn man vor seinem JBoss sitzt .... ;-).

    Bei meinem letzten Projekt hatten wir hitzig darüber diskutiert und sind zu folgendem Conclusio gekommen

    +) wir bauen ein fette Applikation, d.h. Persistence, WebServices, Security, Interceptoren
    +) man kann das alles mit Spring machen/integrieren nur ist das schon recht aufwendig
    +) auch wenn es keiner hören mag - Spring ist proprietär - ist gut und auch nicht so gut (kämpfe regelmäßig mit Spring 1.2, 2.0, 2.5.x Dependencies in Maven Projekten)
    +) auf der EJB 3.0 Seite sind das Standardfunktionalitäten (mit funktionalen Einschränkungen im Vergleich zur Springlösung)
    +) fürs Testen hätte ich gerne einen "Embedded EJB Server", aber das entsprechende JBOSS Projekt hat nicht funktioniert und Glassfish 3.0 wollten wir auch nicht

    Also haben wir uns für EJB 3 entschieden - und das Projekt wurde eingestellt .... :-) ... ehrlicherweise lag das aber nicht an EJB

    Soo far, so good ...
    SIegfried Goeschl
  • User photo
    Herbert Fuchs
    (not a XING member)
    Re^3: Spring 2.5 @Service vs. EJB3 @Stateless
    Gutes Stichwort: maven.

    Ein hervorragendes Beispiel, wie man ein buildsystem soweit aufblasen kann,
    daß es nicht mehr handlebar ist und man mit handgeschriebenen Makefiles
    schneller zum Ziel kommt ;-o


    Gruß
  • Francis Pouatcha
    Francis Pouatcha    Premium Member   Group moderator
    The company name is only visible to registered members.
    Re^3: Spring 2.5 @Service vs. EJB3 @Stateless
    openejb3 bietet eine gute Alternative für die Einbettung von EJB3-Test in IDE (Eclipse/Idea) an. Alles nach Standard. Output läuft ohne großem Aufwand in anderen AppServer.

    Inkompatibilität von cglib Versionen zwischen openejb3 und hibernate. In openejb Beispielen findet man laufende Konfigurationen.

    Wir setzen es zur Zeit in einem Großprojekt mit erfolgt ein.

    Gruß.
    /Francis
  • Francis Pouatcha
    Francis Pouatcha    Premium Member   Group moderator
    The company name is only visible to registered members.
    Re^4: Spring 2.5 @Service vs. EJB3 @Stateless
    Hallo Herbert,

    Für kleine Projekte sehe ich ein, dass man mit make files schneller vorankommt.

    Um jedoch ein Projekt mittlerer Komplexität mit vertrettbarem Aufwand hinzubekommen (Antragsdatenbank mit n Formularen, Datenbankanbindung, PDF-Druck, Validierung), sind wir auf die Wiederverwendung angewiesen.

    Diese Wiederverwendung funktioniert nur wenn man sich auf bestimmte Verfahren einlässt (Spring, EJB3, JPA, maven, apache-Komponenten, ant, iText usw...).

    Glaubst du wirklich dass die make files und der Selbstbezug in der Java-Welt noch eine Chance haben.

    Gruß.
    /Francis
  • Oliver Gierke
    Oliver Gierke    Premium Member
    The company name is only visible to registered members.
    Re^2: Spring 2.5 @Service vs. EJB3 @Stateless
    Hallo Herbert,

    Herbert Fuchs schrieb:

    Es hat mich erstmal einige Tage gekostet, einen sauberen Build-Prozeß (incl. der
    zahllosen dependencies) hinzubekommen. Saubere Strukturierung sieht anders aus.

    Kann es sein, dass dir da eher das Buildsystem im Weg gestanden hat? Core Spring hat nur eine (!) Runtimedependency und das ist commons logging. Ein kleinstmögliches Springprojekt mit Maven besteht aus einer einzigen Dependencydeklaration (entweder org.springframework-spring, oder halt eine Teilbibliothek). Das sind vielleicht 10 Zeilen XML.

    Ich persönlich finde ein Dependencymanagement mit Eclipse oder Ant um Welten umständlicher.

    Wenn dann auch noch immer mehr dynamisch configuriert (und zur Laufzeit gebaut)
    anstatt in compiler-prüfbaren Code programmiert wird, dann bekomme ich ein richtig
    mulmiges Gefühl in der Magengrube.

    Laufzeit ist richtig, aber auch nicht ganz. Ein ApplicationContext wird logischerweise zur Laufzeit erzeugt, allerdings ist das in 99% der Fälle genau 1 mal am Start der Anwendung. Dieses Initialisieren überprüft die Konfiguration recht detailliert und gibt recht aussagekräftige Fehlermeldungen zurück (welche Komponente, konnte weshalb nicht initialisiert werden). Weiterhin helfen Tools wie die SpringIDE schon in der IDE, Konfigurationsfehler zu entdecken. In einem weiteren Schritt spricht ja nichts dagegen, einfach einen Testfall zu schreiben, der die Applikationskonfiguration komplett lädt und somit auf Fehler testet.

    Auf den ersten Blick sieht das ja alles ganz toll aus: viel flexibler, viel mehr wieder-
    verwendbar. Soweit so gut. Aber das ganze muß ja auch noch administriert werden !
    Wenn das Deployment (bei klassischen Anwendungen, zB. in C/C++, kaum mehr als ein paar Files ins target image kopieren, evtl. einmalig ein paar Configfiles anpassen)
    dann zu einem eigenen Projekt wird - auch bei einfachen updates (!) - dann sollte man sich wirklich fragen, ob man damit wirklich etwas gekonnt hat. Immer öfter verschiebt sich der großteil des Aufwands ledeglich von Entwicklung auf Deployment
    und Administration, nur daß einem hier der Compiler nicht mehr helfen kann, und per-instance Tests werden immer aufwendiger (codebase testen reicht dann vorn
    und hinten nicht mehr).

    Ich mache die gegenteilige Erfahrung. Durch sinnvolles Strukturieren der Konfigurationsdateien ist es viel leichter möglich, Subsysteme isoliert zu starten, deren Konfiguration und Funktion zu testen. Gerade das Arbeiten mit Dependency Injection fördert die (Unit)Testbarkeit ungemein und ermöglciht das Testen in unterschiedlichen Granularitäten. Auch für die Konfiguration in unterschiedlichen Umgebungen (Dev, Test, Produktion) gibt es eine Reihe von Mechanismen, die es nicht erforderlich machen, für jeden Plattformwechsel alles umzukonfigurieren.

    Ich kann deinen Unmut allerdings insofern verstehen, als dass es für mich auch eine Weile gedauert hat, bis man diese Art, diese Methodik zu entwickeln verinnerlicht hat. Gerade wenn man bereits stark durch andere Paradigmen und Tools sozialisiert wurde, ist es schwer sich auf den Spring Way einzulassen. Wenn du konkrete Problemfälle hast kann mir dir evtl. dedizierter weiterhelfen?

    Im Prinzip find ich's ja gut, wenn für bestimmte Zwecke eigene (sub-)Sprachen entwickelt werden, um Tipparbeit zu sparen. Aber dann bitte auch gleich so, daß alles auch maschinell validierbar ist und - nicht nur aus Performancegründen, sondern
    eben auch zwecks Robustheit - erstmal Sourcecode rauskommt, der dann durch
    den Compiler geht. DB-Pesistenz wäre zb. ein hervorragendes Beispiel.

    Wo generiert denn wer source code?

    Wo sind die guten alten Build-Configs hin ? Wo die Code-Generatoren ?
    Hat dir nicht gerade eben Generierung misfallen?

    Richtig pervers wirds dann, wenn solche Dinge wie AOP (aka selbstmodifizierender
    Code ;-P) dazu kommen. So macht man die großen Errungenschaften von Java
    (insbesondere strikte Compiler-Prüfungen) einschließlich des "write once - run
    everywhere"-Paradigmum erfolgreich zunichte.

    Eine der Stärken von Spring AOP ist eben die Typsicherheit, die das Interceptorkonzept bei EJB nicht bietet. Aspekte in Spring AOP können vollständig Typsicher gemacht werden, Pointcuts durch die IDE validiert werden. Mit dem AJDT in Eclipse zeigt dir die IDE sogar an welchen Klassen ein Aspekt aktiv wird. Write once runy everywhere geht auch mit AOP. Niemand muss compiletime weaving benutzen. Für einfache Anwendungsfälle reicht das proxybasierte AOP bei weitem aus. Ausserdem ist es verwunderlich, dass viele AOP als Teufelszeug verschreien und dabei oft ohne ihr Wissen AOP über ihre ApplicationServer schon lang benutzen.

    Gruß
    Ollie
    This post was modified on 20 Oct 2008 at 11:23 am.
  • User photo
    Herbert Fuchs
    (not a XING member)
    Re^3: Spring 2.5 @Service vs. EJB3 @Stateless
    Oliver Gierke schrieb:

    Hi,

    Kann es sein, dass dir da eher das Buildsystem im Weg gestanden hat?
    Inwiefern ?
    Ant hat eigentlich saubere Arbeit geleistet (nachdem ich erstmal für dutzende
    Pakete buildfiles geschrieben). Natürlich brauchte ich auch noch für jedes
    Paket ein ebuild, aber das ist wieder eine ganz andere Baustelle ...

    Core Spring hat nur eine (!) Runtimedependency und das ist commons logging.
    Tatsächlich ? Mir war nicht bewußt, daß es bei Java einen Unterschied
    zwischen buildtime und runtime deps gibt. Außer natürlich man bundle'd
    sämtliche deps mit ins target jar mit rein - da kann man sich einreden,
    man würde statisch linken/compilieren - ist aber nicht so.Wenn das jedes
    Paket so macht, dann hat man nicht nur massive code duplication, sondern
    ganz schnell auch mal böse Konflikte. Nein, solche Sauereien gibts bei
    mir nicht !

    Ein kleinstmögliches Springprojekt mit Maven besteht aus einer einzigen Dependencydeklaration (entweder org.springframework-spring, oder halt eine Teilbibliothek). Das sind vielleicht 10 Zeilen XML.
    Tja, maven ... schön und gut, wenn man *alles* damit macht und hintenraus
    nur ein paar jars rauskommen, die in einer *eigenen* vm laufen (also wie
    ein statisch gelinkt'es binary ;-o). Ist aber bei meinen Projekten in 99% der
    Fälle nicht so. Maven spannt (wie ivy auch) praktisch seine eigene Distro auf,
    und genau das ist richtig mies, wenn man mit anderen Distros (bei mir zB.
    Gentoo) arbeitet (das gleich Problem wie mit CPAN oder PEAR).

    Erstmal muß maven natürlich laufen. Wenn dann aber irgentwelche tieferen
    deps wiederum selbst maven zum compilieren brauchen, dann wirds irgentwie
    albern.

    Ich persönlich finde ein Dependencymanagement mit Eclipse oder Ant um Welten umständlicher.
    Naja, über Eclipse sag ich mal besser garnix ... ;-o
    Ant hat eigentlich gar kein Dependency-Management. Wozu auch ? Es ist
    ein Make-System (ja, Makefiles in XML formuliert ;P) für einzelne Pakete (!)
    und kein Distro-System. Dependencies müssen von außerhalb (dem Distro-
    Builder) kommen, es braucht dazu eine klare, saubere Schnittstelle.

    Maven verschmiert die Grenzen zwischen Paket-Build und Distro, mit den
    oben benannten Konsequenzen. Für eine reine Standalone-Lösung sicherlich
    nett, aber zur Integration in eine existierende Distro eigentlich nicht wartbar.

    Wenn dann auch noch immer mehr dynamisch configuriert (und zur Laufzeit gebaut)
    anstatt in compiler-prüfbaren Code programmiert wird, dann bekomme ich ein richtig
    mulmiges Gefühl in der Magengrube.
     
    Laufzeit ist richtig, aber auch nicht ganz. Ein ApplicationContext wird logischerweise zur Laufzeit erzeugt, allerdings ist das in 99% der Fälle genau 1 mal am Start der Anwendung. Dieses Initialisieren überprüft die Konfiguration recht detailliert und gibt recht aussagekräftige Fehlermeldungen zurück (welche Komponente, konnte weshalb nicht initialisiert werden).

    Ja schön. Muß ich also nach jedem kleinen Update nochmal alles ganz
    genau durchtesten, damit nicht irgentwann mal kracht, weil zB. irgentwelche
    Klassen nicht zusammen passen. Sachen die eigentlich der Compiler
    abfangen soll.

    Weiterhin helfen Tools wie die SpringIDE schon in der IDE, Konfigurationsfehler zu entdecken.
    Ahah. IDE aufm Server. Jetzt wirds ja richtig lustig. Bei mir ist da ja noch
    nichtmal die xlib drauf ...

    In einem weiteren Schritt spricht ja nichts dagegen, einfach einen Testfall zu schreiben, der die Applikationskonfiguration komplett lädt und somit auf Fehler testet.
    TDD ist ja schön und gut. Aber wenn man die Sachen so formulieren kann,
    daß allein schon die Sprache 90% der Fehlermöglichkeiten ausschließt
    (was ja plain-Java eigentlich recht gut kann), dann ist mir das tausendmal
    lieber. Wenn zB. Klassen fehlen oder nicht zusammenpassen, dann meckert
    der Compiler. Das geht aber auch nur, wenn der Compiler den ganzen
    Code zum kauen bekommt.

    Ich mache die gegenteilige Erfahrung. Durch sinnvolles Strukturieren der Konfigurationsdateien ist es viel leichter möglich, Subsysteme isoliert zu starten, deren Konfiguration und Funktion zu testen.
    Ja, testen. Ich will aber nicht jeden Pfurz tausendmal testen, sondern möglichst
    alles so formulieren, daß es praktisch kaum noch zu Fehlern (vorallem so Sachen
    wie simple Tippfehler) kommen kann. Die Optimal-Lösung wäre ein System bei
    dem alles, auch die Configfiles durch eine Toolchain gehen und statisch validiert
    werden. Also so als würde man ein großes ELF-Binary draus machen, das alles
    enthält und nur gestartet werden muß ;-)

    Jetzt möcht ich mal sehen, wie diese hochdynamischen Configs statisch
    geprüft werden können ;-P

    Gerade das Arbeiten mit Dependency Injection fördert die (Unit)Testbarkeit ungemein und ermöglciht das Testen in unterschiedlichen Granularitäten.
    Hier gehts schon los: für saubere Modularisierung und Unit-Tests braucht man
    kein externes DI. Da reichen ganz banale Factories aus. Dependencies ist
    Configfiles auszulagern ist eine gefährliche Sache, wenn damit die statische
    Prüfbarkeit verloren geht. Man bräuchte hier ein übergeordnetes Sprach-/
    Maschinenmodell, das alles mindestens genauso typstreng und statisch
    prüfbar abbildet wie das plain-Java ohne VM (zb. via gjc) auch könnte.
    Wenn Fehler erst zur Laufzeit auftreten, ist's idR. schon viel, viel zu spät.

    Auch für die Konfiguration in unterschiedlichen Umgebungen (Dev, Test, Produktion) gibt es eine Reihe von Mechanismen, die es nicht erforderlich machen, für jeden Plattformwechsel alles umzukonfigurieren.
    Die gibt es, sind aber zuweilen recht komplex und bringen wieder andere
    Einschränkungen mit. Ich möchte aber eine Struktur, die das alles garnicht
    erst nötig macht.

    Wenn du konkrete Problemfälle hast kann mir dir evtl. dedizierter weiterhelfen?
    Im Moment nicht, aber ich komm bei Bedarf gern auf Dich zurück :)

    Im Prinzip find ich's ja gut, wenn für bestimmte Zwecke eigene (sub-)Sprachen entwickelt werden, um Tipparbeit zu sparen. Aber dann bitte auch gleich so, daß alles auch maschinell validierbar ist und - nicht nur aus Performancegründen, sondern
    eben auch zwecks Robustheit - erstmal Sourcecode rauskommt, der dann durch
    den Compiler geht. DB-Pesistenz wäre zb. ein hervorragendes Beispiel.
     
    Wo generiert denn wer source code?
     
    Wo sind die guten alten Build-Configs hin ? Wo die Code-Generatoren ?
     
    Hat dir nicht gerade eben Generierung misfallen?

    Nein, im Gegenteil: ich vermisse gerade die Code-Generierung.

    Mal ein banales Beispiel (vielleicht nicht grad das beste ;-)):

    Ich möchte einen kompletten Webserver statisch prüfbar machen. Es soll am
    Ende ein jar (oder vielleicht auch ein ELF) rauskommen, das alles enthält und
    wo auch alle Klassen zusammenpassen. Probleme wie fehlende oder nicht
    zusammenpassende Klassen müssen auch mathematisch nachweisbar
    ausgeschlossen sein. Dynamisches classloading sei also per Def. verboten.

    Jetzt könnte zB. ein Code-Generator die Mapping-Klasse (request URIs/types
    auf webapps, etc) erzeugen, die dann compiliert und in den webserver eingelinkt
    wird. Die Struktur wäre da in etwa: die webapps sind libraries, die vom Mapper
    benutzt werden, der Mapper ist eine Library die vom main-server benutzt wird.
    Also nur noch ein großes Binary, das praktisch keine Configfiles mehr hat.
    (vor vielen, vielen Jahren hatte ich sowas mal in Oberon programmiert - lief
    eigentlich recht robust ;-P).

    Eine der Stärken von Spring AOP ist eben die Typsicherheit, die das Interceptorkonzept bei EJB nicht bietet.
    Typsicher, ok. Aber zu welchem Zeitpunkt ? Compile oder runtime ?

    Aspekte in Spring AOP können vollständig Typsicher gemacht werden, Pointcuts durch die IDE validiert werden.
    Da isses wieder - man braucht 'ne IDE. Ich brauch das aber zum Compile-
    Zeitpunkt, und zwar mit einer strikt nicht-interaktiven Toolchain. Sobald ich
    noch manuell eingreifen muß, ist das ganze für meine Zwecke nicht mehr
    wartbar.

    Write once runy everywhere geht auch mit AOP.
    Sicher, aber zu welchem Preis ?!

    Ehrlichgesagt ist mir in den vergangenen fast zwei Jahrzehnten noch kein
    Fall vorgekommen, wo ich AOP gebraucht hätte. Es gab immer andere
    gute Lösungen (meist direkt vor der Nase;-o). Wozu also das alles ?

    Nehmen wir mal die klassischen Beispiele aus der Literator:

    * Logging: da wird gern gesagt, man könne dann einfach die Logging-Engine
    austauschen und hätte weniger Tipparbeit.

    Ok, die Austauschbarkeit stimmt. Aber lohnt sich dafür AOP wirklich ?
    Warum nicht einfach ein Logging-Objekt in einem (semi-)globalen Context
    mitgeben und das alles weitere (zB. filtering, etc) erledigen lassen ?

    Unter Unix hat man für sowas syslog. Es gibt einfach ein definiertes File
    (pipe) wo reingeschrieben wird. Alles andere interessiert den jeweiligen
    Prozess nicht mehr. Völlig non-invasiv.
    Mit Plan9 wird das (neben vieler anderer Dinge) dank per-process-mounts
    noch eleganter: aus sicht des Prozesses hat das logfile einen hart codierten
    Namen - configuration geschieht außerhalb via mounting.

    Viel Tipparbeit gibts hier übrigends eh nicht zu sparen - die log messages
    muß man eh irgentwann mal schreiben.

    * Tracing:

    Gut, hier kann man sicherlich einiges automatisieren, damit man zB. die
    tracein()'s und traceout()'s nicht mehr manuell platzieren muß. Aber das ist
    eher die Aufgabe für einen (pre-)compiler. Oder gleich einen programmierbaren
    Debugger nehmen.

    * Access control:

    Hier braucht man eh eine genauere Angabe des eigentlichen Zugriffsmusters,
    also kann man auch gleich ein generisches Interface mit entsprechenden
    Parametern aufrufen. Nicht alles läßt einfach so in Modelle wie REST abbilden.
    Und access control auf Funktionen/Methoden ist auch keine gute Lösung -
    schließlich will das ganze ja auch administriert werden - und soll da der Admin
    ernsthaft im Detail wissen müssen, welche Methode was tut ? ;-o

    * Transactions:

    Ui, das ist schon eine Wissentschaft für sich. Wenn das ein gewisses Maß an
    Komplexität erreicht und auch noch mit vernünftiger Performance laufen soll,
    dann ist das nicht gerade trivial. Da verliert man mit so schwer nachvollziehbaren
    Metaprogramming-Ansätzen wie AOP schnell den Überblick. Und gerade Daten-
    Integrität ist eine Sache die man gerne mathematisch nachweisen möchte.
    Sowas überläßt man besser der Datenbank und greift nur über atomische
    stored procedures / views zu (1 query = 1 transaction, basta).

    Ok, fällt jetzt noch jemanden ein wirklich gutes Praxis-Beispiel für AOP ein ?

    Ausserdem ist es verwunderlich, dass viele AOP als Teufelszeug verschreien und dabei oft ohne ihr Wissen AOP über ihre ApplicationServer schon lang benutzen.
    Naja, nicht so richtig AOP, aber anderes Metaprogramming. Wenn man sehr genau
    aufpaßt, kann man das gern tun - es leidet nur die Nachvollziehbarkeit/Prüfbarkeit
    erheblich.

    Früher, zu meinen Oberon-Zeiten, hab ich selbst auch - im reinen Frontend-Bereich -
    Metaprogramming eingesetzt, zB. um recht fix Forms/Elems-Basierte GUIs zu
    bauen (einfach Elems auf Variablen abgebildet, Kommando aufrufen, fertig).
    Ich hatte auch mal angefangen, sowas für Java zu bauen, aber aus Zeitmangel
    nicht fertiggestellt :(


    cu
  • Oliver Gierke
    Oliver Gierke    Premium Member
    The company name is only visible to registered members.
    Re^4: Spring 2.5 @Service vs. EJB3 @Stateless
    Ich hab's grad mal durchgelesen und mir scheint, mein Sozialisierungspunkt aus dem vorherigen Post scheint weiterzugreifen als ich dachte. Was ich verständlich - aber schwierig - finde, ist, dass du versuchst, deinen bisherigen Ansatz und die Art und Weise wie du arbeitest und es gewohnt bist zu arbeiten 1:1 auf Java bzw. JavaEE Entwicklung abzubilden. Das wird nicht wirklich funktionieren. Ich vermute ich würde auf ähnliche Probleme stoßen, wenn ich von der .NET Welt erwartete, das dort alles so funktioniert wie in Java.

    Ich denke daher, dass wir kaum Konsens in allen Punkten erreichen werde, dennoch vielleicht noch einige Ideen bzw. Anmerkungen.

    Herbert Fuchs schrieb:
    Core Spring hat nur eine (!) Runtimedependency und das ist commons logging.
     
    Tatsächlich ? Mir war nicht bewußt, daß es bei Java einen Unterschied zwischen buildtime und runtime deps gibt. Außer natürlich man bundle'd
    sämtliche deps mit ins target jar mit rein - da kann man sich einreden, man würde statisch linken/compilieren - ist aber nicht so.Wenn das jedes Paket so macht, dann hat man nicht nur massive code duplication, sondern
    ganz schnell auch mal böse Konflikte. Nein, solche Sauereien gibts bei
    mir nicht !

    Statisch linken? Willkommen in der Javawelt ;). Nur weil in Spring irgendwo gegen Hibernate API kompiliert wurde, heißt das ja zum einen nicht, dass du diese Klasse auch benutzt und daher b) auch nicht unbedingt Hibernate zur Luafzeit benötigst.

    Genau aus diesem Grund gibt es die Spring Komplettdistribution (spring.jar) UND das ganze nochmal so aufgeteilt, dass man kleine modulare Pakete hat (spring-core.jar, spring-beans.jar usw.)

    In der Distribution auf Sourceforge sind diese Module alle enthalten, genauso wie ALLE evtl. benötigten Drittlibraries und eine Beschreibung, welches Modul Dependencies auf welche libs hat usw.

    Ein kleinstmögliches Springprojekt mit Maven besteht aus einer einzigen Dependencydeklaration (entweder org.springframework-spring, oder halt eine Teilbibliothek). Das sind vielleicht 10 Zeilen XML.
     
    Tja, maven ... schön und gut, wenn man *alles* damit macht und hintenraus
    nur ein paar jars rauskommen, die in einer *eigenen* vm laufen (also wie
    ein statisch gelinkt'es binary ;-o). Ist aber bei meinen Projekten in 99% der
    Fälle nicht so. Maven spannt (wie ivy auch) praktisch seine eigene Distro auf,
    und genau das ist richtig mies, wenn man mit anderen Distros (bei mir zB. Gentoo) arbeitet (das gleich Problem wie mit CPAN oder PEAR).
     
    Erstmal muß maven natürlich laufen. Wenn dann aber irgentwelche tieferen
    deps wiederum selbst maven zum compilieren brauchen, dann wirds irgentwie
    albern.

    Ich weiß nicht, was du genau gemacht hast (oder dir unter der Arbeit mit Maven vorstellst). Maven wird genauso installiert wie Ant und ist genauso ein Kommandozeilentool wie Ant. Mit dem Unterschied, dass es dich der lästigen Arbeit des manuellen Dependencymanagements entledigt.

    Zu den Repositories. Hm... wie verwaltest du denn händisch Abhängigkeiten. Die liegen sicher auch irgendwo auf deiner Platte, oder? Wie handlest du ein Versionsugrade einer Dependency. Das zentrale Repo von Maven reicht in 90% der Fälle aus um die Dependencies zu bekommen die man benötigt.

    Im übrigen sehe ich einen Vorteil darin, mir nicht jedes Jar ergooglen, herunterzuladen, vernünftig versioniert ablegen und die neue Depüendency meinen Arbeitskollegen mitteilen zu müssen. Ein Dependencyelement mehr im pom. Das wandert ins VCS und mit dem nächsten Update haben die Kollegen den exakt gleichen Dependencytree wie ich. Die Zahl der "works-on-my-machine" Fälle haben sich gegenüber manuellem Dependencymanagement sehr stark reduziert.

    Ich spreche daher eher von automatisiertem Dependencymanagement, nicht speziell von Maven.

    Ich persönlich finde ein Dependencymanagement mit Eclipse oder Ant um Welten umständlicher.
     
    Naja, über Eclipse sag ich mal besser garnix ... ;-o
    Ant hat eigentlich gar kein Dependency-Management. Wozu auch ? Es ist
    ein Make-System (ja, Makefiles in XML formuliert ;P) für einzelne Pakete (!)
    und kein Distro-System. Dependencies müssen von außerhalb (dem Distro-
    Builder) kommen, es braucht dazu eine klare, saubere Schnittstelle.

    Die Schnittstelle heißt für Maven pom.xml.

    Laufzeit ist richtig, aber auch nicht ganz. Ein ApplicationContext wird logischerweise zur Laufzeit erzeugt, allerdings ist das in 99% der Fälle genau 1 mal am Start der Anwendung. Dieses Initialisieren überprüft die Konfiguration recht detailliert und gibt recht aussagekräftige Fehlermeldungen zurück (welche Komponente, konnte weshalb nicht initialisiert werden).
     
    Ja schön. Muß ich also nach jedem kleinen Update nochmal alles ganz genau durchtesten, damit nicht irgentwann mal kracht, weil zB. irgentwelche
    Klassen nicht zusammen passen. Sachen die eigentlich der Compiler abfangen soll.

    Diese Art von Tests sind automatisierbar und in den Package bzw. Releaseprozess eingebunden. Desweitern würde ich aber auch einen Teufel eine Änderung die sich im Objektzusammenspiel äußert, ungetestet einfach so zu releasen.

    Weiterhin helfen Tools wie die SpringIDE schon in der IDE, Konfigurationsfehler zu entdecken.
     
    Ahah. IDE aufm Server. Jetzt wirds ja richtig lustig. Bei mir ist da ja noch nichtmal die xlib drauf ...

    Wo schrieb ich was von Server? Du hattest den Punkt bisher auch nicht erwähnt. Die IDE hilft dir beim Entwickeln, und damit auch bei der Problematik Fehler so früh wie möglich zu erkennen. Ich dachte, dass sei der Punkt, der dir wichtig ist.

    In einem weiteren Schritt spricht ja nichts dagegen, einfach einen Testfall zu schreiben, der die Applikationskonfiguration komplett lädt und somit auf Fehler testet.
     
    TDD ist ja schön und gut. Aber wenn man die Sachen so formulieren kann,
    daß allein schon die Sprache 90% der Fehlermöglichkeiten ausschließt
    (was ja plain-Java eigentlich recht gut kann), dann ist mir das tausendmal lieber. Wenn zB. Klassen fehlen oder nicht zusammenpassen, dann meckert
    der Compiler. Das geht aber auch nur, wenn der Compiler den ganzen Code zum kauen bekommt.

    Ein Test der Anwendungskonfiguration hat mit TDD nix zu tun. Automatisierte Tests sollten zu jedem Programm gehören, egal ob die Applikation Testdriven entwickelt wurde oder nicht. Aber eine Testmethode mit

    new ClasspathXmlApplicationContext("foo.xml")
    ist IMHO kein großer aufwand für den Nutzen, den sie bringt.

    Was Compilerchecks für Konfigurationen angeht: wirf mal einen Blick auf Spring JavaConfig. Damit ist genau das möglich.

    Ich mache die gegenteilige Erfahrung. Durch sinnvolles Strukturieren der Konfigurationsdateien ist es viel leichter möglich, Subsysteme isoliert zu starten, deren Konfiguration und Funktion zu testen.
     
    Ja, testen. Ich will aber nicht jeden Pfurz tausendmal testen, sondern möglichst
    alles so formulieren, daß es praktisch kaum noch zu Fehlern (vorallem so Sachen wie simple Tippfehler) kommen kann. Die Optimal-Lösung wäre ein System bei dem alles, auch die Configfiles durch eine Toolchain gehen und statisch validiert werden. Also so als würde man ein großes ELF-Binary draus machen, das alles enthält und nur gestartet werden muß ;-)

    IMHO tut das ein vernünftiges Buildsystem in Kombination mit einer Testsuite.

    Jetzt möcht ich mal sehen, wie diese hochdynamischen Configs statisch geprüft werden können ;-P
    Was heißt den hochdynamisch? Klassennamen werden in der IDE auch in den XML Konfigurationsfiles auch gegengecheckt. Und wenn es denn wieder auf dem Server sein soll: wo überprüft dir denn dein VI, ob du eine Klasse richtig geschrieben hast?

    Gerade das Arbeiten mit Dependency Injection fördert die (Unit)Testbarkeit ungemein und ermöglciht das Testen in unterschiedlichen Granularitäten.
     
    Hier gehts schon los: für saubere Modularisierung und Unit-Tests braucht man
    kein externes DI. Da reichen ganz banale Factories aus.

    Das ist falsch. Wie erhält denn der Client die Referenz auf die Factory? getInstance()? Wie willst du die für Testfälle "austauschen"?
    Ich spreche hier von DI als Konzept, nicht von einem DI Container. Also das Hereinreichen von Dependencies über Konstruktorparameter und/oder Setter.

    Dependencies ist Configfiles auszulagern ist eine gefährliche Sache, wenn damit die statische
    Prüfbarkeit verloren geht. Man bräuchte hier ein übergeordnetes Sprach-/
    Maschinenmodell, das alles mindestens genauso typstreng und statisch
    prüfbar abbildet wie das plain-Java ohne VM (zb. via gjc) auch könnte.

    Nochmal der Hinweiß auf Spring JavaConfig.

    Auch für die Konfiguration in unterschiedlichen Umgebungen (Dev, Test, Produktion) gibt es eine Reihe von Mechanismen, die es nicht erforderlich machen, für jeden Plattformwechsel alles umzukonfigurieren.
     
    Die gibt es, sind aber zuweilen recht komplex und bringen wieder andere
    Einschränkungen mit. Ich möchte aber eine Struktur, die das alles garnicht
    erst nötig macht.

    Dann beglückwünsche ich dich zu deinen Projekten. Ich habe noch nie (!) ein Projekt gesehen, in dem dies möglich war. Sowas hängt nicht von einem selbst ab, sondern an der Infrastruktur und oft auch politischen Entscheidungen. Es ist nicht überall grüne Wiese, wo man sie sich wünscht ;).

    Nein, im Gegenteil: ich vermisse gerade die Code-Generierung.
     
    Mal ein banales Beispiel (vielleicht nicht grad das beste ;-)):
     
    Ich möchte einen kompletten Webserver statisch prüfbar machen. Es soll am Ende ein jar (oder vielleicht auch ein ELF) rauskommen, das alles enthält und
    wo auch alle Klassen zusammenpassen. Probleme wie fehlende oder nicht
    zusammenpassende Klassen müssen auch mathematisch nachweisbar ausgeschlossen sein. Dynamisches classloading sei also per Def. verboten.
     
    Jetzt könnte zB. ein Code-Generator die Mapping-Klasse (request URIs/types
    auf webapps, etc) erzeugen, die dann compiliert und in den webserver eingelinkt wird. Die Struktur wäre da in etwa: die webapps sind libraries, die vom Mapper
    benutzt werden, der Mapper ist eine Library die vom main-server benutzt wird.
    Also nur noch ein großes Binary, das praktisch keine Configfiles mehr hat.
    (vor vielen, vielen Jahren hatte ich sowas mal in Oberon programmiert - lief
    eigentlich recht robust ;-P).

    Das klingt spannend, aber auch nach einer Utopie. Mir begegnen viel eher Anwendungen deren Anforderungen sich regelmäßig ändern, erweitern. D.h. ein kritischer Punkt in einer Architektur ist immer die Wartbarkeit und Erweiterbarkeit. Wenn ich nun hergehe und meine Erstversion so konzipiere, dass sie rocksolid ist, formal verifizierbar (wer bezahlt sowas eigentlich? ;) aber bei der ersten Änderungsanforderung exorbitante Budgets verschlingt, bin ich recht schnell meinen Job los.

    Ich vermute wir entwickeln recht unterschiedliche Software, das Streben nach Kontrolle und Verfizierbarkeit liegt aber glaube ich jedem Entwickler im Blut. Ich glaube aber, dass es immer ein Tradeoff ist und sein wird, dies mit den funktionalen und nichtfunktionalen Anforderung an Software zu verbinden.

    Eine der Stärken von Spring AOP ist eben die Typsicherheit, die das Interceptorkonzept bei EJB nicht bietet.
     
    Typsicher, ok. Aber zu welchem Zeitpunkt ? Compile oder runtime ?

    Runtime. Dieses Feature bietet EJB allerdings nicht, deswegen hatte ich es hervorgehoben (@Originalposter)

    Aspekte in Spring AOP können vollständig Typsicher gemacht werden, Pointcuts durch die IDE validiert werden.
     
    Da isses wieder - man braucht 'ne IDE. Ich brauch das aber zum Compile-
    Zeitpunkt, und zwar mit einer strikt nicht-interaktiven Toolchain. Sobald ich noch manuell eingreifen muß, ist das ganze für meine Zwecke nicht mehr
    wartbar.

    Bei AOP und Compiletimeweaving geht das auch zur Compilezeit. Allerdings brauchst du dann einen anderen Compiler. Einen Tod musst du sterben ;). (Wenn du kein AOP nutzt auch, siehe unten)

    Ehrlichgesagt ist mir in den vergangenen fast zwei Jahrzehnten noch kein
    Fall vorgekommen, wo ich AOP gebraucht hätte. Es gab immer andere
    gute Lösungen (meist direkt vor der Nase;-o). Wozu also das alles ?

    Ich versuch mal die ganzen Beispiele enblock abzuarbeiten. Vielleicht vorweg: Precompiler, Syslog - schön und gut, aber es ist glaube ich vermessen mit diesen Konzepten nach Java zu schlagen. Genausogut könntest du sagen: manuelles Speichermanagement. Bitte, dann wieder auf zu C++. ;9

    Die Alternative zu AOP ist doch das Kodieren der Querschnittsbelange im fachlichen Code. Wenn ich jetzt nur mal die 3 von dir angesprochenen Beispiel nehme: Tracing, Security, Transaktionen. Wenn ich das überall da verteile, wo es eigentlich aktiv werden soll habe ich in vielen Methoden doppelt so viel technischen Code wie fachlichen Code. Schön, der Compiler checkt alles, aber: in einem halben Jahr kommt folgende Anforderung: "Wir hätten gern Caching auf den DB Zugriffen UND wir müssten (fachliche) Funktionalität X um Y erweitern. Schätzen sie den Aufwand."

    Puh... bis die zwei neuen Kollegen, die in der Zwischenzeit am Code sitzen, gefunden haben, wie X überhaupt funktioniert, und was alles Anzufassen ist um Y zu implementieren, bin ich mit einer sauber separierten Codebasis sicher viel schneller am Ziel. Ich sehe also a) einen Vorteil, technischen Code von fachlichem zu separieren, v.a. in Bezug auf die Verständlichkeit des Codes. Natürlich mit dem Tradeoff, dass ich die Verifzierbarkeit des Codes von der Compilezeit zur Testzeit verschiebe. ABER, schreibst du für den Transaktionscode, den Securitycode denn im herkömmlichen Modell keine Tests? Oder wer findet dort Fehler?

    Ein Cache ist im einfachsten Fall exakt ein Advice, der mit einem Pointcut an beliebige Klassen / Methoden gehangen wird. 1 Stelle, 1 Funktionalität, nach Belieben auf andere Teile des Codes anzuwenden (mit einem durchdachten Design logischerweise). Stell dir vor, nach einem weiteren halben Jahr kommt die Anforderung, ein andere Teil des Programms benötigt die gleiche Cachefunktionalität. Was geht wohl schneller, einen weiteren Pointcut zu schreiben, oder den ganzen Wust weiter im fachlichen Code auszubreiten?

    Bzgl. Security: es gibt mit Spring Security ein recht reifes Produkt das auch ACLs ermöglicht. An den Methoden werden dann Permissions definiert und die ACLs können z.B. in einer DB abgelegt werden. Ich hab grad ein projekt auf dem Schirm, in dem man das im Code von Hand macht. Da soll noch mal einer bei AOP von Komplexität sprechen ;). Viel wichtiger: lass mal einen Junior Developer an einer Klasse sitzen, die nur fachliche Code in sich trägt und einer, die alle Aspekte mit beinhaltet. Frage 1: wie schnell schnallt er, was die Klasse tut, Frage 2: wie schnell kann er dann Änderungen daran vornehmen, Frage 3: wie groß ist die Wahrscheinlichkeit, dass seine Änderung einen Fehler in den anderen Sachen erzeugt. ;)

    Ok, fällt jetzt noch jemanden ein wirklich gutes Praxis-Beispiel für AOP ein ?
    Caching, Modulinteroperation (Listener auf AOP Basis), Mandantenfähigkeit. Natürlich geht das auch alles ohne AOP, die Frage ist ja nur, zu welchem Preis.

    Naja, nicht so richtig AOP, aber anderes Metaprogramming. Wenn man sehr genau
    aufpaßt, kann man das gern tun - es leidet nur die Nachvollziehbarkeit/Prüfbarkeit erheblich.
     
    Früher, zu meinen Oberon-Zeiten, hab ich selbst auch - im reinen Frontend-Bereich -
    Metaprogramming eingesetzt, zB. um recht fix Forms/Elems-Basierte GUIs zu bauen (einfach Elems auf Variablen abgebildet, Kommando aufrufen, fertig). Ich hatte auch mal angefangen, sowas für Java zu bauen, aber aus Zeitmangel
    nicht fertiggestellt :(

    Ich wollte gerade fragen. Gerade im Bereich der generativen Programmierung (C++ Templatemetaprogramming) und Generierung im Allgemeinen bedient man sich doch recht ähnlicher Konzepte.

    Gruß
    Ollie
  • User photo
    Herbert Fuchs
    (not a XING member)
    Re^5: Spring 2.5 @Service vs. EJB3 @Stateless
    Oliver Gierke schrieb:
    Ich hab's grad mal durchgelesen und mir scheint, mein Sozialisierungspunkt aus dem vorherigen Post scheint weiterzugreifen als ich dachte. Was ich verständlich - aber schwierig - finde, ist, dass du versuchst, deinen bisherigen Ansatz und die Art und Weise wie du arbeitest und es gewohnt bist zu arbeiten 1:1 auf Java bzw. JavaEE Entwicklung abzubilden.
    Jain. Ich möchte zu allererst mindestens die gleiche Robustheit und
    Nachweisbarkeit wie ich sie zB. von C++ oder "plain-old"-Java
    (das man ja auch in direkt in executables compilieren kann) haben.
    Und gerade hier bringt ja Java - nicht nur durch die Typstrenge, sondern
    auch anderen Arten der (vom Compiler geprüften) formellen Strengen
    (fehlen eigentlich nur noch Constraints ;-)). Das ist ja auch der Grund,
    warum ich mit vielen Projekten, nicht zuletzt im Embedded-Umfeld,
    auf Java umgestiegen bin.

    Wenn aber nun aufgrund der hohen Dynamizität diverser Frameworks
    diese Prüfbarkeit auf das Niveau von Scriptsprachen zurückfällt, dann
    braucht man kein Java mehr ;-o

    Statisch linken? Willkommen in der Javawelt ;).
    Sowas gibts auch bei Java. Spätestens mit gcj ;-P

    Nur weil in Spring irgendwo gegen Hibernate API kompiliert wurde, heißt das ja zum einen nicht, dass du diese Klasse auch benutzt und daher b) auch nicht unbedingt Hibernate zur Luafzeit benötigst.
    Genau das ist das Problem: man weiß es nicht sicher !

    Es kann passieren, daß irgentwann mal eine Klasse dynamisch
    (dh. direkt via Classloader-Aufruf von anderem Java-Code) geladen
    wird und dann etwas fehlt oder nicht zusammen paßt. Hier ist auch
    der Compiler machtlos.

    Auch Unit-Tests helfen da nicht wirklich weiter. Man muß für dann
    allemöglichen Situationen eigne Testcases schreiben. Und auf so
    skurile Fälle wie sie manchmal in der Realität auftreten kommt man
    oft garnicht.

    Gerade in kritischen Bereichen (zB. Embedded) braucht man
    Nachweisbarkeit. Wenn mal eine durchschnittliche Webanwendung
    nicht korrekt läuft, dann kann man damit leben. Bei einer Maschinen-
    Steuerung kostet das mitunter Leben.

    Genau aus diesem Grund gibt es die Spring Komplettdistribution (spring.jar) UND das ganze nochmal so aufgeteilt, dass man kleine modulare Pakete hat (spring-core.jar, spring-beans.jar usw.)
    Und da wirds schon richtig übel: entweder compiliert man gegen die
    Komplett-Distro - dann MUSS man sie auch zur Laufzeit nehmen,
    oder man muß sich vorher für die modularisierte Variante entscheiden,
    dann sollte man aber zur Laufzeit die Finger von der Komplett-Distro lassen.

    In der Distribution auf Sourceforge sind diese Module alle enthalten, genauso wie ALLE evtl. benötigten Drittlibraries und eine Beschreibung, welches Modul Dependencies auf welche libs hat usw.
    Schön und gut. Aber genau das Mitliefern von 3rd-party-Libs ist auch ein
    Grundübel für sich: nicht nur, daß die bundled-libs manchmal ziemlich
    lang hinter'm upstream hinterher hinken, man handelt sich auch schnell
    größen Ärger ein, sobald die Hauptanwendung einige der bundled-libs
    selbst nochmal von anderer Stelle, in anderer Version importiert.
    Java hat kein MVCC-Konzept, das sowas vernünftig handle'n könnte.

    Ich weiß nicht, was du genau gemacht hast (oder dir unter der Arbeit mit Maven vorstellst). Maven wird genauso installiert wie Ant und ist genauso ein Kommandozeilentool wie Ant.
    Ich sprach vorher davon, das Ding erstmal compiliert zu bekommen.
    Und dafür brauch ich dependencies, die selbst wiederum maven
    zum compilieren. Wenn der Topf aber nun ein Loch hat ...

    Mit dem Unterschied, dass es dich der lästigen Arbeit des manuellen Dependencymanagements entledigt.
    Genau hier ist aber das Problem: ich muß das dependency-handling
    selbst machen. Maven weiß nämlich nichts von portage + java-config
    und umgekehrt.

    Mit ant ist das alles einfacher: da hat es wenigstens zum quasi-Standard
    eingebürgert, daß die deps als Menge an .jar's unter ./lib erwartet werden.
    Damit kann ich prima umgehen. Aber wenn dann zB. ivy ins Spiel kommt,
    wirds wieder häßlich.

    Zu den Repositories. Hm... wie verwaltest du denn händisch Abhängigkeiten. Die liegen sicher auch irgendwo auf deiner Platte, oder?
    ja, in /usr/portage ;-P

    Wie handlest du ein Versionsugrade einer Dependency.
    Indem ich das betreffende ebuild anpasse.

    Das zentrale Repo von Maven reicht in 90% der Fälle aus um die Dependencies zu bekommen die man benötigt.
    Tja, dann lieg ich wohl mitten in den verbleibenden 10% ;-o
    Mein Distro-Management heißt "portage" (bzw. im Embedded-Bereich
    "briegel"), nicht "cpan", nicht "pear", erst recht nicht "maven".

    Im übrigen sehe ich einen Vorteil darin, mir nicht jedes Jar ergooglen, herunterzuladen, vernünftig versioniert ablegen und die neue Depüendency meinen Arbeitskollegen mitteilen zu müssen.
    Ja, das ist Aufgabe eines Distro-Managements, nicht eines Paket-
    Buildsystems. Maven verschmiert die Grenzen, sogar noch bis ins
    SCM rein. (Eclipse ist da noch schlimmer, da ist noch die IDE mit
    reingeknotet ;-o).

    Ein Dependencyelement mehr im pom. Das wandert ins VCS und mit dem nächsten Update haben die Kollegen den exakt gleichen Dependencytree wie ich. Die Zahl der "works-on-my-machine" Fälle haben sich gegenüber manuellem Dependencymanagement sehr stark reduziert.
    In kleineren, geschlossenen Projekten, wo jeder die gleiche Distro hat,
    kann man das gern tun. Für XP mag das okay sein, denn da gelten genau
    diese Vorraussetzungen.

    Aber in offenen, verteilten Projekten wird das schnell richtig häßlich.

    Dependencies müssen von außerhalb (dem Distro-
    Builder) kommen, es braucht dazu eine klare, saubere Schnittstelle.
     
    Die Schnittstelle heißt für Maven pom.xml.

    Schön, dann nehmen wir doch mal ein konkretes Beispiel:

    http://www.uniontransit.com/apache/maven-repository/org/apac...

    Erklär mir doch bitte, wie ich daraus nun ein ebuild erzeugen kann ?
    Wo finde ich vorallem erstmal den source-tarball ?

    Ja schön. Muß ich also nach jedem kleinen Update nochmal alles ganz genau durchtesten, damit nicht irgentwann mal kracht, weil zB. irgentwelche
    Klassen nicht zusammen passen. Sachen die eigentlich der Compiler abfangen soll.
     
    Diese Art von Tests sind automatisierbar und in den Package bzw. Releaseprozess eingebunden.

    Mag ja sein, daß das in der Maven-Distro alles getestet ist. Aber inwieweit
    ist das dann auf alle anderen Distros anwendbar ?

    Ordentliches Code- und Release-Management heißt eigentlich, nachträgliche
    Tests soweit es geht unnötig zu machen.

    Desweitern würde ich aber auch einen Teufel eine Änderung die sich im Objektzusammenspiel äußert, ungetestet einfach so zu releasen.
    Definier doch bitte "Objektzusammenspiel" mal etwas näher ;-P

    Sachen wie nicht zusammenpassende/fehlende Klassen/Interfaces sollten
    schon vom Compiler abgefangen werden. Damit fällt schonmal ein großer
    Batzen an Fehlerquellen weg, bevor sie auch nur in die Nähe eines RC kommen.
    Und wenn man Interfaces nicht nur als Programmierkonstrukt, sondern als
    feste Verträge sieht (und dementsprechend handelt!) dann fällt wieder ein noch
    größerer Batzen weg (hier wäre eine Spracherweiterung um richtige design-by-
    contract elemente, zb. constraints, sehr praktisch - dann könnte auch das der
    Compiler gleich mit prüfen).

    Weiterhin helfen Tools wie die SpringIDE schon in der IDE, Konfigurationsfehler zu entdecken.
     
    Ahah. IDE aufm Server. Jetzt wirds ja richtig lustig. Bei mir ist da ja noch nichtmal die xlib drauf ...
     
    Wo schrieb ich was von Server? Du hattest den Punkt bisher auch nicht erwähnt.

    Hätt ich wohl dazu sagen sollen. Bei mir ist so ziemlich alles ein Server,
    die Workstations sind auch bloß Server und Terminal auf einer Box ;-P

    Die IDE hilft dir beim Entwickeln, und damit auch bei der Problematik Fehler so früh wie möglich zu erkennen. Ich dachte, dass sei der Punkt, der dir wichtig ist.
    Dazu bräucht ich erstmal eine IDE, die meinen Ansprüchen gewachsen ist,
    dh. vorallem auf das Wesentliche konzentrieren und never ever mit unnötigen
    Sachen ablenken. Eclipse ist da hier so ziemlich das schlechteste Beispiel
    was mir je untergekommen ist. (BC++-4.5 war damals recht gut, die 5.0
    schon wieder viel zu überfrachtet).

    Ein Test der Anwendungskonfiguration hat mit TDD nix zu tun.
    Nein, mit dem Test der CONFIGURATION nicht - das gehört ja garnicht in
    die Entwicklung, sondern Deployment bzw. Operating. Und genau das ist
    eine Aufgabe, die man für jede individuelle Installation meist nochmal neu
    machen muß. Deshalb sollte hier der Aufwand ja auch auf das nötigste
    minimiert werden ;-P

    Automatisierte Tests sollten zu jedem Programm gehören, egal ob die Applikation Testdriven entwickelt wurde oder nicht. Aber eine Testmethode mit
    new ClasspathXmlApplicationContext("foo.xml")
     
    ist IMHO kein großer aufwand für den Nutzen, den sie bringt.

    So ein Test sagt aber nicht viel aus, nur daß eben sich diese Klasse
    instanzieren läßt (dh. im konkreten Fall der ApplicationContext erzeugt
    werden kann). Wie Aussagekräftig ist das nun ? Von welchen (nicht sofort
    ersichtlichen) Bedingungen hängt der Erfolg/Fehlschlag dieses Tests ab ?

    Was Compilerchecks für Konfigurationen angeht: wirf mal einen Blick auf Spring JavaConfig. Damit ist genau das möglich.
    Soweit ich das erkennen kann, passiert das aber alles erst zur Laufzeit,
    dh. der Compiler kann nicht erkennen, ob das autowire'ing auch später
    wirklich funktionieren wird - im schlimmsten Fall hagelt's Exceptions
    (zur Laufzeit!). Sicherlich kann man auch im Vorfeld einige statische
    Checks laufen lassen, aber das kommt wohl nie an die Robustheit von
    sorgfältig handgeschriebenen Factories (ja, ich weiß, mehr Tipparbeit) ran.

    Die ganze Autowire-Thematik ist ja erstmal überhaupt nicht Spring, und
    auch nicht auf Beans beschränkt. Also warum nicht dafür einen eigenen
    Sprachdialekt schaffen, der das so knapp wie nötig ausdrückt und dennoch
    die Toolchain (statt dem Runtime-System) alles nötige handle'n läßt ?

    Könnte zB. so aussehen

    public class foo ...
    {
    private IOtherObj autowire { scope = session; init = lazy; }
    ....
    }

    Der lästigen getter/setter-Methoden kann man sich auf diese Weise auch
    entledigen, indem man zB. trigger/rules auf Feldern einführt:

    public class foo ...
    {
    public String myName rules { read = getName(...); }
    public String status rules { postWrite = updateMyStatus(); }
    ...
    }

    Und vielleicht auch gleich noch ein paar grundlegende constraints:

    public int myFunc(String par notnull)
    ...
    public int foobar(int i > 0);
    ...


    Das ganze geht dann eben nicht durch eine normale Java-Toolchain,
    sondern eine - nennen wir's mal JavaX - Toolchain. Vorallem fürs autowire
    würde der Compiler erstmal (versteckte) prototypes/interfaces erzeugen,
    und der Linker fügt das dann, zB. anhand der wire'ing-config, zusammen.

    Ja, testen. Ich will aber nicht jeden Pfurz tausendmal testen, sondern möglichst
    alles so formulieren, daß es praktisch kaum noch zu Fehlern (vorallem so Sachen wie simple Tippfehler) kommen kann. Die Optimal-Lösung wäre ein System bei dem alles, auch die Configfiles durch eine Toolchain gehen und statisch validiert werden. Also so als würde man ein großes ELF-Binary draus machen, das alles enthält und nur gestartet werden muß ;-)
     
    IMHO tut das ein vernünftiges Buildsystem in Kombination mit einer Testsuite.

    Das geht aber nur soweit, wie man auch (mit vertretbarem Aufwand)
    sinnvolle Testregeln (oder -Programme) formulieren kann. Je höher die
    Dynamizität und die Komplexität des Codeflow, um so schwieriger wird
    das ganze, exponentiell.

    Und wenn es denn wieder auf dem Server sein soll: wo überprüft dir denn dein VI, ob du eine Klasse richtig geschrieben hast?
    Nein, dafür ist der Compiler da ;-P

    Hier gehts schon los: für saubere Modularisierung und Unit-Tests braucht man
    kein externes DI. Da reichen ganz banale Factories aus.
     
    Das ist falsch. Wie erhält denn der Client die Referenz auf die Factory? getInstance()? Wie willst du die für Testfälle "austauschen"?

    Die Factory wird einfach beim new übergeben.
    Für den Testcase gibts eben 'ne andere Factory.

    Man kann sich die Factories auch per Codegenerator erzeugen lassen,
    aber das wäre

    Ich spreche hier von DI als Konzept, nicht von einem DI Container. Also das Hereinreichen von Dependencies über Konstruktorparameter und/oder Setter.
    Wenn Du natürlich alles erst der Reihe nach über setter machtst, dann
    versteh ich auch, wozu Du ein Framework fürs autowire'ing brauchst ;-P

    Hier kann man schnell den Überblick verlieren und die statische Prüfbarkeit
    geht mehr und mehr verloren. Hier handelst Du Dir etwas ein, daß die
    Mediziner gern "Nebenwirkungen" nennen - Du hast eben keine Blackbox
    mehr, die man man ausgiebig prüfen, notfalls auch beweisen kann.
    Nicht ohne Grund gilt vorallem in kritischen Bereichen die Regel (zumindest
    nicht-deterministische) Abhängigkeiten soweit es nur geht zu vermeiden.

    Fehler im wire'ing sollten bereits nachprüfbar ausgeschlossen sein, bevor
    die Anwendung überhaubt das erste mal startet. Selbst kleine Laufzeitfehler
    können manchmal auch riesigen Schaden verursachen.

    Die gibt es, sind aber zuweilen recht komplex und bringen wieder andere
    Einschränkungen mit. Ich möchte aber eine Struktur, die das alles garnicht
    erst nötig macht.
     
    Dann beglückwünsche ich dich zu deinen Projekten. Ich habe noch nie (!) ein Projekt gesehen, in dem dies möglich war. Sowas hängt nicht von einem selbst ab, sondern an der Infrastruktur und oft auch politischen Entscheidungen. Es ist nicht überall grüne Wiese, wo man sie sich wünscht ;).

    Naja, man muß da schon unterscheiden, wie das Projekt strukturiert ist.
    Bei meinen eigenen (dh. nicht-Kunden-) Projekten verfahre ich wie
    beschrieben. Und da hab ich (mit Ausnahme von Bugs in anderer Leute
    code, zB. kaputten JVMs) sogut wie nie Probleme, die erst beim Testing
    auffallen. Design by contract hat mich da schon oft gut zum Ziel gebracht,
    auch wenn's im Vorfeld erstmal etwas mehr Aufwand macht. (Ja, auch
    wenn's etwas shizophren wirkt, ich schließe auch Verträge mit mir selbst ;-)).

    Das klingt spannend, aber auch nach einer Utopie. Mir begegnen viel eher Anwendungen deren Anforderungen sich regelmäßig ändern, erweitern. D.h. ein kritischer Punkt in einer Architektur ist immer die Wartbarkeit und Erweiterbarkeit.
    Ja, das Problem hab ich auch oft. Ich sage da meiner Kundschaft immer
    ganz klar, daß sowas bösartigste Probleme nach sich ziehen kann. Ein
    guter Kompromiß ist da idR. sauber aufzutrennen, was kritische Kernfragen
    und was eher unkritische (zB. reine Frontend-)Geschichten sind. Das kritische
    läuft dann gewöhnlich sauber geplant (etwas abgemildertes design-by-contract)
    und für die unkritischen Sachen (die dann auch problemlos auswechselbar sind)
    kann man auch mal XP machen.

    Wenn ich nun hergehe und meine Erstversion so konzipiere, dass sie rocksolid ist, formal verifizierbar (wer bezahlt sowas eigentlich? ;) aber bei der ersten Änderungsanforderung exorbitante Budgets verschlingt, bin ich recht schnell meinen Job los.
    Ich kenn ja Deine Projekte / Kunden nicht, aber bei mir passiert sowas meist
    nur wenn der Kunde noch garnicht wirklich weiß, was er machen will bzw.
    seine Aufgabenstellung noch nicht vernünftig strukturiert hat (bei Prototypen
    ist das ja sogar völlig okay). Aber hier sind wir schon lang nicht mehr in der
    Entwicklung, sondern im Projektmanagement ;-P

    Ich vermute wir entwickeln recht unterschiedliche Software, das
    Mag sein. Mein Umfeld zu großem Teil Embedded und HA. Da darf man
    sich keine Fehler leisten, weil dort schnell mal riesigen Summen verbrennen
    oder gar Menschen verletzt werden.

    Streben nach Kontrolle und Verfizierbarkeit liegt aber glaube ich jedem Entwickler im Blut. Ich glaube aber, dass es immer ein Tradeoff ist und sein wird, dies mit den funktionalen und nichtfunktionalen Anforderung an Software zu verbinden.
    Ich denke aber das ist machbar, wenn man sich eine gewisse Disziplin
    auferlegt und sich die richtigen Sprachen/Werkzeuge sucht. Spring könnte
    ich mir für meine Anwendungen derzeit nicht vorstellen, hab nur notgedrungen
    durch Red5 damit zu tun.

    Eine der Stärken von Spring AOP ist eben die Typsicherheit, die das Interceptorkonzept bei EJB nicht bietet.
     
    Typsicher, ok. Aber zu welchem Zeitpunkt ? Compile oder runtime ?
     
    Runtime. Dieses Feature bietet EJB allerdings nicht, deswegen hatte ich es hervorgehoben (@Originalposter)

    Gut, ist schonmal ein Fortschritt zu EJB, reicht mir aber noch nicht aus.
    Bei mir geht ein Paket meist erst überhaupt dann ins Testing, wenn sämtliche
    vom Compiler/Linker prüfbaren Fehlerquellen ausgeschlossen sind (dh. auch
    keine Warnungen mehr übrig bleiben).

    Mal ein kleiner Sidestep in die C-Welt:

    Hier compilier ich praktisch alles in einer sauberen Sysroot-Umgebung, wo
    auch nur die im distro-buildfile deklarierten Dependencies drinstecken. Damit
    erspar ich mir schonmal gut 90% der Fehlerquellen, an denen anderen Distro-
    Maintainer Tag für Tag kämpfen. Macht zwar erstmal etwas Mehrarbeit, um
    diverse kaputte Pakete zu reparieren (grad das ganze autoconf-Gebastel ist
    da echt nervig, aber der Gipfel des unwartbaren Codes sind Mozilla und
    Openoffice), aber dafür weiß man dann woran man ist.
    Seit ich das so rigeros durchziehe, ist es mir auch nie mehr passiert, daß
    ich mir dann ein Zielsystem mit kaputten Updates zerschossen hab ;-P

    Bei AOP und Compiletimeweaving geht das auch zur Compilezeit. Allerdings brauchst du dann einen anderen Compiler. Einen Tod musst du sterben ;). (Wenn du kein AOP nutzt auch, siehe unten)
    Okay, wo gibts den Compiler ? ;-)

    Ich versuch mal die ganzen Beispiele enblock abzuarbeiten. Vielleicht vorweg: Precompiler, Syslog - schön und gut, aber es ist glaube ich vermessen mit diesen Konzepten nach Java zu schlagen. Genausogut könntest du sagen: manuelles Speichermanagement. Bitte, dann wieder auf zu C++. ;9
    Nö, Java hat einige tolle Sachen, zB. saubere Code-Strukturierungen
    (Interface-Klassen statt headerfiles) und vorallem garbage collection.
    Plain-Java (statisch compiliert, und ohne dynamisches classloading, etc)
    hat in Sachen Püfbarkeit und Übersichtlichkeit IMHO C++ einiges vorraus.
    Das benutz ich auch gern.

    Die Alternative zu AOP ist doch das Kodieren der Querschnittsbelange im fachlichen Code. Wenn ich jetzt nur mal die 3 von dir angesprochenen Beispiel nehme: Tracing, Security, Transaktionen. Wenn ich das überall da verteile, wo es eigentlich aktiv werden soll habe ich in vielen Methoden doppelt so viel technischen Code wie fachlichen Code. Schön, der Compiler checkt alles, aber: in einem halben Jahr kommt folgende Anforderung: "Wir hätten gern Caching auf den DB Zugriffen UND wir müssten (fachliche) Funktionalität X um Y erweitern. Schätzen sie den Aufwand."
    DB-Caching ist ein guter Punkt. Da könnte ich jetzt ganze Bücher drüber
    schreiben, aber Java käme da nur am Rande vor. Das ganze steht und
    fällt damit, daß die Anwendung schon genaures über die record lifetimes,
    transaction, etc weiß. Sonst geht gleich wieder das Gefummel los.

    Normalerweise kapselt man DB-Zugriffe auch hinter einem separaten
    DAO-Layer (möglist compile-time statt runtime) bzw. bügelt das direkt
    im DB-Schema, zB. via rules, etc ab und läßt die DB die Transaktionen
    handle'n. (ich rede hier von richtigen Datenbanken, nicht Karteikästen
    mit SQL-artigem Frontend ;-P)

    Ehrlichgesagt hatte ich bisher auch noch nie den Fall, daß ich Dinge
    wie Transaktionen in der Anwendung statt in der DB machen mußte.

    Puh... bis die zwei neuen Kollegen, die in der Zwischenzeit am Code sitzen, gefunden haben, wie X überhaupt funktioniert, und was alles Anzufassen ist um Y zu implementieren, bin ich mit einer sauber separierten Codebasis sicher viel schneller am Ziel. Ich sehe also a) einen Vorteil, technischen Code von fachlichem zu separieren, v.a. in Bezug auf die Verständlichkeit des Codes. Natürlich mit dem Tradeoff, dass ich die Verifzierbarkeit des Codes von der Compilezeit zur Testzeit verschiebe.
    Das kannst Du gern machen, wenn Du an einer großen Anwendung
    baust, die ohnehin schon - aus ganz anderen Gründen - recht lange
    Testcycles zu durchlaufen hat.

    ABER, schreibst du für den Transaktionscode, den Securitycode denn im herkömmlichen Modell keine Tests? Oder wer findet dort Fehler?
    Transaktionscode brauch ich normalerweise nicht - das macht gewöhnlich
    die Datenbank für mich. Wenn ein DBO/DAO einen komplexeren Prozeß
    representiert, dann gehört das vie DB-Schema gekapselt - die Anwendungen
    selbst bekommen ohnehin nur Views zu sehen ;-P

    Security-Code ? Da mußt Du mir schon etwas genauer sagen, was Du
    konkret damit meinst. Access-Control ? Dafür gibts ohnehin kein allgemein-
    gültigen Ansatz - da müssen die Regeln ohnehin von fachlicher Seite
    vorgegeben werden.

    Ein Cache ist im einfachsten Fall exakt ein Advice, der mit einem Pointcut an beliebige Klassen / Methoden gehangen wird. 1 Stelle, 1 Funktionalität, nach Belieben auf andere Teile des Codes anzuwenden (mit einem durchdachten Design logischerweise). Stell dir vor, nach einem weiteren halben Jahr kommt die Anforderung, ein andere Teil des Programms benötigt die gleiche Cachefunktionalität. Was geht wohl schneller, einen weiteren Pointcut zu schreiben, oder den ganzen Wust weiter im fachlichen Code auszubreiten?
    Wenn Du die Zugriffe nicht ohnehin schon gekapselt hast, daß nur ein
    Wrapper getauscht werden muß, dann ist von Anfang an kräftig was
    schiefgelaufen (jaja, es gibt viele Projektmanager die zu Anfang sagen
    "nö brauchen wir nicht" und dann ein paar Monate später erst aufwachen.
    Solche Kurzsichtigkeit sollnse aber schön selber ausbaden ;-P).

    Bzgl. Security: es gibt mit Spring Security ein recht reifes Produkt das auch ACLs ermöglicht. An den Methoden werden dann Permissions definiert und die ACLs können z.B. in einer DB abgelegt werden. Ich hab grad ein projekt auf dem Schirm, in dem man das im Code von Hand macht. Da soll noch mal einer bei AOP von Komplexität sprechen ;).
    Äh, ACLs auf einzelne Methoden ?!
    Was passiert denn, wenn die Kernwendung (bzw. deren einstige Entwickler)
    gar keine Ahnung hat, daß es mal sowas wie Zugriffsverweigerung geben kann ?
    Booom. Exception. Patient tot.

    Da kann man ja gleich wieder scripten ;-O

    Viel wichtiger: lass mal einen Junior Developer an einer Klasse sitzen, die nur fachliche Code in sich trägt und einer, die alle Aspekte mit beinhaltet. Frage 1: wie schnell schnallt er, was die Klasse tut, Frage 2: wie schnell kann er dann Änderungen daran vornehmen, Frage 3: wie groß ist die Wahrscheinlichkeit, dass seine Änderung einen Fehler in den anderen Sachen erzeugt. ;)
    Komplett falscher Ansatz. Gib dem Junior nur ein kleines Projekt, das er auch
    selbst komplett überblicken kann. Divide et impera - hat schon im alten Rom
    gut funktioniert ;-P

    Wenn natürlich irgentwelche Schlipsträger meinen, beliebig Personal hin und
    her schieben zu können, dann sollen sie dafür auch selbst gradestehen.

    Ok, fällt jetzt noch jemanden ein wirklich gutes Praxis-Beispiel für AOP ein ?
     
    Caching, Modulinteroperation (Listener auf AOP Basis), Mandantenfähigkeit. Natürlich geht das auch alles ohne AOP, die Frage ist ja nur, zu welchem Preis.

    Mandantenfähigkeit. Du meinst, daß es verschiedene User (zB. mehrere
    Mitarbeiter) gibt, die bestimmte Dinge (evtl. unterschiedlicher Berechtigung)
    tun können ?

    Das ist ein fachlicher Aspekt, allerspätestens dann, wenn die individuellen
    Berechtigungen geregelt werden sollen.

    Früher, zu meinen Oberon-Zeiten, hab ich selbst auch - im reinen Frontend-Bereich -
    Metaprogramming eingesetzt, zB. um recht fix Forms/Elems-Basierte GUIs zu bauen (einfach Elems auf Variablen abgebildet, Kommando aufrufen, fertig). Ich hatte auch mal angefangen, sowas für Java zu bauen, aber aus Zeitmangel
    nicht fertiggestellt :(
     
    Ich wollte gerade fragen. Gerade im Bereich der generativen Programmierung (C++ Templatemetaprogramming) und Generierung im Allgemeinen bedient man sich doch recht ähnlicher Konzepte.

    Moment, Templates sind etwas ganz, ganz anderes. Das ist eine Form von
    generischen Klassen, dh. bestimmte Operationen laufen auf verschiedenen
    Typen funktional gleich ab.

    Klassisches Beispiel: Liste.
    Du implementierst zunächst einen generischen Datentyp "Liste" (genauer:
    "Liste von ?") und beziehst Dich dort erstmal auf einen noch nicht näher
    bekannten Typ. Erst bei der Deklaration von Referenzvariablen gibts Du
    ein den eigentlichen Zieltyp mit an, zB. "Liste von Personen". Der Compiler
    baut dann im Hintergrund einen eigenen Typ nach der Schablone.
    Mit Metaprogramming hat das erstmal nix zu tun, weil hier immernoch alles
    zur Compile-Zeit läuft.

    In Plain-C(++) geht ja richtiges Metaprogramming auch nicht (da muß man
    sich erst irgentwelche Frameworks bauen) - dazu braucht man zur Laufzeit
    Zugang zu allen Objekten nebst ihren Typinfos (Oberon hatte das schon
    lang vor Java ;-P).


    cu