Este post como siempre, tendrá un poco de polémica, así que me disculpo de antemano (tan simple como no leerme :D). El título dice muchas cosas, pero a la vez no se puede leer sin pensar. Antes de seguir leyendo esta entrada, si eres dev piensa, ¿por qué alguien haría una afirmación así?

El problema

Esto no es por desmeritar a nadie, y a veces entiendo que coleccionar cartones/cursos puede ser gratificante, pero ¿significan algo estos cursos? Hace un tiempo hice un post criticando algunos temas similares sobre obtener certificados cloud sin estudiar, y las personas que se sintieron tocadas, me romantizaron con el “esfuerzo” y que no debo desmerecer el “esfuerzo” de nadie. La verdad no desacredito el esfuerzo, sin embargo, yo personalmente no creo que sacar certificados a diestra y siniestra signifique ser una persona esforzada. Por otro lado, temas similares ocurren con lenguajes de programación. Hay gente que colecciona los lenguajes como si fueran cartas Pokémon.

Si bien aprender varios lenguajes podría servir para seguir el juego de “chamulleo” que existe en el reclutamiento TI, en términos intelectuales y de aprendizaje real, te hago el “spoiler”, no sirve de nada. Por ejemplo si sabes Java y ahora decides aprender C# porque tiene otra sintaxis, estarás básiamente perdiendo el tiempo. Lo mismo si te mueves de Typescript a Python, etc. ¿Por qué te digo esto?

  • Tienes lenguajes que pueden ser procedurales (independiente que sean orientados a objetos)
  • Los patrones de diseño son agnósticos a un lenguaje
  • Los algoritmos también son agnósticos al lenguaje

Pero, ¿es del todo incorrecto no aprender otros lenguajes? La respuesta es depende. Yo lo que recomiendo es aprender otros paradigmas de programación, por ejemplo:

  • Paradigma Funcional: Haskell, Scala Clojure
  • Paradigma Lóhico: Prolog
  • Paradigma simbólico: Sistemas expertos
  • etc (cualquier nuevo paradigma que se desarrolle)

Paradigma Funcional

El paradigma funcional en general es complicado (lo es para mí) porque te saca del modelo al que probablemenete estás acostumbrado (declarativo, procedural). Sin embargo, es un buen ejercicio estudiar este paradigma, para poder usar otras partes del cerebro y realmente salir de la zona de confort. Si no sientes ese calor en el pecho, ni dolor de cabeza cuando estás aprendiendo algo nuevo, significa que realmente no estás aprendiendo o saliendo de la zona de confort.

El ejemplo típico de haskell es mostrar lo expresivo que es programar quick-sort, yo haré una variación de este ejemplo y haré el merge sort.

splitInHalf :: [Int] -> ([Int], [Int])
splitInHalf inputList = 
    Data.List.splitAt (((Data.List.length inputList) + 1) `div` 2) inputList

merge :: [Int] -> [Int] -> [Int]
merge [] [] = []
merge l1 [] = l1
merge [] l2 = l2
merge (x:l1) (y:l2)
    | x < y = x:(merge l1 (y:l2))
    | otherwise = y:(merge (x:l1) l2)

mergeSort :: [Int] -> [Int]
mergeSort [] = []
mergeSort (x:[]) = [x]
mergeSort x = merge x1' x2'
    where
        (x1, x2) = splitInHalf x
        x1' = mergeSort x1
        x2' = mergeSort x2

Si bien, no es la mejor implemetación (soy nuevo en programación funcional y en teoría de categorías), se observa que la implementación no tiene ningún estado, es decir que en ningún momento hice explícito crear un nuevo array, o manipular memoria de cualquier forma. También estos lenguajes en general son de tipado fuerte, y es bastante complejo introducir bugs (ya que todo es sin estado).

Aquí entro en lo personal, me da dolor de estómago cada vez que veo un “roadmap” de Data Engineering, y ponen como requisitos X tecnologías, X nubes, etc. Yo creo que es más correcto tener un modelo mental funcional para probar que los “pipelines” de datos estén correctos y poder definir de forma predecible las entradas y salidas. Por algo, comunmenete se utiliza Scala que es de un paradigma funcional. Y revelando más detalles para quienes no leen papers, el modelo de programación Map-Reduce está basado en un paradigma funcional. De hecho en computación distribuida (concurrencia) es buena idea utilizar este paradigma de programación (ej. para definir procesos, entradas, salidas, idealmente correctitud del programa).

Paradigma Lógico

Siempre que escucho/leo inteligencia artifical en redes sociales (como LinkedIn), lo que muestran es:

Basura

Fig 1: Lo que se muestra que es IA en redes sociales.

Yo en verdad, siento que es mucho más:

  • Problemas de búsqueda (path finding, cualquier problema que tenga un estado inicial y un estado objetivo)
  • Problemas de satisfacción de restricciones (agendamiento y ordenamiento de horarios, Sudoku, cualquier problema que requiera un asignación de variables que idealmente lleve a una solución óptima utilizando alguna métrica de desempeño)
  • Problemas de razonamiento (e.g. Razonar para tomar una acción en base a lo que se percibe del mundo, ej. un robot)
  • Machine Learning
  • Muchos más…

Se observa que Machine Learning es una de entre tantas áreas de la IA, y generalizar como se hace en redes sociales me parece algo brusco. Como dice el título, hablaré del paradigma lógico. En este caso pondré el clásico problema del mundo del Wumpus. En esencia, se tiene un agente que se encuentra en una cueva y debe encontrar un tesoro. El problema es que no todo el mundo es observable, y en esta cueva hay peligros, por ejemplo hay precipicios, y también hay un Wumpus que matará al agente. El mundo del Wumpus sigue las siguientes reglas:

  • Hay un Wumpus en la cueva
  • Sólo hay un único wumpus
  • Si en siente una brisa, significa que adjacente a la brisa hay un precipicio, si se siente un olor, se encuentra cerca el Wumpus.

Este mundo, por ejemplo, se puede representar con axiomas lógicos (“conocimiento del mundo”) para que el agente razone y tome la mejor decisión. Aquí muestro una simulación (un poco fea la interfaz, pero no quise poner más esfuerzo)

wumpus

Fig 2: Simulación Agente en el mundo del Wumpus.

Se puede ver que el agente no tiene conocimiento total del mundo y razon utilizando lógica. En particular para la representación se utilizaron las siguientes cláusulas en lógica proposicional:

$$W_{11} \lor W_{12} \lor \ldots W_{mn}$$

$$(\neg W_{11} \lor \neg W{12}) … \land (\neg W_{mn-1} \lor \neg W_{mn})$$

$$B_{x,y} \iff (P_{x,y+1} \lor P_{x,y-1} \lor P_{x+1,y} \lor P_{x-1,y})$$

$$S_{x,y} \iff (W_{x,y+1} \lor W_{x,y-1} \lor W_{x+1,y} \lor W_{x-1,y})$$

El algoritmo que utilicé fue el algoritmo DPLL, si quieren ver la implementación, está en mi librería opensource pylogic en particular DPLL.

Como se puede observar, es un buen ejercicio a veces repasar, e implementar, por muy complejo que se vea. Yo ahora estoy estudiando teoría de categorías, y me ha servido para entender programación funcional.

Como detalle, en ningún trabajo que he estado he necesitado tener X años de experiencia en lenguaje Y. Y me ha tocado:

  • Python
  • Haskell
  • Hack
  • Java
  • TypeScript
  • Perl
  • Javascript
  • PHP

De hecho como dato freak, pasé una entrevista como Java Senior (apenas con un par de meses de experiencia en Java) y como especialista en Cloud, siendo que con suerte lo toqué un par de meses. Creo que el ejercicio mental, tiene más retorno de inversión que coleccionar lenguajes/certificados, etc.

Conclusiones

  • Aprender distintos paradigmas nos da una caja de herramientas para pensar los problemas de maner diferente
  • El coleccionar lenguajes/papeles no te garantiza que realmente estes aprendiendo algo nuevo
  • Es buen ejercicio a veces tomar e implementar algoritmos que se ven complejos (se repasa recursión, memoization, árboles binarios, etc)