Desde hace varios años en mi curso de Ingeniería de Software @ UNTreF venimos usando Ruby como lenguaje de programación. Una elección con la que estábamos muy conformes. Pero el cambio de plan de estudio del año pasado, cambió radicalmente el perfil de nuestros alumnos y ello nos llevó a replantear varias cuestiones de la forma en que dictamos la materia. Entre ellas el lenguaje de programación.
Dado el perfil de los alumnos pensamos que trabajar con un lenguaje de tipado estático podía resultar más conveniente para explicar algunas cuestiones (cuestiones que previamente no teníamos que explicar porque las estudiaban en materias anteriores). Inicialmente consideramos C# pero luego de algunas pruebas decidimos descartarlo. Finalmente la semana pasada decidimos ir con TypeScript. Yo vengo de armar un programa de entrenamiento para pasantes en uno de mis clientes y considero que TypeScript dió muy buen resultado. Mis colegas estuvieron de acuerdo así que ahí vamos.
Complementando TypeScript el stack de desarrollo que vamos usar está conformado por VScode + yarn + eslint + jest + cucumber + express (nada muy novedoso).
La semana pasada tuve el honor de ser jurado del trabajo final de carrera de Paola Rodrigues quien obtuvo su título de Ingeniera en Computación por la UNTreF. Si bien en las carreras de sistemas hay pocas mujeres, en Ingeniería en Computación suele haber aún menos. De hecho Paola es la segunda egresada mujer de la carrera.
El trabajo de Paola, titulado Análisis, visibilidad de tráfico y seguridad para usuarios finales en redes hogareñas, incluyó el desarrollo de una solución de bajo costo para el control de tráfico en redes hogareñas. El trabajo me resultó muy interesante, una combinación de innovación, programación, hardware y software. ¡Mi felicitaciones para nueva egresada!
El trabajo final de la materia consiste en resolver una problemática de negocio a partir de la implementación de una solución basada en software. Hasta aquí puede sonar como tantos otros trabajos de una materia de una carrera de sistemas. Pero en nuestro caso hay un par de cuestione (que tal vez tampoco son tan novedosas) que a los alumnos les cuestan bastante.
La primera cuestión es que no hay «un enunciado» ni una lista de funcionalidades, hay un «cliente» (rol ocupado por uno de los miembros del equipo docente) con un problema de negocio, los alumnos deben relevar el problema y plantear un proyecto para solucionarlo. Son los alumnos los que tienen que identificar las funcionalidades, darles forma de stories validarlas con el cliente, diseñar, codear, testear e implementar. Parece una desafío usual en una carrera de sistemas pero a pesar de eso muchos alumnos no saben por dónde empezar. Incluso cuando se supone que en materias anteriores ya vieron técnicas para lidiar con relevamiento y modelado de dominio.
Otra cuestión es que el proyecto deben desarrollarlo en 3 semanas, con iteraciones semanales al estilo XP. Eso implica planificar el trabajo a alto nivel (release plan) y también semana a semana, ejecutar dando visibilidad en un esquema de entrega continua y al final de la semana revisar lo realizado tanto a nivel producto como a nivel proceso. Insistimos en que el trabajo sea time-boxed lo cual implica que en caso de retrasos negocien/gestionen alcance. No hay problema en que no logren completar el plan de la semana siempre y cuando lo gestionen. No puede ocurrir que prometan X y luego caigan sorpresivamente a la revisión con menos de X. Seguir este proceso les cuesta muchísimo, en parte porque no tienen práctica en planificación, es un tema que tal vez vieron en alguna materia anterior pero casi sin práctica. Lo otro que suele constarles mucho es la negociación/gestión del alcance. En general si planifican X, hacen lo imposible por cumplir con X cuando muchas veces sería mucho más conveniente gestionar un recorte de alcance o simplemente avisar el cliente que no llegarán a cumplir con el plan. Incluso en ocasiones dejan de lado las buenas prácticas (modularización, testing, convenciones, etc, etc) lo cual no hace más que aumentar/generar deuda técnica que deberán pagar en el corto plazo.
Una de las cuestiones más novedosas para los alumnos es tener que lidiar con dos ambientes cloud, uno de pruebas y otro de producción. Esto en general no lo han hecho en ninguna materia. Esto por momentos se convierte en un gran desafío cuando algo les funciona localmente pero no en los ambientes cloud. Si bien les damos la infraestructura pre-armada y acceso a un log centralizado, muchas olvidan escribir mensajes de log con cual es como si estuvieran a ciegas. Esta cuestión de «build for operations» es uno de los temas de la materia y no esperamos que traigan conocimientos previos.
Finalmente lo que más me llama la atención es cuando los alumnos no aplican los conceptos que hemos estudiado durante toda la materia. El trabajo final juega un rol de trabajo integrador, previo a eso los alumnos trabajan en tareas individuales donde ponen en práctica diversos conceptos. Luego en el trabajo final deben volver a aplicar los conceptos ya estudiados pero ahora en un problema más complejo y trabajando en grupo. Una y otra vez vemos grupos que parecen haberse olvidado por completo de todo lo estudiado.
Hacer un buen diseño no es trivial, más aún: tampoco es trivial decir si un diseño es bueno. ¿Qué es un buen diseño? Alguien podría decir que un buen diseño es un diseño «escalable», pero que pasa si la escalabilidad no es uno de lo requisitos del problema. Creo que muchas veces se persiguen propiedades sin considerar las necesidades. En este sentido creo que una primera propiedad de un buen diseño es que resuelva el problema en cuestión.En línea con esto podríamos decir que un «mal diseño» es uno que no resuelve el problema en cuestión.
Mmmm, esto tampoco cierra. «Diseño bueno» o «diseño malo», no creo que sea una cuestión tan binaria: «bueno o malo». Pero si creo que la evaluación del diseño debe ser en función del problema que queremos resolver. Intento resaltar esto con un ejemplo concreto: puedo hacer un diseño super purista, que cumple con N propiedades, pero luego resulta no factible de ser implementado :-(. Entonces un diseño que no se implementa ya perdió. Nota al margen: creo que esto refleja la diferencia entre «la ciencia teórica» y la ingeniería.
Típicamente los problemas que tenemos que resolver tienen múltiples dimensiones representadas por: a) funcionalidades, el qué, lo que software debe hacer y 2) propiedades, atributos de calidad, el cómo, que influyen en el cómo resolvemos el problema, o sea: lo revolvemos de una forma que resulta mantenible, extensible, performante, etc, etc. A partir de esto creo que no es conveniente una evaluación «binaria» (bueno/malo), sino es que es mejor hablar en un continuo, una gama de grises entre el bueno y el malo.
Es en este grupo de propiedades que definen la solución hay una que destaca por ser de presencia «universal», o sea, que en general es requerida en toda solución: la mantenibilidad. Raro son los casos en los que resolvemos una problema de una y nunca más tenemos que tocar su código. En general nos aproximamos a la solución en forma iterativa y eso no lleva a volver una y otra vez sobre el código previamente escrito. Es ahí donde la mantenibilidad tiene un impacto decisivo en el costo (y los riesgos) de trabajar sobre código previamente escrito. Desde mi perspectiva la mantenibilidad implica: que el código sea legible, fácil de entender, que sea testeable (y que tenga pruebas), que revele su intención, que esté documentado, etc, etc.
Aquí es donde entra mi idea de «diseño decente», es un diseño que puede tener algunos puntos flojos pero que resuelve la dimensión funcional del problema y respeta ciertas premisas de mantenibilidad y testeabilidad de forma tal que nos lleva a generar una implementación que concretamente:
Respeta las convenciones del lenguaje de programación (fácilmente verificable con un linter)
Mantiene una clara separación entre el código de la lógica «de negocio» y el código de entrada/salida (infraestructura)
Tiene pruebas automatizadas
Traigo esta idea de «diseño decente» porque es justamente lo que intento enseñar a mis alumnos.
Luego de varios años dando vueltas sobre este tema, tenemos una carrera. Estoy tentando de decir que tenemos 3 carreras (una diplomatura, una especialización y una maestría) pero en términos formales y por el momento solo tenemos la diplomatura, las otras dos están aún «in-progress».
El detalle interesante es que estas tres titulaciones están armadas en manera incremental. En forma simplificada tenemos nueve materias, cuatro de ellas constituyen el diploma. Luego la especialización agrega cinco materias más y finalmente la maestría agrega una materia más y una tesis. Hay algunos detalles de «articulación» que aún nos falta definir pero la parte interesante es que la diplomatura ya está lista y la empezaremos a dictar el mes próximo: Septiembre 2023.
La diplomatura consta de las siguientes 4 materias:
Software Delivery: esta materia es la que vengo dictando desde hace 4 años bajo el nombre de «Seminario de Software Delivery». En el contexto de la diplomatura seguirá a mi cargo.
Operación y Gestión de Servicios de Software con DevOps: a cargo de Federico Casuscelli
Ingeniería de Software Moderna: a cargo de mi estimado Carlos Fontela
La diplomatura se dicta en modalidad virtual, dos materias por cuatrimestre. A su vez cada materia consta de 6 encuentros online que se realizan cada dos semanas. Finalmente en términos de calendario, las materias que se dictan en el mismo cuatrimestre, se encuentran «defasadas» en una semana. De esta forma el alumno cursa durante 12 semanas consecutivas, una clase por semana, las semanas pares cursa una materia y las semanas impares cursa la otra materia.
En particular, este segundo cuatrimestre de 2023 comenzaremos con el dictado de Ingeniería de Software Moderna y Diseño y Evolución de Arquitecturas. La cursada comenzará a mediados de septiembre. Estamos planificando una charla de presentación para la tercer semana de Agosto.
Respecto del costo, es algo que me excede pero según lineamientos institucionales, creo que serán algo así como 10 cuotas de ~ $40.000 (cuarenta mil pesos argentinos)
Pueden encontrar más detalles sobre las materias y la diplomatura en general en el folleto de difusión.
La ingeniería de software es una «actividad práctica» y en la cual hay ciertos fundamentos conceptuales sobre los cuales están construidas las prácticas y herramientas que utilizamos. Ejemplo: utilizamos la herramienta Jenkins para implementar la práctica de Integración Continua que, entre otras cuestiones, nos da feedback, uno de los pilares en el ejercicio de la ingeniería de software. Un esquema similar es planteado por Kent Beck en el marco de Extreme Programming. Kent Beck nos habla de Valores, Principios y Prácticas.
Curiosamente (o no tanto) la industria y la academia se aproximan de forma distinta a esta tríada (fundamentos-prácticas-herramientas). La academia suele enfocarse en los fundamentos y las prácticas dejando muchas veces bastante marginadas a las herramientas, lo cual en ocasiones suele generar la queja de la industria al ver que los egresados de la universidad no dominan ciertos lenguajes/frameworks /tecnologías de moda.
Por su parte la industria suele enfocarse en las herramientas (de ahí su queja) y algunas prácticas dejando muchas veces de lado los fundamentos. Esto se ve claramente en muchas búsquedas donde directamente se enumeran herramientas casi sin hacer mención a la formación: «Programador React». La falta de programadores es un condimento a toda esta situación y ha potenciado la aparición de cursos informales que muchas veces se venden como alternativas a las carreras universitarias.
En mi constante tránsito entre industria y academia siempre intento recorrer esta tríada de punta a punta. En mis materias estudiamos fundamentos y prácticas utilizando herramientas de uso habitual en la industria. Al mismo tiempo al trabajar en la industria, cuando trabajo con una determinada herramienta me ocupo de entender y difundir las prácticas y fundamentos detrás de la misma. Claro que es un desafió pues las herramientas están en constante evolución y eso requiere un esfuerzo sostenido de mantener actualizado el material de estudio y a própsito de esto, dejó aquí porque tengo que actualizar los videos de GitLab con el release de la version 15.1 🙂
Para este segundo cuatrimestre de 2022 estamos considerando realizar varios cambios en la dinámica de la materia.
En primer lugar tenemos un cambio importante en el equipo docente. Emilio Gutter quien venía desempeñando funciones de JTP ya no estará en la materia. Su lugar lo tomará, al menos parcialmente, Hernán de la Fuente, ex-alumno de la materia, miembro del equipo hace ya varios años y muy próximo a graduarse. También tenemos algunos otras bajas, no todas ellas cubiertas, con lo cual el tamaño del equipo se verá disminuído.
Por otro lado vamos a cambiar el orden de algunos temas y la forma en que los damos. Vamos a mantener una modalidad híbrida en la apuntamos a realizar cambios significativos en la dinámica de las clases presenciales.
También tenemos la intención de «reenfocar» algunas cuestiones, concretamente vamos a quitar un poco de relevancia al modelado de objetos/clases para poner más foco en el proceso de construcción (BDD/TDD) y el trabajo en equipo. Esto implica que algunos de los ejercicio individuales de programación pasarán a ser ejercicios en grupales.
Finalmente el último cambio es tal vez el de mayor impacto, vamos a cambiar el mecanismo de evaluación. Hasta el momento no tomábamos parciales ni final. La evaluación de los alumnos era constante a partir de las distintas tareas semanales y proyecto de TP. La idea es mantener eso pero adicionalmente agregar una instancia de evaluación al final de la materia donde cada alumno individualmente tenga que desarrollar «en vivo» una funcionalidad sobre su proyecto. Cuando digo en vivo me refiero a una sesión tipo pairing, donde el alumno acompañado por un docente desarrolla una funcionalidad de acuerdo al proceso y técnicas estudiadas en la materia. Esto no debería representar ningún desafío para los alumnos ya que es lo que hacemos durante la materia. ¿Entonces por qué lo vamos a hacer? Porque tenemos la sospecha de que al trabajar en equipo no todos los miembros asimilan los conceptos, como que algunos «delegan» en sus compañeros.
Hace ya tiempo venía dando vueltas en mi cabeza la idea de una materia para estudiar ciertas cuestiones «avanzadas» y en un punto hasta filosóficas de nuestra profesión. Dada la gran mezcolanza de temas no lograba darle nombre. Se me ocurrieron nombres como «Desarrollo Profesional de Software», «Programación Avanzada» y «Ejercicio profesional del desarrollo de software» pero ninguno me convencía. Finalmente, el pasado fin de semana me puse a escribir una descripción de los temas a abordar y mientras escribía la bibliografía de referencia me resultó evidente que el título debería ser «Artesanía de Software».
La idea de esta materia es estudiar ciertas cuestiones del ejercicio profesional del desarrollo de software. Es una materia avanzada, no por la complejidad de los temas a abordar sino por el hecho de que para poder abordarlos con profundidad y con una visión crítica es necesario tener algunos años de experiencia en el ejercicio de la profesión y más específicamente en programación. O sea, esta no es una materia para gerentes, analistas o maquetadores, es una materia para programadores.
Si tuviera que ubicar esta materia en el plan de estudio, sería una materia optativa del último año de la carrera.
Sobre los temas
Si miramos los planes de estudio de las carreras de sistemas vemos varias materias de programación: Algoritmos y Programación, Paradigmas de Programación, Programación Concurrente, Programación Orientada a Objetos, Taller de Programación, etc. Cada una de estas materias aborda alguna técnica o aspecto de la programación, pero hay ciertas cuestiones que son en cierto modo transversales a todas estas materias.
Entre estas cuestiones transversales hay temas tan básicos como la elección de los nombres de variables que uno podría pensar que deberían abordarse en las primeras materias de programación pero que en ocasiones no se abordan en profundidad o que incluso cuando sí se abordan, son cuestiones que resulta interesante replanteantearse luego de un par de años programando.
También tenemos algunos otros temas relacionados al versionado que es algo que utilizamos a diario pero que muchas veces lo hacemos en modo automático y sin considerar qué estamos metiendo en cada commit, que mensaje de commit ponemos, con que criterio creamos branches, etc.
Uno de los temas más polémicos y filosóficos que trata la materia es la discusión del desarrollo de software como ingeniería, ciencia u oficio.
Algunos otros temas a cubrir:
Profesionalismo, ética y contratos
Freelancing
Work-life balance
Aprender, enseñar, aprender a aprender y aprender a enseñar
Estimación, No-estimación, presupuestos y planificación
Lenguajes y paradigmas
Tipado estático vs. tipado dinámico vs. no tipado
Código de aplicación y código de pruebas
Las pruebas como documentación
Java, el nuevo cobol
El ascenso de JavaScript
Smalltalk…..
Mantenimiento y evolución
Trabajo con código legado
Código de infraestructura
Versionado y trazabilidad
Revisiones, Pairing y Mobbing
No-code / Low-code
Modalidad de cursada
La materia se dicta en una modalidad de aula invertida durante 16 semanas con un encuentro online de 3 horas por semana y con una dedicación estimada extra clase de unas 4 horas semanales.
La materia incluye lecturas (varias), videos (no tantos), código (tanto para leer y como para escribir) y debate (espero que mucho).
Participantes
Los candidatos a cursar la materia deberían:
Estar a menos de 4 materias para recibirse de una carrera de grado de sistemas/computación.
Tener al menos 3 años de experiencia programando profesionalmente en la industria.
Sentirse cómodos trabajando con al menos dos lenguajes de programación y tener alguna experiencia en al menos otros dos lenguajes (no cuenta HTML, CSS, ni bash).
Bibliografía
Estos son algunas de la fuentes y materiales en los que está basada la materia:
The Pragmatic Programmer, de Hunt & Thomas
Software Craftsmanship: The New Imperative, de Pete McBreen
Code Complete, de Steve McConnell
The Software Craftsman, de Sandro Mancuso
Apprenticeship Patterns: Guidance for the Aspiring Software Craftsman, de Oshineye & Hoover
The Design of the Design, de Brooks
Atomic Habits, de James Clear
Implementation Patterns, de Beck
Refactoring to Patterns, de Kerievsky
xUnit Test Patterns, de Meszaros
A esto se suman varios artículos (algunos formales y otros no tanto) y algunos videos.
Pre-Inscripción
Si el lector llegó hasta este punto, posiblemente se esté preguntando donde se dicta esta materia. La respuesta es que no lo sé. Por el momento tengo armada la estructura de la materia, algunos materiales, muchas ideas pero no tengo institución para dictarla. Claro que podría hacer un curso «no académico» y dictar esto por mi cuenta, pero precisamente lo pensé como materia porque me parece que es un contenido faltante en las carreras de grado de sistemas/computación. Creo que estos temas deben ser parte de la formación académica de los profesionales de esta disciplina.
En fin, por lo pronto y mientras veo como meter esto en una institución, si estás interesado en tomar este curso te invito a que completes este formulario y en cuanto tenga más definiciones me contactaré contigo.
En MeMo2 @ingenieriauba hacemos un primer TP grupal en el que los alumnos deben evolucionar una webapp existente siguiendo un proceso XP-like (iteraciones semanales, planning, review, retro, CI/CD, DDD, BDD/TDD, etc).
Entre las cosas que más énfasis hacemos y que más les cuesta (o que más resistencia le ponen) los alumnos está el desarrollar guiados por pruebas (bdd/tdd) y trabajar todo el tiempo haciendo Mob-Programming (o al menos pair-programming). También les pedimos que hagan Trunk-Based development.
TDD es algo que ya han visto en alguna materia anterior pero de una forma mucho menos profunda que lo que proponemos en MeMo2. En general los alumnos tiene una buena recepción porque nuestra propuesta de BDD+TDD ofrece una guía muy detallada de como transitar el proceso de construcción desde la intención del usuario hasta el código que implementa esa intención en un ambiente donde el usuario puede utilizar la pieza de software construida.
La propuesta de Mob/Pair-Programming les resulta más «rara», sobre todo a los que ya vienen con experiencia laboral. Posiblemente varios de los que ya trabajan en desarrollo no tendrían el visto bueno de sus jefes si pretendieran trabajar todo el tiempo (o la mayor parte) haciendo Mob/Pair Programming. Por esto es que insistimos tanto en que hagan Mob-Programming, si no lo prueban en nuestra materia, es posible que tampoco lo puedan probar en sus trabajos.
Algo similar ocurre con el uso de Trunk-Based development. Muchos de los que ya trabajan suelen utilizar feature-branches (como creo que hace gran parte de los desarrolladores actualmente) y entonces «temen» trabajar todos simultáneamente sobre el mismo branch. La clave aquí de nuestra propuesta es que al trabajar haciendo mob-programming solo hay un único branch de desarrollo activo, con lo cual resulta natural hacer trunk-based development. Al mismo tiempo y más allá de hacer mob-programming, nosotros insistimos en trabajar en pequeños incrementos haciendo commits al trunk/master cada 20 o 30 minutos como máximo, con lo cual las chances y el tamaño de divergencia al trabajar se reduce mucho, llevando casi a cero el tiempo requerido en arreglar conflictos de merge.
El jueves pasado al finalizar la segunda iteración del trabajo grupal hicimos una actividad con los alumnos para relevar cuanto habían usando las técnicas recomendadas y cuán útiles les habían resultado.
Los siguientes gráficos muestran el resultado de la actividad.
Mi sensación es que la mayoría de los alumnos «compra» nuestra propuesta. Veremos que opinan al finalizar el siguiente TP que reviste una complejidad mucho mayor y donde creo que estas técnicas suman aún más valor.
La semana pasada un publiqué artículo contando mi intención de hacer un taller online sobre Docker y Kubernetes. Resulta que hubo varios interesados y por ello ahora quiero compartir algunos detalles sobre la dinámica del taller.
La idea taller es aprender haciendo, con lo cual no bastará con asistir a las sesiones online para aprender. Las sesiones online estarán centradas en 2 cuestiones: presentación/explicación de conceptos y discusión/consultas. Luego, entre sesión y sesión, habrá actividades de estudio y prácticas que es donde espero se produzca el aprendizaje
El taller constará de 4 sesiones online de 2 horas. Cada una de esas sesiones será complementada con un conjunto de ejercicios, lecturas y evaluaciones de nivel que según mi estimación requerirán de unas 2 o 3 horas de trabajo por semana. La duración calendario del taller será 4 semanas.
Los participantes trabajarán localmente en sus máquinas y para algunos ejercicios específicos utilizarán servicios en la nube. Al final de taller los participantes dispondrán de las diapositivas utilizadas, una serie de materiales de estudio y obviamente el código de los ejercicios que hayan resuelto.