martes, 27 de agosto de 2013

Domain-Driven Design

DISCLAIMER: ESTE ARTÍCULO TODAVÍA ESTÁ EN CONSTRUCCIÓN

Como otros resúmenes de libros que he hecho, éste es un intento de clarificar las ideas sobre el libro que estoy actualmente leyendo, Domain-Driven Design: Tackling Complexity in the Heart of Software. No aporto nada nuevo, se trata simplemente de tratar de explicar con mis propias palabras lo leído de forma resumida.

Introducción

El Diseño Guiado por el Dominio (DDD) es un enfoque de diseño de software que enlaza el modelado del dominio y el diseño del software, con el objetivo de crear un modelo del dominio rico que evolucione a través de sucesivas iteraciones del diseño. En muchos proyectos la mayor complejidad es debida al dominio del problema, y es ésta complejidad la que trata de atajar DDD, partiendo de las premisas de que el foco principal del proyecto está sobre el dominio y que el diseño de un dominio complejo se basa en un modelo. DDD está orientado a las metodologías ágiles y supone que el desarrollo es iterativo y que existe una estrecha relación entre los desarrolladores y los expertos del dominio.

Parte I : Poniendo el Modelo del Dominio a Trabajar

Se presentan los objetivos del DDD.

  • 1 - Triturando el Conocimiento: La experimentación usando un lenguaje basado en el modelo y el ciclo de realimentación que se obtiene a través de la implementación hace posible encontrar un modelo rico y destilarlo. Esto convierte el conocimiento del equipo en un modelo valioso.
  • 2 - Comunicación y Uso del Lenguaje: Se debe usar el modelo como base del lenguaje que desarrolladores y expertos de negocio usan día a día, tanto para comunicarse entre ellos como en el código. Este LENGUAJE UBICUO evita tener que traducir entre el lenguaje de unos y otros, aunque cada grupo puede extenderlo con términos propios de su ámbito que no afectan al otro grupo. De esta manera los modelos serán explicativos y se podrán usar sin problemas en las discusiones entre ambos grupos.
  • 3 - Enlazando el Modelo y la Implementación: Si el diseño no está alineado con el modelo es difícil determinar si el software es correcto y es imposible llevar a cabo cambios en el diseño. Se debe buscar un modelo que se pueda implementar, para lo que se necesitan herramientas y lenguajes que soporten un paradigma de modelado, como la programación orientada a objetos.

Parte II: Las Piezas de un Diseño Guiado por el Modelo

Se condensa un núcleo de buenas prácticas del modelado orientado a objetos de dominios, que establecerán el conjunto de piezas del DDD, permitiendo dar orden al modelo y entender el trabajo entre desarrolladores mediante el uso de un lenguaje común. Se hace hincapié en la necesidad de mantener el modelo y la implementación alineados.

  • 4 - Aislando el Dominio: El software que resuelve los problemas del dominio constituye sólo una pequeña parte del sistema, aunque su importancia es inmensa. Es necesario desacoplar el modelo de las demás funciones para evitar la confusión con otros conceptos más tecnológicos. Una buena idea para ello es usar una ARQUITECTURA EN CAPAS.
  • 5 - Un Modelo Expresado Mediante Software: En primer lugar, se revisan las asociaciones en el modelo. Se debe definir la dirección en la que deben ser recorridas, tratar de incluir un calificador para reducir la multiplicidad y eliminar las asociaciones que no sean necesarias. Después se revisan los tres patrones de elementos del modelo: ENTIDADES (objetos que poseen una identidad propia que se debe preservar), OBJETOS DE VALOR (objetos que no tienen identidad y que describen alguna característica de algo) y SERVICIOS (operaciones que conceptualmente no pertenecen a ningún objeto). Estos elementos del modelo se pueden agrupar en MÓDULOS, que deben contener conceptos con gran cohesión entre ellos y permiten deben tener un bajo acoplamiento con otros MÓDULOS para facilitar la comprensión del sistema.
  • 6 - El Ciclo de Vida de un Objeto de Dominio: Algunos objetos son creados, usados en alguna computación y destruidos. Otros viven por más tiempo y no siempre en memoria, también pueden ser almacenados en una base de datos, por ejemplo. Los objetos tienen dependencias con otros y cambian de estado debiendo mantener ciertas condiciones. Existen ciertos patrones que ayudan a gestionar el ciclo de vida de un objeto. Un AGREGADO en un grupo de ENTIDADES y OBJETOS DE VALOR sobre el que se deben mantener ciertas condiciones, con una ENTIDAD como raíz que será la única a la que puedan acceder otros objetos externos. Las FACTORÍAS encapsulan la creación de un objeto o un AGREGADO. Los REPOSITORIOS permiten recuperar la ENTIDAD raíz de un AGREGADO proveyendo un punto de entrada para acceder a un objeto durante su ciclo de vida.
  • 7 - Usando el Lenguaje: Un Ejemplo Extendido: Ejemplo del diseño de un sistema de transporte de carga poniendo en práctica los patrones expuestos en los capítulos anteriores.

Parte III: Refactorizando hacia un Conocimiento más Profundo

Se va más allá de las piezas del DDD para afrontar el reto de montar con ellas modelos que supongan una ventaja. Se revisa el proceso de descubrimiento del modelo y su transformación paulatina a medida que se gana nuevo conocimiento sobre el mismo.

  • 8 - Un Avance Significativo: A medida que se asimila el conocimiento emergen gradualmente modelos más profundos a través de pequeñas refactorizaciones. A veces, el modelo se va clarificando hasta dar lugar a modelos mucho más profundos que dan una visión más clara del sistema. Esta oportunidad hay que aprovecharla cuando sea posible y conviene estar preparado para ello, haciendo explícitos los conceptos del sistema, procurando tener un diseño adaptable en todo momento y destilando el modelo.
  • 9 - Haciendo Explícitos los Conceptos Implícitos: Muchas transformaciones de los modelos ocurren cuando se reconoce un concepto que se ha dado a entender en una conversación o que está presente de forma implícita en el diseño, y se representa de forma explícita en el modelo. Para buscar estos conceptos hay que escuchar el lenguaje que se usa, buscar en los puntos de mayor complicación en el modelo y las contradicciones del modelo, leer sobre el negocio del dominio y probar diferentes posibilidades. Algunos conceptos que son menos obvios son las restricciones, los procesos que pueden ser expresados como SERVICIOS, y las reglas de negocio que se deben cumplir que se pueden encapsular mediante ESPECIFICACIONES.
  • 10 - Diseño Adaptable: El software debe servir tanto a los usuarios como a los propios desarrolladores, que deben ser capaces de hacer evolucionar el código. Para ello es necesario un diseño adaptable que facilite el cambio. Para ello el modelo se debe expresar a través de INTERFACES QUE REVELEN SU PROPÓSITO usando términos del LENGUAJE UBICUO. Estos interfaces deben usar FUNCIONES SIN EFECTOS SECUNDARIOS o, en su defecto utilizar ASERCIONES que expongan cuáles son sus efectos secundarios. También se debe simplificar su interpretación a través de la CLAUSURA DE OPERACIONES, haciendo que las operaciones devuelvan objetos del mismo tipo que sus parámetros. Conviene mantener un mismo NIVEL CONCEPTUAL en cuanto a los elementos del sistema y tratar de utilizar CLASES AUTÓNOMAS dentro de lo posible.
  • 11 - Aplicando Patrones de Análisis: Un patrón de análisis puede servir como guía para la investigación del modelo, aunque no suelen ser aplicables tal cual, sino que deben ser adaptados. Sin embargo, permiten ahorrar tiempo en la investigación del modelo.
  • 12 - Relacionando Patrones de Diseño con el Modelo: Algunos patrones de diseño pueden usar como patrones de dominio, ya que sus elementos se corresponden con conceptos generales que emergen en muchos dominios. Es el caso, por ejemplo, de los patrones ESTRATEGIA o POLÍTICA y COMPUESTO.

Parte IV: Diseño Estratégico

Se tratan los problemas que pueden aparecer en sistemas complejos, organizaciones grandes e interacciones con otros sistemas. El diseño estratégico permite llevar a cabo a gran escala los objetivos establecidos en la primera parte del libro.

  • 14: Manteniendo la Integridad del Modelo
  • 15: Destilación
  • 16: Estructuras de Gran Escala
  • 17: Reunificando la Estrategia

Conclusion

Referencias:

sábado, 13 de abril de 2013

Matemáticas I. Álgebra lineal.

En esta asignatura, de 1º de Ingeniería de Telecomunicación, se estudia el álgebra matricial, que será a su vez utilizada para trabajar con espacios vectoriales y para definir aplicaciones lineales, bilineales y cuadráticas. A su vez se aprenderá a simplificar las matrices que caracterizan a dichas aplicaciones mediante su diagonalización o triangularización según sea posible.

La signatura empieza por un par de teas introductorios que repasan la teoría de conjuntos y las estructuras algebraicas:

  1. Teoría de conjuntos. Aplicaciones. Relaciones. Nociones de lógica.
    • Conjuntos, elementos, subconjuntos.
    • Operaciones entre conjuntos. Propiedades.
    • Aplicaciones. Tipos. Composicion de Aplicaciones.
    • Relaciones binarias: Relaciones de equivalencia, propiedades, relaciones de orden. Orden total y parcial.
  2. Estructuras algebraicas.
    • Leyes de composición. Propiedades.
    • Grupos. Subgrupos.
    • Anillos. Subanillos.
    • Cuerpos. Subcuerpos.
A continuación viene el temario propio de la asignatura, compuesto de los siguientes temas:
  1. Álgebra matricial y sistemas de ecuaciones lineales.
    • Operaciones con matrices.
    • Tipos especiales de matrices.
    • Matrices en el campo complejo.
    • Matrices particionadas.
    • Determinantes.
    • Matriz inversa de una matriz regular.
    • Transformaciones elementales de matrices.
    • Sistemas de ecuaciones lineales.
  2. Espacios vectoriales.
    • Estructura algebraica de espacio vectorial.
    • Subespacios vectoriales.
    • Dependencia e independencia lineal. Base, dimensión y coordenadas.
    • Cambio de base.
    • Dimensión y ecuaciones de un subespacio vectorial.
    • Operaciones con subespacios vectoriales.
    • Definiciónn de norma. Ejemplos de norma.
  3. Espacios con producto escalar.
    • Espacios euclídeos y espacios unitarios.
    • Propiedades del producto escalar. Desigualdad de Schwartz.
    • Norma inducida por un producto escalar.
    • Expresión matricial del producto escalar. Cambio de base.
    • Vectores ortogonales, normados y ortonormados.
    • Método de ortogonalización de Gram-Schmidt.
    • Complemento ortogonal de un subespacio vectorial.
    • Proyección ortogonal sobre un subespacio.
    • Caracterización del elemento mejor aproximación.
  4. Aplicaciones lineales.
    • Definición de aplicación lineal. Propiedades.
    • Imagen y núcleo de una aplicación lineal.
    • Teorema fundamental de las aplicaciones lineales.
    • Clasificación de las aplicaciones lineales.
    • Expresión matricial de una aplicación lineal.
    • Rango de una aplicación lineal.
    • Relación entre las matrices que caracterizan a una misma aplicación lineal en distintas bases.
  5. Diagonalización por transformaciones de semejanza.
    • Introducción.
    • Autovalores y autovectores: cálculo y propiedades.
    • Diagonalización por semejanza.
  6. Triangularización por transformaciones de semejanza.
    • Introducción.
    • Forma de Jordan de matrices de orden dos y tres.
    • Teorema de clasificación de Jordan.
    • Algoritmo de obtención de la forma de Jordan de una matriz.
  7. Formas bilineales y formas cuadráticas.
    • Formas bilineales: expresión matricial.
    • Formas cuadráticas.
    • Formas cuadráticas reales.
    • Diagonalización de una forma cuadrática.
    • Ley de inercia de Sylvester. Signatura de una forma cuadrática.

La bibliografía utilizada en esta asignatura ha sido:

  • Álgebra Lineal. Matemáticas I. Notas de Clase. - Departamento de Matemática Aplicada de la Escuela Superior de Ingenieros Industriales y de Ingenieros de Telecomunicación de Bilbao.
  • Álgebra Lineal. Problemas de Clase. - Departamento de Matemática Aplicada de la Escuela Superior de Ingenieros Industriales y de Ingenieros de Telecomunicación de Bilbao.

jueves, 21 de marzo de 2013

Working Effectively With Legacy Code

Después de estudiar la forma de crear software de la mejor manera posible, usando Patrones de Diseño, evolucionando el diseño mediante TDD, cubriendo el código de pruebas y refactorizándolo cuando se presenta una oportunidad de mejora, me sigo topando con la cruda realidad. Ésta es que la mayor parte del tiempo lo paso trabajando con código ya hecho, por mí o por otras personas, y que no está desarrollado siguiendo las buenas prácticas que ahora intento seguir. Este código es difícil de entender y de mantener y, aunque quiero llevarlo a un estado parecido al código nuevo que desarrollo, esto me parece en ocasiones prácticamente imposible.

Una solución al problema de cómo mejorar este código legado es seguir los consejos que Michael C. Feathers presenta en su libro “Working Effectively With Legacy Code”. En él se presenta su visión sobre qué es el software legado, con que mentalidad enfrentarnos a él y qué técnicas podemos usar para combatir las malas prácticas que hay en él. Este artículo es un resumen de lo que este libro cuenta.

  1. Cambiando el software: El software se puede cambiar por varias razones: añadir funcionalidad, corregir un error, mejorar el diseño u optimizar el uso de los recursos del sistema. En todos los casos se quiere cambiar algún funcionamiento, pero se desea mantener la mayor parte del ya existente.
  2. Trabajando con realimentación: La forma de cambiar el sistema sin introducir errores es trabajar con la realimentación que proporcionan los tests unitarios que cubren el código. Estos tests permiten detectar cualquier comportamiento erróneo que se introduzca en las modificaciones que realicemos. El problema del código legado es que dichos tests no existen, y hay que hacer cambios para introducirlos rompiendo dependencias entre componentes, siendo extremadamente cuidadoso.
  3. Detección y separación: Existen dos motivos para romper las dependencias, detectar cómo afecta un componente a otro, o separar los componentes entre sí y poder ejecutarlos de forma independiente. De todas formas, los componentes deben colaborar entre sí y, para aliviar las dependencias en estas colaboraciones se pueden usar dobles de prueba que sustituyan al colaborador real.
  4. El modelo de costuras: El software no se puede tratar como un listado porque esto dificulta su comprensión y la reutilización de sus componentes. Para poder probarlo es necesario buscar formas de cambiar su comportamiento sin realizar ningún cambio sobre lo que se va a probar, puntos que el autor llama costuras. Estas costuras pueden ser habilitadas de distintas formas y, en función de ello, existen los siguientes tipos: de preprocesado, de enlazado y de objeto.
  5. Herramientas: A la hora de realizar cambios sobre el código legado hay una serie de herramientas que nos van a ayudar. Estas son las herramientas de refactorización automática, los frameworks de objetos “mock” (imitación), y los frameworks de prueba (xUnit, CppUnit, CppUnitLite, Fit, Fitnesse)
  6. No tengo mucho tiempo y tengo que cambiarlo: A veces no se dispone de tiempo para poner bajo tests la clase que tenemos que cambiar. En esos casos se pueden usar una serie de técnicas que, por lo menos, permiten tener bajo tests el código que introduzcamos al hacer los cambios. Estas técnicas consisten en crear una nueva clase o método, o crear una clase o método que envuelva el código existente.
  7. Hacer un cambio se eterniza: Cuando se están haciendo cambios es importante tener realimentación rápida sobre lo que está ocurriendo. Para ello es importante que los proyectos se puedan recompilar rápidamente de forma que no se invierta demasiado tiempo esperando. Para conseguir esta rapidez se deben usar interfaces y paquetes para separar las dependencias entre clases.
  8. Cómo añadir funcionalidad: Una vez que tenemos código bajo test podemos usar las técnicas descritas en este capítulo para añadir nueva funcionalidad de forma controlada. Estas técnicas son TDD y la programación por diferencia. La programación por diferencia, basada en la herencia de implementación, es bastante discutida, pero se puede utilizar de forma inicial a la hora de introducir nuevas funcionalidades y luego, gracias a los tests, ir mejorando el diseño de forma que se elimine su uso.
  9. No puedo incluir esta clase en un test: A veces no es fácil instanciar una clase en un test por distintos motivos. Estos pueden ser la dificultad de crear ciertos objetos debidos a los parámetros de su constructor o las dependencias de éste, que el test no se pueda ejecutar con una determinada clase que depende de una base de datos o parecido, que el constructor tenga efectos colaterales dañinos o que no seamos capaces de comprobar el trabajo que se hace en el constructor. Se presentan una serie de ejemplos donde se solucionan estos problemas a partir de unas útiles técnicas.
  10. No puedo ejecutar este método en un test: Una vez se puede instanciar una clase en un test sólo hemos empezado con lo que tenemos que hacer. Ahora hay que ejecutar alguno de sus métodos y a veces hay que superar problemas como que el método no sea accesible, que se necesiten parámetros difíciles de construir en su llamada, que tenga efectos colaterales perjudiciales o que no se pueda apreciar lo que hace en alguno de los objetos que utiliza. Se presentan una serie de ejemplos donde se solucionan estos problemas a partir de unas útiles técnicas.
  11. Necesito hacer un cambio. ¿Qué métodos debo probar?: Cada cambio en el software tiene una serie de efectos que es necesario considerar. Una técnica útil es hacer un boceto para ver de forma gráfica lo que se ve afectado por cada cambio. Un buen código creará estructuras simples. Es importante saber que los efectos se pueden propagar de tres formas: los valores de retorno de un método, los objetos pasados como parámetros a un método y las variables estáticas o globales. Se pueden simplificar estos bocetos mediante la eliminación de duplicación, y esto lleva a decisiones más sencillas sobre los tests a realizar.
  12. Necesito hacer muchos cambios en un área. ¿Tengo que romper las dependencias para todas las clases implicadas?: A veces es conveniente buscar un lugar donde probar vario cambios a la vez en lugar de poner bajo tests todas las clases implicadas en un cambio. Para ello, a través de los bocetos de efectos se pueden buscar puntos de intercepción, lugares donde se puede probar un determinado cambio. Algunos puntos, donde el boceto de efectos se estrecha, son especialmente indicados para probar varios cambios a la vez.
  13. Necesito hacer un cambio pero no se qué tests escribir: En código legado necesitamos tener tests que permitan preservar el comportamiento del sistema tras las modificaciones. Esos tests se llaman tests de caracterización, y son tests sencillos que simplemente reflejan lo que el sistema hace en este momento. A partir de estos tests se puede refactorizar el código para mejorarlo.
  14. Las dependencias en librerías me están matando: Es importante no confiar demasiado en una librería concreta y llenar el código de llamadas a métodos de esa librería. El uso de forma directa de una librería no favorece la creación de tests.
  15. Mi aplicación está llena de llamadas al API: La mayoría de los sistemas contienen una lógica principal que va más allá de llamadas a la API de una o más librerías. Es importante que el diseño preserve esta lógica para poder hacer buenos tests. A esta separación se puede llegar mediante dos aproximaciones: envolver el API o hacer una extracción basada en responsabilidades.
  16. No entiendo el código suficientemente bien para cambiarlo: Para entender el código existente de cara a hacer un cambio, se pueden usar algunas técnicas de bajo nivel, como tomar notas, hacer bocetos, marcar listados de código para resaltar los aspectos importantes del mismo, hacer una refactorización informal y luego deshacerlo o borrar el código que no se usa.
  17. Mi aplicación no tiene estructura:Las aplicaciones tienden al desorden cuando todo el equipo no es consciente de dicha arquitectura. Para asegurarse que el equipo entiende la arquitectura se puede recurrir a contar la historia del sistema para obtener una visión simple del sistema en su conjunto, usar CRC o “naked CRC” para comunicar el diseño de la aplicación o escrutar las conversaciones sobre el sistema para comprobar que cuando se hace un abstracción al hablar esta tenga una correspondencia en el sistema. Es importante resaltar que el diseño es una tarea que no termina mientras siga habiendo cambios.
  18. Mi código de test está en medio: Tener el código de test mezclado con el código puede no ser bueno por razones de claridad o de recursos. Para separarlo se pueden usar convenciones de nombrado o situar uno y otro en archivos separados.
  19. Mi proyecto no es orientado a objetos. ¿Cómo hago cambios seguros?: Principalmente se habla de lenguajes procedurales. Para estos lenguajes se pueden usar las costuras de procesado o de enlazado, pero si el lenguaje tiene una extensión que sea orientada a objetos, se puede hacer modificaciones que permitan usar las costuras de objeto, que son mucho más potentes.
  20. Esta clase es muy grande y no quiero que crezca más: Las clases grandes generan confusión, dificultad a la hora de planificar las tareas de los desarrolladores y son difíciles de probar. Estas clases tienden a atraer dentro de ellas las nuevas modificaciones y no paran de empeorar. La solución es refactorizar estas clases para hacer que cumplan con el Principio de Única Responsabilidad (SRP). Esta refactorización se debe hacer separando las responsabilidades de cada clase. Para ver estas responsabilidades se pueden agrupar sus métodos, buscar métodos ocultos, buscar las decisiones sobre la misma que puedan cambiar, buscar relaciones internas usando bocetos de propiedades para observar las agrupaciones internas, buscar la responsabilidad principal, hacer refactorizaciones de prueba o centrarse en la tarea que tenemos entre manos. La estrategia a seguir cuando se han identificado las distintas responsabilidades es separarlas a medida que sea necesario en vez de hacer todo a la vez. La mejor táctica para hacerlo sería aplicar el principio de responsabilidad única a nivel de implementación en vez de a nivel de interfaz.
  21. Estoy cambiando el mismo código por todos los sitios: Muchas veces hacemos un cambio y creemos que hemos terminado, pero nos damos cuenta de que debemos hacer este mismo cambio en otras partes del sistema donde el código está duplicado. A través de la refactorización podemos ahorrarnos esta molestia eliminando las duplicidades, consiguiendo además que emerja un mejor diseño y favoreciendo la ortogonalidad del sistema, consiguiendo partes del sistema independientes entre sí.
  22. Necesito cambiar un método monstruoso y no puedo escribir tests para él: Para abordar los cambios en estos métodos monstruosos podemos usar las herramientas de refactorización automáticas, evitando en este paso todo cambio adicional que no soporten. Cuando se refactoriza de forma manual debemos ser mucho más cuidadosos y, para ello, introducir variables que nos permitan sentir los cambios en el sistema, extraer sólo aquello que conocemos, separar el código principal de lo secundario o extraer un objeto método. Se pueden introducir cambios estructurales mientras se refactoriza haciendo que los métodos sean un esqueleto de la lógica que contienen, buscando secuencias de código, extrayendo a la clase actual en un primer paso en vez de llevar el código a otra clase y extrayendo en pequeñas piezas de código.
  23. ¿Cómo sé que no estoy rompiendo nada?: Se puede reducir el riego al editar los cambios si se es plenamente consciente de lo que se está editando, editando con un único objetivo, manteniendo las firmas de los métodos y apoyándose en el compilador para identificar los cambios que se deben hacer.
  24. Nos sentimos abrumados. Esto no va a mejorar: La programación puede ser divertida, aunque trabajar con código legado sea difícil. Rehacer el proyecto desde cero tampoco es una solución porque hay que mantener el mismo avance que el proyecto y esto es muy difícil. Hay que buscar la motivación para trabajar sobre nuestro sistema, solucionando los problemas más inmediatos y haciendo evidente la mejora que podo a poco se produce en el sistema.
  25. Técnicas para romper las dependencias: En este capítulo se definen técnicas para romper las dependencias, pero que no son exactamente refactorizaciones, puesto que están pensadas para hacerse sin tests, con el fin de poder introducir estos tests que nos faltan.

domingo, 10 de marzo de 2013

Fundamentos de Programación II

Esta asignatura, de 1º de Ingeniería de Telecomunicación, es una introducción a la programación orientada a objetos en C++ y a la programación en entono Windows con OWL (Object_Windows_Library).

El temario de esta asignatura fue el siguiente:

  1. Diferencias entre C y C++
  2. Clases y objetos
  3. Herencia y polimorfismo
  4. Interface usuario-máquina
  5. Recursos
  6. Menus
  7. Cajas de diálogo
  8. Ficheros binarios

En el repositorio FundamentosProgramacionII de mi cuenta de Github he dejado el temario completo y los ejercicios y ejemplos de la asignatura.

Al igual que en la asignatura, allá por 1996-1997, he usado el compilador Borland C++ 4.5 para los ejemplos de programación Windows. Para los ejemplos de introducción a la programación orientada a objetos ahora uso NetBeans como IDE con las herramientas g++ y make para Windows de Cygwin.

En cuanto a bibliografía, recomendaría los siguientes recursos:

domingo, 17 de febrero de 2013

Fundamentos de Programación I

Esta asignatura, de 1º de Ingeniería de Telecomunicación, es una introducción a la programación. En ella aprendimos los conceptos fundamentales de un lenguaje de programación a través del aprendizaje del lenguaje C.

El temario de esta asignatura fue el siguiente:

  1. Lenguajes de programación
  2. Introducción al lenguaje C
  3. Tipos de datos
  4. Funciones de entrada y salida
  5. Expresiones y operadores
  6. Sentencias selectivas
  7. Sentencias repetitivas
  8. Funciones
  9. El preprocesador
  10. Arrays
  11. Cadenas de caracteres
  12. Estructuras de datos
  13. Uniones
  14. Operaciones sobre arrays
  15. Listas encadenadas
  16. Operaciones sobre listas encadenadas
  17. Pilas y colas
  18. Métodos de ordenación de estructuras lineales
  19. Ficheros

En el repositorio FundamentosProgramacionI de mi cuenta de Github he dejado el temario completo, los ejercicios y ejemplos de la asignatura y algún ejemplo de examen.

En la asignatura, allá por 1996-1997, usábamos el compilador Borland C 4.5. Yo ahora he decidido usar NetBeans como IDE con las herramientas gcc y make para Windows de Cygwin. También he eliminado las referencias a librerías propietarias de Borland, como conio.h, para que los ejemplos sean más ANSI C.

En cuanto a bibliografía, recomendaría los siguientes recursos:

viernes, 11 de enero de 2013

1º Ingeniería de Telecomunicación

Estas son las asignaturas que estudié en 1º:

  • Fundamentos de Programación I: Programación en lenguaje C.
  • Fundamentos de Programación II: Programación orientada a objetos en C++ y programación en entorno Windows.
  • Matemáticas I: Álgebra lineal
  • Matemáticas II
  • Matemáticas III
  • Matemáticas IV
  • Física I
  • Física II
  • Estadística
  • Electrónica de dispositivos
  • Laboratorio de Electrónica Básica I
  • Teoría de Circuitos I
  • Teoría de Circuitos II

He empezado recuperando de casa de mis padres apuntes, libros y hasta disquetes en los que guardaba las prácticas. Menos mal que alguno de mis compañeros de trabajo todavía conservan disqueteras y me han copiado todos los archivos.

Otra reliquia que he recuperado es la calculadora que nos recomendaron comprar en la asignatura de Teoría de Circuitos y que tanto partido sacamos durante la carrera, la Hewlett Packard 48GX:

Repitiendo

En su día, allá por 1996, comencé la carrera de Ingeniería de Telecomunicación en la Escuela Técnica Superior de Ingenieros de Bilbao. Elegí esta carrera por la curiosidad que sentía en aquel momento por cómo funcionaban cosas como la radio, la televisión o los ordenadores, y eso que no tuve un ordenador en casa hasta que mis padres no me compraron uno al comenzar la carrera.

Pasé por la universidad sin pena ni gloria, académicamente hablando. Conseguí terminarla y presentar mi Proyecto de Fin de Carrera en el 2004. En todo este tiempo pasé por la desilusión de ver que la universidad no era lo que yo esperaba, las ganas de tirar la toalla en algunos momentos y la satisfacción de haberme sabido reponer a los mismos y acabar aquello que había comenzado.

Como algo bueno de ese tiempo, puedo decir que encontré algo que me gustaba y que se ha convertido en mi profesión, el desarrollo de software. Además, muchas de las cosas que en su momento estudié, se han tornado útiles en mi trabajo con el paso del tiempo.

Como algo malo tengo el recuerdo de estudiar las cosas a veces por que sí, sin encontrar el sentido de lo que estaba buscando. Además, la presión de tener que aprender un montón de cosas en un periodo restringido y tener que demostrar el conocimiento en un examen realizado un día concreto fue en ciertas ocasiones algo insoportable.

Y el caso es que desde entonces, he guardado en casa de mis padres, como un tesoro, los libros y apuntes de todo aquello que estudié. Quizá internamente sabía que llegaría un momento en que querría volver a estudiar lo que estudié entonces.

Ese momento ha llegado. Voy a repetir. Tranquilamente, sin prisas ni plazos, voy a volver a estudiar, curso por curso a través de aquellos libros y apuntes, la carrera de Ingeniería de Telecomunicación, porque creo que tengo mucho partido que sacarle todavía a todo ello. Porque en aquellos momentos en los que conseguía olvidarme de la angustia por los exámenes, me gustaba la mayoría de lo que hacía.

Y es que la carrera no es sólo algo que estudias durante unos años de tu vida, sino que, para bien o para mal, es algo que marca tu vida. Y, a pesar de que la sensación cuando terminé fue agridulce, hoy estoy satisfecho de aquel esfuerzo y agradecido a mis padres por habérmelo hecho posible.