Successfully reported this slideshow.
We use your LinkedIn profile and activity data to personalize ads and to show you more relevant ads. You can change your ad preferences anytime.
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?

1,332 views

Published on

Leo Antoli

  • Be the first to comment

  • Be the first to like this

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

×