¿Cómo aprender a programar ?

Actualmente nos encontramos viviendo la Cuarta Revolución Industrial impulsada por las denominadas tecnologías emergentes como: la computación en la nube, el Internet de las Cosas (IoT por las siglas en inglés de Internet of Things),  el Blockchain, la Inteligencia Artificial y el Aprendizaje de Máquina. Esta nueva revolución se caracteriza por operar con grandes volúmenes de datos, en diferentes formatos y distribuidos en diversas partes del mundo.

No sabemos qué trabajos existirán en el futuro, pero lo que sí sabemos es que estarán muy ligados a las tecnologías emergentes antes mencionadas. Por lo tanto, se hace necesario que nos adaptemos e incorporemos el pensamiento computacional en nuestras competencias. Tal como lo indica Jeannette Wing, el pensamiento computacional será una aptitud universal y no única de los científicos de la computación o informáticos. Pensar como un científico de la computación significa más que ser capaz de programar una computadora. Requiere pensar en múltiples niveles de abstracción.

Es en este contexto que nace el proyecto iterando++ que busca desarrollar el pensamiento computacional a través del aprendizaje de la programación. En este artículo intentaremos responder a la pregunta ¿cómo aprender a programar y desarrollar el pensamiento computacional? La respuesta que esbozaremos se enmarca pues en el proceso de resolución de problemas a través del uso del computador, organizando ordenadamente las operaciones a realizar y representando los datos a través de diversas abstracciones con el fin de llegar a una alternativa de solución. Presentaremos además, algunas sugerencias  que nos permitirá iniciar rápidamente en el mundo de la programación. 

Cuando se inicia en el mundo de la programación, se suele creer que lo único que se necesita para programar es el conocimiento de la sintaxis de un lenguaje de programación. Como veremos más adelante, esta es una condición necesaria pero no suficiente. El desarrollo del pensamiento computacional requiere que los seres humanos resuelvan problemas usando el computador, no busca que el humano piense como una computadora. Por el contrario, se busca que la inteligencia e imaginación que nos caracteriza, permita abordar problemas que antes de la era de la computación, eran imposible de resolver.

Este proceso de pensamiento requiere de una serie de conocimientos y habilidades de deben ser adquiridos. A continuación, describiremos los que a nuestro entender son las competencias mínimas que se requieren para poder programar y desarrollar el pensamiento computacional:

  • Conocer la arquitectura de las computadoras.
  • Aplicar correctamente la lógica proposicional.
  • Emplear el diseño algorítmico.
  • Reconocer los paradigmas de programación.
  • Utilizar un lenguaje de programación.
  • Diseñar programas en un Entorno de Desarrollo Integrado.

Conocer la arquitectura de las computadoras

Cuando uno diseña un programa, básicamente lo que está realizando es un conjunto de comandos o instrucciones que le indican a la computadora qué hacer. Por lo tanto, es muy relevante conocer qué puede hacer una computadora. La arquitectura de una computadora describe cómo se organizan de forma sistemática las diversas partes que la componen.

Quizás la arquitectura de computadoras más conocidas es la arquitectura von Neumann. En ella se describe a la computadora como un dispositivo formado por i) una memoria principal, ii) una Unidad Central de Proceso (CPU de las siglas en inglés Central Processing Unit) y iii) dispositivos de entrada y salida. Pero, ¿por qué es importante conocer la arquitectura de las computadoras para programar? Por muchas razones, expondremos a continuación un par de ellas que consideramos relevantes.

Para la programación es muy importante conocer muy bien cómo es que funciona la memoria en la computadora. Comprendiendo esto, es muy fácil entender, por ejemplo, qué es una variable en un programa. Cuando se intenta explicar qué es una variable sin saber cómo funciona la memoria, suelen decir que es como una cajita en donde se guarda un dato. Cuando se explica qué es una variable sabiendo cómo funciona la memoria se suele decir que es un espacio de memoria reservado en donde se puede almacenar un dato. ¿Notan la diferencia?, con la primera definición, la de la cajita, es muy probable que se pueda programar, con la segunda definición, la basada en la memoria, es muy probable que además se desarrolle el pensamiento computacional. Con la primera definición, la de la cajita, será muy complicado entender el concepto de puntero, con la segunda no. Y así, existe una serie de elementos de un programa que guardan estrecha relación con la memoria como las constantes, los arreglos, las referencias, entre otros.

Otro aspecto importante a conocer es el funcionamiento de la CPU. Dentro de la CPU se encuentra el Puntero de Instrucciones (IP por sus siglas en inglés Instruction Pointer) que almacena la dirección de memoria de la próxima instrucción a ejecutar. Sabiendo que existe el IP, fácilmente se pueden entender el control de flujo, las instrucciones de control de flujo (instrucciones selectivas e iterativas), las instrucciones de ruptura de flujo (\texttt{break}, \texttt{continue}, \texttt{return}), las programación modular (llamadas a funciones o procedimientos) y la recursión.

Si quieres aprender a programar rápido, si quieres entender rápidamente los diversos elementos de un lenguaje de programación, si quieres entender el porqué de cada instrucción de un programa, entonces debes entender cómo funciona una computadora, debes conocer la arquitectura de una computadora. 

Si te interesa profundizar más sobre arquitetura de computadoras, te recomendamos el libro Structured Computer Organization de Andrew Tanenbaum.

Aplicar correctamente la lógica proposicional

Foto de George Boole
George Boole

La lógica proposicional puede entenderse como el estudio de las proposiciones lógicas, es decir aquellas proposiciones que solamente pueden tener un posible valor: o verdad o falsedad. Fue el matemático británico George Boole, quien a partir de su libro Laws of Thought,  fundó las bases para la lógica algebraica también llamada lógica simbólica y de esta manera se desarrolló lo que se conoce hoy como el Algebra de Boole.

El álgebra de Boole es un sistema matemático que utiliza variables y operadores lógicos que permiten expresar razonamientos lógicos. Las principales operaciones en el álgebra de Boole son: la negación (\neg), la conjunción(\wedge) y la disyunción (\vee). A continuación se puede apreciar la tabla de verdad de estas operaciones, en donde se puede observar el resultado que se obtiene al aplicar la operación a las variables lógicas p y q.

pq\neg pp \wedge qp \vee q
VVFVV
VFFFV
FVVFV
FFVFF

Pero, ¿por qué es importante la lógica proposicional para la programación? Como ya se había comentado anteriormente, la programación consiste en dar órdenes al computador. En muchas ocasiones, dependiendo de los datos de entrada, los programas deben tomar ciertas decisiones. La forma de expresar una decisión en un programa es a través de razonamientos lógicos usando la lógica proposicional, esto es lo que muchos llaman lógica binaria, lógica de programación o lógica computacional. Por esto es muy importante la lógica para la programación, sin el desarrollo de la lógica proposicional no será posible programar ni entender cómo «piensan» las computadoras.

Pero un buen programador no solamente debe conocer la lógica proposicional sino debe sobre todo saber aplicarla. Es muy diferente entender cómo funciona una proposición lógica que plantear una para tomar determinada decisión. Lo que se requiere para ser un buen programador es saber aplicar la lógica proposicional diseñando diversas operaciones complejas, aplicando diversos teoremas que permiten además reducir la complejidad de las expresiones lógicas.

Si te interesa profundizar más sobre lógica, te recomendamos el libro Logic: A Complete Introduction  de Siu-Fan Lee.

Emplear el diseño algorítmico

diagrama de flujo - ecuación cuadrática
Diagrama de flujo

El algoritmo puede ser definido como como una secuencia de instrucciones no ambiguas que permiten resolver un problema en un tiempo determinado, permiten establecer una salida requerida para cualquier dato de entrada. Para resolver un problema usando el computador, se suelen emplear una serie de fases entre las que podemos mencionar las siguientes:

    1. La definición del problema
    2. El análisis del problema que busca describir el problema en términos de entradas, salidas y las precondiciones que deben cumplir los datos.
    3. El diseño del algoritmo propuesto usando algún formalismo para su representación (diagrama de flujo, como el presentado en la figura, pseudocódigo, diagrama Nassi-Shneiderman, árbol de decisión, tabla de decisión, entre otros).
    4. La codificación del diseño algorítmico en un programa, empleando para ello un lenguaje de programación.
    5. La depuración y pruebas del programa en un Entorno de Desarrollo Integrado (IDE de las siglas en inglés Integrated Development Environment).

 

Pero, ¿por qué es importante el diseño algorítmico? Como podrá notar, en las fases para la resolución de problemas usando el computador, en realidad la utilización del computador se incorpora recién en la fase 4, la fase de codificación. Las fases 1, 2 y 3 son por lo tanto son independientes al lenguaje de programación. Esto significa que el diseño de la solución que se realiza en la fase 3, es una solución universal en el sentido que es independiente del lenguaje de programación, y es por lo general, la parte más difícil del proceso de resolución de problemas.

Esta independencia permite muchas cosas, la más importante, según nuestro punto de vista, es que permite separar el qué del cómo. En la mayoría de las veces es más complicado determinar, en términos computacionales, el qué se tiene que hacer para resolver el problema que la codificación (el cómo se implementa la solución en el computador). Esta independencia parece trivial pero en realidad conseguirla es muy difícil, sobre todo los que están aprendiendo a programar desde cero. Según Jeannette Wing, el pensamiento computacional implica justamente esto «resolver problemas y diseñar algoritmo, basándose en los conceptos fundamentales de la ciencia de la computación». Al dominar esta habilidad, se podrá codificar la misma solución en diferentes lenguajes de programación. Como veremos más adelante, el aprendizaje de la sintaxis de los lenguajes de programación se ve facilitada si se domina el diseño algorítmico.

Por otro lado, es muy común que al diseñar la solución a determinado problema, podamos encontrarnos con varias alternativas de solución, antes este escenario, ¿cuál se debería implementar?, pues la respuesta a esta interrogante se encuentra en la algoritmia. La algoritmia se encarga del estudio de los algoritmos y a través de ella se podrá analizar las alternativas de solución encontradas y analizar su complejidad e inclusive utilizar diversas técnicas algorítmicas para su diseño.

 

Para tema de diseño de algoritmos, hay excelentes libros que recomendamos:

  • En el libro Introduction to the Design and Analysis of Algorithms  de Anany Levitin podrás leer mucho más sobre el análisis de algoritmos y una extensa revisión de las principales técnicas de diseño de algoritmos.
  • El libro Introduction to Algorithms de Thomas Cormen, es todo un clásico. En el podrás encontrar algoritmos clásicos de ordenación así como una descripción completa de las más interesantes estructuras de datos.
  • De igual manera en los libros Algorithms de Robert Sedgewick y The Algorithm Design Manual de Steven Skiena, podrás encontrar una revisión completa de análisis de algoritmos, estructuras de datos, algoritmos de ordenación y técnicas de diseño de algoritmos.

Para el diseño de diagramas de flujo y pseudocódigos, recomendamos el uso de la herramienta PSeInt. La imagen presentada al inicio de esta sección, se ha realizado usando esta herramienta.

Reconocer los paradigmas de programación

taxonomía de los paradigmas de programación
Taxomía de los paradigmas de programación

Un paradigma de programación es un enfoque para programar en una computadora basado en una teoría matemática o un conjunto coherente de principios. Cada paradigma admite un conjunto de conceptos que lo hacen el mejor para un determinado tipo de problema. Como ya se indicó anteriormente, el pensamiento computacional requiere pensar en múltiples niveles de abstracción. Uno de esos niveles de abstracción es el paradigma de programación. Antes de preguntarse ¿qué lenguaje de programación debería usarse?, se debe responder a la interrogante, ¿qué paradigmas de programación es el más adecuado para el tipo de problema que se desea resolver? Típicamente un lenguaje de programación soporte más de un paradigma de programación, por eso es importante conocerlos.

Como puede haber notado, en la figura de taxonomías de paradigmas de programación de Peter Van Roy mostrada al inicio de la sección, existen muchos paradigmas y además existe cierta relación entre alguno de ellos. Vamos a describir brevemente a los que consideramos los dos paradigmas de programación más utilizados en la actualidad: el paradigma imperativo y el paradigma declarativo.

El paradigma imperativo es uno de los paradigmas de programación más antiguos. Presenta una relación estrecha con la arquitectura de la computadora basándose principalmente en la arquitectura de Von Neumann. Funciona cambiando el estado de las variables de un programa a través de operaciones de asignación que se ejecutan paso a paso. El enfoque principal está en cómo lograr el estado meta, es decir, el valor final deseado para las variables de salida. Es muy simple de implementar pero problemas complejos no pueden ser resueltos fácilmente con este paradigma. El paradigma imperativo se puede dividir en 3 grandes categorías: el paradigma de programación procedural, el paradigma orientado a objetos y el procesamiento paralelo.

Por otro lado, el paradigma declarativo, es un estilo de construcción de programas que expresa la lógica de la computación sin hablar de su flujo de control. La atención se centra en lo que hay que hacer, en lugar del cómo se debe hacer. Se puede decir que en la programación imperativa, los programa le indican al computador cómo hacer para resolver un problema mientras que en la programación declarativa los programas le indican al computador qué se debe hacer para resolver un problema. El paradigma declarativo se puede dividir en 3 grandes categorías: paradigma de programación lógico, el paradigma de programación funcional y el enfoque basado en los datos.

Entonces, ¿por qué es importante el reconocer los paradigmas de programación? Pues es el punto de partida para poder seleccionar el lenguaje de programación. En los próximos post que publicaremos, estaremos presentando varios ejemplos de programas  usando el paradigma imperativo. 

Si deseas profundizar más en el tema de paradigmas de programación te recomendamos el libro Concepts, Techniques, and Models of Computer Programming de Peter Van Roy.

Utilizar un lenguaje de programación

portada del libro El Lenguaje de Programación de Kernighan
Libro "El Lenguaje de Programación C" de Brian Kernighan y Dennis Ritchie

Un lenguaje de programación no es más que un lenguaje formal que posee un conjunto de reglas gramaticales y sintácticas a través de las cuales se pueden codificar los programas. Generalmente los programadores usan lenguajes de programación de alto nivel. Este tipo de lenguaje se caracteriza por que permiten expresar los algoritmos de una manera más cercana al razonamiento humano. Lamentablemente las computadoras no «entienden» este tipo de lenguaje pues éstas solo reconocen el lenguaje de máquina, un tipo de lenguaje de bajo nivel. Para solucionar este problema es que nacen unos programas denominados traductores, los que a su vez se pueden clasificar en compiladores e intérpretes.

Los compiladores son traductores que leen un programa escrito en un lenguaje de programación (programa fuente) y lo traduce en un programa equivalente escrito en otro lenguaje de programación (programa destino). Por otro lado, los intérpretes, en lugar de producir un programa destino, ejecuta directamente las operaciones especificadas en el programa fuente a través de datos de entrada proporcionados por el usuario. Es importante conocer el proceso de traducción pues la forma en que se ejecuta un programa es diferente en cada caso. Algunos lenguajes de programación son compilados, otros son interpretados, inclusive existen algunos que son compilados e interpretados.

Es evidente que para escribir programar hay que dominar un lenguaje de programación. Pero el estudio de un lenguaje de programación no debe verse con un fin en sí sino como un medio para aprender a comunicarse con la computadora. Siempre será más importante el diseño algorítmico que la codificación.

Ahora corresponde responder a la pregunta ¿qué lenguaje se debe seleccionar para aprender a programar? Debo indicar que la respuesta a esta pregunta es por cierto bien compleja. Durante mucho tiempo Pascal fue el lenguaje preferido para aprender a programar, luego Scheme comenzó a usarse como primer lenguaje junto con JavaJavaScript es el favorito de muchos en la actualidad y algunos estudios recientes insinúan que Python podría ser la mejor opción.

La respuesta dependerá de para qué quieres aprender a programar. Si quieres aprender a programar para desarrollar el pensamiento computacional, en realidad cualquier lenguaje de programación estará bien. En iterando++ usaremos el lenguaje ANSI C, Java y Python para mostrar que, a nivel de diseño algorítmico, los 3 nos sirven por igual.

Ahora, si quieres aprender a programar videojuegos en redes sociales quizás sea interesante iniciar con JavaScript pero si te interesan los juegos de consola quizás la opción más interesante sea C#. Si tu enfoque es en el desarrollo de gráficos, pues C++ podría ser una opción interesante. Si te interesa más el desarrollo Web pues quizás PHP sea una buena opción. Aunque recuerda que siempre que aprendas bien los fundamentos mencionados anteriormente, aprender nuevos lenguajes será relativamente fácil. Así que no te preocupes demasiado intentando responder esta pregunta. 

  • Si te interesa profundizar en los traductores y en especial de los compiladores, te recomendamos el libro Engineering: A Compiler de Keith Cooper  y Linda Torczon.
  • Si quieres profundizar en el lenguaje ANSI C, no hay mejor libro que C Programming Language de Brian Kernighan  y Dennis Ritchie. Es un libro clásico escrito por el creador del lenguaje C.
  • Si lo tuyo va por la especialización en Java, el mejor libro que hay es Effective Java de Joshua Bloch.
  • Si te interesa más el desarrollo en Python, los dos mejores libros que se han escrito son Learning Python de Mark Lutz y Python Crash Course de Eric Matthes.

Diseñar programas en un Entorno de Desarrollo Integrado

Finalmente llegamos al IDE. Se requiere pues de un programa que permita escribir los programas en un lenguaje de programación y traducirlos. Los IDEs además ofrecen una serie de herramientas que soportan el proceso de resolución de problemas (generación automática de código, compilación, interpretación, inspección de variables, depuración, ejecución paso a paso, entre otros). Por ello es importante conocerlos al detalle pues agilizarán mucho la escritura de código fuente y la depuración de los programas. Dependiendo del lenguaje a utilizar, se pueden usar determinados IDEs. Si estás aprendiendo a programar, es buena idea que le dediques algo de tiempo a estudiar a fondo el IDE.

En la actualidad los IDEs soportan muchos lenguajes, por ejemplo Netbeans, soporta tanto Java, como ANSI C y C++, Eclipe por su lado soporta Java, ANSI C, C++ y Python. Anaconda por su lado soporta a los lenguajes Python y R. Además existen IDEs en línea que no requiere la instalación de ningún programa en el computador, entre ellos podemos mencionar a Repl.it.

Conclusión

Se ha intentado describir en este artículo los requisitos necesario para aprender a programar bien, desde cero como se dice, con la finalidad de propiciar el pensamiento computacional. Como se puede observar, son varios prerrequisitos que se deben cumplir por lo que es imposible que se aprenda a programa en 20 minutos, 1 hora, 1 día o una semana. Es un proceso de aprendizaje constante, iterativo e incremental. El proceso incluye por supuesto escribir programas. Si deseas aprender a programar, debes escribir muchos programas.