Proceso de desarrollo de un programa

La programación es una tarea compleja a la que es mejor enfrentarse de manera iterativa.

Algunos pasos generales para hacerlo son:

  1. Analizar cuidadosamente el problema a resolver.

    • Utilizar en esta etapa lápiz y papel y la ayuda de bosquejos, entre otros recursos.

    • Identificar los datos de entrada y cuáles deben ser las salidas buscadas, para todas las posibles condiciones.

    • Hacer cálculos paso a paso.

    • Identificar resultados intermedios tratando de encontrar el algoritmo adecuado.

  2. Una vez se llega a una primera solución en papel razonable, se pasa a programar, utilizando los recursos provistos por el lenguaje.

    Ya se poseen los elementos imprescindibles para resolver cualquier problema solucionable por un ordenador. En este tema introducimos las funciones, que facilitarán aún más la tarea de la programación.

  3. Una buena práctica de programación exige que comprobemos que el funcionamiento de nuestro código es el correcto, realizando test que nos permitan asegurar que la solución diseñada cumpla con todos los requerimientos.

    Si bien estos test son siempre necesarios, lo son aún más en el caso de las funciones (como podría ser sqrt()) que vayan a formar parte de bibliotecas, las cuales previsiblemente serán utilizadas, una y otra vez, conformando diferentes programas. Un error en una función de este tipo compromete la fiabilidad de todos los programas que la utilizan.

    Verificar si el programa funciona para los casos límites o especiales es una estrategia habitual. Por ello, es importante identificar esos casos para poder testarlos y, en su caso, corregir los fallos.

    En el caso de determinar si un número es primo, ¿funciona para el 2?

  4. Por otro lado, es frecuente que, en un primer esbozo del programa, se asuma que el usuario va a actuar de una determinada forma, prevista de antemano. En ocasiones, el no tener en cuenta todos los posibles casos de uso puede dar un resultado incorrecto o que el programa se interrumpa bruscamente por un error de ejecución. La solución de cada uno de los problemas detectados, implicará probablemente volver al paso 1 y la realización de modificaciones del código más o menos importantes, hasta que se llega a un código robusto y que funcione para todas las posibles entradas de datos.

    En el caso de los primos, ¿qué pasa si el número introducido es menor que dos o incluso negativo?

  5. El primer programa seguramente no constituye la forma más eficiente (más rápida, por ejemplo) de resolver el problema. Un código que ya funciona correctamente puede estar sujeto a mejoras y optimizaciones.

    Encontrar un código eficiente es una tarea en general difícil, y debe ser en todo caso enfrentada cuando ya se tenga un programa básico que funcione correctamente. ¡No se debe caer en la trampa de la optimización prematura!

    En este sentido, es útil conocer que en la gran mayoría de los casos es bueno sacrificar la velocidad de ejecución en aras de una mayor claridad del código.

  6. Así, se debe tener en cuenta que un programa tiene otras virtudes además de dar las salidas correctas para todos los casos. Los programas deben ser legibles, estar escritos de forma clara y consistente, de manera que otros programadores, o el mismo programador original pasado un tiempo, puedan comprenderlos con facilidad para hacer modificaciones, nuevas versiones que son frecuentemente necesarias.

    • los identificadores de las variables deben ser autoexplicativos,

    • las estructuras de control deberán estar bien elegidas.

    • utilizar el sangrado del código y hacer un uso correcto y consistente de los espacios en blanco.

    • los comentarios son útiles para expresar el por qué, pero es mejor evitarlos cuando expresan el qué usando en su lugar código autoexplicativo.

    • es muy importante documentar nuestros programas.

    Frecuentemente ocurre que, en la medida en que el programa crece, se debe reestructurar (refactoring) el código. Legibilidad y fácil reestructuración están íntimamente ligadas.

Las funciones, como veremos enseguida, serán una de las principales herramientas para conseguir buena parte de las pautas anteriores, utilizando técnicas como la del refinamiento descendente.

Como ya se ha comentado con anterioridad, en este curso básico no nos ocuparemos de manejar excepciones, en especial, las causadas por entradas con un formato incorrecto de datos por parte del usuario. La razón principal es la de centrarnos en los aspectos clave de C++, evitando distracciones y exponiendo código de la forma más escueta posible. Esta táctica es la habitual en cualquier texto introductorio sobre lenguajes de programación.

Tampoco se hará hincapié sobre la eficiencia algorítmica. Cuando se manipulan grandes volúmenes de datos, son importantes las consideraciones de cómo crece, por ejemplo, el tiempo de ejecución del programa cuando aumenta el tamaño de los datos de entrada.