21 de diciembre de 2018

A las pruebas me remito

Siempre que escribimos un programa computacional necesitamos verificar que efectivamente funciona tal como se espera. Usualmente ejecutamos el código, si es necesario proporcionamos algunas entradas, y finalmente observamos si la salida obtenida es la que deseamos. De no ser así, hay que revisar el programa, hacer las correcciones necesarias, y repetir todo el proceso anterior. La acción de probar y verificar que un programa genera los resultados esperados usualmente se hace manualmente y no de manera automática. Esto puede resultar tedioso y consumir mucho tiempo cuando el software siendo escrito va más allá de una aplicación relativamente pequeña.

Image result for evidence
Fuente: www.thecaselawfirm.com

Afortunadamente, existen las pruebas unitarias automatizadas, las cuales son porciones de código diseñadas para comprobar que el código principal está funcionando de la manera esperada.

Veamos un ejemplo. Supongamos que deseamos escribir en Python una función que calcule la hipotenusa c de un triángulo rectángulo dados sus catetos a y b:


El teorema de Pitágoras establece que el cuadrado de la hipotenusa es igual a la suma de los cuadrados de las catetos respectivos, es decir:


En Python la función hipotenusa podría quedar codificada de la siguiente manera:
from math import sqrt

def hipotenusa(a, b):
    return sqrt(a ** 2 + b ** 2)
NOTA: Todo el código que aquí se presenta fue probado con Python 3.7.

El siguiente código pudiera considerarse una prueba unitaria encargada de verificar que la función hipotenusa devuelva el resultado esperado a partir de las entradas 3 y 4:
if hipotenusa(3.0, 4.0) == 5.0:
    print('Pasó la prueba')
else:
    print('Falló la prueba')
Sin embargo, escribir pruebas similares al ejemplo anterior no es recomendable dado que requiere teclear mucho código cuando deseamos elaborar múltiples pruebas y además no es la manera convencional de hacerlo.

Fuente: searchengineland.com

La distribución estándar de Python provee dos mecanismos que simplifican la escritura y automatización de nuestras pruebas unitarias: unittest y doctest. La primera opción es un módulo inspirado en los frameworks de pruebas unitarias desarrollados por Erich Gamma y Kent Beck para los lenguajes Java y Smalltalk. La segunda opción, doctest, generalmente se considera más sencilla de usar que unittest, aunque esta última puede ser más adecuada para pruebas más complejas.

A continuación realizaré una breve introducción al módulo de doctest con el fin de elaborar pruebas unitarias al momento de definir funciones en Python.

El doctest va dentro del docstring

Un docstring es una cadena de caracteres que se coloca como primer enunciado de un módulo, clase, método o función, con el fin de explicar su intención. Esto lo expliqué hace algunos años con más lujo de detalle en la entrada de este blog titulada Documentando programas en Python.

La función hipotenusa, definida anteriormente, podría tener el docstring que se muestra aquí:
from math import sqrt

def hipotenusa(a, b):
    '''Calcula la hipotenusa de un triángulo rectángulo.

    Utiliza el teorema de Pitágoras para determinar la
    hipotenusa a partir de los catetos de un triángulo.

    Parámetros:
    a -- primer cateto
    b -- segundo cateto

    '''
    return sqrt(a ** 2 + b ** 2)
Aquí el docstring es una cadena de caracteres multi-líneas, la cual comienza y termina con triples comillas sencillas (''') o dobles (""").

El módulo doctest busca en los docstrings fragmentos de texto que parezcan sesiones interactivas de Python con el fin de ejecutarlos y verificar que funcionan exactamente como se muestran.

Por ejemplo, la siguiente sesión interactiva de Python muestra la manera en que se comporta la función hipotenusa con diferentes argumentos:
>>> hipotenusa(3.0, 4.0)
5.0
>>> hipotenusa(0.0, 0.0)
0.0
>>> hipotenusa(8.0, 15.0)
17.0
>>> hipotenusa(39.0, 80.0)
89.0
>>> round(hipotenusa(1.0, 1.0), 4)
1.4142
NOTA: En el último caso se usó la función round para redondear el resultado a 4 cifras después del punto decimal. Se recomienda hacerlo de esta manera para evitar los problemas de precisión que surgen cuando aparecen números reales con una parte fraccionaria compuesta de muchas cifras.

El texto completo de esta sesión interactiva, incluyendo los indicadores (prompts) del intérprete (>>>), se coloca dentro del doctring, típicamente al final, aunque en realidad puede ir donde sea:
from math import sqrt

def hipotenusa(a, b):
    '''Calcula la hipotenusa de un triángulo rectángulo.

    Utiliza el teorema de Pitágoras para determinar la
    hipotenusa a partir de los catetos de un triángulo.

    Parámetros:
    a -- primer cateto
    b -- segundo cateto
    
    Ejemplos de uso:
    
    >>> hipotenusa(3.0, 4.0)
    5.0
    >>> hipotenusa(0.0, 0.0)
    0.0
    >>> hipotenusa(8.0, 15.0)
    17.0
    >>> hipotenusa(39.0, 80.0)
    89.0
    >>> round(hipotenusa(1.0, 1.0), 4)
    1.4142

    '''
    return sqrt(a ** 2 + b ** 2)

Corriendo las pruebas

Existen dos opciones para correr las pruebas. La primera opción consiste en usar la terminal del sistema y ejecutar un comando similar al siguiente  (suponiendo que el archivo que contiene nuestro código se llama pitagoras.py):
python3 -m doctest pitagoras.py
La opción -m doctest le dice al intérprete de Python que ejecute el módulo doctest. El comando no produce salida alguna en caso de pasar todas las pruebas.

Si alguna prueba llega a fallar, entonces se verá un mensaje con la información pertinente. Por ejemplo, si agregamos al doctring el siguiente caso, el cual tiene un resultado incorrecto:
>>> hipotenusa(2.0, 2.0)
2.0
al correr nuevamente las pruebas obtenemos un mensaje similar al siguiente:
************************************************************
File "pitagoras.py", line 25, in 
pitagoras.hipotenusa
Failed example:
    hipotenusa(2.0, 2.0)
Expected:
    2.0
Got:
    2.8284271247461903
************************************************************
1 items had failures:
   1 of   6 in pitagoras.hipotenusa
***Test Failed*** 1 failures.
Se puede añadir también la opción -v (habilitar modo verboso o detallado) en la línea de comando al momento de correr nuestras pruebas. En este caso se produce un reporte completo con la información de todas las pruebas, hayan sido exitosas o no:
python3 -m doctest pitagoras.py -v
La salida en este caso sería:
Trying:
    hipotenusa(3.0, 4.0)
Expecting:
    5.0
ok
Trying:
    hipotenusa(0.0, 0.0)
Expecting:
    0.0
ok
Trying:
    hipotenusa(8.0, 15.0)
Expecting:
    17.0
ok
Trying:
    hipotenusa(39.0, 80.0)
Expecting:
    89.0
ok
Trying:
    round(hipotenusa(1.0, 1.0), 4)
Expecting:
    1.4142
ok
Trying:
    hipotenusa(2.0, 2.0)
Expecting:
    2.0
************************************************************
File "pitagoras.py", line 25, in 
pitagoras.hipotenusa
Failed example:
    hipotenusa(2.0, 2.0)
Expected:
    2.0
Got:
    2.8284271247461903
1 items had no tests:
    pitagoras
************************************************************
1 items had failures:
   1 of   6 in pitagoras.hipotenusa
6 tests in 2 items.
5 passed and 1 failed.
***Test Failed*** 1 failures.
La segunda opción para correr las pruebas consiste en agregar las siguientes tres líneas de código al final del archivo pitagoras.py:
if __name__ == '__main__':
    import doctest
    doctest.testmod()
La instrucción if anterior revisa si el archivo actual se está ejecutando como un programa (cuando la variable __name__ es igual a la cadena '__main__') o si se importó como un módulo (cuando la variable __name__ es igual al nombre del módulo, en este caso la cadena 'pitagoras'). Solo deseamos llevar a cabo las pruebas cuando el archivo se corre como un programa y, cuando es así, realizamos la importación del módulo doctest seguido de la invocación de su función testmod.

Después de lo anterior podemos correr nuestro archivo como nos resulte más conveniente (por ejemplo, desde la terminal o usando nuestro ambiente de desarrollo predilecto). Si es desde la terminal, basta teclear el siguiente comando:
python3 pitagoras.py
Tal como vimos anteriormente, si no se produce salida alguna quiere decir que se pasaron todas las pruebas.

Si queremos ver todo el reporte de pruebas exitosas y fallidas podemos añadir nuevamente la opción -v en el comando de la terminal:
python3 pitagoras.py -v
Alternativamente, el mismo efecto se puede lograr modificando el código para añadir el parámetro opcional verbose con valor de verdadero (True) al momento de invocar la función testmod:
    doctest.testmod(verbose=True)
Ahora, cada vez que el archivo se corra como un programa, sin importar si se utilizó o no la opción -v desde la terminal, se obtendrá el reporte completo con el resultado de todas las pruebas.

Con todas las adecuaciones mencionadas, el archivo pitagoras.py queda en su versión final así:
from math import sqrt

def hipotenusa(a, b):
    '''Calcula la hipotenusa de un triángulo rectángulo.

    Utiliza el teorema de Pitágoras para determinar la
    hipotenusa a partir de los catetos de un triángulo.

    Parámetros:
    a -- primer cateto
    b -- segundo cateto
    
    Ejemplos de uso:
    
    >>> hipotenusa(3.0, 4.0)
    5.0
    >>> hipotenusa(0.0, 0.0)
    0.0
    >>> hipotenusa(8.0, 15.0)
    17.0
    >>> hipotenusa(39.0, 80.0)
    89.0
    >>> round(hipotenusa(1.0, 1.0), 4)
    1.4142
    >>> hipotenusa(2.0, 2.0)
    2.0

    '''
    return sqrt(a ** 2 + b ** 2)

if __name__ == '__main__':
    import doctest
    doctest.testmod(verbose=True)
Este versión del programa se puede correr desde la terminal, tal como ya se explicó, o desde cualquier editor o ambiente de desarrollo para Python (IDLE, Spyder, Visual Studio Code, etc.) utilizando los respectivos mecanismos disponibles para ejecutar código.

Mejores prácticas

Estas son algunas prácticas recomendadas al momento de escribir pruebas unitarias usando doctest:
  • Deben ser lógicamente lo más simples que se pueda.
  • Deben requerir muy poco tiempo para ejecutarse, de preferencia solo unos cuantos milisegundos. Si las pruebas toman mucho tiempo la gente optará por no correrlas.
  • Deben procurar abarcar todos los posibles caminos de ejecución del código. Por ejemplo, para cada instrucción if debe haber al menos un caso para probar cuando la condición es verdadera y otro caso para cuando la condición es falsa.
  • Todos las funciones, módulos, clases y métodos deben tener pruebas unitarias apropiadas.
  • Incluir casos de prueba para las situaciones de error en donde se lancen excepciones.
Veamos otro ejemplo para demostrar el último punto de arriba. Definamos la función reciproco, la cual obtiene el inverso multiplicativo de su argumento:
def reciproco(x):
    return 1 / x
Una sesión interactiva de Python utilizando esta función se muestra a continuación:
>>> reciproco(2)
0.5
>>> reciproco(4)
0.25
>>> reciproco(1)
1.0
>>> reciproco(0)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "otro_ejemplo.py", line 2, in reciproco
    return 1 / x
ZeroDivisionError: division by zero
La última expresión genera una excepción debido a que Python no permite dividir entre cero.

A partir de la salida de arriba podemos escribir el doctest para la función reciproco. Del mensaje de error solo es necesario conservar dos líneas: la primera (la que comienza con Traceback) y la última (la que contiene el nombre de la excepción y la explicación del error). Por claridad se recomienda eliminar las demás líneas del stack trace.

El docstring completo dentro de su función quedaría así:
def reciproco(x):
    '''Calcula el inverso multiplicativo de x.

    Se cumple que: x * reciproco(x) == 1.0

    Ejemplo de uso:

    >>> reciproco(2)
    0.5
    >>> reciproco(4)
    0.25
    >>> reciproco(1)
    1.0
    >>> reciproco(0)
    Traceback (most recent call last):
    ZeroDivisionError: division by zero
    
    '''
    return 1 / x
Para correr estas pruebas podemos usar cualquiera de las opciones explicadas anteriormente.

Fuente: www.iconarchive.com

Reflexiones finales

¿Qué beneficios ofrece la automatización de las pruebas unitarias? Según quintagroup, algunos ventajas son:
  • Detección temprana de problemas. Las pruebas unitarias permiten encontrar y eliminar errores de manera rápida y oportuna. Es bien sabido que un defecto de software es menos costoso entre más pronto se detecte y elimine.
  • Mitigación del cambio. Se tiene una certeza razonable de que nuestro programa funciona de cierta manera aún después de hacerle modificaciones, ya sea para corregir errores o añadir funcionalidad nueva.
  • Simplificación de la integración. La integración de los diferentes componentes de una aplicación es más sencilla si primero se prueban éstos por separado. 
  • Mejor documentación. Un programador que desea aprender qué funcionalidad proporciona una unidad y cómo usarla puede revisar las pruebas correspondientes para obtener una comprensión básica de su API.
No es un secreto que una clave para desarrollar software de calidad es ir probando el código a medida que se va escribiendo. De hecho, se recomienda primero escribir las prueba antes que el código de la aplicación. A esto se le conoce como desarrollo guiado por pruebas o TDD por sus siglas en inglés. Esta práctica exige que el programador piense más detenidamente sobre el problema a resolver y el diseño que requiere la solución.

Fuente: openclipart.org

Por último, es importante mencionar que la principal limitación de las pruebas unitarias es que no se pueden utilizar para detectar todos los errores en un programa, ya que es imposible evaluar todas sus rutas de ejecución para todos los posibles valores que pueden tomar las variables involucradas, salvo quizás en casos muy triviales. Las pruebas unitarias solo pueden mostrar la presencia o ausencia de errores particulares.

En resumen, las pruebas unitarias son una buena herramienta para facilitar el desarrollo de software de calidad, pero definitivamente no son una bala de plata.

Fuente: magazine.joomla.org

3 de noviembre de 2018

PCAP: Certificación de Python a nivel asociado

Hace unos meses escribí en este blog una entrada sobre la certificación de introducción a la programación usando Python ofrecida por Microsoft. Ahí mencioné también otra certificación de Python, pero en este caso de tipo vendor-neutral (independiente de proveedor), titulada Certified Associate in Python Programming, la cual aún no estaba disponible en aquel momento. En marzo de 2018, el recientemente creado OpenEDG Python Institute finalmente lanzó el respectivo examen de certificación.

Fuente: pythoninstitute.org

En esta entrada del blog de EduPython voy a presentar algunos de los detalles más relevantes de esta nueva certificación, así como mi experiencia en todo el proceso para obtenerla.

Generalidades

El sitio oficial incluye la siguiente descripción:
La certificación como programador de Python a nivel asociado (PCAP por sus siglas en inglés) es una credencial profesional que mide la capacidad de un individuo para realizar tareas de codificación relacionadas con los conceptos básicos de la programación en el lenguaje Python y las nociones y técnicas fundamentales utilizadas en la programación orientada a objetos.

La certificación demuestra que una persona está familiarizada con los conceptos fundamentales de programación de computadoras: sintaxis y semántica del lenguaje Python, ejecución condicional, ciclos, entorno de ejecución, y técnicas de codificación estructurada y orientada a objetos.
La obtención de la certificación PCAP es evidencia de que alguien está plenamente familiarizado con los recursos principales provistos por Python 3, y esto servirá como punto de partida para estudios más avanzados y el inicio de una carrera como desarrollador de software.


Información sobre el examen

  • Nombre del examen: PCAP Certified Associate in Python Programming
  • Clave: PCAP-31-02
  • Nivel: Asociado
  • Certificaciones relacionadas: 
    • PCPP Certified Professional in Python Programming (aún no disponible a la fecha)
  • Requisitos previos: Ninguno
  • Duración: 65 minutos
  • Número de preguntas: 40
  • Calificación mínima para aprobar: 70% (28 aciertos)
  • Formato del examen: Preguntas de opción múltiple con una o varias respuestas
  • Idioma: Inglés
  • Costo: USD 295.00 (con posibilidad de un descuento del 50%, ver descripción más adelante)
  • Lugar donde se presenta: en cualquiera de los cinco mil centros de evaluación autorizados de Pearson VUE alrededor de todo el mundo.

Objetivos del examen

Los interesados en la certificación PCAP deben demostrar conocimiento sobre los siguientes conceptos:
  1. Los fundamentos de la programación de computadoras, es decir, cómo funciona la computadora, cómo se ejecuta un programa, cómo se define y construye el lenguaje de programación, cuál es la diferencia entre compilación e interpretación, qué es Python, cómo se compara con otros lenguajes de programación, y cuáles son las diferencias más importantes entre las principales versiones de Python. 
  2. Los métodos básicos de formato y salida de datos ofrecidos por Python, junto con los tipos principales de datos y operadores numéricos, sus relaciones mutuas y enlaces; el concepto de variables y las convenciones para nombrarlas; el operador de asignación, las reglas que rigen la construcción de expresiones; la entrada y conversión de datos.
  3. Valores booleanos para comparar valores de diferencia y controlar los caminos de ejecución utilizando las instrucciones if e if-else; la utilización de ciclos (while y for) y cómo controlar su comportamiento utilizando las instrucciones break y continue; la diferencia entre operaciones lógicas y de manipulación de bits; el concepto de listas y sus mecanismos de procesamiento, incluyendo la iteración proporcionada por el ciclo for y las rebanadas (slices); la idea de arreglos multidimensionales.
  4. La definición y el uso de funciones: su justificación, propósito, convenciones y trampas; el concepto de pasar argumentos de diferentes maneras y establecer sus valores predeterminados, junto con los mecanismos para devolver los resultados de la función; alcance o visibilidad de nombres; datos compuestos adicionales: tuplas y diccionarios, y su función en el procesamiento de datos.
  5. Módulos de Python: justificación, función, cómo importarlos de diferentes maneras e identificar el contenido de algunos módulos estándar proporcionados por Python; la forma en que los módulos se acoplan para hacer paquetes; el concepto de una excepción y la implementación de Python de las excepciones, incluida la instrucción try-except, con sus aplicaciones, y la instrucción raise; cadenas de caracteres y sus métodos específicos, junto con sus similitudes y diferencias en comparación con las listas.
  6. Los fundamentos de la POO (programación orientada a objetos) y la forma en que se adoptan en Python, mostrando la diferencia entre la POO y el enfoque procedural clásico; las características típicas de objetos: herencia, abstracción, encapsulación y polimorfismo, junto con las particularidades de Python como variables de instancia y de clase, así como la implementación de herencia en Python; las excepciones como objetos; los generadores de Python (la instrucción yield) y las cerraduras léxicas (la palabra reservada lambda); los mecanismos para procesar (crear, leer y escribir) archivos.
También está disponible el temario más detallado del examen.

Fuente: www.123rf.com

Recursos para estudiar

El Python Institute recomienda cualquiera de las siguientes dos opciones para que los interesados puedan prepararse adecuadamente para presentar el examen PCAP:
  • Autoestudio: Curso en línea PCAP: Programming Fundamentals in Python. Este es un curso gratuito que consta de dos partes (cinco módulos en total) y está disponible desde la plataforma educativa de OpenEDG. Cada estudiante inscrito al curso avanza a su propio ritmo, pero debe ir cubriendo los contenidos y exámenes de cada módulo dentro de ciertas fechas que son establecidas al momento de inscribirse. Cada una de las dos partes del curso tiene una duración estimada de 40 horas y se deben concluir en no más de siete semanas. Si el estudiante realiza todos sus exámenes de los módulos dentro de las fechas previamente fijadas y además obtiene una puntuación igual o superior al 70% en el examen final entonces se hace acreedor a un vale de descuento del 50% sobre el costo regular del examen en los centros de evaluación Pearson VUE. Esto quiere decir que en lugar de tener que pagar USD 295.00, el costo del examen queda en USD 147.50 ya con el descuento. El curso no requiere conocimientos previos de programación.
  • Curso presencial: Cisco Networking Academy cuenta con un curso de 70 horas de duración titulado PCAP: Programming Essentials in Python el cual es impartido por un instructor de manera presencial. Los cursos ofrecidos por Cisco tienen un costo, el cual es determinado por la institución académica que los imparte (usualmente alguna escuela o universidad). Cuando un estudiante termina el curso de manera exitosa se lo otorga un vale de descuento del 51% en el examen de certificación, quedando su costo en USD 144.55. La página oficial indica que el curso solo se ofrece en inglés lo que me hace suponer que aún no está disponible en países de habla hispana. Al igual que la opción de autoestudio, este curso tampoco requiere conocimientos previos de programación.


Yo me preparé por mi cuenta para el examen utilizando el curso en línea de OpenEDG. El curso está 100% alineado al examen de certificación, por lo que sirve como un muy buen repaso pero además me ayudó a descubrir aquellos rincones recónditos del lenguaje que ni siquiera sabía que ignoraba, aún a pesar de tener años de experiencia programando en Python. Dado que la mayor parte del contenido me resultaba familiar, lo que hice fue irme directamente a resolver los exámenes de cada módulo. Si me daba cuenta de que había temas en los que tenía algunas dudas, entonces ya optaba por revisar con más detalle los contenidos correspondientes. Bajo este esquema pude prepararme en relativamente poco tiempo. Cabe mencionar que sí me topé con uno que otro error en el contenido del curso, pero nada demasiado grave. Lamentablemente, no hallé en el sitio algún mecanismo para reportar este tipo de problemas.

El sitio oficial del Python Institute tiene disponible un examen de práctica completo (documento PDF) muy parecido al examen real de certificación PCAP. Una pregunta ejemplo tomada de este mismo documento es la siguiente:
What is the expected output of the following snippet?

    i = 250
    while len(str(i)) > 72:
        i *= 2
    else:
        i //= 2
    print(i)

A) 125
B) 250
C) 72
D) 500
La respuesta de la pregunta anterior es A. Si esto no resulta evidente, recomiendo al lector leer otra entrada de mi blog titulada: ¿Dónde quedó el do-while?.

Presentando el examen

Como ya mencioné anteriormente, el examen PCAP se presenta en cualquier centro de evaluación autorizado de Pearson VUE. Es necesario agendar el examen desde su sitio oficial con al menos 24 horas hábiles de anticipación. Ahí mismo se realiza el pago mediante el cargo a una tarjeta de crédito internacional. Durante este proceso se debe proporcionar también el vale de descuento en caso de contar con él.

Pare presentar el examen se recomienda llegar con 15 minutos de antelación al centro de evaluación. Si se llega tarde a la cita el examen se cancela y no hay reembolsos. Al llegar al centro de evaluación el candidato a presentar el examen debe mostrar dos identificaciones vigentes con su nombre y firma, y al menos una de éstas debe ser de emisión gubernamental y contar con foto de la persona.

Fuente: myupdatestar.com

Una vez registrado el candidato se le lleva a un cuarto de examen. No se permite introducir a dicha habitación ningún artículo personal, incluyendo bolsas, libros, notas, teléfono, reloj, ni cartera. El centro de evaluación debe proporcionar un lugar seguro para guardar todos estos objetos. El cuarto tiene la computadora para hacer el examen y una cámara de vigilancia para monitorear al candidato en todo momento y verificar que no haga trampa. La computadora solo puede correr el software para administrar el examen. No hay acceso a Internet ni a ningún otro programa. Al candidato se le brinda un pequeño pintarrón (pizarrón blanco) y un plumón para escribir sobre éste. Lo anterior es por si se requiere hacer algún tipo de cálculo o corrida de escritorio durante el examen. Durante el examen no está permitido salir del cuarto, hablar con alguien más, ni tampoco consumir alimentos o bebidas.

Ya en la computadora, se tienen que aceptar desde un inicio un acuerdo de confidencialidad en donde en esencia el candidato se compromete a no divulgar el contenido del examen. Luego viene un breve tutorial de cómo utilizar el software que se usará para presentar el examen. Lo anterior tiene una duración de unos 10 minutos y no forma parte de los 65 minutos que dura el examen en sí.

Una vez comenzado el examen, la parte superior de la pantalla informa cuánto tiempo queda disponible y cuántas preguntas faltan por responder. Mientras uno esté dentro del tiempo permitido del examen, y no haya seleccionado la opción de concluirlo, es válido navegar de ida y vuelta entre las preguntas, contestarlas en cualquier orden y modificar las respuestas. Al seleccionar la opción de terminar el examen aparece un resumen en donde se nos avisa si alguna pregunta quedó sin contestar para que la podamos responder (si es que aún hay tiempo). Al concluir, el sistema brinda unos minutos para realizar comentarios sobre cualquiera de las preguntas del examen, pero ya sin tener la oportunidad de cambiar nuestras respuestas. Esto es totalmente opcional, y sirve para reportar situaciones en donde uno considera que existe un error o ambigüedad en la redacción de alguna pregunta o en sus incisos de respuesta.

Reporte con el resultado del examen PCAP.

Concluido todo lo anterior el candidato debe retirarse del cuarto de examen para dirigirse con la persona del centro de evaluación responsable del registro y administración del examen quien entregará una hoja impresa con el reporte del resultado del examen. Éste contiene la puntuación total del examen (en porcentaje) y los resultados del aprendizaje desglosado en cuatro secciones (cada sección fue conformada por diez preguntas):
  1. Control y evaluaciones
  2. Colecciones de datos
  3. Funciones y módulos
  4. Clases, objetos y excepciones
Así mismo, el reporte incluye una liga oficial de Pearson VUE junto con un número de validación para verificar que el reporte sea legítimo. Este dato puede ser útil, por ejemplo, para un empleador que desee confirmar de manera fácil y rápida las credenciales de un aspirante a un puesto de trabajo.

A mi parecer, el momento de más nervios de todo este proceso ocurre en los minutos que pasan entre el instante en que uno termina el examen y el cuando finalmente te entregan el reporte impreso con tu resultado. Muchas cosas pueden pasar por tu mente en ese tiempo. Afortunadamente, en este examen obtuve un muy buen resultado. Solo tuve una pregunta incorrecta de las cuarenta que conforman el total del examen, logrando así una puntuación del 97%. Sinceramente, el examen se me hizo relativamente fácil a partir de la preparación que tuve. Mi apreciación es que los exámenes de módulos y el examen final del curso en línea provisto por el Python Institute tienen un nivel de dificultad mayor al del examen real.

Certificado de PCAP

Seis días después me llegó por correo electrónico una confirmación del resultado de mi examen junto con una liga hacia mi expediente digital de OpenEDG de donde pude descargar la versión electrónica del certificado. Como mes y medio después me llegó por correo convencional un paquete desde Polonia, bastante traqueteado por cierto, con la versión en papel de mi certificado junto con una carta de felicitación y una pulsera de plástico azul alusiva al PCAP.

Tal como lo mencioné en la entrada de la certificación de Microsoft, para mí una certificación es un medio de superación personal que sirve para validar y complementar mis habilidades y conocimientos, ya que me motiva a prepararme en temas particulares que de otra forma difícilmente revisaría por mi cuenta. En este sentido veo bastante útil la obtención de la certificación PCAP.


1 de agosto de 2018

Cuando el dictador se jubila

En días pasados recibí un correo electrónico de Jaime Tovar, un destacado ex-alumno mío que actualmente trabaja en el Reino Unido como desarrollador de software sénior. En su mensaje me dio la noticia de que Guido van Rossum había renunciado un día antes a su rol de BDFL (siglas en inglés de “dictador benevolente de por vida”) del lenguaje Python. Jaime me sugirió que escribiera una entrada en este blog para dar a conocer mi opinión al respecto. Inicialmente no estaba muy convencido de que pudiera aportar algún comentario interesante a este hecho, pero después de pensar varios días me di cuenta de que sí tengo algunas reflexiones que puedo compartir con mis apreciables lectores.

Guido van Rossum, creador de Python.
Fuente: www.gacetaholandesa.com

Antecedentes

Guido van Rossum comenzó a escribir la primera implementación del lenguaje Python en diciembre de 1989. Desde aquel entonces, Guido había sido el líder moral indiscutible de la comunidad de Python y el encargado de dirigir la evolución del lenguaje. En 1995, a manera de broma, se le otorgó a Guido el título de “primer BDFL interino”.

Guido (centro) en la primera conferencia de Python en el
Instituto Nacional de Estándares y Tecnología (NIST),
noviembre de 1994 en Gaithersburg, Maryland.
Fuente: legacy.python.org

Pero, ¿qué es exactamente un BDFL? La wikipedia provee la siguiente definición:
BDFL es un título informal que se otorga a ciertos individuos de la comunidad de desarrolladores de software de código abierto que tienen la tarea de asignar las directrices generales y, en ciertas situaciones, las decisiones finales dentro del ámbito de un proyecto. La traducción de Benevolent Dictator for Life es Dictador Benevolente De por vida, lo que conlleva un tanto de informalidad y humor. 
Después de Guido han habido otras personas con el título de BDFL otorgado por parte de sus respectivas comunidades, por ejemplo Linus Torvalds (creador del núcleo o kernel de Linux) y Yukihiro Matsumoto (creador del lenguaje Ruby), por mencionar a un par.

Fuente: image.thmeythmey.com

En su ensayo titulado “Cultivando la noosfera”, Eric Raymond explica cómo la naturaleza del código abierto obliga a que una “dictadura” sea benevolente. Cuando un proyecto se enfrenta a una situación difícil se espera que su BDFL escuche y evalúe pacientemente los argumentos de todas las partes involucradas y finalmente tome la decisión que resulte más conveniente para los intereses de toda la comunidad. Sin benevolencia un desacuerdo mayor puede ocasionar una bifurcación (fork). En este caso una persona o grupo toma el código fuente del proyecto (que al ser abierto cualquiera tiene acceso a él) y comienzan a extenderlo y modificarlo en una dirección distinta a la original. Esto ha ocurrido varias veces en el pasado, por ejemplo cuando MySQL fue bifurcado para crear MariaDB en 2009. Esto fue debido a las preocupaciones que tenían algunos de los desarrolladores principales con respecto a la adquisición anunciada de Sun Micrsoystems (dueños en ese momento de MySQL) por parte de Oracle. La comunidad temía que Oracle, la compañía de bases de datos relacionales más grande del mundo, tuviera como objetivo eliminar eventualmente a MySQL y reducir así su competencia.

Un BDFL usualmente es el autor original de un proyecto. Esto significa que, por lo general, esta persona cuenta con un nivel técnico que otros respetan e incluso admiran. Sin embargo, su destreza tecnológica es tan solo una de varias cualidades que debe tener un buen BDFL. El reto principal de un líder de un proyecto de código abierto es lidiar con personas y coordinarlas, y esto resulta complicado debido a que la mayoría (o incluso todos) son voluntarios y no reciben remuneración económica alguna por su participación. Aquí el respeto, el agradecimiento y el reconocimiento juegan un papel fundamental.

Fuente: www.sieuthichungcu.info

En el año 2009, como broma de April Fool´s Day (equivalente al día de los santos inocentes en muchos países de habla hispana), se coqueteó con la posibilidad de la abdicación de Guido como BDFL. En esa ocasión se presentó el PEP 401 en donde se nombraba a Barry Warsaw como sucesor de Guido. En lugar de BDFL, el título de Barry iba a ser FLUFL (Friendly Language Uncle For Life,  o “tío amistoso del lenguaje de por vida”). Es importante enfatizar que esta noticia tan solo fue una broma de un 1º de abril. Sin embargo, ¿sería esto un augurio de lo que ocurriría casi una década después?

Barry Warsaw, el FLUFL o
“tío amistoso del lenguaje
de por vida”.
Fuente: hwww.linkedin.com

NOTA: Un PEP, o Python Enhancement Proposal, es un documento oficial de la comunidad de Python en el que se informa de una propuesta para mejorar el lenguaje o algún proceso. Posterior a la publicación de un PEP, los miembros de la comunidad discuten sobre la viabilidad de la propuesta y ofrecen sugerencias. La decisión final para aprobar un PEP corre a cargo del BDFL o, en su defecto, por algún delegado del BDFL. Todos los cambios relevantes que ocurren en Python comienzan con uno o varios PEPs. Tristemente, como veremos en un momento, fue a consecuencia de las reacciones negativas que recibió después de aceptar un PEP que Guido optó por anunciar su retiro como BDFL.


La noticia

El pasado jueves 12 de julio, Guido van Rossum comunicó lo siguiente a través de la lista de correo de python-committers:
Asunto: Transferencia de poder

Ahora que está concluido el PEP 572 ya no quiero tener que pelear por un PEP y descubrir que mucha gente detesta mis decisiones.

Quiero descartarme por completo del proceso de toma de decisiones. Seguiré allí por un tiempo como cualquier otro desarrollador del núcleo de Python, y todavía estaré disponible para guiar a las personas, posiblemente ahora con mayor disponibilidad. Pero básicamente me estoy dando unas vacaciones permanentes del puesto de BDFL, y ahora todos ustedes estarán por su propia cuenta.

Esto iba a suceder eventualmente de cualquier manera. Aún está ese autobús al acecho a la vuelta de la esquina, y no me estoy haciendo más joven... (evitaré compartirles mi lista de problemas médicos).

No voy a nombrar un sucesor.

Entonces, ¿qué van a hacer? ¿Crear una democracia? ¿Una anarquía? ¿Una dictadura? ¿Una federación?

No me preocupan las decisiones cotidianas que surgen del sistema de seguimiento de incidentes o desde GitHub. Raramente solicitan mi opinión, y por lo general no es realmente importante. Así que esto continúa como siempre.

Las decisiones que más importan probablemente son:
  • ¿Cómo se deciden las PEPs?
  • ¿Cómo iniciar a los nuevos desarrolladores del núcleo de Python?
Es posible que podamos escribir procesos para estas cosas vía PEPs (quizás dichas PEPs podrían conformar una especie de constitución). Pero hay un truco aquí. Voy a dejar que todos ustedes (los autores de los “commits”) lo resuelvan por sí mismos.

Tengan en cuenta que aún existe un código de conducta. Si no les gusta dicho documento, la única opción podría ser dejar este grupo voluntariamente. Quizás hay detalles aún por decidir, por ejemplo: ¿cuándo debería ser expulsada alguna persona? (esto implica restringirle el acceso a las listas de correo de python-dev o python-ideas, ya que éstas también están cubiertas por el código de conducta).

Finalmente, un recordatorio de que los registros de esta lista son públicos (https://mail.python.org/pipermail/python-committers/) aunque la membresía es restringida (limitada solamente a los desarrolladores del núcleo de Python). Todavía estaré aquí, pero estoy intentado dejar que todos ustedes resuelvan algo por su propia cuenta. Estoy cansado y necesito un descanso muy largo.

— Guido van Rossum (python.org/~guido)
El PEP 572 al que Guido se refiere al inicio de su comunicado es sobre “Expresiones de asignación”, un cambio previsto para ser incorporado en la versión 3.8 del lenguaje que está programada a ser liberada en octubre de 2019. Actualmente, las asignaciones a variables en Python deben realizarse usando un enunciado (statement) de asignación. Veamos el siguiente ejemplo:
# Código para Python 3.0 y superior
r = input('¿Deseas continuar? (s/n) ')     # 1  
while r in 'Ss':                           # 2
    print('Tu respuesta fue:', r)          # 3
    print('Continuando...')                # 4
    r = input('¿Deseas continuar? (s/n) ') # 5
Las líneas 1 y 5 son enunciados de asignación. De hecho, son exactamente el mismo enunciado. Esta duplicación es necesaria aquí dado que Python no cuenta con un enunciado do-while y el valor de la variable r es requerida tanto en la condición (línea 2) como en el cuerpo (línea 3) del enunciado while.

El PEP 572 introduce un nuevo operador de asignación := (un signo de dos puntos seguido de un signo de igual) que permite realizar asignaciones dentro de una expresión. Este nuevo operador es esencialmente equivalente al operador de asignación = (un signo de igual) soportado por los lenguajes basados en C (C++, C#, Java, JavaScript, etc.). Ahora con el operador de asignación := el código de arriba podría quedar escrito de manera más compacta así:
# Código para Python 3.8
while (r := input('¿Deseas continuar? (s/n) ')) in 'Ss': # 1
    print('Tu respuesta fue:', r)                        # 2
    print('Continuando...')                              # 3
Hay que notar que la asignación de r se realiza ahora dentro de la misma expresión condicional del enunciado while (línea 1) reduciendo con ello dos líneas del programa. Cada vez que se realiza la condición del while, se realiza primero la re-asignación de la variables r.

A muchas personas no le gustó esta adición al lenguaje. Hubo a quienes simplemente no les gustó la sintaxis del nuevo operador. A muchos otros no les gustó en absoluto la idea de tener una forma alternativa de realizar asignaciones de variables por considerar que estaba quebrantando el Zen de Python, el cual es una serie de principios de software que influyen en el diseño del lenguaje.

La gente en desacuerdo comenzó a compartir su opinión al respecto con poca mesura, tanto a Guido como a la Internet. Y así fue como se abrió esta pequeña caja de Pandora.

Pandora's Box by Arthur Rackham
“Caja de Pandora” de Arthur Rackham.
Fuente: talesfortadpoles.ie

Francamente, a mí no me gustó al principio la propuesta ni la sintaxis seleccionada. Después de algunos días de asimilación me acostumbré a la idea y creo que sí utilizaría este nuevo operador, aunque solo en ciertos contextos. Sin embargo, como educador, lo más probable es que optaría por no enseñarlo a mis alumnos, al menos no durante un curso de introducción a la programación. La razón es simple: idealmente cada enunciado debe tener un solo efecto. Si un enunciado tiene dos o más efectos resulta más difícil de entender. Es preferible que cada efecto esté en su propia línea. En el último código, la línea 1 tiene dos efectos: la asignación y el resultado de la condición del ciclo. Esta complejidad no la necesita un principiante, y por tanto me parece más conveniente evitarla. Y así es como enseñamos a programar: evitando presentar a nuestros estudiantes aquellos elementos del lenguaje que no contribuyen a lograr nuestros objetivos académicos.

Reflexiones

Antes que todo, pienso que es una pena que Guido haya abandonado su puesto como BDFL. Sin embargo entiendo y respeto completamente su decisión y no puedo mas que sentir un profundo agradecimiento por todo el tiempo y la dedicación que invirtió para lograr lo que actualmente es Python y su vibrante comunidad. También hay que recalcar que Guido no va a esfumarse. De hecho, él continuará presidiendo la Python Software Foundation (PSF), que es la organización dedicada a fomentar el desarrollo de la comunidad de Python. En la biografía de su cuenta de Twitter, Guido ahora se describe como “Creador de Python y BDFL emérito”.

Es válido que la gente esté en desacuerdo con nuestras ideas y es muy valioso que podamos discutir, pero siempre y cuando lo hagamos de manera inteligente y respetuosa. Lamentablemente, en muchas ocasiones lo anterior es la excepción y no la regla. Lo que ocurrió a raíz del PEP 572 es un fenómeno que estamos viendo en otros lados. Al parecer todo el mundo se siente con la libertad de expresar su opinión y ahora, gracias a la Internet y a las redes sociales, tenemos a nuestra disposición un público de un tamaño que jamás nos hubiéramos imaginado tan solo hace algunos años. En principio esto parece algo bueno, ya que podría ser la base para una verdadera democratización, en donde todos pueden hacer oír su voz. Pero lo que ha pasado en muchos casos es que los que hablan y gritan más fuerte son los que han estado dominado el escenario. Muchas personas se sienten con todo el derecho de vociferar su opinión, no importándoles si sus argumentos cuentan o no con un sustento razonable. ¿A caso ser escandaloso tiene más peso que ser instruido?

Fuente: www.vexels.com

Un número desmedido de personas repudiaron la decisión de Guido de aprobar el PEP 572 y se lo manifestaron de manera hiriente. En una entrevista realizada por InfoWorld hace unos días, Guido comentó que sentía que había perdido la confianza de los desarrolladores del núcleo de Python cuando varios de ellos le atacaron de manera personal en redes sociales como Twitter. Al igual que la mayoría de esos desarrolladores, el rol de BDFL que desempeñaba Guido era también a título de voluntario. ¿Qué puede ser más desmoralizante que hacer un trabajo de manera generosa y a cambio de ello recibir severas críticas y agresiones?

Regresemos ahora al tema de las dictaduras benevolentes. Si vivimos en un país democrático muy probablemente consideramos que la democracia es el estilo de gobierno que nos conviene emular en otros entornos de nuestra sociedad. Pero la democracia no funciona en todos los contextos. Imaginemos un hogar conformado por cinco personas: tres hijos pequeños, la mamá y el papá. Si cada mañana deciden entre todos el menú para desayunar de manera democrática existe una alta probabilidad de que acabarán comiendo siempre helado y hot cakes. La verdad es que unos buenos padres procurarán brindar una alimentación balanceada a sus hijos, no porque quieran fastidiarlos dándoles comida que a lo mejor no les gusta, sino porque buscan su bienestar a largo plazo. En otras palabras, los padres juegan el rol de dictadores benevolentes. Unos padres amorosos seguramente escucharán y tomarán en cuenta las opiniones de sus hijos, pero finalmente tomarán decisiones que no siempre serán populares ni bien recibidas.

Fuente: www.shutterstock.com

La comunidad de Python decidió desde sus inicios que su forma de gobierno iba ser a través de un dictador benevolente. La idea era contar con una persona sabia y visionaria que pudiera tomar las decisiones difíciles, cuidando siempre los intereses de la propia comunidad. Ése era el acuerdo. Inicialmente, para cada situación importante, iba a haber un espacio para discutir los diferentes puntos de vista. Pero al final Guido tomaría la última decisión y todos tendrían que acatarla. Guido era el capitán del barco, y se le otorgó a él la confianza y el permiso para dirigir la nave de acuerdo a su criterio. Se estableció desde el principio que esto no iba funcionar como una democracia. Por lo tanto, una vez tomada una decisión por parte del BDFL ya no queda nada más que hacer, salvo apechugar en caso de que no fuera de nuestro agrado. Al parecer no todo el mundo entiende cómo funciona este estilo de gobierno. Después de que Guido anunció su decisión sobre el PEP 572 muchos inconformes sintieron que estaban en su derecho de lanzarse a la yugular del BDFL.

He podido de ver de primera mano que Guido tiene una personalidad conciliadora y no busca imponerse. Esto contrasta con otros BDFLs, como es el caso de Linus Torvalds, quien no tiene problemas en mandar al carajo a quienes no comparten su punto de vista. Incluso Torvalds alguna una vez dijo: “No soy una persona amable, y tú no me interesas. Me importa la tecnología y el núcleo de Linux; eso es lo importante para mí”. Pero Guido no es así. Él es un individuo gentil que busca llevarse bien con la gente y que pone a las personas por encima de la tecnología. Es probable que esa forma afable de ser lo llevaría a ir acumulando a través de los años una enorme presión que finalmente terminaría por reventarlo.

Lo que mucha gente se pregunta ahora es: ¿qué va a pasar con Python? ¿Qué va a ocurrir si se decide que el lenguaje evolucione bajo un esquema en donde mucha gente pueda meter su cuchara? Esto preocupa porque viene a la mente aquel viejo proverbio inglés que dice: “Demasiados cocineros echan a perder el caldo”.

https://d12m9erqbesehq.cloudfront.net/wp-content/uploads/sites/21338/2018/04/12132631/cooking.jpg
Fuente: northwoodelementary.eventsmart.com

En el pasado, algunos lenguajes de programación han sido diseñados y extendidos mediante comités conformados por múltiples compañías e individuos. Ese fue el caso de la estandarización de Common Lisp. Cada miembro del comité tenía su propia visión de lo que consideraba que debía incluir el lenguaje. El problema fue que las visiones individuales no necesariamente coincidían entre sí. Si alguien quería que se incorporara una determinada característica en el lenguaje a menudo tenía que realizar concesiones con los otros miembros del comité. Así pues quedó finalmente un lenguaje gigantesco (la especificación original consistía de más de mil páginas) y chipotudo (con inconsistencias y redundancias). Bien dijo el ingeniero automotriz británico Alec Issigonis (creador del auto Mini original): “un camello es un caballo diseñado por un comité”.

Fuente: medium.com

Otro problema que tienen los comités es que frecuentemente tardan mucho tiempo en generar resultados, sobre todo si el número de integrantes es grande. Podemos observar esta situación en la evolución que ha tenido el lenguaje Java comparada con el lenguaje C#. En el año 1995, Sun Microsystems liberó la primera versión de Java. Por su parte, Microsoft sacó C# al mercado siete años después. Aunque inicialmente C# fue denunciado por muchos como una copia deficiente de Java, al paso de los años esta situación cambió. Java poco a poco se fue rezagando a tal grado que ahora es Java quien le está copiando a C#. Por ejemplo, las funciones anónimas (conocidas también como lambdas) aparecieron en C# 3.0 en 2007, pero fue hasta el 2014 que fueron incorporadas a Java 8. El lenguaje Java tarda más tiempo en avanzar debido a que depende del Proceso de la Comunidad Java (JCP por sus siglas en inglés), que está subordinado a un comité relativamente extenso que se encarga de tomar todas las decisiones relacionadas con la plataforma Java. Por otro lado, el rápido y ágil progreso de C# ha sido producto de un pequeño equipo encabezado por el eminente ingeniero de software danés Anders Hejlsberg (creador de Turbo Pascal, Delphi y C#).

¿Tomará Python el camino de un estilo de gobierno encabezado por un comité? En la entrevista de InfoWorld previamente mencionada, Guido comentó lo siguiente:
El grupo de desarrolladores del núcleo de Python acordó una agenda para llegar a una conclusión. La fecha límite para las propuestas es el 1° de octubre de 2018. Entonces, me parece, que para el 1° de noviembre de 2018 se han comprometido a haber seleccionado una propuesta para una estructura de gobierno. Luego, para el 1° de enero de 2019, se comprometieron a elegir o designar efectivamente, o como sea que se indique en sus documentos de gobierno, a las personas que estarán a cargo.

Si una de las propuestas es que haya un solo BDFL, esa propuesta deberá redactarse detalladamente
para el 1° de octubre, indicando cómo se seleccionará, cuánto tiempo permanecerá a cargo, cómo se le puede impugnar, y todo eso. Tal vez para el 1° de enero tendrán una persona real designada.
En un podcast de PythonBytes, Carol Willing y Brett Cannon, dos de los desarrolladores del núcleo de Python, comentaron cómo creen ellos que va a quedar conformado el nuevo modelo de gobierno para Python. Al parecer se está pensando en que haya un nuevo BDFL, o alternativamente un “consejo de ancianos” compuesto por entre 3 y 5 personas. Esto me parece una muy buena noticia por la razón que ya expuse anteriormente.

Fuente: maxima.id

Haciendo a un lado la dimisión de Guido como BDFL, hay que reconocer que Python está viviendo su mejor momento y dudo que esto vaya a cambiar en el futuro inmediato. Según Stack Overlow, de los principales lenguajes de programación, Python ha sido el que más ha crecido en los últimos cinco años dentro de los países con mayores ingresos. El índice TIOBE de julio de 2018 coloca a Python como el cuarto lenguaje de programación más popular del momento, solo atrás de Java, C y C++. Por otra parte, Python aparece en el primer puesto tanto en el índice de popularidad de lenguajes de programación (PyPL) de julio 2018 como en la clasificación 2018 de los principales lenguajes de programación de la revista IEEE Spectrum.

Una gran parte de la comunidad de Python está conformada por usuarios que no son desarrolladores de software pero que sí necesitan programar para resolver problemas de cómputo científico, ciencia de datos y aprendizaje automático. Estos usuarios dependen de herramientas basadas en Python como Jupyter, NumPy, SciPy, Matplotlib, pandas y TensorFlow. No veo que el retiro de Guido les pudiera afectar, incluso si la evolución del lenguaje se detuviera por algunos años. La inmensa comunidad de Python está muy bien consolidada y eso permitirá que trascienda más allá de una sola persona. Desde luego que vamos a extrañar al buen Guido, nuestro dictador benevolente, pero me siento optimista sobre el destino de Python.

Con Guido, BDFL emérito.
Foto tomada durante PyCon USA, mayo de 2018.