INSTITUTO TECNOLÓGICO SUPERIOR DE LA SIERRA NORTE DE PUEBLA Ingeniería Informática. Fundamentos de Programación. Unidad 1. Evolución de los Paradigmas de Programación. 1.1 Conceptos básicos. ¿Qué es un lenguaje de programación? Los lenguajes de programación son un conjunto de reglas, herramientas y condiciones que admiten crear programas o aplicaciones dentro de una computadora. Estos programas son los que permitirán ordenar distintas acciones a la computadora en un “idioma” comprensible por ella. Como su nombre lo indica, un lenguaje tiene su parte sintáctica y su parte semántica. ¿Qué quiere decir esto? Que todo lenguaje de programación posee reglas acerca de cómo se deben escribir las sentencias y de qué forma. A su vez, los lenguajes de programación se dividen en tres grandes grupos: los lenguajes de máquina, los de bajo nivel y los de alto nivel. A continuación se explica brevemente cada uno de ellos. Lenguajes de máquina. Los lenguajes de máquina son los que entiende una computadora sin la necesidad de realizar ninguna traducción. Escribirlos resulta extremadamente difícil para un programador convencional. Hoy en día, nadie programa en este lenguaje, pero como es necesario para que la computadora entienda lo que tiene que hacer, existen programas que se encargan de transformar el código comprensible por un programador, en código comprensible por una computadora. Las instrucciones en este tipo de lenguaje se componen de la unidad de memoria más pequeña que existe dentro de una computadora, que se llama bit. Cada una de estas unidades puede tener sólo dos valores posibles: 1 ó 0. En seguida se muestran algunos ejemplos de sentencias en este tipo de lenguaje: Figura 1.1 Ejemplo de instrucciones en lenguaje máquina. Para facilitar la tarea del programador, se han diseñado otros tipos de lenguajes, que son más comprensibles que el de máquina. Éstos son el de bajo nivel y el de alto nivel. 1 INSTITUTO TECNOLÓGICO SUPERIOR DE LA SIERRA NORTE DE PUEBLA Ingeniería Informática. Fundamentos de Programación. Lenguajes de bajo nivel. Los lenguajes de bajo nivel, también llamados ensambladores, son aquellos cuyas sentencias están formadas por códigos nemotécnicos (abreviaturas de palabras en inglés). Son lenguajes que, por más complejos que sean, resultan mucho más comprensibles que los lenguajes de máquina. A continuación se ilustra un ejemplo de código para este tipo de lenguaje: Figura 1.2 Ejemplo de instrucciones en lenguaje de bajo nivel. Estos lenguajes son, además, dependientes de la arquitectura de cada procesador, ya que cada procesador ofrece un conjunto de instrucciones distinto para trabajar en este nivel de programación. Una vez escrito el programa en este lenguaje, se necesita otro llamado programa ensamblador, para que traduzca las sentencias en instrucciones comprensibles por la máquina. 2 INSTITUTO TECNOLÓGICO SUPERIOR DE LA SIERRA NORTE DE PUEBLA Ingeniería Informática. Fundamentos de Programación. Lenguajes de alto nivel. Los lenguajes de alto nivel son aquellos que poseen sentencias formadas por palabras similares a las de los lenguajes humanos. Por lo tanto, resulta mucho más sencillo escribir un programa en un lenguaje de alto nivel para luego traducirlo en código comprensible para una computadora. Algunos ejemplos de este tipo de lenguaje son: Pascal, Delphi, Cobol, FoxPro, Java y la mayoría de los lenguajes visuales, como Visual Basic, Visual FoxPro, etc. Además, se puede decir que, dentro de este conjunto de lenguajes de programación, algunos son de más alto nivel que otros, pero, en general, todos entran en esta categoría. En el caso de C, muchos autores opinan que este lenguaje es de nivel medio, o sea, que posee una escritura sencilla y comprensible por los programadores, pero a la vez ofrece una potente y variada gama de posibilidades para realizar miles de tareas con una computadora. Se puede hacer casi lo mismo que con un lenguaje ensamblador. Hasta es posible insertar código assembler dentro del código de C. En conclusión, C pertenece a un nivel intermedio entre un lenguaje de bajo nivel y uno de alto nivel. Tipos de programación. No sólo existen varios tipos de lenguajes de programación, sino que también se pueden encontrar distintas formas de programar una aplicación. Hay diversos paradigmas que permiten encontrar una solución más adecuada a los problemas. La idea es que el programador los conozca y sepa seleccionar el adecuado para cada situación particular. Lo que es verdad, es que, para cada paradigma conviene utilizar ciertos lenguajes de programación, y no cualquiera. Esto se debe a que la mayoría de los lenguajes fueron creados para ser utilizados en determinados ambientes de programación. En seguida se muestran las formas de programar más conocidas y utilizadas en la actualidad. Un paradigma de programación representa un enfoque particular o filosofía para la construcción del software. No es mejor uno que otro sino que cada uno tiene ventajas y desventajas. También hay situaciones donde un paradigma resulta más apropiado que otro. Algunos ejemplos de paradigmas de programación: El paradigma imperativo es considerado el más común y está representado, por ejemplo, por el C o por BASIC. El paradigma funcional está representado por la familia de lenguajes LISP (en particular Scheme), ML o Haskell. 3 INSTITUTO TECNOLÓGICO SUPERIOR DE LA SIERRA NORTE DE PUEBLA Ingeniería Informática. Fundamentos de Programación. El paradigma lógico, un ejemplo es PROLOG. El paradigma orientado a objetos. Un lenguaje completamente orientado a objetos es Smalltalk. Nota: La representación orientada a objetos mejora la estructura de los datos y por lo tanto se ha aplicado a diferentes paradigmas como Redes de Petri, Imperativo Secuencial, Lógica de Predicados, Funcional, etc. No obstante, la manipulación no queda fundamentalmente afectada y por lo tanto el paradigma inicial tampoco a pesar de ser re-orientado a objetos. Si bien puede seleccionarse la forma pura de estos paradigmas al momento de programar, en la práctica es habitual que se mezclen, dando lugar a la programación multiparadigma. Actualmente el paradigma de programación más usado debido a múltiples ventajas, es la programación orientada a objetos 1.2 Programación secuencial y estructurada. Programación Secuencial (Lineal). Figura 1.3 Programación secuencial. Este tipo de programación se basa en la creación de programas a partir de un conjunto de sentencias escritas de forma secuencial y cuya ejecución sigue dicha secuencia. Se utiliza la sentencia como goto o similar para realizar una bifurcación en la ejecución del programa hacia una etiqueta determinada. Una etiqueta es una marca en el código de un programa para que sea referenciado en algún momento de su ejecución. Algunos lenguajes que se utilizan para este tipo de programación son Basic, Assembler, Fortran y Cobol, entre otros. 4 INSTITUTO TECNOLÓGICO SUPERIOR DE LA SIERRA NORTE DE PUEBLA Ingeniería Informática. Fundamentos de Programación. Programación Estructurada. Figura 1.4 Programación estructurada (estructura selectiva). La programación estructurada es una forma de escribir programación de computadora de forma clara, para ello se utilizan únicamente tres estructuras: secuencial, selectiva e iterativa; siendo innecesario y no permitiéndose el uso de la instrucción o instrucciones de transferencia incondicional (GOTO). Surgimiento de la programación estructurada. A finales de los años sesenta surgió una nueva forma de programar que no solamente daba lugar a programas fiables y eficientes, sino que además estaban escritos de manera que facilitaba su comprensión posterior. Un famoso Teorema de Dijkstra, demostrado por Edsger Dijkstra en los años sesenta, demostró que todo programa puede escribirse utilizando únicamente las tres instrucciones de control siguientes: Secuencia. Instrucción condicional. Iteración, o bucle de instrucciones. Solamente con estas tres estructuras se puede hacer un programa informático, si bien los lenguajes de programación, y sus compiladores, tienen un repertorio de estructuras de control mayor. Ventajas de la programación estructurada. Con la programación estructurada, elaborar programas de computadora sigue siendo una labor que demanda esfuerzo, creatividad, habilidad y cuidado. Sin embargo, con este estilo se pueden obtener las siguientes ventajas: 5 INSTITUTO TECNOLÓGICO SUPERIOR DE LA SIERRA NORTE DE PUEBLA Ingeniería Informática. Fundamentos de Programación. 1. Los programas son más fáciles de entender, ya que pueden ser leídos de forma secuencial, sin necesidad de hacer seguimiento a saltos de línea (GOTO) dentro de bloques de código para entender la lógica. 2. La estructura del programa es más clara puesto que las instrucciones están más ligadas o relacionadas entre sí. 3. Reducción del esfuerzo en las pruebas. El seguimiento de las fallas ("debugging") se facilita debido a la lógica más visible, por lo que los errores se pueden detectar y corregir más fácilmente. 4. Reducción de los costos de mantenimiento. 5. Programas más sencillos y más rápidos. 6. Los bloques de código son auto explicativos, lo que apoya a la documentación. Desventajas de la programación estructurada. El principal inconveniente de este método de programación, es que se obtiene un único bloque de programa, que cuando se hace demasiado grande puede resultar problemático su manejo, esto se resuelve empleando la programación modular, definiendo módulos interdependientes programados y compilados por separado. Un método un poco más sofisticado es la programación por capas, en la que los módulos tienen una estructura jerárquica muy definida y se denominan capas. 1.3 Programación Orientada a Objetos. Figura 1.5 Programación orientada a objetos. 6 INSTITUTO TECNOLÓGICO SUPERIOR DE LA SIERRA NORTE DE PUEBLA Ingeniería Informática. Fundamentos de Programación. La Programación Orientada a Objetos (POO u OOP según siglas en inglés) es un paradigma de programación que define los programas en términos de "clases de objetos", objetos que son entidades que combinan estado (es decir, datos), comportamiento (esto es, procedimientos o métodos) e identidad (propiedad del objeto que lo diferencia del resto). La programación orientada a objetos expresa un programa como un conjunto de estos objetos, que colaboran entre ellos para realizar tareas. Esto permite hacer los programas y módulos más fáciles de escribir, mantener y reutilizar. De esta forma, un objeto contiene toda la información, (los denominados atributos) que permiten definirlo e identificarlo frente a otros objetos pertenecientes a otras clases (e incluso entre objetos de una misma clase, al poder tener valores bien diferenciados en sus atributos). A su vez, dispone de mecanismos de interacción (los llamados métodos) que favorecen la comunicación entre objetos (de una misma clase o de distintas), y en consecuencia, el cambio de estado en los propios objetos. Esta característica lleva a tratarlos como unidades indivisibles, en las que no se separan (ni deben separarse) información (datos) y procesamiento (métodos). Dada esta propiedad de conjunto de una clase de objetos, que al contar con una serie de atributos definitorios, requiere de unos métodos para poder tratarlos (lo que hace que ambos conceptos están íntimamente entrelazados), el programador debe pensar indistintamente en ambos términos, ya que no debe nunca separar o dar mayor importancia a los atributos en favor de los métodos, ni viceversa. Hacerlo puede llevar al programador a seguir el hábito erróneo de crear clases contenedoras de información por un lado y clases con métodos que manejen esa información por otro (llegando a una programación estructurada camuflada en un lenguaje de programación orientado a objetos). Esto difiere de la programación estructurada tradicional, en la que los datos y los procedimientos están separados y sin relación, ya que lo único que se busca es el procesamiento de unos datos de entrada para obtener otros de salida. La programación estructurada anima al programador a pensar sobre todo en términos de procedimientos o funciones, y en segundo lugar en las estructuras de datos que esos procedimientos manejan. En la programación estructurada se escriben funciones y después se les pasan datos. Los programadores que emplean lenguajes orientados a objetos definen objetos con datos y métodos y después envían mensajes a los objetos diciendo que realicen esos métodos en sí mismos. Algunas personas también distinguen la POO sin clases, la cual es llamada a veces programación basada en objetos. 7 INSTITUTO TECNOLÓGICO SUPERIOR DE LA SIERRA NORTE DE PUEBLA Ingeniería Informática. Fundamentos de Programación. Origen. Los conceptos de la programación orientada a objetos tienen origen en Simula 67, un lenguaje diseñado para hacer simulaciones, creado por Ole-Johan Dahl y Kristen Nygaard del Centro de Cómputo Noruego en Oslo. Según se sabe, la historia es que trabajaban en simulaciones de naves, y fueron confundidos por la explosión combinatoria de cómo las diversas cualidades de diversas naves podían afectar unas a las otras. La idea que se les ocurrió fue agrupar los diversos tipos de naves en diversas clases de objetos, siendo responsable cada clase de objetos de definir sus propios datos y comportamiento. Fueron refinados más tarde en Smalltalk, que fue desarrollado en Simula en Xerox PARC (y cuya primera versión fue escrita sobre Basic) pero diseñado para ser un sistema completamente dinámico en el cual los objetos se podrían crear y modificar "en marcha" en lugar de tener un sistema basado en programas estáticos. La programación orientada a objetos tomó posición como el estilo de programación dominante a mediados de los años ochenta, en gran parte debido a la influencia de C++, una extensión del lenguaje de programación C. Su dominación fue consolidada gracias al auge de las Interfaces gráficas de usuario, para las cuales la programación orientada a objetos está particularmente bien adaptada. En este caso, se habla también de programación dirigida por eventos. Las características de orientación a objetos fueron agregadas a muchos lenguajes existentes durante ese tiempo, incluyendo Ada, BASIC, Lisp, Pascal, entre otros. La adición de estas características a los lenguajes que no fueron diseñados inicialmente para ellas condujo a menudo a problemas de compatibilidad y a la capacidad de mantenimiento del código. Los lenguajes orientados a objetos "puros", por otra parte, carecían de las características de las cuales muchos programadores habían venido a depender. Para saltar este obstáculo, se hicieron muchas tentativas para crear nuevos lenguajes basados en métodos orientados a objetos, pero permitiendo algunas características imperativas de maneras "seguras". El Eiffel de Bertrand Meyer fue un temprano y moderadamente acertado lenguaje con esos objetivos pero ahora ha sido esencialmente reemplazado por Java, en gran parte debido a la aparición de Internet, y a la implementación de la máquina virtual de Java en la mayoría de los navegadores. 8 INSTITUTO TECNOLÓGICO SUPERIOR DE LA SIERRA NORTE DE PUEBLA Ingeniería Informática. Fundamentos de Programación. 1.4 Relación entre la Programación Orientada a Objetos y la programación estructurada. Diferencias con la programación estructurada. Aunque la programación estructurada (a veces llamada procedural o procedimental) condujo a mejoras de la técnica de programación secuencial, los métodos modernos de diseño de software orientado a objetos incluyen mejoras entre las que están el uso de los patrones de diseño, diseño por contrato, y lenguajes de modelado (ejemplo: UML). Las principales diferencias entre la programación estructurada y la orientada a objetos son: La programación orientada a objetos es más moderna, es una evolución de la programación estructurada que plasma en el diseño de una familia de lenguajes conceptos que existían previamente con algunos nuevos. La programación orientada a objetos se basa en lenguajes que soportan sintáctica y semánticamente la unión entre los tipos abstractos de datos y sus operaciones (a esta unión se la suele llamar clase). La programación orientada a objetos incorpora en su entorno de ejecución mecanismos tales como el polimorfismo y el envío de mensajes entre objetos. Erróneamente se le adjudica a la programación estructurada clásica ciertos problemas como si fueran inherentes a la misma. Esos problemas fueron haciéndose cada vez más graves y antes de la programación orientada a objetos diversos autores (de los que destaca Yourdon) encontraron soluciones basadas en aplicar estrictas metodologías de trabajo. De esa época son los conceptos de cohesión y acoplamiento. De esos problemas se destacan los siguientes: Modelo mental anómalo. La imagen que se tiene del mundo se apoya en los seres, a los que se les asignan nombres sustantivos, mientras la programación clásica se basa en el comportamiento, representado usualmente por verbos. Es difícil modificar y extender los programas, pues suele haber datos compartidos por varios subprogramas, que introducen interacciones ocultas entre ellos. Es difícil mantener los programas. Casi todos los sistemas informáticos grandes tienen errores ocultos, que no surgen a la luz hasta después de muchas horas de funcionamiento. Es difícil reutilizar los programas. Es prácticamente imposible aprovechar en una aplicación nueva las subrutinas que se diseñaron para otra. Es compleja la coordinación y organización entre programadores para la creación de aplicaciones de media y gran envergadura. En la programación orientada a objetos pura no deben utilizarse llamadas de subrutinas, únicamente mensajes. 9 INSTITUTO TECNOLÓGICO SUPERIOR DE LA SIERRA NORTE DE PUEBLA Ingeniería Informática. Fundamentos de Programación. Por ello, a veces recibe el nombre de programación sin CALL, igual que la programación estructurada se llama también programación sin GOTO. Sin embargo, no todos los lenguajes orientados a objetos prohíben la instrucción CALL (o su equivalente), permitiendo realizar programación híbrida, imperativa y orientada a objetos a la vez. La Programación Orientada a Objetos (POO) como solución. La programación orientada a objetos es una nueva forma de programar que trata de encontrar una solución a estos problemas. Introduce nuevos conceptos, que superan y amplían conceptos antiguos ya conocidos. Entre ellos destacan los siguientes: Objeto: entidad provista de un conjunto de propiedades o atributos (datos) y de comportamiento o funcionalidad (métodos). Corresponden a los objetos reales del mundo, o a objetos internos del sistema (del programa). Clase: definiciones de las propiedades y comportamiento de un tipo de objeto concreto. La instanciación es la lectura de estas definiciones y la creación de un objeto a partir de ellas. Método: algoritmo asociado a un objeto (o a una clase de objetos), cuya ejecución se desencadena tras la recepción de un "mensaje". Desde el punto de vista del comportamiento, es lo que el objeto puede hacer. Un método puede producir un cambio en las propiedades del objeto, o la generación de un "evento" con un nuevo mensaje para otro objeto del sistema. Evento: un suceso en el sistema (tal como una interacción del usuario con la máquina, o un mensaje enviado por un objeto). El sistema maneja el evento enviando el mensaje adecuado al objeto pertinente. También se puede definir como evento, a la reacción que puede desencadenar un objeto, es decir la acción que genera. Mensaje: una comunicación dirigida a un objeto, que le ordena que ejecute uno de sus métodos con ciertos parámetros asociados al evento que lo generó. Propiedad o atributo: contenedor de un tipo de datos asociados a un objeto (o a una clase de objetos), que hace los datos visibles desde fuera del objeto, y cuyo valor puede ser alterado por la ejecución de algún método. Estado interno: es una propiedad invisible de los objetos, que puede ser únicamente accedida y alterada por un método del objeto, y que se utiliza para indicar distintas situaciones posibles para el objeto (o clase de objetos). Componentes de un objeto: atributos, identidad, relaciones y métodos. Representación de un objeto: un objeto se representa por medio de una tabla o entidad que está compuesta por sus atributos y funciones correspondientes. 10 INSTITUTO TECNOLÓGICO SUPERIOR DE LA SIERRA NORTE DE PUEBLA Ingeniería Informática. Fundamentos de Programación. En comparación con un lenguaje imperativo, una "variable", no es más que un contenedor interno del atributo del objeto o de un estado interno, así como la "función" es un procedimiento interno del método del objeto. Lenguajes orientados a objetos. Entre los lenguajes orientados a objetos destacan los siguientes: Action Script 3. Ada. C++. C#. VB.Net. Visual FoxPro. Clarion. Builder C++. Delphi. Harbour. Eiffel. Java. Léxico (en castellano). Objective-C. Ocaml. Oz. Perl (soporta herencia múltiple). PHP (en su versión 5). PowerBuilder. Python. Ruby. Smalltalk. Magik (SmallWorld). Muchos de estos lenguajes de programación no son puramente orientados a objetos, sino que son híbridos que combinan la POO con otros paradigmas. Al igual que C++ otros lenguajes, como OOCOBOL, OOLISP, OOPROLOG y Object REXX, han sido creados añadiendo extensiones orientadas a objetos a un lenguaje de programación clásico. Un nuevo paso en la abstracción de paradigmas de programación es la Programación Orientada a Aspectos (POA). Aunque es todavía una metodología en estado de maduración, cada vez atrae a más investigadores e incluso proyectos comerciales en todo el mundo. 11 INSTITUTO TECNOLÓGICO SUPERIOR DE LA SIERRA NORTE DE PUEBLA Ingeniería Informática. Fundamentos de Programación. También es necesario recalcar que en la programación orientada a objetos es factible de utilizar JavaScript. 1. 5 Metodología para la solución de problemas mediante el enfoque estructurado y el orientado a objetos. Metodología para la Solución de Problemas por medio de Computadoras. Hoy en día, las computadoras están presentes no sólo en ambientes específicos a los que sólo unos pocos tienen acceso, sino que también en muchos hogares se puede encontrar una. Esto hace que, con el paso de los días, más y más personas se interesen por desarrollar aplicaciones que corran en computadoras con el simple objetivo de solucionar problemas, tanto de negocios como cotidianos. La tarea del programador es indicarle a la computadora un conjunto de instrucciones para que ella solucione un problema. El idioma que el programador utiliza para indicarle todo esto a una computadora es lo que se conoce como lenguaje de programación. Para resolver un problema mediante una computadora, se suelen seguir ciertos pasos, que son parte de una metodología. Los más importantes son listados a continuación: Análisis del problema. Construcción de un algoritmo mediante un diagrama de flujo y pseudocódigo. Codificación del algoritmo. Pruebas, ajustes y documentación. Los pasos de la metodología son más, pero, para centrarse en los más importantes, sólo se explicaran los recién mencionados. Análisis del problema. La primera etapa de la metodología para resolver un problema mediante una computadora es el análisis. Esta etapa se basa en recolectar y analizar información que permita identificar tres componentes básicos: los datos de entrada, los de salida deseables y un proceso que permita obtener dichos datos de salida, ver la siguiente figura. 12 INSTITUTO TECNOLÓGICO SUPERIOR DE LA SIERRA NORTE DE PUEBLA Ingeniería Informática. Fundamentos de Programación. Figura 1.6 Componentes de la etapa de análisis de un problema. Los datos de entrada son los datos que se ingresarán de alguna forma o mediante algún método en el programa. Éstos pueden ser desde una lista de alumnos de una facultad, hasta un archivo binario con información codificada que contiene los saldos de cuentas bancarias. Los datos de salida son aquellos que resultan de aplicar el algoritmo, y constituyen el objetivo de todo el proceso. Éstos pueden no ser datos propiamente dichos, sino el resultado de aplicar un proceso específico a los datos de entrada. Algunos ejemplos, pueden ser: un listado de los clientes morosos de un club deportivo, el ordenamiento de alguna estructura de datos determinada, u operaciones matemáticas, como por ejemplo: la obtención del factorial de un determinado número. Si se analiza un problema determinado y se identifica que es necesario listar los clientes que deban más de dos cuotas de su crédito, un proceso que se puede aplicar para resolver dicho problema es una simple búsqueda en que la condición de filtro sea “que deba más de dos cuotas”. Entonces, en esta etapa de la metodología se deben analizar los posibles procesos que permitan llegar a la solución del problema. De acuerdo con la complejidad del problema, existirá uno o más. Construcción de un algoritmo. La siguiente etapa de la metodología es el diseño y la construcción del algoritmo que permitirá obtener el resultado deseado. Cuando se analiza el problema, se determina qué se debía hacer para llegar a los objetivos buscados, y ahora, en la etapa del diseño del algoritmo, se debe determinar cómo se llevará a cabo esto. Una recomendación a esta altura de la metodología es dividir el proceso en tareas más sencillas y más fáciles de implementar (para más detalles consultar la sección Técnicas de diseño de programas dentro del presente documento). Por ejemplo, si se quieren imprimir las facturas de los clientes que pagaron el último mes, se pueden definir dos tareas específicas: la primera generar las facturas en alguna estructura de datos acorde con la información requerida, y la segunda recorrer las estructuras e imprimirlas. Así, el proceso central, que era obtener las facturas de los clientes, se dividió en dos tareas más sencillas e independientes entre sí: por un lado, generar las facturas, y por otro, imprimirlas. 13 INSTITUTO TECNOLÓGICO SUPERIOR DE LA SIERRA NORTE DE PUEBLA Ingeniería Informática. Fundamentos de Programación. Una vez determinadas las tareas o los módulos que componen el algoritmo, lo que se debe hacer es escribirlo utilizando tanto diagramas de flujo como pseudocódigo. Cualquiera de estas dos herramientas son válidas para crear algoritmos; se puede usar una u otra, o bien ambas. En la práctica, solían usarse más los diagramas de flujo, pero últimamente se está utilizando con más frecuencia el pseudocódigo. Con la experiencia, esta etapa se suele saltar, y se escribe el algoritmo directamente en algún lenguaje de programación. Pero lo recomendable en todo momento es no dejar estos diagramas (o el pseudocódigo) a un lado, porque constituyen una fuente muy importante en la documentación del sistema que se está desarrollando. Pero ¿qué son un diagrama de flujo y el pseudocódigo? Bueno, en los siguientes párrafos se explica un poco mejor cada uno de ellos. Diagramas de flujo. Son un esquema para representar gráficamente un algoritmo. Los diagramas de flujo sirven para indicar cómo es el flujo de ejecución de las acciones que debe realizar el programa, más allá del lenguaje de programación que se utilice. Existen diversas formas de hacerlos, pero se han fijado algunas pautas generales para este tipo de diagramas. A continuación, en la Tabla 1 se puede apreciar cada una de las figuras que se utilizan en un diagrama de flujo, y también una breve descripción. 14 INSTITUTO TECNOLÓGICO SUPERIOR DE LA SIERRA NORTE DE PUEBLA Ingeniería Informática. Fundamentos de Programación. Tabla 1.1 Figuras básicas para crear un diagrama de flujo. Ahora se muestra un pequeño ejemplo de un diagrama de flujo que incrementa un número de uno en uno hasta llegar a 100, y va mostrando dicho número en cada iteración. Este ejemplo se muestra en la Figura 1.4. 15 INSTITUTO TECNOLÓGICO SUPERIOR DE LA SIERRA NORTE DE PUEBLA Ingeniería Informática. Fundamentos de Programación. Figura 1.7 Simple ejemplo de un diagrama de flujo. Los diagramas de flujo suelen estar acompañados de pseudocódigo, pero no siempre es así. Para empezar a programar es recomendable tenerlos en cuenta, porque son de gran utilidad, ya que fijan muchos conceptos. Pseudocódigo. El pseudocódigo es otra forma de diagramar algoritmos o, mejor dicho, especificar las acciones que debe ejecutar un programa. La forma de hacerlo es mediante un lenguaje muy sencillo y similar al nuestro. La idea es ir escribiendo con palabras sencillas las acciones que debe seguir el programa para alcanzar los objetivos. Por ejemplo, si se escribiese el pseudocódigo del programa que se muestra en el diagrama de flujo de la Figura 1.4. 16 INSTITUTO TECNOLÓGICO SUPERIOR DE LA SIERRA NORTE DE PUEBLA Ingeniería Informática. Fundamentos de Programación. Figura 1.8 Ejemplo de pseudocódigo. Como se puede apreciar en el ejemplo anterior, escribir un programa en pseudocódigo es muy sencillo. Esto se puede hacer antes o después de realizar el diagrama de flujo. Es más, uno se puede basar en el otro para realizarlo. Con la práctica teniendo uno, el otro sale como si fuese una traducción. Codificación del algoritmo. La etapa siguiente a la construcción del algoritmo es su codificación. En este punto de la metodología es donde se puede optar por infinidad de alternativas, dado que existen miles y miles de lenguajes de programación para crear programas. Algunos se adaptan más que otros a determinadas necesidades, todo depende de lo que se desee hacer. Pruebas, ajustes y documentación. Una vez escrito el algoritmo, no termina la labor como programador. Falta probar que todo funcione bien y, en el caso de que esto no sea así, realizar los ajustes necesarios para el correcto funcionamiento del programa. En esta etapa es donde se profundizan tareas como la depuración, una técnica para encontrar errores y seguir la ejecución de un programa paso a paso. Por último, cuando se tiene la aplicación funcionando correctamente, se debe documentar todo. Lo importante de esto es que, muchas veces, se debe retocar código fuente antiguo, o que hace mucho que no se consulta, y no se recuerda qué es lo que hacía dicho programa. Cuando son muchas líneas de código y las tareas del programa no son sencillas, costará mucho tener que leer de nuevo todo el código para entenderlo. 17 INSTITUTO TECNOLÓGICO SUPERIOR DE LA SIERRA NORTE DE PUEBLA Ingeniería Informática. Fundamentos de Programación. Por lo tanto, es recomendable comentar el código: dejar escrito, en un archivo o en un soporte de papel, un diagrama de flujo o pseudocódigo del programa, de modo que se pueda analizar la aplicación más rápidamente. La documentación también incluye, si es necesario, los manuales de usuario. Estos documentos son instrucciones acerca de cómo se debe usar la aplicación en caso de que deba utilizarla una persona que no conoce de programación Técnicas de Diseño de Programas. Existen en la programación varias metodologías para el diseño de software. Algunas de ellas, como la de programación monolítica, han demostrado ser contraproducentes para el desarrollo de software a gran escala y han sido reemplazadas por nuevas propuestas, más versátiles y eficientes. Otras en cambio siguen vigentes bajo nuevas formas de expresión y filosofías de programación, tal es el caso de la programación modular y su aplicación en la Programación Orientada a Objetos. Enfoque Monolítico o Programación No Estructurada. Este era el método de diseño de facto en los primeros días de la programación, cuando no existían grandes adelantos en la teoría de desarrollo de software, y es la forma como se empieza a aprender a programar. Consiste en organizar secuencialmente bloques de instrucciones y llamadas a otros bloques según la lógica de solución del problema, accesando y modificando datos globales a todo el programa. Aquí, el uso de instrucciones de salto condicionales e incondicionales para llamar a ejecución a un bloque de instrucciones y su correspondiente retorno al punto de llamada era la norma. A este estilo de codificación (más bien al código resultante) se le denomina espaguetti. Figura 1.9 Programación No Estructurada. El código completo del programa opera directamente sobre datos globales. 18 INSTITUTO TECNOLÓGICO SUPERIOR DE LA SIERRA NORTE DE PUEBLA Ingeniería Informática. Fundamentos de Programación. Muchos lenguajes de programación no ofrecen mecanismos para el diseño estructurado de programas y la única forma posible de desarrollo de software es haciendo uso de las instrucciones de salto (p. ej. Ensamblador, COBOL y BASIC). Por otro lado, los lenguajes modernos que proveen instrucciones de salto como herramientas alternativas o por compatibilidad con versiones previas tienen una amplia base de usuarios que continua creando código espagueti, aun cuando, el lenguaje ofrece mecanismos para la programación estructurada. En particular usuarios del popular Visual Basic, en su mayoría ex usuarios de COBOL y Clipper, abusan de las instrucciones de salto en las aplicaciones puesto que ese fue el modo en que aprendieron a programar, lo que incide directamente en la lectura, prueba, depuración y mantenimiento del código. Con el advenimiento de las modernas técnicas de programación este método de programación se volvió obsoleto, y en la actualidad apenas es utilizado en la programación de drivers (manejadores de dispositivos) y chips de ROM, el llamado firmware. Esta técnica de programación ofrece tremendas desventajas una vez que el programa se hace suficientemente grande. Por ejemplo, si la misma secuencia de instrucciones se necesita en diferentes situaciones dentro del programa, la secuencia debe ser repetida. Esto ha conducido a la idea de extraer estas secuencias, darles un nombre y ofrecer una técnica para llamarlas y regresar desde estos procedimientos. Programación Procedimental (Estructurada). Es una de las más importantes técnicas de programación jamás inventada. Es uno de los métodos de diseño más flexibles y potentes para mejorar la productividad en la programación. Se fundamenta en una serie de descomposiciones sucesivas del problema inicial, y está inspirado en la técnica "Divide y Vencerás" que usaba el conquistador Alejandro Magno para derrotar a sus enemigos. Su utilización tiene muchos beneficios, entre los que se encuentran la facilidad en la escritura, lectura y comprensión de los programas y el permitir ahorrar espacio que de otro modo estaría ocupado por código duplicado. Con la programación procedimental se pueden combinar las secuencias de instrucciones repetibles en un solo lugar. Una llamada de procedimiento se utiliza para invocar al procedimiento. Después de que la secuencia es procesada, el flujo de control regresa al punto de llamada para proseguir con la ejecución de la instrucción ubicada inmediatamente después de la que hizo la llamada. 19 INSTITUTO TECNOLÓGICO SUPERIOR DE LA SIERRA NORTE DE PUEBLA Ingeniería Informática. Fundamentos de Programación. Figura 1.10 Programación Procedimental. El código completo del programa opera directamente sobre datos globales. Al introducir parámetros así como procedimientos de procedimientos (subprocedimientos) los programas ahora pueden ser escritos en forma más estructurada y libre de errores. Por ejemplo, si un procedimiento ya es correcto, cada vez que es usado produce resultados correctos. Por consecuencia, en caso de errores, se puede reducir la búsqueda a aquellos lugares que todavía no han sido revisados. De este modo, un programa puede ser visto como una secuencia de llamadas a procedimientos. El programa principal es responsable de pasar los datos a las llamadas individuales y actúa como un director, los datos son procesados por los procedimientos y, una vez que el programa ha terminado, los datos resultantes son presentados. Así, el flujo de datos puede ser ilustrado como 20 INSTITUTO TECNOLÓGICO SUPERIOR DE LA SIERRA NORTE DE PUEBLA Ingeniería Informática. Fundamentos de Programación. una gráfica jerárquica, un árbol, como se muestra en la siguiente Figura para un programa sin subprocedimientos. Figura 1.11 Programación Procedimental. El programa principal coordina las llamadas a procedimientos y pasa los datos apropiados en forma de parámetros. Con esta metodología el programa se divide en partes independientes, cada una de las cuales ejecuta una única actividad o tarea y se codifican independientemente de los demás. Cada una de ellas se analiza, codifica y pone a punto por separado. Siguiendo un método ascendente o descendente de desarrollo se llegará a la descomposición final del problema en módulos en forma jerárquica. Las descomposiciones resultantes reciben luego el refinamiento progresivo del repertorio de instrucciones que van a formar parte de cada pieza del programa. Si la tarea asignada a cada procedimiento es demasiado compleja, éste deberá descomponerse en otros procedimientos más pequeños. Este proceso de subdivisión sucesiva continúa hasta que cada procedimiento tenga solamente una tarea específica que realizar. Esta tarea puede ser entrada, salida, procesamiento de datos, control de otros procedimientos o una combinación de estos. Un procedimiento puede transferir temporalmente el control (bifurcación) a otro. Sin embargo, cada procedimiento debe eventualmente devolver el control al procedimiento del que lo recibió. Los procedimientos son independientes en el sentido de que ninguno puede tener acceso directo a otro, excepto al módulo al que llama y a sus propios submódulos. No obstante, los resultados producidos por un procedimiento pueden ser utilizados por cualquier otro cuando se transfiera el control a ellos. 21 INSTITUTO TECNOLÓGICO SUPERIOR DE LA SIERRA NORTE DE PUEBLA Ingeniería Informática. Fundamentos de Programación. Dado que los procedimientos son independientes, diferentes programadores pueden trabajar simultáneamente en diferentes partes del mismo programa. Esto reducirá el tiempo de diseño del algoritmo y la posterior codificación. Además un procedimiento se puede modificar radicalmente sin afectar a los demás, incluso sin alterar su función principal. Resumiendo: se tiene ahora un programa único dividido en pequeñas piezas llamadas procedimientos que interactúan entre sí, fácilmente comprensible, modificable y flexible. Para posibilitar el uso de procedimientos generales o grupos de procedimientos también en otros programas, aquéllos deben estar disponibles en forma separada. Por esa razón, la programación modular permite el agrupamiento de procedimientos dentro de módulos. Programación Modular. La programación modular es una generalización de la programación procedimental. Aquí los procedimientos con una funcionalidad común son agrupados en módulos separados. Un programa por consiguiente, ya no consiste solamente de una sección. Ahora está dividido en varias secciones más pequeñas que interactúan a través de llamadas a procedimientos y que integran el programa en su totalidad. Figura 1.12 Programación Modular. 22 INSTITUTO TECNOLÓGICO SUPERIOR DE LA SIERRA NORTE DE PUEBLA Ingeniería Informática. Fundamentos de Programación. El programa principal coordina las llamadas a procedimientos en módulos separados y pasa los datos apropiados en forma de parámetros. Cada módulo puede contener sus propios datos. Esto permite que cada módulo maneje un estado interno que es modificado por las llamadas a procedimientos de ese módulo. Sin embargo, solamente hay un estado por módulo y cada módulo existe cuando más una vez en todo el programa. Técnicas de Diseño Modular. Las siguientes técnicas se derivan directamente de la Programación Modular. Método Descendente (Top-Down). También conocido como de arriba a abajo consiste en establecer una serie de niveles de mayor a menor complejidad que den solución al problema. Luego se crea una relación entre las etapas de la estructuración de forma que una etapa jerárquica y su inmediato inferior se relacionen mediante una interfaz claramente definida de entradas y salidas de información. El Top-Down es muy popular por ser metodológico para la enseñanza de la programación, por favorecer la rápida creación de una estructura de diseño inicial flexible y fácil de comprender y por ser muy útil en la solución de problemas complejos. Método Ascendente (Bottom-Up). El diseño ascendente se refiere a la identificación de aquellos procesos que necesitan computarizarse conforme vayan apareciendo, su análisis como sistema y su codificación, o bien, la adquisición de paquetes de software para satisfacer el problema inmediato. Cuando la programación se realiza internamente y se hace un enfoque ascendente, es difícil llegar a integrar los subsistemas al grado tal de que el desempeño global sea fluido. Los problemas de integración entre los subsistemas son sumamente costosos, y muchos de ellos no se solucionan hasta que la programación alcanza la fecha límite para la integración total del sistema. En esta fecha, ya se cuenta con muy poco tiempo, presupuesto o paciencia de los usuarios, como para corregir aquellas delicadas interfaces, que en un principio, se ignoran. Aunque cada subsistema parece ofrecer lo que se requiere, cuando se contempla al sistema como una entidad global, éste padece de ciertas limitaciones por haber tomado un enfoque ascendente. Una de ellas es la duplicación de esfuerzos para accesar al software y más aún al introducir los datos. Otro es que se introducen al sistema muchos datos carentes de valor. Un tercero y tal vez el más serio inconveniente del enfoque ascendente, es que los objetivos globales de la organización 23 INSTITUTO TECNOLÓGICO SUPERIOR DE LA SIERRA NORTE DE PUEBLA Ingeniería Informática. Fundamentos de Programación. no fueron considerados y en consecuencia no se satisfacen. Sobra decir que esta técnica de diseño es la menos usada por sus múltiples inconvenientes. Otras Técnicas de Diseño. Las siguientes técnicas de diseño pueden conjugarse con las técnicas de diseño modular antes mencionadas, tanto para el diseño de los módulos como para estructurar la rutina principal del programa. Método de la Línea Recta. Este método es excelente para diseñar programas pequeños, programas complejos o para utilizarse como complemento a la modularización. Consiste en estructurar el flujo del programa para el caso de la solución más simple y fácil del problema, sin tomar en cuenta casos especiales, validaciones ni decisiones que provoquen bifurcaciones. De esta manera se construye un diseño inicial fácil de comprender y verificar. Una vez completado este diseño inicial y comprobada su correctitud, se procede a agregar por pasos las rutas alternas que representan las diferentes condiciones del planteamiento, lo cual significa añadir flujos de control adicionales y se prueba iterativamente el programa con cada nueva bifurcación que se añada para asegurar que se mantiene la correctitud. Cuando todas las condiciones se han integrado al diseño, se proceden a agregar uno a uno los casos especiales que se espera maneje el programa, probando también cada nueva adición para continuar garantizando la fiabilidad de la estructura. Por último se añaden las validaciones a los datos de entrada, las de los datos intermedios producidos en lo interno para utilizarse en la generación de los datos de salida, y los datos de salida mismos. Estas validaciones se integran también de manera incremental, procurando no alterar el estado del diseño alcanzado en las operaciones anteriores. Al final de todo este proceso se obtendrá un diseño final completo, confiable y seguro. Aunque el método implica tiempo y esfuerzo adicional, es muy adecuado para principiantes y para la solución de problemas complejos que requieran un diseño fino y bien organizado. Enfoque E-P-S. Este enfoque se fundamenta en el método de diseño Top-Down. Con este enfoque el programa se divide en 3 módulos bien diferenciados: el de Entrada, el de Procesamiento y el de Salida. De ahí su nombre. Todos los módulos se desarrollan y prueban de manera independiente, lo que permite al programador concentrarse en las funciones específicas de cada uno y evitar la carga mental de pensar en la solución total del problema y la ofuscación en el diseño e implementación del programa completo. 24 INSTITUTO TECNOLÓGICO SUPERIOR DE LA SIERRA NORTE DE PUEBLA Ingeniería Informática. Fundamentos de Programación. Programación Orientada a Objetos (POO). En contraste con las anteriores técnicas de programación, ahora tenemos una telaraña de objetos interactuando, cada uno de los cuáles mantiene su propio estado al interactuar con los demás mediante mensajes. Figura 1.13: Programación Orientada a Objetos. Los objetos del programa interactúan mandando mensajes unos a otros. La POO resuelve problemas importantes de la programación modular. Entre ellos tenemos los siguientes: Ahora los datos no deben crearse y destruirse explícitamente, sino de manera automática. Los datos y las operaciones no están desacoplados, conduciendo a una estructura centrada en los datos en lugar de centrada en los procedimientos (o los algoritmos). Mayor protección y seguridad de los datos y operaciones de los objetos, tanto de accesos externos como internos. 25 INSTITUTO TECNOLÓGICO SUPERIOR DE LA SIERRA NORTE DE PUEBLA Ingeniería Informática. Fundamentos de Programación. Aunque aparentemente la POO parece una técnica más elegante de programación modular, no lo es. Sus características adicionales particulares a la orientación a objetos hacen de la POO una técnica novedosa de programación, aplicable a problemas y entornos específicos. 26 INSTITUTO TECNOLÓGICO SUPERIOR DE LA SIERRA NORTE DE PUEBLA Ingeniería Informática. Fundamentos de Programación. Referencias: J. F. Díaz, Técnicas de Diseño de Programas, 2010. [en línea]: http://www.galeon.com/neoprogramadores/t_dis_sw.htm Consultado: 22 de Julio de 2010. Urbaez Wilder, Metodología para la solución de un problema mediante un ordenador, 2010. [en línea]: http://www.desarrolloweb.com/articulos/2144.php Consultado: 23 de Julio de 2010. Pedraza C., Pascual D., Programación OO vs Programación clásica, Universidad Politécnica de Valencia, 2010. [en línea]: http://users.dsic.upv.es/asignaturas/facultad/lsi/trabajos/022000.doc Consultado: 23 de Julio de 2010. Kioskea Networks, Lenguaje de programación, Kioskea.net, 16 de octubre de 2008. [en línea]: http://es.kioskea.net/contents/langages/langages.php3, Consultado: 23 de Julio de 2010. Wikipedia, Programación orientada a objetos, Wikipedia.org, 27 de Julio de 2010. [en línea]: http://es.wikipedia.org/wiki/Programaci%C3%B3n_orientada_a_objetos, Consultado: 19 de Julio de 2010. Wikipedia, Programación estructurada, Wikipedia.org, 20 de Julio de 2010. [en línea]: http://es.wikipedia.org/wiki/Programaci%C3%B3n_estructurada, Consultado: 20 de Julio de 2010. Wikipedia, Paradigma de programación, Wikipedia.org, 29 de Junio de 2010. [en línea]: http://es.wikipedia.org/wiki/Paradigma_de_programaci%C3%B3n, Consultado: 21 de Julio de 2010. 27