En la primera parte de esta serie vimos una primera introducción a Scala como lenguaje de programación definiendo algunas características de su sintaxis. En esta segunda parte pasaremos a la práctica utilizando una Code Kata.
En las artes marciales, se denomina kata a una representación, individual o colectiva, de un conjunto de movimientos. En disciplinas como el Karate se suelen enseñar en exhibiciones. El objetivo de las mismas es repetir los movimientos una y otra vez hasta que los mismos surjan de manera natural.
En programación, denominamos code kata a una definición de un problema relativamente simple, que resolvemos una y otra vez cuando estamos aprendiendo un lenguaje o una técnica como TDD. En este caso elegiremos una kata llamada Karate Chop, que define lo siguiente:
Dada una lista ordenada y un número, devolver la posición del mismo en la lista o -1 si no se encuentra, utilizando búsqueda binaria para ello.
El objetivo en este caso era ver si podía aprender lo mínimo necesario para poder escribir una solución a esta Kata utilizando Scala y utilizando la sintaxis de programación estructurada o orientada a objetos a la que estoy acostumbrado. Tras varias iteraciones agregando tests y condiciones, llegué al siguiente resultado:
def chop (target: Int, searchBox: Array[Int]) : Int = { | |
val size = searchBox.size | |
if (size == 0) { | |
return –1 | |
} | |
if (size == 1){ | |
if(searchBox(0) == target){ | |
return 0 | |
} else { | |
return –1 | |
} | |
} | |
val pointer = searchBox.size / 2 | |
val searchResult = searchBox(pointer) | |
if(searchResult == target){ | |
return pointer | |
} | |
if (searchResult < target){ | |
val partialResult = chop(target, searchBox.slice(pointer, size)) | |
if(partialResult == –1) | |
return –1 | |
return pointer + partialResult | |
} | |
if (searchResult > target){ | |
return chop(target, searchBox.slice(0, pointer)); | |
} | |
return –1 | |
} |
Para hacer las pruebas se suele usar un framework como ScalaTest, o recurrir a JUnit o TestNG de Java, que, como hemos mencionado anteriormente, son compatibles. En mi caso me limité a crear una pequeña función auxiliar que simplemente comparaba el resultado de la función y escribía por pantalla si había discrepancias:
def assert(expected: Int, actual: Int){ | |
if(expected == actual){ | |
println("OK"); | |
} | |
else { | |
println("Error, expected: " + expected + " actual: "+ actual); | |
} | |
} |
Finalmente, para comprobar que el código “funciona” he usado el siguiente conjunto de casos de prueba:
def main(args: Array[String]){ | |
test(–1, 2, Array.emptyIntArray) | |
test(0, 1, Array(1,2,3,4,5)) | |
test(2, 3, Array(1,2,3,4,5)) | |
test(2, 3, Array(1,2,3)) | |
test(0, 1, Array(1)) | |
test(4, 5, Array(1,2,3,4,5)) | |
test(3, 4, Array(1,2,3,4,5)) | |
test(1, 2, Array(1,2,3,4,5)) | |
test(–1, 0, Array(1,2,3,4,5)) | |
test(–1, 7, Array(1,2,3,4,5)) | |
} | |
def test(expected: Int, target: Int, searchBox: Array[Int]): Unit ={ | |
assert(expected, chop(target, searchBox)) | |
} |
Escribiendo esta función aprendí varias cosas sobre Scala:
- No necesitamos escribir el tipo de dato, ya que tenemos las palabras reservadas var para variables y val para objetos inmutables. Scala infiere el tipo de dato en tiempo de compilación por nosotros de la misma manera que lo hace C#, de manera que tenemos un sistema de tipos sólido y más sencillo de escribir.
-
Como curiosidades de sintaxis, el tipo de respuesta de una función lo definimos al final de la misma, en la definición de los parámetros también se declara primero el nombre y después el tipo, y el acceso a arrays se realiza mediante paréntesis en vez de corchetes.
#Conclusiones
Lo más importante que podemos ver en este ejemplo, es que no necesitamos cambiar nuestra manera de programar para comenzar a usar Scala, y que podemos ir agregando características funcionales de lenguaje a nuestro código poco a poco.
En el siguiente artículo de la serie volveremos a la teoría, retomando por donde lo habíamos dejado, viendo características como las Case Classes, el reconocimiento de patrones, y otros ejemplos de código, más funcionales que podemos encontrar en GitHub.
Mientras tanto, aquí están algunos enlaces sobre coding katas que he usado para hacer este artículo:
- El código completo de la kata está disponible en: https://github.com/rlbisbe/codekatas/blob/master/src/main/scala/KarateChop.scala
- Un artículo apoyando las code katas: http://www.peterprovost.org/blog/2012/05/02/kata-the-only-way-to-learn-tdd/
- Un artículo cuestionando las code katas: http://codekata.com/kata/kata02-karate-chop/
- La kata original que he usado en este artículo: https://hackhands.com/dont-code-katas/