martes, 14 de febrero de 2023

The Psychology of Computer Programming

En este blog he procurado dejar registro de la mayoría de mis lecturas que tienen relación con las TIC (Tecnologías de la Información y las Comunicaciones). Sin embargo, en ocasiones hay lecturas maravillosas, pero densas, que dejo reposar y a las cuales regreso periódicamente, hasta que aparece el momento preciso para escribir, liberar, desahogar... Una de esas lecturas es el libro La psicología de la programación, un clásico de medio siglo que sigue vigente. Espero finalizar de escribir algunas ideas sobre este libro antes de iniciar las clases en la Universidad...

Este libro no se consigue en Colombia, tuve que importarlo hace tres (3) años, después de una pequeña revisión de literatura que hicimos para actualizar y modificar los cursos de programación en la Universidad donde trabajo. Me gusta regresar cada semestre a leerlo, porque muchas de las ideas que aparecen allí siguen vigentes y me aportan en mi tarea de profesor.

El libro fue escrito en 1969 y publicado en 1971 y promocionaron una edición especial por las bodas de plata (Silver) en 2019 y como homenaje póstumo a su autor, Gerald M. Weinberg, quien murió en 2018. Gerald M. Weinberg (1933 - 2018) fue un profesor y científico de la computación, orientado a la psicología y la antropología de la Ingeniería del Software. Parte de su reconocimiento está en lo que se conoce como "Egoless programming", un estilo de programación más cooperativo y menos individual, que sigue vigente en esta época de alta demanda de programadores y que se mencionará más adelante.

Hay un sitio web dedicado a Weinberg y su obra y allí se puede leer una bonita cita de motivación que hoy me inspiró a cumplir ese compromiso pendiente de escribir sobre el libro:

"Each person is important and can mean something for the world. You can do more than you think. Feel inspired by this."

Regresando al libro, consiste en trece (13) capítulos, los cuales están organizados en cuatro (4) grandes partes:

  1. La programación como una actividad humana (human performance)
  2. La programación como una actividad social
  3. La programación como una actividad individual
  4. Herramientas de programación

Puesto que el libro está en inglés, en algunas partes citaré textualmente oraciones y párrafos, aunque procurando mantener la redacción en español.

1. Programming as a Human Performance

La programación de computadores es una actividad humana. Aunque hay máquinas involucradas, implica la sinergia del trabajo individual de grupos de personas. Históricamente hay cierta mística en torno a los programadores, con el salario como uno de esos elementos místicos. En la actualidad sigue siendo así, como puede leerse en esta entrada de 2020 y esta otra de 2021.

Capítulo 1 Reading Programs: Como actividad humana, la programación es muy parecida a leer y escribir textos en lenguaje natural, por lo que su enseñanza y aprendizaje y su puesta en práctica deberían considerar en gran medida la importancia de leer código.

Programming is, among other things, a kind of writing. One way to learn writing is to write, but in all other forms of writing, one also reads. We read examples -both good and bad- to facilitate learning.

Resulta interesante que desde los inicios de los años 70 del siglo pasado ya se hablaba de la importancia de leer código y de leerse código entre pares (algo que aparecerá en capítulos posteriores).

Cuando se leen programas es necesario comprender y descifrar el código escrito antes de juzgarlo (y de juzgar al programador). Hay, por lo menos, cinco (5) cosas que influyen en el código y que originan limitaciones, restricciones que llevan al programador a tomar determinadas decisiones:

Primero las características de la máquina (machine limitations), como la memoria, el procesador, la capacidad de almacenamiento y transacciones de red, entre otras. Aunque en estos tiempos de computación en la nube y virtualización hay más portabilidad e independencia del hardware, sigue siendo muy importante la influencia de la infraestructura tecnológica para la cual se escribe un programa.

Segundo las características del lenguaje de programación (language limitations). Hoy abundan los lenguajes de programación, los hay de todos los sabores y colores y cada quien sigue el ranking que más le favorece para que el lenguaje de su predilección sea el primero del top. Sin embargo, cada lenguaje tiene sus propias limitaciones y sus fortalezas, limitando al programador y originando tareas de programación innecesarias. No existe el lenguaje de programación que sirva para todo.

Tercero las características del programador (programmer limitations), su formación, experiencia y competencia individual. Un programador puede no ser experto en determinado lenguaje, por lo cual termina implementando tareas que el lenguaje ya trae incorporadas. También, el programador puede tener poca experiencia e implementar una solución ineficiente o hasta incorrecta.

"The programmer did not have full mastery of his computer, his language, or himself...There are, of course, programmer limitations other than merely not knowing the full power of the language -vocabulary limitations, we might say..."

En cuarto lugar debe considerarse la historia (historical traces), de las personas, de la empresa, del software. Es probable que un código fuente inapropiado jamás se cambie durante muchos años. La experiencia me enseña que las soluciones temporales se vuelven permanentes, que la inercia es una fuerza muy poderosa y la mediocridad siempre será enemiga de las cosas bien echas.

"...The prehistoric origins of certain pieces of code are almost beyond belief..."

Y en quinto lugar están las especificaciones (specifications), con lo cual aparecen los usuarios que participan en el proceso de desarrollo.

"...We might begin to believe that very little of th coding that is done in the world has much to do with the problems we are trying to solve..." 

"...Writing a program is a process of learning -both for the programmer and the person who commissions the program..."

Capítulo 2 What makes a good program?: Si se quiere estudiar la programación como una actividad humana, es necesario disponer de algunas medidas. Hay que responder qué hace que un programa sea mejor que otro y qué hace que un programador sea mejor que otro. Y no es algo sencillo, no solo porque hay elementos subjetivos que llevan a un programador a juzgar su propio código mejor que el de otros, sino por los diversos aspectos a considerar cuando se lee (y juzga) el código, como las mencionadas en el capítulo anterior. De cualquier manera se requieren medidas y el libro detalla cuatro (4)

Lo primero es cumplir con las especificaciones (specifications), que el programa haga lo que se espera que haga, que sea correcto. Esa es la primera variable que un profesor de programación evalúa (por ejemplo el suscrito). En ocasiones los estudiantes argumentan que sus programas hacen otras cosas, pero no cumplen con lo mínimo solicitado, leer unas entradas y generar con ellas unas salidas previamente establecidas. De ahí la importancia de mecanismos automáticos para evaluar esta dimensión.

En segundo lugar está el cumplimiento del tiempo estimado para escribir el programa, cumplir el cronograma (schedule). Desde un punto de vista organizacional y económico hay que evaluar el costo de no tener el programa o de tener un programa ineficiente o imperfecto.

"...a program that is late is often worthless. At the very least, we have to measure the costs of not having the program against any potential savings that a more efficient program would produce..."

En eso de cumplir el tiempo planeado,  en el contexto educativo el profesor estima un tiempo, usualmente las dos (2) horas de un examen, pero esa estimación no siempre aplica a todos los estudiantes. Yo suelo estimar una (1) hora y la diferencia por encima de ese máximo la considero como parte de la calificación, pero siempre hay sorpresas y debo ajustar... Lo propio sucede en las organizaciones, aunque allí los gerentes de proyecto suelen estimar y se equivocan a menudo...

En tercer lugar está la adaptabilidad (adaptability). Puesto que los cambios son algo muy común en la vida humana, eso se traslada a los programas de computador y se espera que un programa se pueda adaptar fácilmente. Sin embargo, este atributo puede originar que se requiera más tiempo de desarrollo del estimado o que se sacrifique eficiencia u otras variables.

"...the great majority of programs that are writen, especially by professional programmers, remain in existence for a definite life span. And during that span, most of them become modified..."

Y en cuarto lugar está la eficiencia (efficiency), cuya medición no es simple, pues va mucho más allá de solo el tiempo que tarda el programa en ejecutarse. En cursos de Análisis y Diseño de Algoritmos se cómo estimar formalmente el tiempo lógico de ejecución y el uso de memoria en condiciones ideales o abstractas y cómo llevar esas estimaciones a máquinas reales y específicas.

En la actualidad existen y se usan herramientas capaces de analizar el código fuente y evaluar muchas variables, como se menciona en el libro de Ingeniería de Software en Google.

Capítulo 3 How can we study programming?: Los dos primeros capítulos definieron la programación como parte del comportamiento humano. Tal  complejidad implica un enfoque mixto entre lo psicológico, antropológico y sociológico. Muchos argumentan que el enfoque de Weinberg es más antropológico que psicológico. En este capítulo se sugieren cinco métodos para estudiar la programación, con sus correspondientes inconvenientes y recomendaciones.

El primer método es la introspección (introspection), que el mismo autor manifiesta como no científico, pero que conviene tener en cuenta. Se trata de preguntarle al programador, preguntarle al estudiante si hablamos en el contexto educativo. Aunque se introduce cierta subjetividad y sesgo por parte del programador, nada mejor que preguntarle ¿por qué hizo eso, por qué así, cómo cree que podría mejorarse?.

El segundo método es la observación (observation), que involucra fenómenos como el efecto Hawthorne y la misma subjetividad del observador. Aquí hay mucho de técnicas de investigación antropológicas y psicológicos.

El tercer método son los experimentos (experiment), pero hay elementos éticos complejos y difícilmente un programador aceptará convertirse en ratón de laboratorio, aunque ese es el más apropiado para hacer investigación en ingeniería del software.

Un cuarto método es el uso de medidas o variables psicológicas (psychological measurement), para lo cual es clave tener claro qué es lo que se mide y cómo se mide. La complejidad está en la gran cantidad de variables involucradas y que no siempre hay instrumentos para medirlas. Un instrumento común son lo cuestionarios, para lo cual se debe considerar la cultura y de ahí la diferencia entre los métodos en sociología y antropología. Los primeros buscan respuestas dentro de una cultura que conocen y los segundos buscan preguntas para una cultura desconocida y que se quiere conocer. La psicología de la programación parece estar más orientada a esto último.

De la mano con el método anterior está el uso de datos existentes sobre el comportamiento de un programador (using behavioral science data). Este método es retrospectivo, se está mirando el pasado, a veces incompleto, pero es una buena fuente de datos e información para estudiar el fenómeno.

En general no es tarea sencilla el estudio científico de la programación como comportamiento humano. No obstante ya hay más de medio siglo en esta tarea, como el caso del Grupo de Interés en Psicología de la Programación (PPIG). Desde mi experiencia personal en competencias de programación (Competitive Programing), hay oportunidades para seguir haciendo investigación en estos tópicos.

2. Programming as a Social Activity

Ya aceptamos que la programación es un actividad humana, pero no es una actividad individual y solitaria, sino una actividad de grupos de personas, cooperativa, una actividad social. Hay tres niveles de grupos de personas, una especie de jerarquía: el grupo, el equipo y el proyecto, cada una tiene un capítulo en esta parte.

Hay una nota al inicio de esta parte que ajusta su definición de equipo de programación después de cincuenta años:

"...A programing team is a collection of programmers who are trying to produce better products by working together.."

Capítulo 4 The Programming Group: Al hablar de grupos conviene diferenciar los grupos formales e informales dentro de una organización. En ocasiones se cree que las jerarquías de la estructura organizacional rigen el comportamiento de las personas, pero la realidad es otra.

"...But human interactions are never narrow, never straight, and hardly ever in the directions shown an organization charts. Many serious mistakes have been made in imagining that formal structure was the only structure in a organization.."

Es muy importante reconocer, comprender y considerar los mecanismos informales de los programadores, sobre todo si se quieren implementar transformaciones o investigar.

Otro elemento muy destacado de este capítulo es lo que se conoce como "Egoless programming". Entre muchas otras ideas aparece la necesidad de aceptar la posibilidad de errores y de corregirse mutuamente entre pares. Hay un decálogo que se extrae de este capítulo y que muchos usan como mandamientos, pese a que el profesor Weinberg afirma que hay muchos malentendidos sobre su propuesta. Dejaré este tema y el decálogo para detallar en otra entrada posterior...

Capítulo 5 The Programming Team: Un grupo de programadores no es un equipo, el equipo implica un problema más grande y mucho más de dos o tres programadores trabajando juntos. Tiene mucho que ver con la experiencia de los programadores,  la habilidades  de trabajo en equipo y de  liderazgo, así como la comunicación y la resolución de conflictos. Este y el siguiente capítulo están más cercanos a lo que llamamos Ingeniería de Software y no tanto solo la programación y siguen vigentes, a juzgar por el libro citado previamente de Ingeniería de Software en Google.

"...The lack of experience in programming becomes more evident as the size of the system to be produced increases. Although we have seen that the programmer does not, ideally, work in isolation, even when de problem is small, there is a social difference between small programs and large ones..."

Cuando se trata de equipos es importante  considerar al menos cuatro cosas:

  1. La conformación de los equipos, su tamaño, la asignación y distribución de roles y responsabilidades. Usualmente hay una relación entre la arquitectura subyacente y  la organización del equipo.
  2. Los mecanismos como se establecen y aceptan las metas individuales y del equipo, las reglas de juego cuando hay errores y fallas y el código de conducta para ser efectivos y mantener una unidad entre las personas, pese a los inconvenientes que puedan derivar del proyecto.
  3. El liderazgo del equipo y la designación, formación o descubrimiento de los líderes. En este caso el liderazgo no se puede entender como posiciones de autoridad y poder, jerárquicas, sino como un habilidad para influir en las personas y lograr que se cumplan las metas, más allá de mandar y obedecer. En el contexto de programadores no funciona el autoritarismo, se requieren líderes democráticos y capaces de generar motivación,  no tanto administradores y jefes clásicos. Esto es algo que sigue vigente, pues en materia de TIC y programadores hablamos de creatividad y  colaboración, no tanto de imposiciones y obediencia.
  4. El manejo de las crisis de los equipos, resolución de conflictos, comunicación efectiva, entre otros. Desde el reclutamiento hasta el cierre de un proyecto o la promoción o traslado de un programador involucran aspectos humanos, en contraposición de la naturaleza técnica de la programación.
Este capítulo es algo que solo logran dimensionar y comprender quienes realmente han tenido la oportunidad de convivir varios meses con programadores en equipos grandes para proyectos grandes y reales. En lo académico un proyecto de clase o un trabajo de grado no pasa de un grupo de máximo cinco personas, estudiantes, quienes suelen obedecer a un profesor. En este aspecto hay un desafío y oportunidad en  la academia y la investigación, que nos demanda acercarnos más a las empresas y seguir de cerca el mundo de verdad...

Capítulo 6 The Programming Project: Como dice el libro de Ingeniería de Software en Google, la diferencia entre programación e ingeniería de software está en la escala de tiempo, del problema y del equipo. Al hablar de proyectos estamos hablando de coordinar varios equipos, de escalar el liderazgo, de gestionar los cambios y de medir el rendimiento: de los productos, del proyecto, de los equipos, de los grupos de trabajo y  de cada individuo programador...

Este capítulo, aunque escrito hace medio  siglo, sigue vigente y resume mucho de la abundante teoría, libros y artículos de ingeniería del software. A lo mejor un error que algunos cometen es olvidar la naturaleza humana de la programación, deshumanizar esa actividad y centrarse en modelos burocráticos clásicos, donde priman las metodologías y el cumplir a pie de letra las prácticas estandarizadas. Suficiente con buena comunicación, buen trabajo en equipo y buen liderazgo, algo que no siempre es fácil juntar para llegar al éxito.

3. Programming as a Individual Activity

En contraste con la parte 2, que se refirió a los aspectos sociales, esta tercera parte agrupa cuatro (4) capítulos, que se centran en la individualidad de un programador, sin que esto implique, como ya se dijo, un trabajo en solitario:

  • Capítulo 7 Variations in the Programming Task
  • Capítulo 8 Personality Factors
  • Capítulo 9 Intelligence, or Problem Solving Ability
  • Capítulo 10 Motivation, Training, and Experience
Estos capítulos son claves para reclutamiento de personal en las empresas y también para los profesores que formamos en primera instancia ese talento.

El el capítulo 7 se inicia con esta frase:

"...Programming like loving is a single word that encompasses an infinitude of activities..."

Esta frase se refiere a que hay diversas tareas de programación [y de ingeniería del software]. Por ejemplo, hoy se habla de desarrollador backend, frontend y full stack, tester, arquitecto, ingeniero cloud, devops y muchos otros roles y perfiles, que implican tareas muy específicas y diferentes pero relacionadas entre si. Además, dependiendo de los requerimientos, la organización y la etapa del proyecto,  hay variaciones en las tareas que debe realizar cada programador. Y, por otra parte, hay diferencias entre un programador novato y uno profesional, o lo que actualmente se conoce como junior y senior.  

En ese sentido, no es  sencillo juzgar como bueno o malo el trabajo de un programador y es aún más complejo establecer comparaciones entre dos programadores. Desde mi experiencia, solo en lo referente a programación, las competencias (maratones) ayudan a establecer ciertos niveles, pero es solo una fotografía, una instantánea del desempeño en un momento determinado. Adicionalmente, aunque la individualidad es relevante y es el foco de esta parte del libro, siempre se trabaja en equipo, no es posible desligar la influencia de lo social en lo individual. Por lo tanto,  un programador podría ser excelente en un equipo determinado, pero con otro equipo podría tener un rendimiento inferior o fracasar totalmente.

Pero es necesario evaluar cada programador y compararlo con otros. Para tal efecto se puede recurrir a cada uno de los tres criterios que se exponen en los siguientes capítulos:

El capítulo 8 habla sobre la personalidad, que puede variar, dependiendo de la organización, el equipo de trabajo, el proyecto y muchos otros aspectos del entorno. Hay diversos instrumentos y mecanismos para evaluar la personalidad y así ubicar a una persona en la tarea de programación más acertada.

¿Qué define a determinado programador: Es introvertido, comunicativo, propositivo, crítico, humilde, asertivo, superficial, meticuloso, ordenado, divergente, líder...? Son muchas las variables de personalidad y no hay que engañarse: en un proyecto, bajo determinadas condiciones de la organización, una persona podría asumir el rol de líder y hacerlo mejor que cualquier otro miembro del equipo. Pero en otro proyecto o bajo otras condiciones, esa misma persona podría desempeñarse mejor como un programador experto, cumpliendo con entregables y tiempos claramente definidos...

Con el tiempo, un buen programador que llegue a ser líder y gerente,  posiblemente logre aprender a identificar perfiles y a sacar lo mejor de cada persona, que es lo ideal para potenciar el talento, retenerlo y de paso lograr el éxito en los proyectos y los negocios...

El capítulo 9 se aleja de la personalidad, cuya evaluación podría ser bastante subjetiva y da paso a la capacidad cognitiva, la inteligencia y las habilidades de resolver problemas abstractos y  complejos, como los problemas matemáticos o de computación. Al igual que la personalidad, existen muchos test de inteligencia y son muchas las variables involucradas.

Éste capítulo deja planteada la pregunta de si la inteligencia es lo mismo que la habilidad de resolver problemas, si es una condición necesaria o es un super conjunto. En la actualidad se habla de Pensamiento Computacional (Computational Thinking) y desde esa disciplina floreciente hay nuevas perspectivas y preguntas...

Finalmente, el capítulo 10 se centra en la motivación, el entrenamiento y la experiencia. La experiencia se gana con el tiempo y la densidad y calidad del trabajo, pero no es suficiente para ser un buen programador. Un buen programador siempre está motivado y se mantiene entrenando.

Por la experiencia en maratones de programación, entrenar es la clave, pero para entrenar hay que mantener la motivación por largo tiempo, lo cual es un desafío tanto en el contexto académico como en el contexto laboral. La pregunta entonces para profesores y líderes de equipos y empresarios es ¿cómo mantener motivado a un  programador para que su desempeño sea el ideal? y de paso ¿cómo mantener motivado a un equipo de programadores?.

Igual que las partes anteriores, aunque es un libro escrito hace más de cincuenta años,  muchas de las ideas planteadas siguen vigentes, incluso con el auge de la Inteligencia Artificial y la explosión de cambios tecnológicos que vivimos en esta época. Sin duda este libro es de lectura obligada para líderes de TI en organizaciones y para los profesores que intentamos enfrentar el difícil reto de formar talento digital...

4. Programming Tools

Esta última parte no la detallaré por capítulos, no obstante los listo a continuación:

  • Capítulo 11 Programming Languages
  • Capítulo 12 Some Principles for Programming Language Design
  • Capítulo 13 Other Programming Tools

Los sistemas son complejos y la computación es compleja, ya lo dijo Dijkstra en su conferencia On the cruelty of really teaching computing science. Y también lo es la programación, como algo más específico, pero que es el núcleo de la computación. Además de los aspectos humanos individuales y sociales, programar involucra muchas herramientas: el hardware, el sistema operativo, el lenguaje, el entorno de desarrollo (IDE Integrated Development Environment), los componentes para depuración, pruebas, documentación, control de versiones y muchos más.

En ocasiones un programador promedio que use y domine muy buenas herramientas podría rendir mucho más que uno experto y del top mundial sin herramientas o con herramientas pobres. Además, las herramientas dependen del proyecto y la  necesidad.

En el caso de los lenguajes de programación hay una Torre de Babel permanente. El libro cita otro libro contemporáneo: Programming Languages: History and Fundamentals de Jean E. Sammet de 1969, cuya  portada referencia una pintura de Pieter Brueghel. Para esa época la cantidad de  lenguajes de  programación eran 118 y a hoy son más de 8000. Y cada día aparecen nuevos ranking de lenguajes y muchos lenguajes antiguos se niegan a morir, como por ejemplo COBOL.

El  lenguaje de programación es la clave y hay que saberlo seleccionar, sobre todo cuando se trata del contexto educativo. ¿Qué lenguaje usar para aprender a programar por primera vez? ¿Qué entorno de desarrollo? ¿Qué herramientas usar? Yo pienso que sería interesante un aprendizaje multilenguaje, como yo aprendí, con un libro que usaba BASIC, COBOL y C de los cuales luego salté a C++, Java y muchos otros, hasta JavaScript y Python que hoy tienden a dominar en popularidad...

* ConTICtualizando

Releyendo este libro, como cada inicio de semestre desde hace cuatro (4) años, encontré unas notas escritas a mano y recordé que siempre comenzaba a escribir sobre el libro y jamás finalizaba. Siempre aparecen otras tareas, otros compromisos y en últimas es un libro viejo, de hace más de medio siglo.

Pero este semestre había una diferencia y es que había leído y escrito algo corto sobre un libro reciente y relacionado con el mismo tema: el libro de Ingeniería de Software en Google. Ese contraste y la frase de motivación de Weinberg me llevaron a cumplir la tarea pendiente...

La moda por estos días es la Inteligencia Artificial, cosas como el Chat GPT3 y las herramientas inteligentes generadoras de contenidos digitales. El hombre ha fabricado su propia obsolescencia y hasta la programación es obsoleta, por lo menos la programación tradicional. El desafío académico y de negocio es gigante, aunque muchos aún no logran comprenderlo o aceptarlo.

Este libro, que corresponde a los orígenes de la computación, es propicio para estos tiempos en que nace una Inteligencia Artificial de verdad, que ya no es una promesa ni ciencia ficción. Ya están aquí los seres artificiales e invisibles, escondidos en la máquina y que remplazarán a quienes no cambien, ni se adapten ni evolucionen...

A lo mejor es tiempo de escribir The Psichology of Artificial Intelligence, antes de que la inteligencia artificial escriba The history of Natural Intelligence y pasemos al olvido...


No hay comentarios:

Publicar un comentario