• Save
Mehr Dynamik Durch Skriptsprachen
Upcoming SlideShare
Loading in...5
×
 

Mehr Dynamik Durch Skriptsprachen

on

  • 4,820 views

 

Statistics

Views

Total Views
4,820
Views on SlideShare
4,820
Embed Views
0

Actions

Likes
0
Downloads
0
Comments
0

0 Embeds 0

No embeds

Accessibility

Categories

Upload Details

Uploaded via as Adobe PDF

Usage Rights

© All Rights Reserved

Report content

Flagged as inappropriate Flag as inappropriate
Flag as inappropriate

Select your reason for flagging this presentation as inappropriate.

Cancel
  • Full Name Full Name Comment goes here.
    Are you sure you want to
    Your message goes here
    Processing…
Post Comment
Edit your comment

Mehr Dynamik Durch Skriptsprachen Presentation Transcript

  • 1. Mehr Dynamik bei der Softwareentwicklung Skriptsprachen im Vergleich
  • 2. Wer ich bin... Mein eigener Chef (Extremer) Softwareentwickler (Agiler) Coach Testgetrieben http://johanneslink.net
  • 3. Java-Frust public class Person... public String getName() { return name; } public static List<Person> sortByName(Set<Person> people) { List<Person> sortedResult = new ArrayList<Person>(people); Comparator<Person> nameComparator = new Comparator<Person>() { public int compare(Person o1, Person o2) { return o1.getName().compareTo(o2.getName()); } }; Collections.sort(sortedResult, nameComparator); return sortedResult; } public class FinancialInstrument... public String getName() { return name; }
  • 4. Java-Frust public class Person implements Namable... public String getName() { return name; } public class MyHelper... public static List<Person> Namable> List<T> sortByName(Set<T> namables) { public static <T extends sortByName(Set<Person> people) { List<Person> sortedResult = ArrayList<T>(namables); List<T> sortedResult = new new ArrayList<Person>(people); Comparator<Person> nameComparator = Comparator<T>() { Comparator<T> nameComparator = new new Comparator<Person>() { public int compare(Person T o2) { public int compare(T o1, o1, Person o2) { return o1.getName().compareTo(o2.getName()); return o1.getName().compareTo(o2.getName()); } } }; }; Collections.sort(sortedResult, nameComparator); Collections.sort(sortedResult, nameComparator); return sortedResult; return sortedResult; } } public class FinancialInstrument implements Namable... public String getName() { return name; }
  • 5. Java-Frust public class Person... public String getName() { return name; } public class MyHelper... public static <T extends Namable> List<T> sortByName(Set<T> namables) { List<T> sortedResult = new ArrayList<T>(namables); Comparator<T> nameComparator = new Comparator<T>() { public int compare(T o1, T o2) { Collection sortByName return o1.getName().compareTo(o2.getName()); self sort: [:each | each name] }; } Collections.sort(sortedResult, nameComparator); return sortedResult; } public class FinancialInstrument... public String getName() { return name; }
  • 6. Typische Java Smells public class MyHelper... public static <T extends Namable> List<T> sortByName(Set<T> namables) { List<T> sortedResult = new ArrayList<T>(namables); Comparator<T> nameComparator = new Comparator<T>() { public int compare(T o1, T o2) { return o1.getName().compareTo(o2.getName()); } }; Collections.sort(sortedResult, nameComparator); return sortedResult; } • Variables Verhalten erfordert eigene (anonyme) Klasse • Incomplete Library Smell • Statische Typisierung erzwingt viele gemeinsame Interfaces • Unvorhergesehene Veränderung => Neukompilierung
  • 7. Die Rettung naht: Dynamische Skriptsprachen • Scripting • Dynamik
  • 8. Scripting • Knappe und ausdrucksstarke Syntax • Ausführung von Programmcode ohne (spürbare) Compilierung • Selbstständige Skripte • Aus einer Applikation heraus List<Person> people = new ArrayList<Person>(); people.add(new Person(quot;Dierkquot;)); ... List<Person> sorted = (List<Person>) Eval.x(people, quot;x.sort {it.name}quot; );
  • 9. Dynamik • Dynamische Typisierung • Closures • Meta-Programmierung
  • 10. Dynamische Typisierung aka „Duck Typing“ def sortByName(unsorted) { unsorted.sort {it.name} } def people = [ new Student(quot;Johannesquot;), new Person(quot;Dierkquot;) ] def sorted = sortByName(people) assert sorted[0].name == quot;Dierkquot; assert sorted[1].name == quot;Johannesquot;
  • 11. Closures (1) Programmlogik als vollwertiges Objekt def sorter = { unsorted -> unsorted.sort {it.name} } def sorted = sorter(people) //oder so: def sorted = sorter.call(people)
  • 12. Closures (2) • Iteration als typischer Anwendungsfall def namen = [quot;Johannesquot;, quot;Frankquot;, quot;Dierkquot;] def auswahl = namen.findAll {name -> name.contains quot;nquot;} assert auswahl == [quot;Johannesquot;, quot;Frankquot;] List<String> auswahl = new ArrayList<String>(); for (String name : namen) { if (name.contains(quot;nquot;)) { auswahl.add(name); } } Äquivalenter Java Code
  • 13. Meta-Programmierung • Erweiterung existierender Klassen • Hinzufügen von Methoden zur Laufzeit • Erweiterung / Veränderung der Sprache durch Eingriff Verwendung eines „Meta Object Protocol“
  • 14. Meta Object Protocol „A metaobject protocol (MOP) is an interpreter of the semantics of a program that is open and extensible“ (Wikipedia) Class.metaClass.'static'.create = { Object[] args -> class MyObject { def prop delegate.metaClass.invokeConstructor(*args) } void setProperty(String name, value) { prop = value assert }new ArrayList() == ArrayList.create() def getProperty(String name) { assert new HashMap() == HashMap.create() prop assert new Integer(42) == Integer.create(42) } assert new Dimension(1,1) == Dimension.create(1,1) } def obj = new MyObject() obj.firstName = quot;Johannesquot; obj.lastName = quot;Linkquot; assert obj.firstName == quot;Linkquot;
  • 15. Vorteile / Nachteile dynamischer Skriptsprachen • Vorteile: • Weniger Code • Weniger Duplikation • Verständlichere Abstraktionen • Mehr Deployment-Optionen • Nachteile: • Erschwerte statische Codeanalyse • Schlechtere Performance
  • 16. Welche Skriptsprachen gibt es? • Verbreiteste Skriptsprachen: Perl, PHP, Python, Ruby, JavaScript • Mehr als 200 verschiedene Sprachen allein auf der Java VM: Groovy, JRuby, Scala, Bistro ... • Heute im Visier: JavaScript, Ruby und Groovy
  • 17. Groovy • Volle Objekt- • Volle Integration Orientierung ohne mit der Java- primitive Typen Plattform • Optionale statische • Generics Typisierung • Annotations • Closures • Security-Model • Listen und Maps • Wird (immer) in als Literale echten Bytecode kompiliert
  • 18. Groovy - Vereinfachte Syntax System.out.println(quot;Hello World!quot;); //Java style println 'Hello, World!' def vorname = 'Stefan' println quot;$vorname, ich hol' den Wagen.quot; String lang = quot;quot;quot;Du, ${vorname}, der Wagen steht eine Zeile weiter.quot;quot;quot; assert 0.5 == 1/2 class Person { def name } def johannes = new Person(name: quot;Johannesquot;) assert johannes.name == quot;Johannesquot;
  • 19. Groovy -Closures def to = quot;JUGSquot; def say = { msg -> msg + quot;, $toquot; } assert say(quot;Halloquot;) == quot;Hallo, JUGSquot; to = quot;JUG Colognequot; assert say(quot;Halloquot;) == quot;Hallo, JUG Colognequot; (1..10).each { println it } [a:1, b:2].each { key, value -> println quot;key: $key, value: $valuequot; }
  • 20. JavaScript • Objektorientiert - aber nicht klassenbasiert • Keine statische Typisierung • Syntax und ein paar Basis-Objekte an Java angelehnt • Läuft (interpretiert) in jedem Browser - im Detail unterschiedlich • Enge Verknüpfung mit DOM • Rhino-JS-Engine in Java SE 6 enthalten • Standardisiert als ECMAScript
  • 21. JavaScript - Basistypen var name = 'Johannes'; assertEqual('Johannes Link', name + ' Link'); var eins = 1 assertEqual(2, eins + 1) assertEqual('11', eins + '1') var liste = [1, 2, 'drei'] assertEqual('drei', liste[2]) var isBig = eins > 1000 if (isBig) fail()
  • 22. JavaScript - Objekte var johannes = new Object(); johannes.firstName = quot;Johannesquot; johannes.lastName = quot;Linkquot; johannes.name = function() { return this.firstName + ' ' + this.lastName } assertEqual('Johannes Link', johannes.name()); var johannes = { firstName: 'Johannes', lastName: 'Link', name: function() { return this.firstName + ' ' + this.lastName } }
  • 23. JavaScript - Prototypen (1) function Person(firstName, lastName) { this.firstName = firstName this.lastName = lastName } Person.prototype.name = function() { return this.firstName + ' ' + this.lastName } var johannes = new Person('Johannes', 'Link') assertEqual('Johannes Link', johannes.name()) assertEqual(true, johannes instanceof Person)
  • 24. JavaScript - Prototypen (2) johannes.name = function() { return 'Joe Cartwright' } assertEqual('Joe Cartwright', johannes.name()) function Student(firstName, lastName) { Person.call(this, firstName, lastName); } Student.prototype = new Person(); Student.prototype.name = function() { return this.firstName; } var jannek = new Student('Jannek', 'Link'); assertEqual('Jannek', jannek.name()); assertEqual('Link', jannek.lastName);
  • 25. Ruby • Sprachumfang und Mächtigkeit ähnlich wie bei Groovy • C-Implementierung als Interpreter • „Berühmt“ durch Ruby on Rails • Ausschließlich dynamische Typen • JRuby: Byte-Code und Java- Integration
  • 26. Ruby - Code class Person attr_reader :first_name, :last_name def initialize(first_name, last_name) @first_name = first_name @last_name = last_name end end class Person def name() first_name + quot; quot; + last_name end end johannes = Person.new(quot;Johannesquot;, quot;Linkquot;) assert_equal quot;Johannes Linkquot;, johannes.name
  • 27. Ruby - Blocks def three_times(arg) yield arg yield arg yield arg end three_times (quot;JUGSquot;) { |name| puts quot;Hello, quot; + name } def twice(arg, action) action.call(arg) action.call(arg) end print_ciao = proc { |name| puts quot;Ciao, quot; + name } twice quot;JUGSquot;, print_ciao
  • 28. Ruby - Mixins module Debug def who_am_i quot;#{self.class.name}quot; end end class Person include Debug end johannes = Person.new(quot;Johannesquot;, quot;Linkquot;) assert_equal quot;Personquot;, johannes.who_am_i s = quot;Ein Stringquot; class Array s.extend Debug include Debug assert_equal quot;Stringquot;, s.who_am_i end assert_equal quot;Arrayquot;, [1, 2, 3].who_am_i
  • 29. Ruby Classes are Objects johannes = Person.new(quot;Johannesquot;, quot;Linkquot;) assert_equal Person, johannes.class assert_equal Class, Person.class assert_equal Class, Class.class assert_equal Module, Class.superclass assert_equal Object, Module.superclass class Class alias_method :old_new, :new def new(*args) puts quot;Objekt wird erzeugt...quot; old_new(*args) end end
  • 30. Ruby Events Event Hook Methodenaufruf Kernel::system Methode hinzufügen Module#method_added Unterklasse erzeugen Class#inherited ...
  • 31. Vergleich (1) Groovy JavaScript Ruby / JRuby gering, deutlich groß, Verbreitung mittel, wachsend wachsend gleichbleibend wenig eingebaut, Bibliotheken J2EE + GDK zahlreich /+J2EE viele externe Libs dynamisch, Typisierung dynamisch dynamisch optional statisch Objektorien- Objekte + vollständig vollständig tierung primitive Typen Vererbung klassenbasiert Prototyp-basiert klassenbasiert sehr mächtig MOP gering sehr mächtig++ (ab 1.5)
  • 32. Vergleich (2) Groovy JavaScript Ruby / JRuby gut, aber mit Java-Integration optimal gering prinzp. Problemen Laufzeit- kompilierter interpretiert / interpretiert umgebung Bytecode auf JVM JVM Bytecode Tool- mäßig bis gut mäßig mäßig bis gut Unterstützung (IDEA) Typisches Scripting in Java- Ajax im Browser Ruby on Rails Anwendungsfeld Applikationen langsam, besser Performance langsam meist ausreichend werdend http://shootout.alioth.debian.org/
  • 33. Strack Trace Java Thread [main] (Suspended (breakpoint at line 22 in JavaPerson)) JavaPerson.doubleName() line: 22 JavaTester.run() line: 7 Tester.test(Class<Runnable>) line: 16 Tester.main(String[]) line: 6
  • 34. Stack Trace Groovy Thread [main] (Suspended (breakpoint at line 18 in GroovyPerson)) GroovyPerson.doubleName() line: 18 NativeMethodAccessorImpl.invoke0(Method, Object, Object[]) NativeMethodAccessorImpl.invoke(Object, Object[]) line: 39 DelegatingMethodAccessorImpl.invoke(Object, Object[]) line: 25 Method.invoke(Object, Object...) line: 585 CachedMethod.invoke(Object, Object[]) line: 95 MetaClassHelper.doMethodInvoke(Object, MetaMethod, Object[]) line: 599 MetaClassImpl.invokeMethod(Class, Object, String, Object[], boolean, boolean) line: 904 MetaClassImpl.invokeMethod(Object, String, Object[]) line: 740 InvokerHelper.invokePogoMethod(Object, String, Object) line: 773 InvokerHelper.invokeMethod(Object, String, Object) line: 753 ScriptBytecodeAdapter.invokeMethodN(Class, Object, String, Object[]) line: 167 ScriptBytecodeAdapter.invokeMethod0(Class, Object, String) line: 195 GroovyTester.run() line: 7 Tester.test(Class<Runnable>) line: 16 Tester.main(String[]) line: 7
  • 35. Warum gerade jetzt? • Normale Pendelschwingung zwischen dynamischer und statischer Typisierung • Frust über Redundanz und wachsende Komplexität von Java • Domänen-spezifische Sprachen sind auf dem Vormarsch • Multi-Sprachen-Systeme werden hoffähig • Mehr Wissen über sinnvolle Einsatzszenarien der unterschiedlichen Programmiersprachen
  • 36. Einsatzmuster für Scripting (von Dierk König) • Alleskleber • Weiches Herz • Kluge Anpassung • Endoskopische Operation • Grenzenlose Offenheit • Heinzelmännchen • Prototyp
  • 37. Einsatzmuster: Alleskleber • Applikationen aus bestehenden Komponenten zusammenbauen • Java und .NET sind gut geeignet für stabile Infrastruktur: Middleware, Frameworks, Widget Sets, Services • Scripting ist gut geeignet für flexible View- und Controller-Schichten (z.B. Grails)
  • 38. Alleskleber Demo: RSS Reader • Zusammenbau von XML Parser, Java Networking und Swing Widget Bibliothek, um einen Standard-RSS Feed darzustellen
  • 39. Einsatzmuster: Weiches Herz • Fachliche Modelle auslagern bei vorgegebenem Java-Applikationsgerüst • Fachlichen Erkenntnisfortschritt ermöglichen: Entitäten, Beziehungen und Verhalten bleiben durch Scripting flexibel • Verhaltensänderung zur Laufzeit
  • 40. Weiches Herz Beispiel: Bonusberechnung umsatz = mitarbeiter.umsatz switch(umsatz / 1000) { case 0..100: return umsatz * 0.04 case 100..200: return umsatz * 0.05 case {it > 200}: bonusClub.add(mitarbeiter) return umsatz * 0.06 } Binding binding = new Binding(); binding.setVariable(quot;mitarbeiterquot;, mitarbeiter); binding.setVariable(quot;bonusClubquot;, bonusClub); GroovyShell shell = new GroovyShell(binding); File script = new File(filename); BigDecimal bonus = (BigDecimal) shell.evaluate(script);
  • 41. Einsatzmuster: Kluge Anpassung • Konfigurationen mit Ausführungs-Logik als Ersatz für XML-Konfigurationen • Mit Referenzen, Schleifen, Bedingungen, Vererbung, Ausführungslogik, Umgebungsermittlung, ... • Typischer Anwendungsfall für domänen- spezifische Sprachen (DSLs) • Veränderungen durch den Experten
  • 42. DSL-Beispiel (Bernd Schiffer): Entfernungsberechnung assert 5001.m == 2000.m + 3.km + 1.m class Distance { def meter assert werteAus('5002 m == 2000 m + 3 km + 2 m') def plus(other) { new Distance(meter: meter + other.meter) def werteAus(String ausdruck) { } boolean equals(other) { Eval.me( this.meter == other.meter } ausdruck.replaceAll(quot; (m|km)quot;, { } alle, einheit -> quot;.${einheit}quot; })) class DistanceCategory { } static def getM(distance) { new Distance(meter: distance) } static def getKm(distance) { new Distance(meter: distance * 1000) } }
  • 43. Einsatzmuster: Endoskopische Operation • Minimal-invasive Eingriffe quot;in vivoquot; • Viele Notwendigkeiten für Anpassungen ad-hoc Anfragen sind nicht vorhersehbar • Schlüsselloch für die Live Ausführung von Scripts schaffen, z.B. in einem speziellen Servlet • Unglaublich wertvoll für Produkt-Support, Fehleranalyse, Hot-Fixes, Notfälle
  • 44. Endoskopische Operation: im Servlet Probleme mit der Datenbank Verbindung? def ds = Config.dataSource ds.connection = new DebugConnection(ds.connection) Gefährliche Benutzer rauswerfen users = servletContext.getAttribute('users') bad = users.findAll { user -> user.cart.items.any { it.price < 0 } } servletContext.setAttribute('users', users - bad)
  • 45. Einsatzmuster: Grenzenlose Offenheit • Jede Zeile Code wird änderbar • Manchmal sind die vorgesehenen Variationspunkte nicht ausreichend • Einfache Änderungen ohne langwieriges Setup für Kompilation und Deployment • Perl, PHP, Python, etc. machen es vor
  • 46. Einsatzmuster: Heinzelmännchen • Repetitive Aufgaben automatisieren • Automatisierter Build, kontinuierliche Integration, Deployment, Installationen, Server-Überwachung, Reports, Statistiken, Erzeugen von Dokumentation, funktionale Tests uvm. • Anwendungen mit Ant, Maven und Co.
  • 47. Heinzelmännchen: Mail schicken def users = [ [name:'Johannes', email:'jux@johanneslink.net'], [name:'Teilnehmer', email:'wer@wo.net']] def ant = new groovy.util.AntBuilder() for (user in users) { ant.mail(mailhost: 'smtp.googlemail.com', mailport: '465', ssl: 'true', user: quot;$mailUserquot;, password: quot;$passwordquot;, subject: 'Vortrag ist bald fertig') { from(address: 'johannes.link@googlemail.com') to(address: user.email) message( quot;quot;quot; Hallo ${user.name}, Der Vortrag ist fast fertig: ${new Date().toGMTString()} quot;quot;quot; ) } }
  • 48. Einsatzmuster: Prototyp • Machbarkeitsstudien auf der Zielplattform • quot;Spikesquot; für technologische oder algorithmische Ideen mit besserer Ausdrucksmächtigkeit, schnellerem Feedback und besseren Analysemöglichkeiten • Wahlmöglichkeit für spätere (Teil-) Portierung nach Java / C#
  • 49. Weitere Informationen • Groovy: • http://groovy.codehaus.org/ • Dierk König et al: „Groovy in Action“ • JavaScript: • http://developer.mozilla.org/en/docs/JavaScript • David Flanagan: „JavaScript: The Definitive Guide“ • Microsoft: „ JScript Deviations from ES3“ • Ruby: • http://www.ruby-lang.org • Dave Thomas et al.: „Programming Ruby: The Pragmatic Programmers' Guide“ • http://www.nealford.com/downloads/conferences/ Neal_Ford-Comparing_Groovy_and_JRuby-slides.pdf
  • 50. Zusammenfassung • Java - und andere Entreprise-Plattformen - haben Einschränkungen: • Anpassungen zur Laufzeit • Präzision im Ausdruck • Erweiterbarkeit der Sprache • Dynamische Skriptsprachen sind in diesen Punkten flexibler und mächtiger • bringen jedoch andere Probleme mit sich • Nicht statisch vs dynamisch, sondern...
  • 51. Zeremonie versus Essenz