Quiero hacer ágil, ¿ y ahora qué: Java, Ruby o Scala ? Leo Antoli @lantoli Conferencia Agile-Spain 2011 - Castellón
Antes de empezar <ul><ul><li>Hacer ágil o ser ágil, esa es la cuestión </li></ul></ul><ul><ul><li>¿ Se puede Cobol ágil o ...
Fuera de la sesión <ul><ul><li>Lenguajes en cliente </li></ul></ul><ul><ul><li>Frameworks </li></ul></ul><ul><ul><li>Sólo ...
Un lenguaje para dominarlos a todos
Popularidad <ul><li>1 - Java </li></ul><ul><li>2 - C </li></ul><ul><li>3 - C++ </li></ul><ul><li>4 - C# </li></ul><ul><li>...
Popularidad <ul><li>Google Code Jam 2011 </li></ul>
Causa/efecto o correlación
Sopa de letras
Diseño simple, arquitectura <ul><li>- Pasa todas las pruebas  (hace lo que tiene que hacer, pero no más) - Minimiza las du...
Entrega continua de valor: ¿ sólo con pruebas automáticas ?
¿ TDD/BDD obligatorio ? ... Anda antes de correr
Dinámico o Estático <ul><li>- Estáticos tienen problemas, muchas redundancias y son menos legibles que los dinámicos </li>...
Conciso o verboso <ul><li>... </li></ul><ul><li>public   class   StringCalculator   { </li></ul><ul><li>public   int   add...
Conciso o verboso <ul><li>class   Integer </li></ul><ul><li>   def   negative? </li></ul><ul><li>     self   <   0 </li></...
Conciso o verboso <ul><li>... </li></ul><ul><li>@Test </li></ul><ul><li>public   void   testAddEmpty ()   throws  Exceptio...
Conciso o verboso <ul><li>describe  &quot;String calculator&quot;   do </li></ul><ul><li>   before  do </li></ul><ul><li> ...
Conciso o verboso <ul><li>... </li></ul><ul><li>ROMANS   =  { M:  1000 ,  CM :  900 , D:  500 ,  CD :  400 , C:  100 ,  XC...
Llamar métodos por nombre / introspección <ul><li>class  Integer </li></ul><ul><li>   def  to_fizzbuzz1 </li></ul><ul><li>...
Llamar métodos por nombre / introspección <ul><li>describe  &quot;FizzBuzz identity cases&quot;   do </li></ul><ul><li>   ...
Inferencia de tipos <ul><li>Java </li></ul><ul><li>int x = 1 + 2 * 3; </li></ul><ul><li>String y = x.toString(); </li></ul...
Tipos covariantes y contracovariantes, not reified (type erasure), ... <ul><li>Java: </li></ul><ul><li>Vehiculo[] v = new ...
Abrir clases o conversiones implícitas (vistas) <ul><li>2 days ago  </li></ul><ul><li>5 days from_now </li></ul><ul><li>cl...
Duck typing, Interfaces o Structural typing <ul><li>class  Duck  {   </li></ul><ul><li>   def  quack  =  println ( &quot;Q...
Missing method, invokedynamic (java7), Dynamic trait <ul><li>class Roman </li></ul><ul><li>  def romanToInt(str) </li></ul...
Módulos, mixins, traits, herencia múltiple, ... <ul><li>class miclase </li></ul><ul><li>{ </li></ul><ul><li>     include E...
JVM <ul><li>Groovy </li></ul><ul><li>Scala </li></ul><ul><li>JRuby </li></ul><ul><li>Jython </li></ul><ul><li>Clojure </li...
Rendimiento <ul><li>¿ Compilado o interpretado ? </li></ul><ul><li>¿ Estáticos o dinámicos ?  </li></ul><ul><li>¿ Intensiv...
Funcionales, recursión, complejidad, O(N), ... <ul><li>   def   to_fib_recursive </li></ul><ul><li>     return   self   if...
No olvidemos... <ul><ul><li>IDE y herramientas </li></ul></ul><ul><ul><li>Rendimiento </li></ul></ul><ul><ul><li>Chequeos ...
¡WARNING! La siguiente sección contiene opiniones subversivas que pueden herir la sensibilidad
Tipos de tipados  :-) <ul><li>¿Se realiza chequeo de tipos? </li></ul><ul><ul><li>Sí -> Tipado fuerte </li></ul></ul><ul><...
Tipos de tipados  :-) <ul><li>¿Java, Scala, C#...? Tipado fuerte y estático </li></ul><ul><li>¿JS, Ruby ....? Tipado  fuer...
El compilador es tonto <ul><ul><li>Necesita información extra para chequear los tipos </li></ul></ul><ul><ul><ul><li>Ruido...
Enter TDD (que cansino...) <ul><ul><li>No existe técnica para resolver el problema de detección de errores funcionales al ...
Enter TDD (que cansino...) <ul><ul><li>No existe técnica para resolver el problema de detección de errores funcionales al ...
Enter TDD (que cansino...) <ul><ul><li>No existe técnica para resolver el problema de detección de errores funcionales al ...
Tipado dinámico wins! <ul><li>Invocando el principio KISS: </li></ul><ul><li>IF ( &quot;TDD lo necesito sí o sí&quot;  </l...
Tipado estático strikes back <ul><ul><li>Inferencia de tipos </li></ul></ul><ul><ul><li>Tipado estructural </li></ul></ul>...
¿Y los DSL? <ul><ul><li>Hacen tu código más cercano al dominio del problema </li></ul></ul><ul><ul><li>Legibilidad aumenta...
¡YA ME VOY! Y ahora pasemos a las conclusiones (Gracias Leo!)
Conclusiones <ul><li>- ¿  Dinámicos   para equipos pequeños con gente muy buena ? </li></ul><ul><li>- ¿  Estáticos  para p...
Upcoming SlideShare
Loading in...5
×

Quiero hacer ágil, ¿y ahora qué: Java, Ruby o Scala?

695

Published on

Leo Antoli

0 Comments
0 Likes
Statistics
Notes
  • Be the first to comment

  • Be the first to like this

No Downloads
Views
Total Views
695
On Slideshare
0
From Embeds
0
Number of Embeds
0
Actions
Shares
0
Downloads
13
Comments
0
Likes
0
Embeds 0
No embeds

No notes for slide

Quiero hacer ágil, ¿y ahora qué: Java, Ruby o Scala?

  1. 1. Quiero hacer ágil, ¿ y ahora qué: Java, Ruby o Scala ? Leo Antoli @lantoli Conferencia Agile-Spain 2011 - Castellón
  2. 2. Antes de empezar <ul><ul><li>Hacer ágil o ser ágil, esa es la cuestión </li></ul></ul><ul><ul><li>¿ Se puede Cobol ágil o Ruby sin tests y en cascada ? </li></ul></ul><ul><ul><li>¿ Se puede ser ágil con Java ? </li></ul></ul><ul><ul><li>  El lenguaje es muy importante... pero es sólo una herramienta </li></ul></ul><ul><ul><li>¿ Por qué Java, Scala y Ruby ? </li></ul></ul><ul><ul><li>¿ Cuáles son las buenas prácticas técnicas (aplicables a ágil y cascada ?  </li></ul></ul><ul><ul><li>¿ Se pueden usar nuevos lenguajes en tus desarrollos actuales ? </li></ul></ul>
  3. 3. Fuera de la sesión <ul><ul><li>Lenguajes en cliente </li></ul></ul><ul><ul><li>Frameworks </li></ul></ul><ul><ul><li>Sólo se tratan algunos lenguajes </li></ul></ul>
  4. 4. Un lenguaje para dominarlos a todos
  5. 5. Popularidad <ul><li>1 - Java </li></ul><ul><li>2 - C </li></ul><ul><li>3 - C++ </li></ul><ul><li>4 - C# </li></ul><ul><li>5 - PHP </li></ul><ul><li>6 - Objective-C </li></ul><ul><li>7 - Visual Basic </li></ul><ul><li>8 - Python </li></ul><ul><li>9 - Perl </li></ul>10 - Javascript 11 - Ruby 25 - COBOL 27 - Scheme (LISP) 30 - Fortran 35 - Haskell 40 - Prolog 50 - Scala >51 Groovy
  6. 6. Popularidad <ul><li>Google Code Jam 2011 </li></ul>
  7. 7. Causa/efecto o correlación
  8. 8. Sopa de letras
  9. 9. Diseño simple, arquitectura <ul><li>- Pasa todas las pruebas  (hace lo que tiene que hacer, pero no más) - Minimiza las duplicaciones  (si quiero cambiar el comportamiento lo hago en un solo sitio) - Maximiza la claridad (expresa bien las intenciones, es fácil de entender) - Es conciso (usa el menor número de clases y métodos, cumpliendo las otras reglas) </li></ul><ul><li>Estos mandamientos se resumen en dos: </li></ul><ul><li>- Quitar duplicación de código </li></ul><ul><li>- Mejorar los nombres mal puestos </li></ul><ul><li>Arquitectura: El conjunto de decisiones de diseño significativas (costosas de cambiar) </li></ul>
  10. 10. Entrega continua de valor: ¿ sólo con pruebas automáticas ?
  11. 11. ¿ TDD/BDD obligatorio ? ... Anda antes de correr
  12. 12. Dinámico o Estático <ul><li>- Estáticos tienen problemas, muchas redundancias y son menos legibles que los dinámicos </li></ul><ul><li>- La solución son los dinámicos o hay algo entre medias ? </li></ul>
  13. 13. Conciso o verboso <ul><li>... </li></ul><ul><li>public class StringCalculator { </li></ul><ul><li>public int add ( String inputStr ) { </li></ul><ul><li>    String firstLine = getLineDelimiters ( inputStr ); </li></ul><ul><li>    String textWithNumbers = getStringWithoutDelimiterLine ( inputStr ); </li></ul><ul><li>    List < String > delimiters = getDelimiters ( firstLine ); </li></ul><ul><li>    List < Integer > numbers = getAllowedNumbers ( getNumbers ( textWithNumbers, delimiters )); </li></ul><ul><li>    checkNegativeNumbers ( numbers ); </li></ul><ul><li>    return getSum ( numbers ); </li></ul><ul><li>} </li></ul><ul><li>... </li></ul><ul><li>private static int getSum ( List < Integer > numbers ) {     SUMA LOS ELEMENTOS DE UNA LISTA </li></ul><ul><li>    int sum = 0 ; </li></ul><ul><li>    for ( int num : numbers ) { </li></ul><ul><li>      sum += num ; </li></ul><ul><li>    } </li></ul><ul><li>    return sum ; </li></ul><ul><li>} </li></ul><ul><li>private static void checkNegativeNumbers ( List < Integer > numbers)  throws IllegalArgumentException { </li></ul><ul><li>    List < Integer > negatives = new ArrayList < Integer >(); DECLARAR VARIABLE </li></ul><ul><li>    for ( int num : numbers ) { LISTA NUMEROS NEGATIVOS </li></ul><ul><li>        if ( num < 0 ) { </li></ul><ul><li>              negatives . add ( num ); </li></ul><ul><li>        } </li></ul><ul><li>    } </li></ul><ul><li>    if ( negatives . size () > 0 ) { </li></ul><ul><li>            throw new IllegalArgumentException ( &quot;no se permiten negativos: &quot;   + negatives . toString ()); </li></ul><ul><li>    } </li></ul><ul><li>} </li></ul><ul><li>... </li></ul>121 líneas
  14. 14. Conciso o verboso <ul><li>class Integer </li></ul><ul><li>   def negative? </li></ul><ul><li>     self < 0 </li></ul><ul><li>   end </li></ul><ul><li>   def suitable_for_string_calculator? </li></ul><ul><li>     self <= 1000 </li></ul><ul><li>   end </li></ul><ul><li>   end </li></ul><ul><li> </li></ul><ul><li>class Calculator </li></ul><ul><li>   def add (args) </li></ul><ul><li>     strnumbers, delimiter = extract_strnumbers_and_delimiter args </li></ul><ul><li>     numbers = get_number_list strnumbers, delimiter </li></ul><ul><li>     get_only_suitable_numbers numbers </li></ul><ul><li>     check_negatives_numbers numbers </li></ul><ul><li>     numbers . inject 0 , :+                                                                                  SUMA LOS ELEMENTOS DE UNA LISTA </li></ul><ul><li>   end </li></ul><ul><li>   def get_number_list (numbers_str, delimiter) </li></ul><ul><li>     numbers_str . split(delimiter) . collect { | num | num . to_i } </li></ul><ul><li>   end </li></ul><ul><li>   def get_only_suitable_numbers (numbers) </li></ul><ul><li>     numbers . select! & :suitable_for_string_calculator? </li></ul><ul><li>   end </li></ul><ul><li>   def check_negatives_numbers (numbers) </li></ul><ul><li>     negatives = numbers . select & :negative?                                                             LISTA NUMEROS NEGATIVOS </li></ul><ul><li>     raise &quot;negatives not allowed (#{ negatives . join( ', ' ) })&quot; if negatives . any?                  IF AL FINAL </li></ul><ul><li>   end </li></ul><ul><li>   def extract_strnumbers_and_delimiter (args) </li></ul><ul><li>       delimiters = /[n,]/ </li></ul><ul><li>       text = args . dup </li></ul><ul><li>       first_line = text . slice!( %r{^//(.+)n} ) </li></ul><ul><li>       delimiters = first_line . scan( %r{[([^]]+)]} ) . flatten << delimiters if first_line </li></ul><ul><li>       return text, Regexp . union(delimiters) </li></ul><ul><li>   end </li></ul><ul><li>end </li></ul>43 líneas
  15. 15. Conciso o verboso <ul><li>... </li></ul><ul><li>@Test </li></ul><ul><li>public void testAddEmpty () throws Exception { </li></ul><ul><li>    assertEquals ( &quot;adding empty string&quot; , 0 , calc . add ( &quot;&quot; )); </li></ul><ul><li>} </li></ul><ul><li>@Test </li></ul><ul><li>public void testSingleElement () throws Exception { </li></ul><ul><li>    assertEquals ( &quot;adding simple element&quot; , 1 , calc . add ( &quot;1&quot; )); </li></ul><ul><li>    assertEquals ( &quot;adding more simple elements&quot; , 345 , calc . add ( &quot;345&quot; )); </li></ul><ul><li>} </li></ul><ul><li>@Test </li></ul><ul><li>public void testTwoElementsSum () throws Exception { </li></ul><ul><li>    assertEquals ( &quot;adding two elements&quot; , 3 , calc . add ( &quot;1,2&quot; )); </li></ul><ul><li>    assertEquals ( &quot;adding two more elements&quot; , 201 , calc . add ( &quot;123,78&quot; )); </li></ul><ul><li>} </li></ul><ul><li>@Test </li></ul><ul><li>public void testNewLineDelimitier () throws Exception { </li></ul><ul><li>    assertEquals ( &quot;adding with different delimiter&quot; , 6 , calc . add ( &quot;1n2,3&quot; )); </li></ul><ul><li>} </li></ul><ul><li>PROBANDO EXCEPCIONES </li></ul><ul><li>@Test </li></ul><ul><li>public void testNegativesThrowsException () throws Exception { </li></ul><ul><li>    try { </li></ul><ul><li>      calc . add ( &quot;6,-8,3,-52&quot; ); </li></ul><ul><li>    fail ( &quot;testing negative numbers, shouldn't be here&quot; ); </li></ul><ul><li>    } catch ( Exception e ) { </li></ul><ul><li>      String msg = e . getMessage (); </li></ul><ul><li>      assertTrue ( &quot;contains negative sentence&quot; , </li></ul><ul><li>      msg . contains ( &quot;no se permiten negativos&quot; )); </li></ul><ul><li>      assertTrue ( &quot;contains negative number&quot; , msg . contains ( &quot;-8&quot; )); </li></ul><ul><li>      assertTrue ( &quot;contains negative number&quot; , msg . contains ( &quot;-52&quot; )); </li></ul><ul><li>    } </li></ul><ul><li>} </li></ul><ul><li>... </li></ul>
  16. 16. Conciso o verboso <ul><li>describe &quot;String calculator&quot; do </li></ul><ul><li>   before do </li></ul><ul><li>     @calculator = Calculator . new </li></ul><ul><li>   end </li></ul><ul><li>   it &quot;empty should be 0&quot; do </li></ul><ul><li>     @calculator . add( &quot;&quot; ) . should == 0 </li></ul><ul><li>   end </li></ul><ul><li>PROBANDO VARIOS CASOS CON HASHTABLE </li></ul><ul><li>   { &quot;&quot; => 0 , &quot;1&quot; => 1 , &quot;345&quot; => 345 , &quot;1,1&quot; => 2 , &quot;3,4&quot; => 7 , &quot;1,1,1&quot; => 3 , </li></ul><ul><li>     &quot;1,2,3&quot; => 6 , &quot;5n2n3&quot; => 10 , &quot;123,78&quot; => 201 } . each do | numbers, result | </li></ul><ul><li>     it &quot;adding #{ numbers } should be #{ result }&quot; do </li></ul><ul><li>       @calculator . add(numbers) . should == result </li></ul><ul><li>     end </li></ul><ul><li>   end </li></ul><ul><li>   it &quot;delimiter , and n should work&quot; do </li></ul><ul><li>     @calculator . add( &quot;1n2,3&quot; ) . should == 6 </li></ul><ul><li>   end </li></ul><ul><li>   it &quot;different delimiters specified in first line should work&quot; do </li></ul><ul><li>     @calculator . add( &quot;//[%]n2%6&quot; ) . should == 8 </li></ul><ul><li>     @calculator . add( &quot;//[;]n1;2&quot; ) . should == 3 </li></ul><ul><li>     @calculator . add( &quot;//[+]n8+12,43&quot; ) . should == 63 </li></ul><ul><li>   end </li></ul><ul><li>   it &quot;doesn't allow negative numbers&quot; do PROBANDO EXCEPCIONES </li></ul><ul><li>      expect { @calculator . add( &quot;1n-2n-3n4&quot; ) } . to raise_error( Exception , &quot;negatives not allowed (-2, -3)&quot; ) </li></ul><ul><li>    end </li></ul><ul><li>   it &quot;big numbers should be ignored&quot; do </li></ul><ul><li>     @calculator . add( &quot;2,1001&quot; ) . should == 2 </li></ul><ul><li>     @calculator . add( &quot;2,1000&quot; ) . should == 1002 </li></ul><ul><li>   end </li></ul><ul><li>... </li></ul>
  17. 17. Conciso o verboso <ul><li>... </li></ul><ul><li>ROMANS = { M: 1000 , CM : 900 , D: 500 , CD : 400 , C: 100 , XC : 90 , L: 50 , XL : 40 , X: 10 , IX : 9 , V: 5 , IV : 4 , I: 1 } </li></ul><ul><li>class Fixnum </li></ul><ul><li>   def to_roman </li></ul><ul><li>     return nil unless self > 0 && self < 4000 </li></ul><ul><li>     remaining_number = self </li></ul><ul><li>     ROMANS . inject ( &quot;&quot; ) do | roman_str, current_number | </li></ul><ul><li>         times,remaining_number = remaining_number . divmod current_number [ 1 ] </li></ul><ul><li>         roman_str + current_number [ 0 ]. to_s * times </li></ul><ul><li>     end </li></ul><ul><li>   end </li></ul><ul><li>end </li></ul><ul><li>TRANSFORMATIONS = { </li></ul><ul><li>   I: 1 , II : 2 , III : 3 , IV : 4 , V: 5 , VI : 6 , VII : 7 , VIII : 8 , IX : 9 , X: 10 , XI : 11 , XII : 12 , XIV : 14 , XV : 15 , </li></ul><ul><li>   XIX : 19 , XXXIX : 39 , XL : 40 , XLI : 41 , L: 50 , LXXXIX : 89 , XC : 90 , XCIX : 99 , C: 100 , CCCXCIX : 399 , CD : 400 , </li></ul><ul><li>   D: 500 , DCCCXCIX : 899 , CM : 900 , M: 1000 , MMXI : 2011 , MMMCMXCIX : 3999 </li></ul><ul><li>} </li></ul><ul><li>describe &quot;From arabic to roman numerals. &quot; do </li></ul><ul><li>   TRANSFORMATIONS . each do | roman, arabic | </li></ul><ul><li>     it( &quot;transforms #{ arabic } to #{ roman }&quot; ) do </li></ul><ul><li>       arabic . to_roman . should == roman . to_s </li></ul><ul><li>     end </li></ul><ul><li>   end </li></ul><ul><li>   [ - 10 , 0 , 4000 , 4100 ]. each do | bad_arabic | </li></ul><ul><li>     it( &quot;#{ bad_arabic } can not be transformed to roman numeral&quot; ) do </li></ul><ul><li>       bad_arabic . to_roman . should == nil </li></ul><ul><li>     end </li></ul><ul><li>   end </li></ul><ul><li>end </li></ul>
  18. 18. Llamar métodos por nombre / introspección <ul><li>class Integer </li></ul><ul><li>   def to_fizzbuzz1 </li></ul><ul><li>     return &quot;FizzBuzz&quot; if fizzbuzz? </li></ul><ul><li>     return &quot;Fizz&quot; if fizz? </li></ul><ul><li>     return &quot;Buzz&quot; if buzz? </li></ul><ul><li>     self </li></ul><ul><li>   end </li></ul><ul><li>   FIZZBUZZ3 = { fizzbuzz?: &quot;FizzBuzz&quot; , buzz?: &quot;Buzz&quot; , fizz?: &quot;Fizz&quot; } </li></ul><ul><li>   def to_fizzbuzz3 </li></ul><ul><li>     FIZZBUZZ3 .each do | method , name | </li></ul><ul><li>       return name if send method </li></ul><ul><li>     end </li></ul><ul><li>     self </li></ul><ul><li>   end </li></ul><ul><li>   def multiple_of? n </li></ul><ul><li>     self % n == 0 </li></ul><ul><li>   end </li></ul><ul><li>   def fizz? </li></ul><ul><li>     multiple_of? 3 </li></ul><ul><li>   end </li></ul><ul><li>  ... </li></ul><ul><li>   def fizzbuzz? </li></ul><ul><li>     multiple_of? 15 </li></ul><ul><li>   end </li></ul>
  19. 19. Llamar métodos por nombre / introspección <ul><li>describe &quot;FizzBuzz identity cases&quot; do </li></ul><ul><li>   it &quot;1 should be 1&quot; do </li></ul><ul><li>     1 . to_fizzbuzz . should == 1 </li></ul><ul><li>   end </li></ul><ul><li>   it &quot;4 should be 4&quot; do </li></ul><ul><li>     4 . to_fizzbuzz . should == 4 </li></ul><ul><li>   end </li></ul><ul><li>end </li></ul><ul><li>... </li></ul><ul><li>describe &quot;FizzBuzz FizzBuzz cases&quot; do </li></ul><ul><li>     it &quot;15 should be Buzz&quot; do </li></ul><ul><li>       15 . to_fizzbuzz . should == &quot;FizzBuzz&quot; </li></ul><ul><li>     end </li></ul><ul><li>... </li></ul><ul><li>end </li></ul><ul><li>describe &quot;FizzBuzz testing all implementations&quot; do </li></ul><ul><li>    [ :to_fizzbuzz1 , :to_fizzbuzz2 , :to_fizzbuzz3 ]. each do | impl | </li></ul><ul><li>        ( 1 . . 100 ) . each do | n | </li></ul><ul><li>          it &quot;trying impl. #{ impl } for number #{ n }&quot; do </li></ul><ul><li>            n . send(impl) . should == n . to_fizzbuzz </li></ul><ul><li>          end </li></ul><ul><li>        end </li></ul><ul><li>     end </li></ul><ul><li>end </li></ul>
  20. 20. Inferencia de tipos <ul><li>Java </li></ul><ul><li>int x = 1 + 2 * 3; </li></ul><ul><li>String y = x.toString(); </li></ul><ul><li>List<String> lista = new ArrayList<String>(); </li></ul><ul><li>Map<String, Integer> m = new HashMap<String, Integer>(); </li></ul><ul><li>public int incrementar(int x) { </li></ul><ul><li>return x + 1; </li></ul><ul><li>} </li></ul><ul><li>Java 7:  </li></ul><ul><li>Map<String, List<String>> myMap = new HashMap<>(); </li></ul><ul><li>Scala </li></ul><ul><li>val x = 1 + 2 * 3  </li></ul><ul><li>val y = x.toString()  </li></ul><ul><li>val lista : List[String] = new ArrayList[String] </li></ul><ul><li>val lista = new ArrayList[String] </li></ul><ul><li>val lista = List </li></ul><ul><li>val lista = List(&quot;elm1&quot;, &quot;elm2&quot;) </li></ul><ul><li>val m = new HashMap[String,Int] </li></ul><ul><li>def incrementar(x: Int) : Int = x + 1 </li></ul><ul><li>def incrementar(x: Int) = x + 1 </li></ul><ul><li>  </li></ul>
  21. 21. Tipos covariantes y contracovariantes, not reified (type erasure), ... <ul><li>Java: </li></ul><ul><li>Vehiculo[] v = new Vehiculo[10]; </li></ul><ul><li>Coche[] c = new Coche[10]; </li></ul><ul><li>v = c; // CORRECTO </li></ul><ul><li>List<Vehiculo> vlist = new ArrayList<Vehiculo>(); </li></ul><ul><li>List<Coche> vcoche = new ArrayList<Coche>(); </li></ul><ul><li>vlist = vcoche;  </li></ul><ul><li>// ERROR - Type mismatch: cannot convert from List<Coche> to List<Vehiculo> </li></ul><ul><li>Scala: </li></ul><ul><li>class Stack[+A] { </li></ul><ul><li>    def push[B >: A](elem: B) .... </li></ul>
  22. 22. Abrir clases o conversiones implícitas (vistas) <ul><li>2 days ago  </li></ul><ul><li>5 days from_now </li></ul><ul><li>class DateHelper(number: Int) {  </li></ul><ul><li>  def days(when: String) : Date = {  </li></ul><ul><li>    var date = Calendar.getInstance()  </li></ul><ul><li>    when match {  </li></ul><ul><li>        case &quot;ago&quot; => date.add(Calendar.DAY_OF_MONTH, -number)  </li></ul><ul><li>        case &quot;from_now&quot; => date.add(Calendar.DAY_OF_MONTH, number)  </li></ul><ul><li>        case _ => date  </li></ul><ul><li>    }  </li></ul><ul><li>    date.getTime()  </li></ul><ul><li>  }  </li></ul><ul><li>} </li></ul><ul><li>implicit def convertInt2DateHelper(number: Int) = new DateHelper(number) </li></ul><ul><li>final class RichChar(c: Char) </li></ul><ul><li>  {  </li></ul><ul><li>          def isDigit: Boolean = Character.isDigit(c) // isLetter, isWhitespace, etc.   </li></ul><ul><li>  }  </li></ul><ul><li>  object RichCharTest { </li></ul><ul><li>         implicit def charWrapper(c: char) = new RichChar(c)  </li></ul><ul><li>         def main(args: Array[String]) { println( '0' .isDigit) </li></ul><ul><li>  } </li></ul><ul><li>} </li></ul>
  23. 23. Duck typing, Interfaces o Structural typing <ul><li>class Duck {   </li></ul><ul><li>  def quack = println ( &quot;Quaaaaaack !&quot; )   </li></ul><ul><li>   def feathers = println ( &quot;The duck has white and gray feathers.&quot; )   </li></ul><ul><li>}    </li></ul><ul><li>class Person {   </li></ul><ul><li>  def quack = println ( &quot;The person imitates a duck.&quot; )   </li></ul><ul><li>  def feathers = println ( &quot;The person takes a feather from the ground and shows it.&quot; )   </li></ul><ul><li>} </li></ul><ul><li>...   </li></ul><ul><li>def inTheForest ( duck : { def quack ; def feathers }) = {   </li></ul><ul><li>    duck.quack  </li></ul><ul><li>    duck.feathers  </li></ul><ul><li>} type ActAsADuck = { </li></ul><ul><li>    def quack  </li></ul><ul><li>    def feathers </li></ul><ul><li>} </li></ul>
  24. 24. Missing method, invokedynamic (java7), Dynamic trait <ul><li>class Roman </li></ul><ul><li>  def romanToInt(str) </li></ul><ul><li>    # ... </li></ul><ul><li>  end </li></ul><ul><li>  def method_missing(methId) </li></ul><ul><li>    str = methId.id2name </li></ul><ul><li>    romanToInt(str) </li></ul><ul><li>  end </li></ul><ul><li>end </li></ul><ul><li>r = Roman.new </li></ul><ul><li>r.iv      #=> 4 </li></ul><ul><li>r.xxiii   #=> 23 </li></ul><ul><li>r.mm      #=> 2000 </li></ul><ul><li>miXml.persona.nombre , o miJson.persona.nombre ;-) </li></ul><ul><li>Rails lo usa muchísimo, por ejemplo find_by_columns </li></ul>
  25. 25. Módulos, mixins, traits, herencia múltiple, ... <ul><li>class miclase </li></ul><ul><li>{ </li></ul><ul><li>    include Enumerable # tengo gratis inject, all?, any?, collect... </li></ul><ul><li>    def each .... </li></ul><ul><li>} </li></ul><ul><li>Comparable, con <=> tengo <, <=, ==, >, >=, between? </li></ul><ul><li>Puedo mezclar los módulos que quiera </li></ul>
  26. 26. JVM <ul><li>Groovy </li></ul><ul><li>Scala </li></ul><ul><li>JRuby </li></ul><ul><li>Jython </li></ul><ul><li>Clojure </li></ul><ul><li>... </li></ul><ul><li>Quien lo iba a imaginar </li></ul>
  27. 27. Rendimiento <ul><li>¿ Compilado o interpretado ? </li></ul><ul><li>¿ Estáticos o dinámicos ?  </li></ul><ul><li>¿ Intensivo IO o CPU ? </li></ul><ul><li>¿ Funcionales (y no-SQL), objectivo contrario a lenguajes dinámicos ? </li></ul><ul><li>Actors ? transactional memory ? &quot;let it crash&quot; ? Monads ? </li></ul>&quot;SETI@home has been a success,obviously not in finding aliens,but in demonstrating the potential of large-scale distributed computing&quot;
  28. 28. Funcionales, recursión, complejidad, O(N), ... <ul><li>   def to_fib_recursive </li></ul><ul><li>     return self if zero? or one? </li></ul><ul><li>     ( self - 1 ) . to_fib_recursive + ( self - 2 ) . to_fib_recursive </li></ul><ul><li>   end </li></ul><ul><li>   def to_fib_tail </li></ul><ul><li>   return self if zero? or one? </li></ul><ul><li>     first,second = 0 , 1 </li></ul><ul><li>     ( self - 1 ) . times do </li></ul><ul><li>       first,second = second, first + second </li></ul><ul><li>     end </li></ul><ul><li>     second </li></ul><ul><li>   end </li></ul><ul><li>   def to_fib_inject </li></ul><ul><li>     return self if zero? or one? </li></ul><ul><li>     fib = ( self - 1 ) . times . inject( [ 0 , 1 ] ) do | group, n | </li></ul><ul><li>        [ group [ 1 ] , group [ 0 ] + group [ 1 ] ] </li></ul><ul><li>     end </li></ul><ul><li>     fib [ 1 ] </li></ul><ul><li>   end </li></ul><ul><li>   def to_fib_formula </li></ul><ul><li>     ( ( ( GOLDEN_RATIO ** self ) - (( - GOLDEN_RATIO ) ** ( - self )) ) / ROOT_FIVE ) . to_i </li></ul><ul><li>   end </li></ul><ul><li>   def one? </li></ul><ul><li>       self == 1 </li></ul><ul><li>   end </li></ul><ul><li>   ROOT_FIVE = Math . sqrt( 5 ) </li></ul><ul><li>   GOLDEN_RATIO = ( 1 + ROOT_FIVE ) / 2 </li></ul><ul><li>end </li></ul>
  29. 29. No olvidemos... <ul><ul><li>IDE y herramientas </li></ul></ul><ul><ul><li>Rendimiento </li></ul></ul><ul><ul><li>Chequeos compilación </li></ul></ul><ul><ul><li>Independencia plataforma </li></ul></ul><ul><ul><ul><li>Lenguaje </li></ul></ul></ul><ul><ul><ul><li>Librerías </li></ul></ul></ul><ul><ul><li>Muy bueno para frameworks genéricos (Rails, RSpec, Cucumber, etc.) pero para APIs ni interfaces ni tipos </li></ul></ul><ul><ul><li>Los dinámicos son de verdad más productivos ? </li></ul></ul>
  30. 30. ¡WARNING! La siguiente sección contiene opiniones subversivas que pueden herir la sensibilidad
  31. 31. Tipos de tipados  :-) <ul><li>¿Se realiza chequeo de tipos? </li></ul><ul><ul><li>Sí -> Tipado fuerte </li></ul></ul><ul><ul><li>No -> Tipado débil </li></ul></ul><ul><li>¿Cuándo se realiza el chequeo de tipos? </li></ul><ul><ul><li>En tiempo de ejecución -> Tipado dinámico </li></ul></ul><ul><ul><li>En tiempo de compilación -> Tipado estático </li></ul></ul>
  32. 32. Tipos de tipados  :-) <ul><li>¿Java, Scala, C#...? Tipado fuerte y estático </li></ul><ul><li>¿JS, Ruby ....? Tipado fuerte y dinámico </li></ul><ul><li>¿C, C++? Tipado débil (al menos en mis tiempos) </li></ul>
  33. 33. El compilador es tonto <ul><ul><li>Necesita información extra para chequear los tipos </li></ul></ul><ul><ul><ul><li>Ruido sintáctico -> Boilerplate code </li></ul></ul></ul><ul><ul><ul><li>Dependencia del IDE (CTRL+Space) </li></ul></ul></ul><ul><ul><ul><li>Reza para que sea rápido (ADA, ¿Scala?) </li></ul></ul></ul><ul><ul><li>Los errores de tipos son los sencillos </li></ul></ul><ul><ul><li>Es incapaz de detectar los errores semánticos, los realmente complicados </li></ul></ul>
  34. 34. Enter TDD (que cansino...) <ul><ul><li>No existe técnica para resolver el problema de detección de errores funcionales al 100% </li></ul></ul><ul><ul><li>Pero TDD y BDD son muy efectivos! </li></ul></ul>
  35. 35. Enter TDD (que cansino...) <ul><ul><li>No existe técnica para resolver el problema de detección de errores funcionales al 100% </li></ul></ul><ul><ul><li>Pero TDD y BDD son muy efectivos! </li></ul></ul><ul><li>Ahora os cuento un secreto.... </li></ul>
  36. 36. Enter TDD (que cansino...) <ul><ul><li>No existe técnica para resolver el problema de detección de errores funcionales al 100% </li></ul></ul><ul><ul><li>Pero TDD y BDD son muy efectivos! </li></ul></ul><ul><li>Ahora os cuento un secreto.... </li></ul><ul><li>¡ TDD también detecta errores sintácticos y de tipos ! </li></ul><ul><li>¡ Y los detecta al 100 % ! </li></ul><ul><li>(al menos en mi experiencia) </li></ul>
  37. 37. Tipado dinámico wins! <ul><li>Invocando el principio KISS: </li></ul><ul><li>IF ( &quot;TDD lo necesito sí o sí&quot;  </li></ul><ul><li>      && &quot;TDD detecta errores de tipado y de sintaxis&quot;) { </li></ul><ul><li>    DO Eliminar compilador </li></ul><ul><li>} </li></ul><ul><li>Y de paso elimino el ruido sintáctico: </li></ul><ul><ul><li>Escribo menos código </li></ul></ul><ul><ul><li>El código es más legible </li></ul></ul><ul><ul><li>Ciclo de desarrollo más ágil </li></ul></ul>
  38. 38. Tipado estático strikes back <ul><ul><li>Inferencia de tipos </li></ul></ul><ul><ul><li>Tipado estructural </li></ul></ul><ul><li>¿Tanta complejidad hará que el compilador sea lento? </li></ul><ul><li>¿Realmente que me aporta? </li></ul><ul><li>¿Qué gano respecto a un lenguaje dinámico usando TDD? </li></ul>
  39. 39. ¿Y los DSL? <ul><ul><li>Hacen tu código más cercano al dominio del problema </li></ul></ul><ul><ul><li>Legibilidad aumenta </li></ul></ul><ul><ul><li>Lenguajes dinámicos son buenos para esto </li></ul></ul><ul><ul><ul><li>Son maleables </li></ul></ul></ul><ul><ul><ul><li>Muchas capacidades de metaprogramación </li></ul></ul></ul><ul><ul><ul><li>¡Ruby y Groovy! </li></ul></ul></ul><ul><ul><li>Los lenguajes estáticos normalmente son malos para esto: JMock Vs. Spock Vs. RSpec Vs. Jasmine </li></ul></ul><ul><ul><li>! Pero Scala es muy bueno ! </li></ul></ul>
  40. 40. ¡YA ME VOY! Y ahora pasemos a las conclusiones (Gracias Leo!)
  41. 41. Conclusiones <ul><li>- ¿ Dinámicos para equipos pequeños con gente muy buena ? </li></ul><ul><li>- ¿  Estáticos  para proyectos grandes o con varios equipos ? </li></ul><ul><li>- ¿  Funcionales  para problemas específicos ? </li></ul><ul><li>Kent Beck:  &quot;Simplemente cuenta la historia.  No me gustan las conclusiones morales al final de las historias.&quot; </li></ul><ul><li>Así que cada uno saque sus propias conclusiones :-) </li></ul><ul><li>Muchas gracias </li></ul>Leo Antoli               @lantoli Enrique Amodeo     @eamodeorubio
  1. A particular slide catching your eye?

    Clipping is a handy way to collect important slides you want to go back to later.

×